5050 */
5151class StructuresTest extends TestCase
5252{
53+ /**
54+ * How many iterations do for each date/time test
55+ * @var int
56+ */
57+ public static $ iterations = 10 ;
58+
5359 public function testInit (): AProtocol
5460 {
5561 try {
@@ -71,40 +77,42 @@ public function testInit(): AProtocol
7177 }
7278
7379 /**
74- * @depends testInit
80+ * @depends testInit
81+ * @dataProvider providerTimestamp
7582 */
76- public function testDate (AProtocol $ protocol )
83+ public function testDate (int $ timestamp , AProtocol $ protocol )
7784 {
7885 try {
79- $ date = date ('Y-m-d ' );
86+ $ date = gmdate ('Y-m-d ' , $ timestamp );
8087
8188 //unpack
8289 $ protocol ->run ('RETURN date($date) ' , [
8390 'date ' => $ date
8491 ]);
8592 $ rows = $ protocol ->pull ();
8693 $ this ->assertInstanceOf (Date::class, $ rows [0 ][0 ]);
87- $ this ->assertEquals ($ date , (string )$ rows [0 ][0 ]);
94+ $ this ->assertEquals ($ date , (string )$ rows [0 ][0 ], ' unpack ' . $ date . ' != ' . $ rows [ 0 ][ 0 ] );
8895
8996 //pack
9097 $ protocol ->run ('RETURN toString($date) ' , [
9198 'date ' => $ rows [0 ][0 ]
9299 ]);
93100 $ rows = $ protocol ->pull ();
94- $ this ->assertEquals ($ date , $ rows [0 ][0 ]);
101+ $ this ->assertEquals ($ date , $ rows [0 ][0 ], ' pack ' . $ date . ' != ' . $ rows [ 0 ][ 0 ] );
95102 } catch (Exception $ e ) {
96103 $ this ->markTestIncomplete ($ e ->getMessage ());
97104 }
98105 }
99106
100107 /**
101- * @depends testInit
108+ * @depends testInit
109+ * @dataProvider providerTimestampTimezone
102110 */
103- public function testDateTime (AProtocol $ protocol )
111+ public function testDateTime (int $ timestamp , string $ timezone , AProtocol $ protocol )
104112 {
105113 try {
106- $ datetime = \DateTime:: createFromFormat ( ' U.u ' , bcadd ( strtotime ( ' 2021-01-12 15:30:25+01:00 ' ), 0.123456 , 6 ), new \ DateTimeZone ( ' UTC ' ))
107- -> setTimezone ( new \DateTimeZone (' +0100 ' ))
114+ $ timestamp = bcadd ( $ timestamp , fmod ( microtime ( true ), 1 ) , 6 );
115+ $ datetime = \DateTime:: createFromFormat ( ' U.u ' , $ timestamp , new \DateTimeZone ($ timezone ))
108116 ->format ('Y-m-d\TH:i:s.uP ' );
109117
110118 //unpack
@@ -113,41 +121,49 @@ public function testDateTime(AProtocol $protocol)
113121 ]);
114122 $ rows = $ protocol ->pull ();
115123 $ this ->assertInstanceOf (DateTime::class, $ rows [0 ][0 ]);
116- $ this ->assertEquals ($ datetime , (string )$ rows [0 ][0 ]);
124+ $ this ->assertEquals ($ datetime , (string )$ rows [0 ][0 ], ' unpack ' . $ datetime . ' != ' . $ rows [ 0 ][ 0 ] );
117125
118126 //pack
119127 $ protocol ->run ('RETURN toString($date) ' , [
120128 'date ' => $ rows [0 ][0 ]
121129 ]);
122130 $ rows = $ protocol ->pull ();
123- $ this ->assertEquals ($ datetime , $ rows [0 ][0 ]);
131+ // neo4j returns fraction of seconds not padded with zeros ... zero timezone offset returns as Z
132+ $ datetime = preg_replace (["/\.?0+(.\d{2}:\d{2})$/ " , "/\+00:00$/ " ], ['$1 ' , 'Z ' ], $ datetime );
133+ $ this ->assertEquals ($ datetime , $ rows [0 ][0 ], 'pack ' . $ datetime . ' != ' . $ rows [0 ][0 ]);
124134 } catch (Exception $ e ) {
125135 $ this ->markTestIncomplete ($ e ->getMessage ());
126136 }
127137 }
128138
129139 /**
130- * @depends testInit
140+ * @depends testInit
141+ * @dataProvider providerTimestampTimezone
131142 */
132- public function testDateTimeZoneId (AProtocol $ protocol )
143+ public function testDateTimeZoneId (int $ timestamp , string $ timezone , AProtocol $ protocol )
133144 {
134145 try {
146+ $ timestamp = bcadd ($ timestamp , fmod (microtime (true ), 1 ), 6 );
147+ $ datetime = \DateTime::createFromFormat ('U.u ' , $ timestamp , new \DateTimeZone ($ timezone ))
148+ ->format ('Y-m-d\TH:i:s.u ' ) . '[ ' . $ timezone . '] ' ;
149+
135150 //unpack
136- $ protocol ->run ('RETURN datetime({
137- year: 1984, month: 11, day: 11,
138- hour: 12, minute: 31, second: 14, nanosecond: 645876123,
139- timezone: \'Europe/Stockholm \'
140- }) ' );
151+ $ protocol ->run ('RETURN datetime($dt) ' , [
152+ 'dt ' => $ datetime
153+ ]);
141154 $ rows = $ protocol ->pull ();
142155 $ this ->assertInstanceOf (DateTimeZoneId::class, $ rows [0 ][0 ]);
143- $ this ->assertEquals (' 1984-11-11T13:31:14.645876+01:00[Europe/Stockholm] ' , (string )$ rows [0 ][0 ]);
156+ $ this ->assertEquals ($ datetime , (string )$ rows [ 0 ][ 0 ], ' unpack ' . $ datetime . ' != ' . $ rows [0 ][0 ]);
144157
145158 //pack
146159 $ protocol ->run ('RETURN toString($dt) ' , [
147160 'dt ' => $ rows [0 ][0 ]
148161 ]);
149162 $ rows = $ protocol ->pull ();
150- $ this ->assertEquals ('1984-11-11T12:31:14.645876123+01:00[Europe/Stockholm] ' , $ rows [0 ][0 ]);
163+ // neo4j returns fraction of seconds not padded with zeros ... also contains timezone offset before timezone id
164+ $ datetime = preg_replace ("/\.?0+\[/ " , '[ ' , $ datetime );
165+ $ rows [0 ][0 ] = preg_replace ("/([+\-]\d{2}:\d{2}|Z)\[/ " , '[ ' , $ rows [0 ][0 ]);
166+ $ this ->assertEquals ($ datetime , $ rows [0 ][0 ], 'pack ' . $ datetime . ' != ' . $ rows [0 ][0 ]);
151167 } catch (Exception $ e ) {
152168 $ this ->markTestIncomplete ($ e ->getMessage ());
153169 }
@@ -172,27 +188,28 @@ public function testDuration(AProtocol $protocol)
172188 $ protocol ->run ('RETURN duration($d) ' , ['d ' => $ duration ]);
173189 $ rows = $ protocol ->pull ();
174190 $ this ->assertInstanceOf (Duration::class, $ rows [0 ][0 ]);
175- $ this ->assertEquals ($ duration , (string )$ rows [0 ][0 ]);
191+ $ this ->assertEquals ($ duration , (string )$ rows [0 ][0 ], ' unpack ' . $ duration . ' != ' . $ rows [ 0 ][ 0 ] );
176192
177193 //pack
178194 $ protocol ->run ('RETURN toString($d) ' , [
179195 'd ' => $ rows [0 ][0 ]
180196 ]);
181197 $ rows = $ protocol ->pull ();
182- $ this ->assertEquals ($ duration , $ rows [0 ][0 ]);
198+ $ this ->assertEquals ($ duration , $ rows [0 ][0 ], ' pack ' . $ duration . ' != ' . $ rows [ 0 ][ 0 ] );
183199 }
184200 } catch (Exception $ e ) {
185201 $ this ->markTestIncomplete ($ e ->getMessage ());
186202 }
187203 }
188204
189205 /**
190- * @depends testInit
206+ * @depends testInit
207+ * @dataProvider providerTimestamp
191208 */
192- public function testLocalDateTime (AProtocol $ protocol )
209+ public function testLocalDateTime (int $ timestamp , AProtocol $ protocol )
193210 {
194211 try {
195- $ datetime = \DateTime::createFromFormat ('U.u ' , bcadd ( strtotime ( ' 2021-01-12 15:30:25+01:00 ' ), 0.123456 , 6 ) )
212+ $ datetime = \DateTime::createFromFormat ('U.u ' , $ timestamp )
196213 ->format ('Y-m-d\TH:i:s.u ' );
197214
198215 //unpack
@@ -201,26 +218,29 @@ public function testLocalDateTime(AProtocol $protocol)
201218 ]);
202219 $ rows = $ protocol ->pull ();
203220 $ this ->assertInstanceOf (LocalDateTime::class, $ rows [0 ][0 ]);
204- $ this ->assertEquals ($ datetime , (string )$ rows [0 ][0 ]);
221+ $ this ->assertEquals ($ datetime , (string )$ rows [0 ][0 ], ' unpack ' . $ datetime . ' != ' . $ rows [ 0 ][ 0 ] );
205222
206223 //pack
207224 $ protocol ->run ('RETURN toString($dt) ' , [
208225 'dt ' => $ rows [0 ][0 ]
209226 ]);
210227 $ rows = $ protocol ->pull ();
211- $ this ->assertEquals ($ datetime , $ rows [0 ][0 ]);
228+ $ datetime = rtrim ($ datetime , '.0 ' );
229+ $ this ->assertEquals ($ datetime , $ rows [0 ][0 ], 'pack ' . $ datetime . ' != ' . $ rows [0 ][0 ]);
212230 } catch (Exception $ e ) {
213231 $ this ->markTestIncomplete ($ e ->getMessage ());
214232 }
215233 }
216234
217235 /**
218- * @depends testInit
236+ * @depends testInit
237+ * @dataProvider providerTimestamp
219238 */
220- public function testLocalTime (AProtocol $ protocol )
239+ public function testLocalTime (int $ timestamp , AProtocol $ protocol )
221240 {
222241 try {
223- $ time = \DateTime::createFromFormat ('U.u ' , bcadd (time (), 0.123456 , 6 ))
242+ $ timestamp = bcadd ($ timestamp , fmod (microtime (true ), 1 ), 6 );
243+ $ time = \DateTime::createFromFormat ('U.u ' , $ timestamp )
224244 ->format ('H:i:s.u ' );
225245
226246 //unpack
@@ -229,14 +249,15 @@ public function testLocalTime(AProtocol $protocol)
229249 ]);
230250 $ rows = $ protocol ->pull ();
231251 $ this ->assertInstanceOf (LocalTime::class, $ rows [0 ][0 ]);
232- $ this ->assertEquals ($ time , (string )$ rows [0 ][0 ]);
252+ $ this ->assertEquals ($ time , (string )$ rows [0 ][0 ], ' unpack ' . $ time . ' != ' . $ rows [ 0 ][ 0 ] );
233253
234254 //pack
235255 $ protocol ->run ('RETURN toString($t) ' , [
236256 't ' => $ rows [0 ][0 ]
237257 ]);
238258 $ rows = $ protocol ->pull ();
239- $ this ->assertEquals ($ time , $ rows [0 ][0 ]);
259+ $ time = rtrim ($ time , '.0 ' );
260+ $ this ->assertEquals ($ time , $ rows [0 ][0 ], 'pack ' . $ time . ' != ' . $ rows [0 ][0 ]);
240261 } catch (Exception $ e ) {
241262 $ this ->markTestIncomplete ($ e ->getMessage ());
242263 }
@@ -353,32 +374,68 @@ public function testRelationship(AProtocol $protocol)
353374 }
354375
355376 /**
356- * @depends testInit
377+ * @depends testInit
378+ * @dataProvider providerTimestampTimezone
357379 */
358- public function testTime (AProtocol $ protocol )
380+ public function testTime (int $ timestamp , string $ timezone , AProtocol $ protocol )
359381 {
360- $ time = \DateTime::createFromFormat ('U.u ' , bcadd (strtotime ('2021-01-12 15:30:25+01:00 ' ), 0.123456 , 6 ), new \DateTimeZone ('UTC ' ))
361- ->setTimezone (new \DateTimeZone ('+0100 ' ))
362- ->format ('H:i:s.uP ' );
363-
364382 try {
383+ $ timestamp = bcadd ($ timestamp , fmod (microtime (true ), 1 ), 6 );
384+ $ time = \DateTime::createFromFormat ('U.u ' , $ timestamp , new \DateTimeZone ($ timezone ))
385+ ->format ('H:i:s.uP ' );
386+
365387 //unpack
366388 $ protocol ->run ('RETURN time($t) ' , [
367389 't ' => $ time
368390 ]);
369391 $ rows = $ protocol ->pull ();
370392 $ this ->assertInstanceOf (Time::class, $ rows [0 ][0 ]);
371- $ this ->assertEquals ($ time , (string )$ rows [0 ][0 ]);
393+ $ this ->assertEquals ($ time , (string )$ rows [0 ][0 ], ' unpack ' . $ time . ' != ' . $ rows [ 0 ][ 0 ] );
372394
373395 //pack
374396 $ protocol ->run ('RETURN toString($t) ' , [
375397 't ' => $ rows [0 ][0 ]
376398 ]);
377399 $ rows = $ protocol ->pull ();
378- $ this ->assertEquals ($ time , $ rows [0 ][0 ]);
400+ // neo4j returns fraction of seconds not padded with zeros ... zero timezone offset returns as Z
401+ $ time = preg_replace (["/\.?0+(.\d{2}:\d{2})$/ " , "/\+00:00$/ " ], ['$1 ' , 'Z ' ], $ time );
402+ $ this ->assertEquals ($ time , $ rows [0 ][0 ], 'pack ' . $ time . ' != ' . $ rows [0 ][0 ]);
379403 } catch (Exception $ e ) {
380404 $ this ->markTestIncomplete ($ e ->getMessage ());
381405 }
382406 }
383407
408+ public function providerTimestamp (): \Generator
409+ {
410+ for ($ i = 0 ; $ i < self ::$ iterations ; $ i ++) {
411+ $ ts = $ this ->randomTimestamp ();
412+ yield 'ts: ' . $ ts => [$ ts ];
413+ }
414+ }
415+
416+ public function providerTimestampTimezone (): \Generator
417+ {
418+ for ($ i = 0 ; $ i < self ::$ iterations ; $ i ++) {
419+ $ tz = \DateTimeZone::listIdentifiers ()[array_rand (\DateTimeZone::listIdentifiers ())];
420+ $ ts = $ this ->randomTimestamp ($ tz );
421+ yield 'ts: ' . $ ts . ' tz: ' . $ tz => [$ ts , $ tz ];
422+ }
423+ }
424+
425+ /**
426+ * @param string $timezone
427+ * @return int
428+ */
429+ private function randomTimestamp (string $ timezone = '+0000 ' ): int
430+ {
431+ try {
432+ $ zone = new \DateTimeZone ($ timezone );
433+ $ start = new \DateTime ('-3 years ' , $ zone );
434+ $ end = new \DateTime ('+3 years ' , $ zone );
435+ return rand ($ start ->getTimestamp (), $ end ->getTimestamp ());
436+ } catch (Exception $ e ) {
437+ return time ();
438+ }
439+ }
440+
384441}
0 commit comments