diff --git a/composer.json b/composer.json index 1423da7..e2052d1 100644 --- a/composer.json +++ b/composer.json @@ -11,6 +11,7 @@ ], "require": { "php": "^7.4", + "ext-bcmath": "*", "symfony/polyfill": "^1.12" }, "require-dev": { diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 3335207..746074a 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -16,12 +16,15 @@ tests/Psl/Arr - - tests/Psl/Random - tests/Psl/Collection + + tests/Psl/Math + + + tests/Psl/Random + @@ -31,6 +34,12 @@ src + + src/bootstrap.php + src/Psl/internal.php + src/Psl/Str/constants.php + src/Psl/Math/constants.php + \ No newline at end of file diff --git a/src/Psl/Math/base_convert.php b/src/Psl/Math/base_convert.php index 25de988..9785fe1 100644 --- a/src/Psl/Math/base_convert.php +++ b/src/Psl/Math/base_convert.php @@ -12,25 +12,35 @@ use Psl\Str\Byte; * Converts the given string in base `$from_base` to base `$to_base`, assuming * letters a-z are used for digits for bases greater than 10. The conversion is * done to arbitrary precision. + * + * Example: + * + * Math\base_convert('10', 2, 10) + * => Str(2) + * + * Math\base_convert('5497', 10, 2) + * => Str('1010101111001') + * + * Math\base_convert('2014587925987', 10, 36) + * => Str('pphlmw9v') */ function base_convert(string $value, int $from_base, int $to_base): string { Psl\invariant('' !== $value, 'Unexpected empty string, expected number in base %d', $from_base); Psl\invariant($from_base >= 2 && $from_base <= 36, 'Expected $from_base to be between 2 and 36, got %d', $from_base); Psl\invariant($to_base >= 2 && $to_base <= 36, 'Expected $to_base to be between 2 and 36, got %d', $to_base); - Psl\invariant(true === \bcscale(0), 'Unexpected bcscale failure'); $from_alphabet = Byte\slice(Str\ALPHABET_ALPHANUMERIC, 0, $from_base); $result_decimal = '0'; /** @var string $place_value */ - $place_value = \bcpow((string) $from_base, (string) (Byte\length($value) - 1)); + $place_value = \bcpow((string)$from_base, (string)(Byte\length($value) - 1)); /** @var string $digit */ foreach (Byte\chunk($value) as $digit) { $digit_numeric = Byte\search_ci($from_alphabet, $digit); Psl\invariant(null !== $digit_numeric, 'Invalid digit %s in base %d', $digit, $from_base); - $result_decimal = \bcadd($result_decimal, \bcmul((string) $digit_numeric, $place_value)); + $result_decimal = \bcadd($result_decimal, \bcmul((string)$digit_numeric, $place_value)); /** @var string $place_value */ - $place_value = \bcdiv($place_value, (string) $from_base); + $place_value = \bcdiv($place_value, (string)$from_base); } if (10 === $to_base) { @@ -40,9 +50,9 @@ function base_convert(string $value, int $from_base, int $to_base): string $to_alphabet = Byte\slice(Str\ALPHABET_ALPHANUMERIC, 0, $to_base); $result = ''; do { - $result = $to_alphabet[(int) \bcmod($result_decimal, (string) $to_base)] . $result; + $result = $to_alphabet[(int)\bcmod($result_decimal, (string)$to_base)] . $result; /** @var string $result_decimal */ - $result_decimal = \bcdiv($result_decimal, (string) $to_base); + $result_decimal = \bcdiv($result_decimal, (string)$to_base); } while (\bccomp($result_decimal, '0') > 0); return $result; diff --git a/src/Psl/Math/ceil.php b/src/Psl/Math/ceil.php index 7304747..aa1f129 100644 --- a/src/Psl/Math/ceil.php +++ b/src/Psl/Math/ceil.php @@ -6,6 +6,17 @@ namespace Psl\Math; /** * Return the smallest integer value greater than or equal to the given number. + * + * Example: + * + * Math\ceil(5.5) + * => Float(6.0) + * + * Math\ceil(-10.0) + * => Float(-10.0) + * + * Math\ceil(-5.5) + * => Float(-5.0) */ function ceil(float $float): float { diff --git a/src/Psl/Math/constants.php b/src/Psl/Math/constants.php index ec050c7..e41e6b8 100644 --- a/src/Psl/Math/constants.php +++ b/src/Psl/Math/constants.php @@ -21,6 +21,9 @@ const UINT16_MAX = 65535; const PI = 3.141592653589793238462643; +/** + * The base of the natural system of logarithms, or approximately 2.7182818284590452353602875. + */ const E = 2.7182818284590452353602875; const INFINITY = \INF; diff --git a/src/Psl/Math/cos.php b/src/Psl/Math/cos.php index f074ccd..fa2006f 100644 --- a/src/Psl/Math/cos.php +++ b/src/Psl/Math/cos.php @@ -6,6 +6,14 @@ namespace Psl\Math; /** * Return the cosine of the given number. + * + * Example: + * + * Math\cos(0.0) + * => Float(1.0) + * + * Math\ceil(1.0) + * => Float(0.5403023058681398) */ function cos(float $num): float { diff --git a/src/Psl/Math/div.php b/src/Psl/Math/div.php index 18f1b72..8310622 100644 --- a/src/Psl/Math/div.php +++ b/src/Psl/Math/div.php @@ -7,6 +7,17 @@ namespace Psl\Math; /** * Returns the result of integer division of the given numerator by the given denominator. * + * Example: + * + * Math\div(10, 2) + * => Int(5) + * + * Math\div(5, 2) + * => Int(2) + * + * Math\div(15, 20) + * => Int(0) + * * If the denominator is 0, a DivisionByZeroError exception is thrown. * If the numerator is Math\INT64_MAX and the denominator is -1 then an ArithmeticError exception is thrown. */ diff --git a/src/Psl/Math/exp.php b/src/Psl/Math/exp.php index d2e35ca..5c2264d 100644 --- a/src/Psl/Math/exp.php +++ b/src/Psl/Math/exp.php @@ -5,7 +5,15 @@ declare(strict_types=1); namespace Psl\Math; /** - * Returns e to th power of the given number. + * Returns Math\E to the power of the given number. + * + * Example: + * + * Math\exp(12) + * => Float(162754.79141900392) + * + * Math\exp(5.7) + * => Float(298.8674009670603) */ function exp(float $num): float { diff --git a/src/Psl/Math/from_base.php b/src/Psl/Math/from_base.php index 3dd005e..0039c3e 100644 --- a/src/Psl/Math/from_base.php +++ b/src/Psl/Math/from_base.php @@ -10,6 +10,14 @@ use Psl\Str\Byte; /** * Converts the given string in the given base to an int, assuming letters a-z * are used for digits when `$from_base` > 10. + * + * Example: + * + * Math\from_base('10', 2) + * => Int(2) + * + * Math\from_base('ff', 15) + * => Int(255) */ function from_base(string $number, int $from_base): int { diff --git a/src/Psl/Math/max_by.php b/src/Psl/Math/max_by.php index 9f248d2..cca047d 100644 --- a/src/Psl/Math/max_by.php +++ b/src/Psl/Math/max_by.php @@ -4,6 +4,8 @@ declare(strict_types=1); namespace Psl\Math; +use Psl; + /** * Returns the largest element of the given iterable, or null if the * iterable is empty. @@ -24,6 +26,7 @@ function max_by(iterable $values, callable $num_func) $max_num = null; foreach ($values as $value) { $value_num = $num_func($value); + Psl\invariant(\is_numeric($value_num), 'Expected $num_func to return a numeric value, %s returned.', \gettype($value_num)); if (null === $max_num || $value_num >= $max_num) { $max = $value; $max_num = $value_num; diff --git a/tests/Psl/Math/AbsTest.php b/tests/Psl/Math/AbsTest.php index 12fb1df..e0162ab 100644 --- a/tests/Psl/Math/AbsTest.php +++ b/tests/Psl/Math/AbsTest.php @@ -5,8 +5,40 @@ declare(strict_types=1); namespace Psl\Tests\Math; use PHPUnit\Framework\TestCase; +use Psl\Math; class AbsTest extends TestCase { - // TODO: add tests. + /** + * @dataProvider provideData + */ + public function testAbs($expected, $number): void + { + self::assertSame($expected, Math\abs($number)); + } + + public function provideData(): array + { + return [ + [ + 5, + 5 + ], + + [ + 5, + -5 + ], + + [ + 5.5, + -5.5 + ], + + [ + 10.5, + 10.5 + ] + ]; + } } diff --git a/tests/Psl/Math/BaseConvertTest.php b/tests/Psl/Math/BaseConvertTest.php index ab8a0c2..387c419 100644 --- a/tests/Psl/Math/BaseConvertTest.php +++ b/tests/Psl/Math/BaseConvertTest.php @@ -5,8 +5,76 @@ declare(strict_types=1); namespace Psl\Tests\Math; use PHPUnit\Framework\TestCase; +use Psl\Math; class BaseConvertTest extends TestCase { - // TODO: add tests. + /** + * @dataProvider provideData + */ + public function testBaseConvert(string $expected, string $value, int $from, int $to): void + { + self::assertSame($expected, Math\base_convert($value, $from, $to)); + } + + public function provideData(): array + { + return [ + [ + '2', + '10', + 2, + 16 + ], + + [ + '2', + '10', + 2, + 10 + ], + + [ + 'f', + '15', + 10, + 16 + ], + + [ + '10', + '2', + 16, + 2 + ], + + [ + '1010101111001', + '5497', + 10, + 2 + ], + + [ + '48p', + '1010101111001', + 2, + 36 + ], + + [ + 'pphlmw9v', + '2014587925987', + 10, + 36 + ], + + [ + 'zik0zj', + (string) Math\INT32_MAX, + 10, + 36 + ] + ]; + } } diff --git a/tests/Psl/Math/CeilTest.php b/tests/Psl/Math/CeilTest.php index 726c934..0ef708f 100644 --- a/tests/Psl/Math/CeilTest.php +++ b/tests/Psl/Math/CeilTest.php @@ -5,8 +5,45 @@ declare(strict_types=1); namespace Psl\Tests\Math; use PHPUnit\Framework\TestCase; +use Psl\Math; class CeilTest extends TestCase { - // TODO: add tests. + /** + * @dataProvider provideData + */ + public function testCiel(float $expected, float $number): void + { + self::assertSame($expected, Math\ceil($number)); + } + + public function provideData(): array + { + return [ + [ + 5.0, + 5.0 + ], + + [ + 5.0, + 4.8 + ], + + [ + 0.0, + 0.0 + ], + + [ + 1.0, + 0.4 + ], + + [ + -6.0, + -6.5 + ] + ]; + } } diff --git a/tests/Psl/Math/CosTest.php b/tests/Psl/Math/CosTest.php index 5ad5221..8070c75 100644 --- a/tests/Psl/Math/CosTest.php +++ b/tests/Psl/Math/CosTest.php @@ -5,8 +5,45 @@ declare(strict_types=1); namespace Psl\Tests\Math; use PHPUnit\Framework\TestCase; +use Psl\Math; class CosTest extends TestCase { - // TODO: add tests. + /** + * @dataProvider provideData + */ + public function testCos(float $expected, float $number): void + { + self::assertSame($expected, Math\cos($number)); + } + + public function provideData(): array + { + return [ + [ + 0.5403023058681398, + 1.0 + ], + + [ + 1.0, + 0.0 + ], + + [ + 0.10291095660695612, + 45.45, + ], + + [ + 0.28366218546322625, + -5 + ], + + [ + -0.9983206000589924, + -15.65 + ] + ]; + } } diff --git a/tests/Psl/Math/DivTest.php b/tests/Psl/Math/DivTest.php index 7d5c8c1..28bb8b2 100644 --- a/tests/Psl/Math/DivTest.php +++ b/tests/Psl/Math/DivTest.php @@ -5,8 +5,44 @@ declare(strict_types=1); namespace Psl\Tests\Math; use PHPUnit\Framework\TestCase; +use Psl\Math; class DivTest extends TestCase { - // TODO: add tests. + /** + * @dataProvider provideData + */ + public function testDiv(int $expected, int $numerator, int $denominator): void + { + self::assertSame($expected, Math\div($numerator, $denominator)); + } + + public function provideData(): array + { + return[ + [ + 2, + 5, + 2, + ], + + [ + 5, + 10, + 2 + ], + + [ + 0, + 15, + 20 + ], + + [ + 1, + 10, + 10 + ] + ]; + } } diff --git a/tests/Psl/Math/ExpTest.php b/tests/Psl/Math/ExpTest.php index 4a12c82..c58cd4b 100644 --- a/tests/Psl/Math/ExpTest.php +++ b/tests/Psl/Math/ExpTest.php @@ -5,8 +5,35 @@ declare(strict_types=1); namespace Psl\Tests\Math; use PHPUnit\Framework\TestCase; +use Psl\Math; class ExpTest extends TestCase { - // TODO: add tests. + /** + * @dataProvider provideData + */ + public function testExp(float $expected, float $number): void + { + self::assertSame($expected, Math\exp($number)); + } + + public function provideData(): array + { + return [ + [ + 162754.79141900392, + 12.0, + ], + + [ + 298.8674009670603, + 5.7, + ], + + [ + Math\INFINITY, + 1000000, + ] + ]; + } } diff --git a/tests/Psl/Math/FloorTest.php b/tests/Psl/Math/FloorTest.php index ba97502..fb3e875 100644 --- a/tests/Psl/Math/FloorTest.php +++ b/tests/Psl/Math/FloorTest.php @@ -5,8 +5,45 @@ declare(strict_types=1); namespace Psl\Tests\Math; use PHPUnit\Framework\TestCase; +use Psl\Math; class FloorTest extends TestCase { - // TODO: add tests. + /** + * @dataProvider provideData + */ + public function testFloor(float $expected, float $number): void + { + self::assertSame($expected, Math\floor($number)); + } + + public function provideData(): array + { + return [ + [ + 4, + 4.3, + ], + + [ + 9, + 9.9, + ], + + [ + 3, + Math\PI + ], + + [ + -4, + -Math\PI + ], + + [ + 2, + Math\E + ] + ]; + } } diff --git a/tests/Psl/Math/FromBaseTest.php b/tests/Psl/Math/FromBaseTest.php index e5a8feb..c156e5a 100644 --- a/tests/Psl/Math/FromBaseTest.php +++ b/tests/Psl/Math/FromBaseTest.php @@ -5,8 +5,77 @@ declare(strict_types=1); namespace Psl\Tests\Math; use PHPUnit\Framework\TestCase; +use Psl\Exception; +use Psl\Math; class FromBaseTest extends TestCase { - // TODO: add tests. + /** + * @dataProvider provideData + */ + public function testFromBase(int $expected, string $value, int $from_base): void + { + self::assertSame($expected, Math\from_base($value, $from_base)); + } + + public function provideData(): array + { + return [ + [ + 5497, + '1010101111001', + 2 + ], + + [ + 2014587925987, + 'pphlmw9v', + 36 + ], + + [ + Math\INT32_MAX, + 'zik0zj', + 36 + ], + + [ + 15, + 'F', + 16 + ] + ]; + } + + public function testInvalidDigitThrows(): void + { + $this->expectException(Exception\InvariantViolationException::class); + $this->expectExceptionMessage('Invalid digit Z in base 16'); + + Math\from_base('Z', 16); + } + + public function testSpecialCharThrows(): void + { + $this->expectException(Exception\InvariantViolationException::class); + $this->expectExceptionMessage('Invalid digit * in base 16'); + + Math\from_base('*', 16); + } + + public function testEmptyValueThrows(): void + { + $this->expectException(Exception\InvariantViolationException::class); + $this->expectExceptionMessage('Unexpected empty string, expected number in base 16'); + + Math\from_base('', 16); + } + + public function testInvalidFromBaseThrows(): void + { + $this->expectException(Exception\InvariantViolationException::class); + $this->expectExceptionMessage('Expected $from_base to be between 2 and 36, got 64'); + + Math\from_base('z', 64); + } } diff --git a/tests/Psl/Math/LogTest.php b/tests/Psl/Math/LogTest.php index fa503cc..f0f663a 100644 --- a/tests/Psl/Math/LogTest.php +++ b/tests/Psl/Math/LogTest.php @@ -5,8 +5,69 @@ declare(strict_types=1); namespace Psl\Tests\Math; use PHPUnit\Framework\TestCase; +use Psl\Exception; +use Psl\Math; class LogTest extends TestCase { - // TODO: add tests. + /** + * @dataProvider provideData + */ + public function testLog(float $expected, float $number, ?float $base = null): void + { + self::assertSame($expected, Math\log($number, $base)); + } + + public function provideData(): array + { + return [ + [ + 1.6863989535702288, + 5.4, + null + ], + + [ + 0.6574784600188808, + 5.4, + 13 + ], + + [ + 1.7323937598229686, + 54.0, + 10 + ], + + [ + 0, + 1, + null + ], + ]; + } + + public function testNegativeInputThrows(): void + { + $this->expectException(Exception\InvariantViolationException::class); + $this->expectExceptionMessage('Expected positive number for log, got -45'); + + Math\log(-45); + } + + public function testNonPositiveBaseThrows(): void + { + $this->expectException(Exception\InvariantViolationException::class); + $this->expectExceptionMessage('Expected positive base for log, got 0.0'); + + Math\log(4.4, 0.0); + } + + public function testBaseOneThrowsForUndefinedLogarithm(): void + { + $this->expectException(Exception\InvariantViolationException::class); + $this->expectExceptionMessage('Logarithm undefined for base 1'); + + Math\log(4.4, 1.0); + } } diff --git a/tests/Psl/Math/MaxByTest.php b/tests/Psl/Math/MaxByTest.php index 183d0e7..31ed39f 100644 --- a/tests/Psl/Math/MaxByTest.php +++ b/tests/Psl/Math/MaxByTest.php @@ -5,8 +5,50 @@ declare(strict_types=1); namespace Psl\Tests\Math; use PHPUnit\Framework\TestCase; +use Psl\Iter; +use Psl\Math; +use Psl\Str; class MaxByTest extends TestCase { - // TODO: add tests. + /** + * @dataProvider provideData + */ + public function testMaxBy($expected, iterable $values, callable $fun): void + { + self::assertSame($expected, Math\max_by($values, $fun)); + } + + public function provideData(): array + { + return [ + [ + 'bazqux', + ['foo', 'bar', 'baz', 'qux', 'foobar', 'bazqux'], + fn ($value) => Str\length($value) + ], + + [ + ['foo', 'bar', 'baz'], + [ + ['foo'], + ['foo', 'bar'], + ['foo', 'bar', 'baz'] + ], + fn ($arr) => Iter\count($arr) + ], + + [ + 9, + Iter\range(0, 9), + fn ($i) => $i + ], + + [ + null, + [], + fn ($i) => $i + ] + ]; + } } diff --git a/tests/Psl/Math/MaxTest.php b/tests/Psl/Math/MaxTest.php index 450e802..b2d8782 100644 --- a/tests/Psl/Math/MaxTest.php +++ b/tests/Psl/Math/MaxTest.php @@ -5,8 +5,36 @@ declare(strict_types=1); namespace Psl\Tests\Math; use PHPUnit\Framework\TestCase; +use Psl\Iter; +use Psl\Math; class MaxTest extends TestCase { - // TODO: add tests. + /** + * @dataProvider provideData + */ + public function testMax($expected, iterable $numbers): void + { + self::assertSame($expected, Math\max($numbers)); + } + + public function provideData(): array + { + return [ + [ + 10, + Iter\range(0, 10, 2) + ], + + [ + 15, + [...Iter\to_array(Iter\range(0, 10)), 15] + ], + + [ + null, + [] + ] + ]; + } } diff --git a/tests/Psl/Math/MaxvaTest.php b/tests/Psl/Math/MaxvaTest.php index 7278068..3dbe0dc 100644 --- a/tests/Psl/Math/MaxvaTest.php +++ b/tests/Psl/Math/MaxvaTest.php @@ -5,8 +5,45 @@ declare(strict_types=1); namespace Psl\Tests\Math; use PHPUnit\Framework\TestCase; +use Psl\Iter; +use Psl\Math; class MaxvaTest extends TestCase { - // TODO: add tests. + /** + * @dataProvider provideData + */ + public function testMaxva($expected, $first, $second, ...$rest): void + { + self::assertSame($expected, Math\maxva($first, $second, ...$rest)); + } + + public function provideData(): array + { + return [ + [ + 10, + 10, + 5, + ...Iter\range(0, 9, 2) + ], + + [ + 18, + 18, + 15, + ...Iter\to_array(Iter\range(0, 10)), + 15 + ], + + [ + 64, + 19, + 15, + ...Iter\range(0, 45, 5), + 52, + 64 + ] + ]; + } } diff --git a/tests/Psl/Math/MeanTest.php b/tests/Psl/Math/MeanTest.php index b4cd89d..c1466cd 100644 --- a/tests/Psl/Math/MeanTest.php +++ b/tests/Psl/Math/MeanTest.php @@ -5,8 +5,63 @@ declare(strict_types=1); namespace Psl\Tests\Math; use PHPUnit\Framework\TestCase; +use Psl\Arr; +use Psl\Iter; +use Psl\Math; class MeanTest extends TestCase { - // TODO: add tests. + /** + * @dataProvider provideData + */ + public function testMean($expected, iterable $numbers): void + { + self::assertSame($expected, Math\mean($numbers)); + } + + public function provideData(): array + { + return [ + [ + 5.0, + [ + 10, + 5, + ...Iter\range(0, 9, 2), + ], + ], + + [ + 7.357142857142858, + [ + 18, + 15, + ...Iter\to_array(Iter\range(0, 10)), + 15, + ], + ], + + [ + 26.785714285714285, + [ + 19, + 15, + ...Iter\range(0, 45, 5), + 52, + 64, + ], + ], + + [ + 100.0, + Arr\fill(100, 0, 100) + ], + + + [ + null, + [] + ] + ]; + } } diff --git a/tests/Psl/Math/MedianTest.php b/tests/Psl/Math/MedianTest.php index f015040..e3877b8 100644 --- a/tests/Psl/Math/MedianTest.php +++ b/tests/Psl/Math/MedianTest.php @@ -5,8 +5,62 @@ declare(strict_types=1); namespace Psl\Tests\Math; use PHPUnit\Framework\TestCase; +use Psl\Arr; +use Psl\Iter; +use Psl\Math; class MedianTest extends TestCase { - // TODO: add tests. + /** + * @dataProvider provideData + */ + public function testMedian($expected, iterable $numbers): void + { + self::assertSame($expected, Math\median($numbers)); + } + + public function provideData(): array + { + return [ + [ + 5.0, + [ + 10, + 5, + ...Iter\range(0, 9, 2), + ], + ], + + [ + 6.5, + [ + 18, + 15, + ...Iter\to_array(Iter\range(0, 10)), + 15, + ], + ], + + [ + 22.5, + [ + 19, + 15, + ...Iter\range(0, 45, 5), + 52, + 64, + ], + ], + + [ + 100.0, + Arr\fill(100, 0, 100) + ], + + [ + null, + [] + ] + ]; + } } diff --git a/tests/Psl/Math/MinByTest.php b/tests/Psl/Math/MinByTest.php index dcd6fb9..30c6ef4 100644 --- a/tests/Psl/Math/MinByTest.php +++ b/tests/Psl/Math/MinByTest.php @@ -5,8 +5,50 @@ declare(strict_types=1); namespace Psl\Tests\Math; use PHPUnit\Framework\TestCase; +use Psl\Iter; +use Psl\Math; +use Psl\Str; class MinByTest extends TestCase { - // TODO: add tests. + /** + * @dataProvider provideData + */ + public function testMinBy($expected, iterable $values, callable $fun): void + { + self::assertSame($expected, Math\min_by($values, $fun)); + } + + public function provideData(): array + { + return [ + [ + 'qux', + ['foo', 'bar', 'baz', 'qux', 'foobar', 'bazqux'], + fn ($value) => Str\length($value) + ], + + [ + ['foo'], + [ + ['foo'], + ['foo', 'bar'], + ['foo', 'bar', 'baz'] + ], + fn ($arr) => Iter\count($arr) + ], + + [ + 0, + Iter\range(0, 9), + fn ($i) => $i + ], + + [ + null, + [], + fn ($i) => $i + ] + ]; + } } diff --git a/tests/Psl/Math/MinTest.php b/tests/Psl/Math/MinTest.php index e5de154..23c0d7c 100644 --- a/tests/Psl/Math/MinTest.php +++ b/tests/Psl/Math/MinTest.php @@ -5,8 +5,37 @@ declare(strict_types=1); namespace Psl\Tests\Math; use PHPUnit\Framework\TestCase; +use Psl\Iter; +use Psl\Math; class MinTest extends TestCase { - // TODO: add tests. + + /** + * @dataProvider provideData + */ + public function testMin($expected, iterable $numbers): void + { + self::assertSame($expected, Math\min($numbers)); + } + + public function provideData(): array + { + return [ + [ + 0, + Iter\range(0, 10, 2) + ], + + [ + 4, + [...Iter\to_array(Iter\range(5, 10)), 4] + ], + + [ + null, + [] + ] + ]; + } } diff --git a/tests/Psl/Math/MinvaTest.php b/tests/Psl/Math/MinvaTest.php index 22ce2e6..919b1ed 100644 --- a/tests/Psl/Math/MinvaTest.php +++ b/tests/Psl/Math/MinvaTest.php @@ -5,8 +5,45 @@ declare(strict_types=1); namespace Psl\Tests\Math; use PHPUnit\Framework\TestCase; +use Psl\Iter; +use Psl\Math; class MinvaTest extends TestCase { - // TODO: add tests. + /** + * @dataProvider provideData + */ + public function testMainva($expected, $first, $second, ...$rest): void + { + self::assertSame($expected, Math\minva($first, $second, ...$rest)); + } + + public function provideData(): array + { + return [ + [ + 5, + 10, + 5, + ...Iter\range(7, 9, 2) + ], + + [ + 4, + 18, + 15, + ...Iter\to_array(Iter\range(4, 10)), + 15 + ], + + [ + 15, + 19, + 15, + ...Iter\range(40, 45, 5), + 52, + 64 + ] + ]; + } } diff --git a/tests/Psl/Math/RoundTest.php b/tests/Psl/Math/RoundTest.php index 7cab6a9..7f0c56c 100644 --- a/tests/Psl/Math/RoundTest.php +++ b/tests/Psl/Math/RoundTest.php @@ -5,8 +5,63 @@ declare(strict_types=1); namespace Psl\Tests\Math; use PHPUnit\Framework\TestCase; +use Psl\Math; class RoundTest extends TestCase { - // TODO: add tests. + + /** + * @dataProvider provideData + */ + public function testRound(float $expected, float $number, int $precision = 0): void + { + self::assertSame($expected, Math\round($number, $precision)); + } + + public function provideData(): array + { + return [ + [ + 5.46, + 5.45663, + 2, + ], + + [ + 4.8, + 4.811, + 1, + ], + + [ + 5.0, + 5.42, + 0 + ], + + [ + 5.0, + 4.8, + 0 + ], + + [ + 0.0, + 0.4242, + 0, + ], + + [ + 0.5, + 0.4634, + 1, + ], + + [ + -6.57778, + -6.5777777777, + 5, + ], + ]; + } } diff --git a/tests/Psl/Math/SinTest.php b/tests/Psl/Math/SinTest.php index fa920e6..e812a23 100644 --- a/tests/Psl/Math/SinTest.php +++ b/tests/Psl/Math/SinTest.php @@ -5,8 +5,46 @@ declare(strict_types=1); namespace Psl\Tests\Math; use PHPUnit\Framework\TestCase; +use Psl\Math; class SinTest extends TestCase { - // TODO: add tests. + + /** + * @dataProvider provideData + */ + public function testSin(float $expected, float $number): void + { + self::assertSame($expected, Math\sin($number)); + } + + public function provideData(): array + { + return [ + [ + -0.9589242746631385, + 5.0 + ], + + [ + -0.9961646088358407, + 4.8 + ], + + [ + 0.0, + 0.0 + ], + + [ + 0.3894183423086505, + 0.4 + ], + + [ + -0.21511998808781552, + -6.5 + ] + ]; + } } diff --git a/tests/Psl/Math/SqrtTest.php b/tests/Psl/Math/SqrtTest.php index a00ef6a..3286fce 100644 --- a/tests/Psl/Math/SqrtTest.php +++ b/tests/Psl/Math/SqrtTest.php @@ -5,8 +5,51 @@ declare(strict_types=1); namespace Psl\Tests\Math; use PHPUnit\Framework\TestCase; +use Psl\Math; class SqrtTest extends TestCase { - // TODO: add tests. + + /** + * @dataProvider provideData + */ + public function testSqrt(float $expected, float $number): void + { + self::assertSame($expected, Math\sqrt($number)); + } + + public function provideData(): array + { + return [ + [ + 2.23606797749979, + 5.0 + ], + + [ + 2.1908902300206643, + 4.8 + ], + + [ + 0.6324555320336759, + 0.4 + ], + + [ + 2.5495097567963922, + 6.5 + ], + + [ + 1.4142135623730951, + 2 + ], + + [ + 1, + 1 + ] + ]; + } } diff --git a/tests/Psl/Math/SumFloatsTest.php b/tests/Psl/Math/SumFloatsTest.php index 1bc5778..36a4251 100644 --- a/tests/Psl/Math/SumFloatsTest.php +++ b/tests/Psl/Math/SumFloatsTest.php @@ -5,8 +5,51 @@ declare(strict_types=1); namespace Psl\Tests\Math; use PHPUnit\Framework\TestCase; +use Psl\Iter; +use Psl\Math; class SumFloatsTest extends TestCase { - // TODO: add tests. + /** + * @dataProvider provideData + */ + public function testSumFloats(float $expected, iterable $numbers): void + { + self::assertSame($expected, Math\sum_floats($numbers)); + } + + public function provideData(): array + { + return [ + [ + 116.70000000000005, + [ + 10.9, + 5, + ...Iter\range(0, 9.8798, 0.48), + ], + ], + + [ + 103.0, + [ + 18, + 15, + ...Iter\to_array(Iter\range(0, 10)), + 15, + ], + ], + + [ + 323.54, + [ + 19.5, + 15.8, + ...Iter\range(0.5, 45, 5.98), + 52.8, + 64, + ] + ], + ]; + } } diff --git a/tests/Psl/Math/SumTest.php b/tests/Psl/Math/SumTest.php index a3a5d24..2f6038b 100644 --- a/tests/Psl/Math/SumTest.php +++ b/tests/Psl/Math/SumTest.php @@ -5,8 +5,51 @@ declare(strict_types=1); namespace Psl\Tests\Math; use PHPUnit\Framework\TestCase; +use Psl\Iter; +use Psl\Math; class SumTest extends TestCase { - // TODO: add tests. + /** + * @dataProvider provideData + */ + public function testSum(int $expected, iterable $numbers): void + { + self::assertSame($expected, Math\sum($numbers)); + } + + public function provideData(): array + { + return [ + [ + 60, + [ + 10, + 5, + ...Iter\range(0, 9), + ], + ], + + [ + 103, + [ + 18, + 15, + ...Iter\to_array(Iter\range(0, 10)), + 15, + ], + ], + + [ + 534, + [ + 178, + 15, + ...Iter\range(0, 45, 5), + 52, + 64, + ] + ], + ]; + } } diff --git a/tests/Psl/Math/TanTest.php b/tests/Psl/Math/TanTest.php index aa476c2..4576952 100644 --- a/tests/Psl/Math/TanTest.php +++ b/tests/Psl/Math/TanTest.php @@ -5,8 +5,46 @@ declare(strict_types=1); namespace Psl\Tests\Math; use PHPUnit\Framework\TestCase; +use Psl\Math; class TanTest extends TestCase { - // TODO: add tests. + + /** + * @dataProvider provideData + */ + public function testTan(float $expected, float $number): void + { + self::assertSame($expected, Math\tan($number)); + } + + public function provideData(): array + { + return [ + [ + -3.380515006246586, + 5.0 + ], + + [ + -11.384870654242922, + 4.8 + ], + + [ + 0.0, + 0.0 + ], + + [ + 0.4227932187381618, + 0.4 + ], + + [ + -0.22027720034589682, + -6.5 + ] + ]; + } } diff --git a/tests/Psl/Math/ToBaseTest.php b/tests/Psl/Math/ToBaseTest.php index f8b6640..c8b1921 100644 --- a/tests/Psl/Math/ToBaseTest.php +++ b/tests/Psl/Math/ToBaseTest.php @@ -5,8 +5,62 @@ declare(strict_types=1); namespace Psl\Tests\Math; use PHPUnit\Framework\TestCase; +use Psl\Exception; +use Psl\Math; class ToBaseTest extends TestCase { - // TODO: add tests. + + /** + * @dataProvider provideData + */ + public function testFromBase(string $expected, int $value, int $to_base): void + { + self::assertSame($expected, Math\to_base($value, $to_base)); + } + + public function provideData(): array + { + return [ + [ + '1010101111001', + 5497, + 2 + ], + + [ + 'pphlmw9v', + 2014587925987, + 36 + ], + + [ + 'zik0zj', + Math\INT32_MAX, + 36 + ], + + [ + 'f', + 15, + 16 + ] + ]; + } + + public function testNegativeValueThrows(): void + { + $this->expectException(Exception\InvariantViolationException::class); + $this->expectExceptionMessage('Expected non-negative base conversion input, got -5'); + + Math\to_base(-5, 16); + } + + public function testInvalidToBaseThrows(): void + { + $this->expectException(Exception\InvariantViolationException::class); + $this->expectExceptionMessage('Expected $to_base to be between 2 and 36, got 64'); + + Math\to_base(1, 64); + } }