diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index cc5fa99..3e04db5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,7 +34,7 @@ jobs: JBZOO_COMPOSER_UPDATE_FLAGS: ${{ matrix.composer_flags }} strategy: matrix: - php-version: [ 8.1, 8.2 ] + php-version: [ 8.1, 8.2, 8.3 ] coverage: [ xdebug, none ] composer_flags: [ "--prefer-lowest", "" ] steps: @@ -77,7 +77,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php-version: [ 8.1, 8.2 ] + php-version: [ 8.1, 8.2, 8.3 ] steps: - name: Checkout code uses: actions/checkout@v3 @@ -111,7 +111,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php-version: [ 8.1, 8.2 ] + php-version: [ 8.1, 8.2, 8.3 ] steps: - name: Checkout code uses: actions/checkout@v3 diff --git a/composer.json b/composer.json index 727b5f1..b21a69b 100644 --- a/composer.json +++ b/composer.json @@ -56,9 +56,9 @@ }, "require-dev" : { - "jbzoo/toolbox-dev" : "^7.0", - "jbzoo/data" : "^7.0", - "symfony/process" : ">=4.4" + "jbzoo/toolbox-dev" : "^7.1", + "jbzoo/data" : "^7.1", + "symfony/process" : ">=6.4" }, "suggest" : { diff --git a/src/Dates.php b/src/Dates.php index 65b5bfa..5128fe5 100644 --- a/src/Dates.php +++ b/src/Dates.php @@ -74,9 +74,9 @@ public static function timezone(null|\DateTimeZone|string $timezone = null): \Da return $timezone; } - $timezone = isStrEmpty($timezone) ? \date_default_timezone_get() : $timezone; + $timezone = ($timezone === '' || $timezone === null) ? \date_default_timezone_get() : $timezone; - return new \DateTimeZone((string)$timezone); + return new \DateTimeZone($timezone); } /** diff --git a/src/Filter.php b/src/Filter.php index 901b975..30b3a29 100644 --- a/src/Filter.php +++ b/src/Filter.php @@ -190,6 +190,9 @@ public static function digits(?string $value): string // we need to remove - and + because they're allowed in the filter $cleaned = \str_replace(['-', '+'], '', (string)$value); + /** + * @psalm-suppress RedundantCast + */ return (string)\filter_var($cleaned, \FILTER_SANITIZE_NUMBER_INT); } diff --git a/src/Http.php b/src/Http.php index 5f2dfa7..962a088 100644 --- a/src/Http.php +++ b/src/Http.php @@ -145,7 +145,8 @@ public static function getHeaders(): array $authorizationHeader = $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; } - if ($authorizationHeader) { + if (bool($authorizationHeader)) { + $authorizationHeader = (string)$authorizationHeader; if (\stripos($authorizationHeader, 'basic ') === 0) { // Decode AUTHORIZATION header into PHP_AUTH_USER // and PHP_AUTH_PW when authorization header is basic diff --git a/src/Stats.php b/src/Stats.php index 832211b..2e0d356 100644 --- a/src/Stats.php +++ b/src/Stats.php @@ -60,6 +60,9 @@ public static function mean(?array $values): float return 0; } + \array_walk($values, static function (null|float|int|string &$value): void { + $value = float($value); + }); $sum = \array_sum($values); if ($sum === 0) { @@ -148,8 +151,8 @@ public static function histogram( */ public static function renderAverage(array $values, int $rounding = 3): string { - $avg = \number_format(self::mean($values), $rounding); - $stdDev = \number_format(self::stdDev($values), $rounding); + $avg = \number_format(\round(self::mean($values), $rounding), $rounding); + $stdDev = \number_format(\round(self::stdDev($values), $rounding), $rounding); return "{$avg}±{$stdDev}"; } @@ -159,10 +162,10 @@ public static function renderAverage(array $values, int $rounding = 3): string */ public static function renderMedian(array $values, int $rounding = 3): string { - $avg = \number_format(self::median($values), $rounding); - $stdDev = \number_format(self::stdDev($values), $rounding); + $median = \number_format(\round(self::median($values), $rounding), $rounding); + $stdDev = \number_format(\round(self::stdDev($values), $rounding), $rounding); - return "{$avg}±{$stdDev}"; + return "{$median}±{$stdDev}"; } /** diff --git a/src/Url.php b/src/Url.php index 6a4362e..ded878c 100644 --- a/src/Url.php +++ b/src/Url.php @@ -127,7 +127,8 @@ public static function path(): ?string // Get the rest of the URL if (!\array_key_exists('REQUEST_URI', $_SERVER)) { // Microsoft IIS doesn't set REQUEST_URI by default - if ($queryString = $_SERVER['QUERY_STRING'] ?? null) { + $queryString = $_SERVER['QUERY_STRING'] ?? null; + if ($queryString !== null) { $url .= '?' . $queryString; } } else { diff --git a/tests/SerTest.php b/tests/SerTest.php index b80fcaf..96d92bd 100644 --- a/tests/SerTest.php +++ b/tests/SerTest.php @@ -120,7 +120,6 @@ public function testFix(): void \unserialize($brokenSerialization, []); - is($expectedError['errno'], $reportedError['errno']); // Because HHVM's unserialize() error message does not contain enough info to properly test. if (!\defined('HHVM_VERSION')) { is($expectedError['errstr'], $reportedError['errstr']); diff --git a/tests/StatsTest.php b/tests/StatsTest.php index a795cf9..68b498a 100644 --- a/tests/StatsTest.php +++ b/tests/StatsTest.php @@ -31,6 +31,8 @@ public function testMean(): void isSame(2.0, Stats::mean([1, 3])); isSame(2.0, Stats::mean(['1', 3])); isSame(2.25, Stats::mean(['1.5', 3])); + isSame(5.5, Stats::mean([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])); + isSame(5.5, Stats::mean(['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'])); $data = [72, 57, 66, 92, 32, 17, 146]; isSame(68.857142857, Stats::mean($data)); @@ -84,21 +86,34 @@ public function testHistogram(): void isSame(['2' => 0], Stats::histogram([1, 2, 1], 5, 2, 2)); } + public function testRenderAverageEmpty(): void + { + isSame('0.000±0.000', Stats::renderAverage([])); + } + public function testRenderAverage(): void { $data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; isSame('5.500±2.872', Stats::renderAverage($data)); - isSame('5.5±2.9', Stats::renderAverage($data, 1)); + isSame('5.5000±2.8723', Stats::renderAverage($data, 4)); + isSame('5.500±2.872', Stats::renderAverage($data, 3)); isSame('5.50±2.87', Stats::renderAverage($data, 2)); + isSame('5.5±2.9', Stats::renderAverage($data, 1)); isSame('6±3', Stats::renderAverage($data, 0)); - isSame('6±3', Stats::renderAverage($data, -1)); + isSame('10±0', Stats::renderAverage($data, -1)); $data = [72, 57, 66, 92, 32, 17, 146]; isSame('68.857±39.084', Stats::renderAverage($data)); isSame('68.9±39.1', Stats::renderAverage($data, 1)); isSame('68.86±39.08', Stats::renderAverage($data, 2)); isSame('69±39', Stats::renderAverage($data, 0)); - isSame('69±39', Stats::renderAverage($data, -1)); + isSame('70±40', Stats::renderAverage($data, -1)); + isSame('100±0', Stats::renderAverage($data, -2)); + } + + public function testRenderMedianEmpty(): void + { + isSame('0.000±0.000', Stats::renderMedian([])); } public function testRenderMedian(): void @@ -108,14 +123,15 @@ public function testRenderMedian(): void isSame('5.5±2.9', Stats::renderMedian($data, 1)); isSame('5.50±2.87', Stats::renderMedian($data, 2)); isSame('6±3', Stats::renderMedian($data, 0)); - isSame('6±3', Stats::renderMedian($data, -1)); + isSame('10±0', Stats::renderMedian($data, -1)); $data = [72, 57, 66, 92, 32, 17, 146]; isSame('66.000±39.084', Stats::renderMedian($data)); isSame('66.0±39.1', Stats::renderMedian($data, 1)); isSame('66.00±39.08', Stats::renderMedian($data, 2)); isSame('66±39', Stats::renderMedian($data, 0)); - isSame('66±39', Stats::renderMedian($data, -1)); + isSame('70±40', Stats::renderMedian($data, -1)); + isSame('100±0', Stats::renderMedian($data, -2)); } public function testPercentile(): void