diff --git a/tests/e2e/Adapter/Scopes/AggregationTests.php b/tests/e2e/Adapter/Scopes/AggregationTests.php index b9cc4578b..4dd5fc8ed 100644 --- a/tests/e2e/Adapter/Scopes/AggregationTests.php +++ b/tests/e2e/Adapter/Scopes/AggregationTests.php @@ -1583,7 +1583,7 @@ public function testFloatAggregateOverflowIsRefused(): void ], permissions: [Permission::create(Role::any()), Permission::read(Role::any())], )); - foreach ([['huge', 1e308], ['huge', 1e308], ['spread', 1e308], ['spread', -1e308], ['spread', 0.0], ['single', 1e308]] as [$series, $reading]) { + foreach ([['huge', 1e308], ['huge', 1e308], ['sunk', -1e308], ['sunk', -1e308], ['spread', 1e308], ['spread', -1e308], ['spread', 0.0], ['single', 1e308]] as [$series, $reading]) { $database->createDocument($collection, new Document([ 'series' => $series, 'reading' => $reading, @@ -1594,6 +1594,8 @@ public function testFloatAggregateOverflowIsRefused(): void $overflows = [ [Query::equal('series', ['huge']), Query::sum('reading', 'result')], [Query::equal('series', ['huge']), Query::avg('reading', 'result')], + [Query::equal('series', ['sunk']), Query::sum('reading', 'result')], + [Query::equal('series', ['sunk']), Query::avg('reading', 'result')], [Query::sum('reading', 'result'), Query::groupBy(['series'])], ]; if (! $database->getAdapter() instanceof SQLite) { diff --git a/tests/e2e/Adapter/Scopes/DocumentTests.php b/tests/e2e/Adapter/Scopes/DocumentTests.php index 973550113..08b70c605 100644 --- a/tests/e2e/Adapter/Scopes/DocumentTests.php +++ b/tests/e2e/Adapter/Scopes/DocumentTests.php @@ -2868,6 +2868,34 @@ public function testSumOverflowIsRefused(): void $database->deleteCollection($collection); } + public function testNegativeSumOverflowIsRefused(): void + { + $database = $this->getDatabase(); + $collection = 'sum_underflow_'.\substr(\uniqid(), -6); + $database->createCollection(Collection::create( + id: $collection, + attributes: [Attribute::double(key: 'reading', required: true)], + permissions: [Permission::create(Role::any()), Permission::read(Role::any())], + )); + foreach ([-1e308, -1e308] as $reading) { + $database->createDocument($collection, new Document([ + 'reading' => $reading, + '$permissions' => [Permission::read(Role::any())], + ])); + } + + foreach ([[[], null], [[], 5], [[Query::lessThan('reading', 0)], null]] as [$queries, $max]) { + try { + $database->sum($collection, 'reading', $queries, $max); + $this->fail('A sum that overflows below the range of a double is refused'); + } catch (LimitException) { + $this->addToAssertionCount(1); + } + } + + $database->deleteCollection($collection); + } + public function testUpdateDocument(): void { $document = $this->initDocumentsFixture(); diff --git a/tests/unit/Adapter/SumResultTest.php b/tests/unit/Adapter/SumResultTest.php index 1de358180..f14dd3e8d 100644 --- a/tests/unit/Adapter/SumResultTest.php +++ b/tests/unit/Adapter/SumResultTest.php @@ -27,10 +27,24 @@ public static function sums(): iterable yield 'negative double with an exponent' => ['-1.5e300', -1.5e300]; yield 'decimal past the range of an integer' => ['18446744073709551614', 18446744073709551614.0]; yield 'no rows' => [null, 0]; + yield 'infinity' => ['INF', \INF]; + yield 'negative infinity' => ['-INF', -\INF]; + yield 'infinity in another case' => ['Inf', \INF]; + yield 'not a number word' => ['overflow', 0]; } #[DataProvider('sums')] public function testASumIsReadAsTheNumberTheEngineSent(?string $sent, int|float $expected): void + { + $this->assertSame($expected, $this->sumOf($sent)); + } + + public function testANotANumberSumIsReadAsNan(): void + { + $this->assertNan($this->sumOf('NAN')); + } + + private function sumOf(?string $sent): int|float { $pdo = $this->createStub(PDO::class); $pdo->method('prepare')->willReturnCallback(function () use ($sent): PDOStatement { @@ -47,6 +61,6 @@ public function testASumIsReadAsTheNumberTheEngineSent(?string $sent, int|float $adapter->setNamespace('namespace'); $adapter->setAuthorization(new Authorization()); - $this->assertSame($expected, $adapter->sum(Collection::create(id: 'readings'), 'reading')); + return $adapter->sum(Collection::create(id: 'readings'), 'reading'); } } diff --git a/tests/unit/AggregateOverflowTest.php b/tests/unit/AggregateOverflowTest.php index 299825895..e04b74645 100644 --- a/tests/unit/AggregateOverflowTest.php +++ b/tests/unit/AggregateOverflowTest.php @@ -78,6 +78,15 @@ public function testAnAggregateThatOverflowsIsRefused(bool $stringify, Query $ag $database->aggregate(self::COLLECTION, [$aggregate]); } + #[DataProvider('overflows')] + public function testAnAggregateThatOverflowsBelowTheRangeIsRefused(bool $stringify, Query $aggregate): void + { + $database = $this->database($stringify, [-1e308, -1e308]); + + $this->expectException(LimitException::class); + $database->aggregate(self::COLLECTION, [$aggregate]); + } + public function testAnAggregateThatOverflowsInOneGroupIsRefused(): void { $database = $this->database(false, [1e308, 1e308, 1.0]); diff --git a/tests/unit/SumOverflowTest.php b/tests/unit/SumOverflowTest.php index d18b74982..b9bd5f8e2 100644 --- a/tests/unit/SumOverflowTest.php +++ b/tests/unit/SumOverflowTest.php @@ -82,6 +82,18 @@ public function testASumThatOverflowsIsRefused(Closure $adapter): void $database->sum(self::COLLECTION, 'reading'); } + /** + * @param Closure(): Adapter $adapter + */ + #[DataProvider('adapters')] + public function testANegativeSumThatOverflowsIsRefused(Closure $adapter): void + { + $database = $this->database($adapter, [-1e308, -1e308]); + + $this->expectException(LimitException::class); + $database->sum(self::COLLECTION, 'reading'); + } + /** * @param Closure(): Adapter $adapter */