Skip to content

Commit

Permalink
PHPLIB-1148: Add comparator for Int64 objects
Browse files Browse the repository at this point in the history
  • Loading branch information
alcaeus committed Jun 21, 2023
1 parent 8e4aea0 commit b46461f
Show file tree
Hide file tree
Showing 7 changed files with 219 additions and 23 deletions.
2 changes: 1 addition & 1 deletion phpunit.evergreen.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
beStrictAboutOutputDuringTests="true"
beStrictAboutChangesToGlobalState="true"
colors="true"
bootstrap="vendor/autoload.php"
bootstrap="tests/bootstrap.php"
defaultTestSuite="Default Test Suite"
>

Expand Down
2 changes: 1 addition & 1 deletion phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
beStrictAboutOutputDuringTests="true"
beStrictAboutChangesToGlobalState="true"
colors="true"
bootstrap="vendor/autoload.php"
bootstrap="tests/bootstrap.php"
defaultTestSuite="Default Test Suite"
>

Expand Down
61 changes: 61 additions & 0 deletions tests/Comparator/Int64Comparator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

namespace MongoDB\Tests\Comparator;

use MongoDB\BSON\Int64;
use SebastianBergmann\Comparator\Comparator;
use SebastianBergmann\Comparator\ComparisonFailure;

use function is_int;
use function is_numeric;
use function is_string;
use function sprintf;

use const PHP_INT_SIZE;

class Int64Comparator extends Comparator
{
public function accepts($expected, $actual)
{
// Only compare if either value is an Int64
return ($expected instanceof Int64 && $this->isComparable($actual))
|| ($actual instanceof Int64 && $this->isComparable($expected));
}

public function assertEquals($expected, $actual, $delta = 0.0, $canonicalize = false, $ignoreCase = false): void
{
if (PHP_INT_SIZE == 8) {
// On 64-bit systems, compare integers directly
$expectedValue = (int) $expected;
$actualValue = (int) $actual;
} else {
// On 32-bit systems, compare integers as strings
$expectedValue = (string) $expected;
$actualValue = (string) $actual;
}

if ($expectedValue === $actualValue) {
return;
}

throw new ComparisonFailure(
$expected,
$actual,
'',
'',
false,
sprintf(
'Failed asserting that %s matches expected %s.',
$this->exporter->export($actual),
$this->exporter->export($expected)
)
);
}

private function isComparable($value): bool
{
return $value instanceof Int64 // Int64 instances
|| is_int($value) // Integer values
|| (is_string($value) && is_numeric($value)); // Numeric strings (is_numeric accepts floats)
}
}
147 changes: 147 additions & 0 deletions tests/Comparator/Int64ComparatorTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
<?php

namespace MongoDB\Tests\Comparator;

use Generator;
use MongoDB\BSON\Int64;
use PHPUnit\Framework\TestCase;
use SebastianBergmann\Comparator\ComparisonFailure;

class Int64ComparatorTest extends TestCase
{
/** @dataProvider provideAcceptsValues */
public function testAccepts(bool $expectedResult, $expectedValue, $actualValue): void
{
$this->assertSame($expectedResult, (new Int64Comparator())->accepts($expectedValue, $actualValue));
}

public static function provideAcceptsValues(): Generator
{
yield 'Expects Int64, Actual Int64' => [
'expectedResult' => true,
'expectedValue' => new Int64(123),
'actualValue' => new Int64(123),
];

yield 'Expects Int64, Actual int' => [
'expectedResult' => true,
'expectedValue' => new Int64(123),
'actualValue' => 123,
];

yield 'Expects Int64, Actual string' => [
'expectedResult' => true,
'expectedValue' => new Int64(123),
'actualValue' => '123',
];

yield 'Expects Int64, Actual float' => [
'expectedResult' => false,
'expectedValue' => new Int64(123),
'actualValue' => 123.0,
];

yield 'Expects int, Actual Int64' => [
'expectedResult' => true,
'expectedValue' => 123,
'actualValue' => new Int64(123),
];

yield 'Expects string, Actual Int64' => [
'expectedResult' => true,
'expectedValue' => '123',
'actualValue' => new Int64(123),
];

yield 'Expects float, Actual Int64' => [
'expectedResult' => false,
'expectedValue' => 123.0,
'actualValue' => new Int64(123),
];

yield 'Expects float, Actual Float' => [
'expectedResult' => false,
'expectedValue' => 123.0,
'actualValue' => 123.0,
];

yield 'Expects string, Actual string' => [
'expectedResult' => false,
'expectedValue' => '123',
'actualValue' => '123',
];
}

/**
* @dataProvider provideMatchingAssertions
* @doesNotPerformAssertions
*/
public function testMatchingAssertions($expected, $actual): void
{
(new Int64Comparator())->assertEquals($expected, $actual);
}

public static function provideMatchingAssertions(): Generator
{
yield 'Expected Int64, Actual Int64' => [
'expected' => new Int64(123),
'actual' => new Int64(123),
];

yield 'Expected Int64, Actual int' => [
'expected' => new Int64(123),
'actual' => 123,
];

yield 'Expected Int64, Actual string' => [
'expected' => new Int64(123),
'actual' => '123',
];

yield 'Expected int, Actual Int64' => [
'expected' => 123,
'actual' => new Int64(123),
];

yield 'Expected string, Actual Int64' => [
'expected' => '123',
'actual' => new Int64(123),
];
}

/** @dataProvider provideFailingValues */
public function testFailingAssertions($expected, $actual): void
{
$this->expectException(ComparisonFailure::class);

(new Int64Comparator())->assertEquals($expected, $actual);
}

public static function provideFailingValues(): Generator
{
yield 'Expected Int64, Actual Int64' => [
'expected' => new Int64(123),
'actual' => new Int64(456),
];

yield 'Expected Int64, Actual int' => [
'expected' => new Int64(123),
'actual' => 456,
];

yield 'Expected Int64, Actual string' => [
'expected' => new Int64(123),
'actual' => '456',
];

yield 'Expected int, Actual Int64' => [
'expected' => 123,
'actual' => new Int64(456),
];

yield 'Expected string, Actual Int64' => [
'expected' => '123',
'actual' => new Int64(456),
];
}
}
8 changes: 0 additions & 8 deletions tests/SpecTests/DocumentsMatchConstraint.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@
use function PHPUnit\Framework\logicalOr;
use function sprintf;

use const PHP_INT_SIZE;

/**
* Constraint that checks if one document matches another.
*
Expand Down Expand Up @@ -308,12 +306,6 @@ private function prepareBSON($bson, bool $isRoot, bool $sortKeys = false)
$bson[$key] = $this->prepareBSON($value, false, $sortKeys);
continue;
}

/* Convert Int64 objects to integers on 64-bit platforms for
* compatibility reasons. */
if ($value instanceof Int64 && PHP_INT_SIZE != 4) {
$bson[$key] = (int) ((string) $value);
}
}

return $bson;
Expand Down
13 changes: 0 additions & 13 deletions tests/UnifiedSpecTests/Constraint/Matches.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@
use function strpos;
use function strrchr;

use const PHP_INT_SIZE;

/**
* Constraint that checks if one value matches another.
*
Expand Down Expand Up @@ -425,17 +423,6 @@ private static function prepare($bson)
return $bson;
}

/* Convert Int64 objects to integers on 64-bit platforms for
* compatibility reasons. */
if ($bson instanceof Int64 && PHP_INT_SIZE != 4) {
return (int) ((string) $bson);
}

/* TODO: Convert Int64 objects to integers on 32-bit platforms if they
* can be expressed as such. This is necessary to handle flexible
* numeric comparisons if the server returns 32-bit value as a 64-bit
* integer (e.g. cursor ID). */

// Serializable can produce an array or object, so recurse on its output
if ($bson instanceof Serializable) {
return self::prepare($bson->bsonSerialize());
Expand Down
9 changes: 9 additions & 0 deletions tests/bootstrap.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

use MongoDB\Tests\Comparator\Int64Comparator;
use SebastianBergmann\Comparator\Factory as ComparatorFactory;

require __DIR__ . '/../vendor/autoload.php';

// Register custom comparators
ComparatorFactory::getInstance()->register(new Int64Comparator());

0 comments on commit b46461f

Please sign in to comment.