[
{"name": "four replies: mean 11500, p95 is the largest of four (rank ceil 3.8 = 4), jitter (2000+1000+2000)/3 = 1666.67 rounds to 1667", "args": [[10000, 12000, 11000, 13000]], "expect": {"sent": 4, "received": 4, "lost": 0, "lossBasisPoints": 0, "minUs": 10000, "avgUs": 11500, "maxUs": 13000, "p95Us": 13000, "jitterUs": 1667}},
{"name": "one of four lost is 25.00% loss; jitter skips the lost probe: (2000+1000)/2 = 1500", "args": [[1000, null, 3000, 2000]], "expect": {"sent": 4, "received": 3, "lost": 1, "lossBasisPoints": 2500, "minUs": 1000, "avgUs": 2000, "maxUs": 3000, "p95Us": 3000, "jitterUs": 1500}},
{"name": "every probe lost: 100% loss and no latency figures", "args": [[null, null, null]], "expect": {"sent": 3, "received": 0, "lost": 3, "lossBasisPoints": 10000, "minUs": null, "avgUs": null, "maxUs": null, "p95Us": null, "jitterUs": null}},
{"name": "a single reply has no jitter", "args": [[500]], "expect": {"sent": 1, "received": 1, "lost": 0, "lossBasisPoints": 0, "minUs": 500, "avgUs": 500, "maxUs": 500, "p95Us": 500, "jitterUs": null}},
{"name": "one of three lost is 3333.33 bp, rounded down to 3333", "args": [[100, null, 200]], "expect": {"sent": 3, "received": 2, "lost": 1, "lossBasisPoints": 3333, "minUs": 100, "avgUs": 150, "maxUs": 200, "p95Us": 200, "jitterUs": 100}},
{"name": "two of three lost is 6666.67 bp, rounded up to 6667", "args": [[null, 700, null]], "expect": {"sent": 3, "received": 1, "lost": 2, "lossBasisPoints": 6667, "minUs": 700, "avgUs": 700, "maxUs": 700, "p95Us": 700, "jitterUs": null}},
{"name": "mean 1.5 rounds half-up to 2", "args": [[1, 2]], "expect": {"sent": 2, "received": 2, "lost": 0, "lossBasisPoints": 0, "minUs": 1, "avgUs": 2, "maxUs": 2, "p95Us": 2, "jitterUs": 1}},
{"name": "p95 of 1000..20000 is the 19th value, 19000, not the maximum", "args": [[1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 11000, 12000, 13000, 14000, 15000, 16000, 17000, 18000, 19000, 20000]], "expect": {"sent": 20, "received": 20, "lost": 0, "lossBasisPoints": 0, "minUs": 1000, "avgUs": 10500, "maxUs": 20000, "p95Us": 19000, "jitterUs": 1000}},
{"name": "jitter follows send order, not sorted order: (20+40+30)/3 = 30; mean 27.5 rounds to 28", "args": [[30, 10, 50, 20]], "expect": {"sent": 4, "received": 4, "lost": 0, "lossBasisPoints": 0, "minUs": 10, "avgUs": 28, "maxUs": 50, "p95Us": 50, "jitterUs": 30}},
{"name": "zero-microsecond replies are replies, not losses", "args": [[0, 0]], "expect": {"sent": 2, "received": 2, "lost": 0, "lossBasisPoints": 0, "minUs": 0, "avgUs": 0, "maxUs": 0, "p95Us": 0, "jitterUs": 0}},
{"name": "one of seven lost is 1428.57 bp, rounded to 1429", "args": [[null, 5, 5, 5, 5, 5, 5]], "expect": {"sent": 7, "received": 6, "lost": 1, "lossBasisPoints": 1429, "minUs": 5, "avgUs": 5, "maxUs": 5, "p95Us": 5, "jitterUs": 0}},
{"name": "jitter 0.5 rounds half-up to 1; mean 0.67 rounds to 1", "args": [[0, 1, 1]], "expect": {"sent": 3, "received": 3, "lost": 0, "lossBasisPoints": 0, "minUs": 0, "avgUs": 1, "maxUs": 1, "p95Us": 1, "jitterUs": 1}},
{"name": "an empty run is an error", "args": [[]], "expectError": "samplesUs must not be empty"},
{"name": "a negative round-trip time is an error", "args": [[5, -1]], "expectError": "samples must not be negative"},
{"name": "a fractional sample is refused, not truncated", "args": [[1.5]], "expectError": "each sample must be a whole number of microseconds or null"},
{"name": "a text sample is refused", "args": [["5"]], "expectError": "each sample must be a whole number of microseconds or null"}
]