Skip to content

Commit 87e78bf

Browse files
committed
PHPLIB-1011: Support asserting multiple types in legacy $$type operator
This refactors DocumentsMatchConstraint to use the IsBsonType constraint from the unified test runner.
1 parent d2347f5 commit 87e78bf

File tree

2 files changed

+33
-143
lines changed

2 files changed

+33
-143
lines changed

tests/SpecTests/DocumentsMatchConstraint.php

Lines changed: 16 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,11 @@
44

55
use ArrayObject;
66
use InvalidArgumentException;
7-
use LogicException;
8-
use MongoDB\BSON\BinaryInterface;
9-
use MongoDB\BSON\DBPointer;
10-
use MongoDB\BSON\Decimal128;
117
use MongoDB\BSON\Int64;
12-
use MongoDB\BSON\Javascript;
13-
use MongoDB\BSON\MaxKey;
14-
use MongoDB\BSON\MinKey;
15-
use MongoDB\BSON\ObjectId;
16-
use MongoDB\BSON\Regex;
17-
use MongoDB\BSON\Symbol;
18-
use MongoDB\BSON\Timestamp;
19-
use MongoDB\BSON\Undefined;
20-
use MongoDB\BSON\UTCDateTime;
218
use MongoDB\Model\BSONArray;
229
use MongoDB\Model\BSONDocument;
10+
use MongoDB\Tests\UnifiedSpecTests\Constraint\IsBsonType;
2311
use PHPUnit\Framework\Constraint\Constraint;
24-
use PHPUnit\Framework\Constraint\IsInstanceOf;
25-
use PHPUnit\Framework\Constraint\IsNull;
26-
use PHPUnit\Framework\Constraint\IsType;
27-
use PHPUnit\Framework\Constraint\LogicalNot;
28-
use PHPUnit\Framework\Constraint\LogicalOr;
2912
use RuntimeException;
3013
use SebastianBergmann\Comparator\ComparisonFailure;
3114
use SebastianBergmann\Comparator\Factory;
@@ -39,6 +22,12 @@
3922
use function is_float;
4023
use function is_int;
4124
use function is_object;
25+
use function PHPUnit\Framework\assertThat;
26+
use function PHPUnit\Framework\containsOnly;
27+
use function PHPUnit\Framework\isInstanceOf;
28+
use function PHPUnit\Framework\isType;
29+
use function PHPUnit\Framework\logicalAnd;
30+
use function PHPUnit\Framework\logicalOr;
4231
use function sprintf;
4332

4433
use const PHP_INT_SIZE;
@@ -131,133 +120,18 @@ private function doEvaluate($other, $description = '', $returnResult = false)
131120
}
132121

133122
/**
134-
* @param mixed $actualValue
123+
* @param string|string[] $expectedType
124+
* @param mixed $actualValue
135125
*/
136-
private function assertBSONType(string $expectedType, $actualValue): void
126+
private function assertBSONType($expectedType, $actualValue): void
137127
{
138-
switch ($expectedType) {
139-
case 'double':
140-
(new IsType('float'))->evaluate($actualValue);
128+
assertThat(
129+
$expectedType,
130+
logicalOr(isType('string'), logicalAnd(isInstanceOf(BSONArray::class), containsOnly('string'))),
131+
'$$type requires string or string[]'
132+
);
141133

142-
return;
143-
144-
case 'string':
145-
(new IsType('string'))->evaluate($actualValue);
146-
147-
return;
148-
149-
case 'object':
150-
LogicalOr::fromConstraints(
151-
new IsType('object'),
152-
new LogicalNot(new IsInstanceOf(BSONArray::class))
153-
)->evaluate($actualValue);
154-
155-
return;
156-
157-
case 'array':
158-
LogicalOr::fromConstraints(
159-
new IsType('array'),
160-
new IsInstanceOf(BSONArray::class)
161-
)->evaluate($actualValue);
162-
163-
return;
164-
165-
case 'binData':
166-
(new IsInstanceOf(BinaryInterface::class))->evaluate($actualValue);
167-
168-
return;
169-
170-
case 'undefined':
171-
(new IsInstanceOf(Undefined::class))->evaluate($actualValue);
172-
173-
return;
174-
175-
case 'objectId':
176-
(new IsInstanceOf(ObjectId::class))->evaluate($actualValue);
177-
178-
return;
179-
180-
case 'boolean':
181-
(new IsType('bool'))->evaluate($actualValue);
182-
183-
return;
184-
185-
case 'date':
186-
(new IsInstanceOf(UTCDateTime::class))->evaluate($actualValue);
187-
188-
return;
189-
190-
case 'null':
191-
(new IsNull())->evaluate($actualValue);
192-
193-
return;
194-
195-
case 'regex':
196-
(new IsInstanceOf(Regex::class))->evaluate($actualValue);
197-
198-
return;
199-
200-
case 'dbPointer':
201-
(new IsInstanceOf(DBPointer::class))->evaluate($actualValue);
202-
203-
return;
204-
205-
case 'javascript':
206-
(new IsInstanceOf(Javascript::class))->evaluate($actualValue);
207-
208-
return;
209-
210-
case 'symbol':
211-
(new IsInstanceOf(Symbol::class))->evaluate($actualValue);
212-
213-
return;
214-
215-
case 'int':
216-
(new IsType('int'))->evaluate($actualValue);
217-
218-
return;
219-
220-
case 'timestamp':
221-
(new IsInstanceOf(Timestamp::class))->evaluate($actualValue);
222-
223-
return;
224-
225-
case 'long':
226-
LogicalOr::fromConstraints(
227-
new IsType('int'),
228-
new IsInstanceOf(Int64::class)
229-
)->evaluate($actualValue);
230-
231-
return;
232-
233-
case 'decimal':
234-
(new IsInstanceOf(Decimal128::class))->evaluate($actualValue);
235-
236-
return;
237-
238-
case 'minKey':
239-
(new IsInstanceOf(MinKey::class))->evaluate($actualValue);
240-
241-
return;
242-
243-
case 'maxKey':
244-
(new IsInstanceOf(MaxKey::class))->evaluate($actualValue);
245-
246-
return;
247-
248-
case 'number':
249-
LogicalOr::fromConstraints(
250-
new IsType('int'),
251-
new IsInstanceOf(Int64::class),
252-
new IsType('float'),
253-
new IsInstanceOf(Decimal128::class)
254-
)->evaluate($actualValue);
255-
256-
return;
257-
258-
default:
259-
throw new LogicException('Unsupported type: ' . $expectedType);
260-
}
134+
IsBsonType::anyOf(...(array) $expectedType)->evaluate($actualValue);
261135
}
262136

263137
/**

tests/SpecTests/DocumentsMatchConstraintTest.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ public function provideBSONTypes()
9898
'binData' => ['binData', new Binary('', 0)],
9999
'undefined' => ['undefined', $undefined],
100100
'objectId' => ['objectId', new ObjectId()],
101-
'boolean' => ['boolean', true],
101+
'bool' => ['bool', true],
102102
'date' => ['date', new UTCDateTime()],
103103
'null' => ['null', null],
104104
'regex' => ['regex', new Regex('.*')],
@@ -120,6 +120,22 @@ public function provideBSONTypes()
120120
];
121121
}
122122

123+
public function testBSONTypeAssertionsWithMultipleTypes(): void
124+
{
125+
$c1 = new DocumentsMatchConstraint(['x' => ['$$type' => ['double', 'int']]]);
126+
127+
$this->assertResult(true, $c1, ['x' => 1], 'int is double or int');
128+
$this->assertResult(true, $c1, ['x' => 1.4], 'double is double or int');
129+
$this->assertResult(false, $c1, ['x' => 'foo'], 'string is not double or int');
130+
131+
$c2 = new DocumentsMatchConstraint(['x' => ['$$type' => ['number', 'string']]]);
132+
133+
$this->assertResult(true, $c2, ['x' => 1], 'int is number or string');
134+
$this->assertResult(true, $c2, ['x' => 1.4], 'double is number or string');
135+
$this->assertResult(true, $c2, ['x' => 'foo'], 'string is number or string');
136+
$this->assertResult(false, $c2, ['x' => true], 'bool is not number or string');
137+
}
138+
123139
/**
124140
* @dataProvider errorMessageProvider
125141
*/

0 commit comments

Comments
 (0)