@@ -18,14 +18,26 @@ class MatchesTest extends FunctionalTestCase
18
18
public function testMatchesDocument ()
19
19
{
20
20
$ c = new Matches (['x ' => 1 , 'y ' => ['a ' => 1 , 'b ' => 2 ]]);
21
-
22
21
$ this ->assertResult (false , $ c , ['x ' => 1 , 'y ' => 2 ], 'Incorrect value ' );
23
22
$ this ->assertResult (true , $ c , ['x ' => 1 , 'y ' => ['a ' => 1 , 'b ' => 2 ]], 'Exact match ' );
24
23
$ this ->assertResult (true , $ c , ['x ' => 1 , 'y ' => ['a ' => 1 , 'b ' => 2 ], 'z ' => 3 ], 'Extra keys in root are permitted ' );
25
24
$ this ->assertResult (false , $ c , ['x ' => 1 , 'y ' => ['a ' => 1 , 'b ' => 2 , 'c ' => 3 ]], 'Extra keys in embedded are not permitted ' );
26
25
$ this ->assertResult (true , $ c , ['y ' => ['b ' => 2 , 'a ' => 1 ], 'x ' => 1 ], 'Root and embedded key order is not significant ' );
27
26
}
28
27
28
+ public function testDoNotAllowExtraRootKeys ()
29
+ {
30
+ $ c = new Matches (['x ' => 1 ], null , false );
31
+ $ this ->assertResult (false , $ c , ['x ' => 1 , 'y ' => 1 ], 'Extra keys in root are prohibited ' );
32
+ }
33
+
34
+ public function testDoNotAllowOperators ()
35
+ {
36
+ $ c = new Matches (['x ' => ['$$exists ' => true ]], null , true , false );
37
+ $ this ->assertResult (false , $ c , ['x ' => 1 ], 'Operators are not processed ' );
38
+ $ this ->assertResult (true , $ c , ['x ' => ['$$exists ' => true ]], 'Operators are not processed but compared as-is ' );
39
+ }
40
+
29
41
public function testOperatorExists ()
30
42
{
31
43
$ c = new Matches (['x ' => ['$$exists ' => true ]]);
@@ -52,12 +64,10 @@ public function testOperatorExists()
52
64
public function testOperatorType ()
53
65
{
54
66
$ c = new Matches (['x ' => ['$$type ' => 'string ' ]]);
55
-
56
67
$ this ->assertResult (true , $ c , ['x ' => 'foo ' ], 'string matches string type ' );
57
68
$ this ->assertResult (false , $ c , ['x ' => 1 ], 'integer does not match string type ' );
58
69
59
70
$ c = new Matches (['x ' => ['$$type ' => ['string ' , 'bool ' ]]]);
60
-
61
71
$ this ->assertResult (true , $ c , ['x ' => 'foo ' ], 'string matches [string,bool] type ' );
62
72
$ this ->assertResult (true , $ c , ['x ' => true ], 'bool matches [string,bool] type ' );
63
73
$ this ->assertResult (false , $ c , ['x ' => 1 ], 'integer does not match [string,bool] type ' );
@@ -70,30 +80,19 @@ public function testOperatorMatchesEntity()
70
80
$ entityMap ['object ' ] = ['y ' => 1 ];
71
81
72
82
$ c = new Matches (['x ' => ['$$matchesEntity ' => 'integer ' ]], $ entityMap );
73
-
74
83
$ this ->assertResult (true , $ c , ['x ' => 1 ], 'value matches integer entity (embedded) ' );
75
84
$ this ->assertResult (false , $ c , ['x ' => 2 ], 'value does not match integer entity (embedded) ' );
76
85
$ this ->assertResult (false , $ c , ['x ' => ['y ' => 1 ]], 'value does not match integer entity (embedded) ' );
77
86
78
87
$ c = new Matches (['x ' => ['$$matchesEntity ' => 'object ' ]], $ entityMap );
79
-
80
88
$ this ->assertResult (true , $ c , ['x ' => ['y ' => 1 ]], 'value matches object entity (embedded) ' );
81
89
$ this ->assertResult (false , $ c , ['x ' => 1 ], 'value does not match object entity (embedded) ' );
82
90
$ this ->assertResult (false , $ c , ['x ' => ['y ' => 1 , 'z ' => 2 ]], 'value does not match object entity (embedded) ' );
83
91
84
92
$ c = new Matches (['$$matchesEntity ' => 'object ' ], $ entityMap );
85
-
86
93
$ this ->assertResult (true , $ c , ['y ' => 1 ], 'value matches object entity (root-level) ' );
87
94
$ this ->assertResult (true , $ c , ['x ' => 2 , 'y ' => 1 ], 'value matches object entity (root-level) ' );
88
95
$ this ->assertResult (false , $ c , ['x ' => ['y ' => 1 , 'z ' => 2 ]], 'value does not match object entity (root-level) ' );
89
-
90
- $ c = new Matches (['$$matchesEntity ' => 'undefined ' ], $ entityMap );
91
-
92
- $ this ->assertResult (false , $ c , 'undefined ' , 'value does not match undefined entity (root-level) ' );
93
-
94
- $ c = new Matches (['x ' => ['$$matchesEntity ' => 'undefined ' ]], $ entityMap );
95
-
96
- $ this ->assertResult (false , $ c , ['x ' => 'undefined ' ], 'value does not match undefined entity (embedded) ' );
97
96
}
98
97
99
98
public function testOperatorMatchesHexBytes ()
@@ -107,13 +106,11 @@ public function testOperatorMatchesHexBytes()
107
106
rewind ($ stream2 );
108
107
109
108
$ c = new Matches (['$$matchesHexBytes ' => 'DEADBEEF ' ]);
110
-
111
109
$ this ->assertResult (true , $ c , $ stream1 , 'value matches hex bytes (root-level) ' );
112
110
$ this ->assertResult (false , $ c , $ stream2 , 'value does not match hex bytes (root-level) ' );
113
111
$ this ->assertResult (false , $ c , 1 , 'value is not a stream ' );
114
112
115
113
$ c = new Matches (['x ' => ['$$matchesHexBytes ' => '90ABCDEF ' ]]);
116
-
117
114
$ this ->assertResult (true , $ c , ['x ' => $ stream2 ], 'value matches hex bytes (embedded) ' );
118
115
$ this ->assertResult (false , $ c , ['x ' => $ stream1 ], 'value does not match hex bytes (embedded) ' );
119
116
$ this ->assertResult (false , $ c , ['x ' => 1 ], 'value is not a stream ' );
@@ -122,14 +119,12 @@ public function testOperatorMatchesHexBytes()
122
119
public function testOperatorUnsetOrMatches ()
123
120
{
124
121
$ c = new Matches (['$$unsetOrMatches ' => ['x ' => 1 ]]);
125
-
126
122
$ this ->assertResult (true , $ c , null , 'null value is considered unset (root-level) ' );
127
123
$ this ->assertResult (true , $ c , ['x ' => 1 ], 'value matches (root-level) ' );
128
124
$ this ->assertResult (true , $ c , ['x ' => 1 , 'y ' => 1 ], 'value matches (root-level) ' );
129
125
$ this ->assertResult (false , $ c , ['x ' => 2 ], 'value does not match (root-level) ' );
130
126
131
127
$ c = new Matches (['x ' => ['$$unsetOrMatches ' => ['y ' => 1 ]]]);
132
-
133
128
$ this ->assertResult (true , $ c , new stdClass (), 'missing value is considered unset (embedded) ' );
134
129
$ this ->assertResult (false , $ c , ['x ' => null ], 'null value is not considered unset (embedded) ' );
135
130
$ this ->assertResult (true , $ c , ['x ' => ['y ' => 1 ]], 'value matches (embedded) ' );
@@ -151,14 +146,12 @@ public function testOperatorSessionLsid()
151
146
$ lsidWithExtraField = (array ) $ session ->getLogicalSessionId () + ['y ' => 1 ];
152
147
153
148
$ c = new Matches (['$$sessionLsid ' => 'session ' ], $ entityMap );
154
-
155
149
$ this ->assertResult (true , $ c , $ session ->getLogicalSessionId (), 'session LSID matches (root-level) ' );
156
150
$ this ->assertResult (false , $ c , $ lsidWithWrongId , 'session LSID does not match (root-level) ' );
157
151
$ this ->assertResult (false , $ c , $ lsidWithExtraField , 'session LSID does not match (root-level) ' );
158
152
$ this ->assertResult (false , $ c , 1 , 'session LSID does not match (root-level) ' );
159
153
160
154
$ c = new Matches (['x ' => ['$$sessionLsid ' => 'session ' ]], $ entityMap );
161
-
162
155
$ this ->assertResult (true , $ c , ['x ' => $ session ->getLogicalSessionId ()], 'session LSID matches (embedded) ' );
163
156
$ this ->assertResult (false , $ c , ['x ' => $ lsidWithWrongId ], 'session LSID does not match (embedded) ' );
164
157
$ this ->assertResult (false , $ c , ['x ' => $ lsidWithExtraField ], 'session LSID does not match (embedded) ' );
@@ -173,9 +166,9 @@ public function testErrorMessages($expectedMessagePart, Matches $constraint, $ac
173
166
try {
174
167
$ constraint ->evaluate ($ actualValue );
175
168
$ this ->fail ('Expected a comparison failure ' );
176
- } catch (ExpectationFailedException $ failure ) {
177
- $ this ->assertStringContainsString ('Failed asserting that expected value matches actual value. ' , $ failure ->getMessage ());
178
- $ this ->assertStringContainsString ($ expectedMessagePart , $ failure ->getMessage ());
169
+ } catch (ExpectationFailedException $ e ) {
170
+ $ this ->assertStringContainsString ('Failed asserting that expected value matches actual value. ' , $ e ->getMessage ());
171
+ $ this ->assertStringContainsString ($ expectedMessagePart , $ e ->getMessage ());
179
172
}
180
173
}
181
174
@@ -250,6 +243,66 @@ public function errorMessageProvider()
250
243
];
251
244
}
252
245
246
+ /**
247
+ * @dataProvider operatorErrorMessageProvider
248
+ */
249
+ public function testOperatorSyntaxValidation ($ expectedMessage , Matches $ constraint )
250
+ {
251
+ $ this ->expectException (ExpectationFailedException::class);
252
+ $ this ->expectExceptionMessage ($ expectedMessage );
253
+
254
+ $ constraint ->evaluate (['x ' => 1 ], '' , true );
255
+ }
256
+
257
+ public function operatorErrorMessageProvider ()
258
+ {
259
+ $ entityMap = new EntityMap ();
260
+ $ entityMap ['notSession ' ] = 1 ;
261
+
262
+ return [
263
+ '$$exists type ' => [
264
+ '$$exists requires bool ' ,
265
+ new Matches (['x ' => ['$$exists ' => 1 ]]),
266
+ ],
267
+ '$$type type (string) ' => [
268
+ '$$type requires string or string[] ' ,
269
+ new Matches (['x ' => ['$$type ' => 1 ]]),
270
+ ],
271
+ '$$type type (string[]) ' => [
272
+ '$$type requires string or string[] ' ,
273
+ new Matches (['x ' => ['$$type ' => [1 ]]]),
274
+ ],
275
+ '$$matchesEntity type ' => [
276
+ '$$matchesEntity requires string ' ,
277
+ new Matches (['x ' => ['$$matchesEntity ' => 1 ]]),
278
+ ],
279
+ '$$matchesEntity undefined entity ' => [
280
+ 'No entity is defined for "undefined" ' ,
281
+ new Matches (['$$matchesEntity ' => 'undefined ' ]),
282
+ ],
283
+ '$$matchesHexBytes type ' => [
284
+ '$$matchesHexBytes requires string ' ,
285
+ new Matches (['$$matchesHexBytes ' => 1 ]),
286
+ ],
287
+ '$$matchesHexBytes string format ' => [
288
+ '$$matchesHexBytes requires pairs of hex chars ' ,
289
+ new Matches (['$$matchesHexBytes ' => 'f00 ' ]),
290
+ ],
291
+ '$$sessionLsid type ' => [
292
+ '$$sessionLsid requires string ' ,
293
+ new Matches (['x ' => ['$$sessionLsid ' => 1 ]]),
294
+ ],
295
+ '$$sessionLsid undefined entity ' => [
296
+ 'No entity is defined for "undefined" ' ,
297
+ new Matches (['$$sessionLsid ' => 'undefined ' ]),
298
+ ],
299
+ '$$sessionLsid invalid entity ' => [
300
+ '$$sessionLsid requires session entity ' ,
301
+ new Matches (['x ' => ['$$sessionLsid ' => 'notSession ' ]], $ entityMap ),
302
+ ],
303
+ ];
304
+ }
305
+
253
306
private function assertResult ($ expected , Matches $ constraint , $ value , $ message )
254
307
{
255
308
$ this ->assertSame ($ expected , $ constraint ->evaluate ($ value , '' , true ), $ message );
0 commit comments