1 / 0)->toThrow(DivisionByZeroError::class); }); test('the average is guarded before it divides', function () use ($src) { expect($src)->not->toContain("/ (\$host['total_polls'] - \$host['failed_polls'])"); expect($src)->toContain("\$successful_polls = \$host['total_polls'] - \$host['failed_polls'];") ->toContain('if ($successful_polls > 0) {'); }); test('the guarded average still matches the original formula', function () { /* the rewrite has to be arithmetic-neutral for every input that already worked, so compare it against the expression it replaced */ $original = function (int $total, int $failed, float $avg, float $ping) : float { return (($total - 1 - $failed) * $avg + $ping) / ($total - $failed); }; $guarded = function (int $total, int $failed, float $avg, float $ping) : float { $successful = $total - $failed; if ($successful > 0) { return (($successful - 1) * $avg + $ping) / $successful; } return $ping; }; foreach ([[1, 0, 0.0, 12.5], [2, 0, 12.5, 7.5], [10, 3, 20.0, 5.0], [500, 499, 3.0, 9.0]] as $case) { [$total, $failed, $avg, $ping] = $case; expect($guarded($total, $failed, $avg, $ping))->toBe($original($total, $failed, $avg, $ping)); } }); test('inconsistent counters fall back to the sample instead of dividing', function () { $guarded = function (int $total, int $failed, float $avg, float $ping) : float { $successful = $total - $failed; if ($successful > 0) { return (($successful - 1) * $avg + $ping) / $successful; } return $ping; }; // failed_polls ahead of total_polls is the shape that used to be fatal expect($guarded(1, 1, 4.0, 9.0))->toBe(9.0) ->and($guarded(1, 5, 4.0, 9.0))->toBe(9.0); }); test('a failed write cannot be used as a parse offset', function () use ($src) { $write = strpos($src, '$requestsize = @fwrite($handle, $data);'); $guard = strpos($src, 'if ($requestsize === false) {'); $parse = strpos($src, "@unpack('s', substr(\$response, \$requestsize + 2))"); expect($write)->not->toBeFalse() ->and($guard)->not->toBeFalse() ->and($parse)->not->toBeFalse(); // the guard has to sit between the write and the offset arithmetic expect($guard)->toBeGreaterThan($write) ->and($guard)->toBeLessThan($parse); });