File Coverage

lib/Test/Neo4j/Types.pm
Criterion Covered Total %
statement 344 344 100.0
branch 9 10 90.0
condition 5 15 33.3
subroutine 53 53 100.0
pod 5 5 100.0
total 416 427 97.4


line stmt bran cond sub pod time code
1 3     3   206243 use v5.10;
  3         30  
2 3     3   14 use strict;
  3         6  
  3         57  
3 3     3   12 use warnings;
  3         5  
  3         152  
4              
5             package Test::Neo4j::Types;
6             # ABSTRACT: Tools for testing Neo4j type modules
7             $Test::Neo4j::Types::VERSION = '0.02';
8              
9 3     3   16 use Test::More 0.94;
  3         37  
  3         16  
10 3     3   2225 use Test::Exception;
  3         9654  
  3         9  
11 3     3   2238 use Test::Warnings qw(warnings :no_end_test);
  3         5930  
  3         27  
12              
13 3     3   362 use Exporter 'import';
  3         6  
  3         152  
14 3     3   117 BEGIN { our @EXPORT = qw(
15             neo4j_node_ok
16             neo4j_relationship_ok
17             neo4j_path_ok
18             neo4j_point_ok
19             neo4j_datetime_ok
20             )}
21              
22             {
23             # This happens within new versions of Neo4j/Types.pm,
24             # but we can't be sure the version is new enough:
25             package # local
26             Neo4j::Types;
27 3     3   18 use warnings::register;
  3         5  
  3         968  
28             }
29              
30              
31             sub _element_id_test {
32 12     12   35 my ($BOTH, $ID_ONLY, $new, $class, $prefix) = @_;
33            
34             subtest "${prefix}element_id", sub {
35 12     12   9682 plan tests => 6;
36            
37 12         7333 my $both = $new->($class, {%$BOTH});
38 12         143 my $id_only = $new->($class, {%$ID_ONLY});
39 12 100       166 lives_ok { $both->element_id } 'optional op element_id' if $both->can('element_id');
  4         132  
40 12 100       1533 dies_ok { $both->element_id } 'optional op element_id' if ! $both->can('element_id');
  8         335  
41             SKIP: {
42 12 100       2876 skip 'optional op element_id unimplemented', 2+3 unless $class->can('element_id');
  12         85  
43 3     3   22 no strict 'refs';
  3         5  
  3         599  
44 4         10 my ($element_id, $id) = map { "$prefix$_" } qw( element_id id );
  8         21  
45            
46             # When both IDs are present, id() MAY warn
47 4         18 is $both->$element_id(), $BOTH->{$element_id}, "$element_id";
48 4         1570 warnings { is $both->$id(), $BOTH->{$id}, "legacy $id" };
  4         61  
49            
50             # For a missing element ID, element_id() returns the numeric ID and MUST warn
51 4         1606 my @w_eid = warnings { is $id_only->$element_id(), $ID_ONLY->{$id}, "no $element_id with legacy $id" };
  4         53  
52 4         1586 ok @w_eid, "no $element_id warns";
53 4 50       1465 warn @w_eid if @w_eid > 1;
54 3     3   20 no warnings 'Neo4j::Types';
  3         8  
  3         11839  
55 4         25 is warnings { $id_only->$element_id() }, @w_eid - 1, "no $element_id warn cat is Neo4j::Types";
  4         51  
56             };
57 12         132 };
58             }
59              
60              
61             sub _node_test {
62 3     3   18 my ($node_class, $new) = @_;
63            
64 3         12 plan tests => 12 + 5 + 7 + 1 + 1;
65            
66 3         1926 my ($n, @l, $p);
67            
68 3         33 $n = $new->($node_class, my $id_only = {
69             id => 42,
70             labels => ['Foo', 'Bar'],
71             properties => { foofoo => 11, barbar => 22, '123' => [1, 2, 3] },
72             });
73 3         43 is $n->id(), 42, 'id';
74 3         1303 @l = $n->labels;
75 3         53 is scalar(@l), 2, 'label count';
76 3         1090 is $l[0], 'Foo', 'label Foo';
77 3         1090 is $l[1], 'Bar', 'label Bar';
78 3     3   1091 lives_and { is scalar($n->labels), 2 } 'scalar context';
  3         55  
79 3         1144 is $n->get('foofoo'), 11, 'get foofoo';
80 3         1136 is $n->get('barbar'), 22, 'get barbar';
81 3         1067 is_deeply $n->get('123'), [1, 2, 3], 'get 123';
82 3         2036 $p = $n->properties;
83 3         26 is ref($p), 'HASH', 'props ref';
84 3         1089 is $p->{foofoo}, 11, 'props foofoo';
85 3         1095 is $p->{barbar}, 22, 'props barbar';
86 3         1111 is_deeply $p->{123}, [1, 2, 3], 'props 123';
87            
88 3         2088 $n = $new->($node_class, {
89             id => 0,
90             properties => { '0' => [] },
91             });
92 3         38 is $n->id(), 0, 'id 0';
93 3         1091 is ref($n->get('0')), 'ARRAY', 'get 0 ref';
94 3         1063 is scalar(@{$n->get('0')}), 0, 'get 0 empty';
  3         14  
95 3         1065 $p = $n->properties;
96 3         26 is_deeply $p, {0=>[]}, 'props deeply';
97 3         2238 is_deeply [$n->properties], [{0=>[]}], 'props list context';
98            
99 3         2576 $n = $new->($node_class, { });
100 3         38 ok ! defined($n->id), 'id gigo';
101 3         1078 @l = $n->labels;
102 3         48 is scalar(@l), 0, 'no labels';
103 3     3   1138 lives_and { is scalar($n->labels), 0 } 'scalar context no labels';
  3         47  
104 3         1129 $p = $n->properties;
105 3         24 is ref($p), 'HASH', 'empty props ref';
106 3         1079 is scalar(keys %$p), 0, 'empty props empty';
107 3         1121 is_deeply [$n->get('whatever')], [undef], 'prop undef';
108 3         1687 ok ! exists $n->properties->{whatever}, 'prop remains non-existent';
109            
110             # element ID
111 3         1017 my $both = { element_id => 'e17', id => 17 };
112 3         17 _element_id_test($both, $id_only, $new, $node_class, '');
113            
114 3         8550 ok $n->DOES('Neo4j::Types::Node'), 'does role';
115             }
116              
117              
118             sub neo4j_node_ok {
119 3     3 1 2734 my ($class, $new, $name) = @_;
120 3   33     29 $name //= "neo4j_node_ok '$class'";
121 3     3   17 subtest $name, sub { _node_test($class, $new) };
  3         2653  
122             }
123              
124              
125             sub _relationship_test {
126 3     3   23 my ($rel_class, $new) = @_;
127            
128 3         12 plan tests => 11 + 5 + 8 + 3 + 1;
129            
130 3         1672 my ($r, $p);
131            
132 3         50 $r = $new->($rel_class, my $id_only = {
133             id => 55,
134             type => 'TEST',
135             start_id => 34,
136             end_id => 89,
137             properties => { foo => 144, bar => 233, '358' => [3, 5, 8] },
138             });
139 3         53 is $r->id, 55, 'id';
140 3         1136 is $r->type, 'TEST', 'type';
141 3         1098 is $r->start_id, 34, 'start id';
142 3         1077 is $r->end_id, 89, 'end id';
143 3         1056 is $r->get('foo'), 144, 'get foo';
144 3         1093 is $r->get('bar'), 233, 'get bar';
145 3         1083 is_deeply $r->get('358'), [3, 5, 8], 'get 358';
146 3         1820 $p = $r->properties;
147 3         43 is ref($p), 'HASH', 'props ref';
148 3         1108 is $p->{foo}, 144, 'props foo';
149 3         1109 is $p->{bar}, 233, 'props bar';
150 3         1067 is_deeply $p->{358}, [3, 5, 8], 'props 358';
151            
152 3         1714 $r = $new->($rel_class, {
153             id => 0,
154             properties => { '0' => [] },
155             });
156 3         49 is $r->id(), 0, 'id 0';
157 3         1075 is ref($r->get('0')), 'ARRAY', 'get 0 ref';
158 3         1112 is scalar(@{$r->get('0')}), 0, 'get 0 empty';
  3         14  
159 3         1081 $p = $r->properties;
160 3         31 is_deeply $p, {0=>[]}, 'props deeply';
161 3         2201 is_deeply [$r->properties], [{0=>[]}], 'props list context';
162            
163 3         2553 $r = $new->($rel_class, { });
164 3         34 ok ! defined($r->id), 'id gigo';
165 3         1025 ok ! defined($r->type), 'no type';
166 3         1011 ok ! defined($r->start_id), 'no start id';
167 3         1019 ok ! defined($r->end_id), 'no end id';
168 3         999 $p = $r->properties;
169 3         25 is ref($p), 'HASH', 'empty props ref';
170 3         1087 is scalar(keys %$p), 0, 'empty props empty';
171 3         1124 is_deeply [$r->get('whatever')], [undef], 'prop undef';
172 3         1725 ok ! exists $r->properties->{whatever}, 'prop remains non-existent';
173            
174             # element ID
175 3         1055 my $both = {
176             element_id => 'e60', id => 60,
177             start_element_id => 'e61', start_id => 61,
178             end_element_id => 'e62', end_id => 62,
179             };
180 3         14 _element_id_test($both, $id_only, $new, $rel_class, '');
181 3         7694 _element_id_test($both, $id_only, $new, $rel_class, 'start_');
182 3         7667 _element_id_test($both, $id_only, $new, $rel_class, 'end_');
183            
184 3         7564 ok $r->DOES('Neo4j::Types::Relationship'), 'does role';
185             }
186              
187              
188             sub neo4j_relationship_ok {
189 3     3 1 3869 my ($class, $new, $name) = @_;
190 3   33     26 $name //= "neo4j_relationship_ok '$class'";
191 3     3   16 subtest $name, sub { _relationship_test($class, $new) };
  3         2111  
192             }
193              
194              
195             sub _path_test {
196 2     2   7 my ($path_class, $new) = @_;
197            
198 2         8 plan tests => 3 + 3 + 6 + 6 + 1;
199            
200 2         1081 my (@p, $p, @e);
201            
202             my $new_path = sub {
203 6     6   11 my $i = 0;
204 6 100       13 map { my $o = $_; bless \$o, 'Test::Neo4j::Types::Path' . ($i++ & 1 ? 'Rel' : 'Node') } @_;
  18         24  
  18         79  
205 2         12 };
206            
207 2         6 @p = $new_path->( \6, \7, \8 );
208 2         9 $p = $new->($path_class, \@p);
209 2         23 @e = $p->elements;
210 2         58 is_deeply [@e], [@p], 'deeply elements 3';
211 2         2006 @e = $p->nodes;
212 2         60 is_deeply [@e], [$p[0],$p[2]], 'deeply nodes 2';
213 2         1664 @e = $p->relationships;
214 2         37 is_deeply [@e], [$p[1]], 'deeply rel 1';
215            
216 2         1327 @p = $new_path->( \9 );
217 2         9 $p = $new->($path_class, \@p);
218 2         23 @e = $p->elements;
219 2         31 is_deeply [@e], [@p], 'deeply elements 1';
220 2         1333 @e = $p->nodes;
221 2         25 is_deeply [@e], [$p[0]], 'deeply nodes 1';
222 2         1320 @e = $p->relationships;
223 2         24 is_deeply [@e], [], 'deeply rel 0';
224            
225 2         1068 @p = $new_path->( \1, \2, \3, \4, \5 );
226 2         13 $p = $new->($path_class, \@p);
227 2         14 @e = $p->elements;
228 2         29 is_deeply [@e], [@p], 'deeply elements 5';
229 2     2   2363 lives_and { is scalar($p->elements), 5 } 'scalar context elements';
  2         37  
230 2         767 @e = $p->nodes;
231 2         37 is_deeply [@e], [$p[0],$p[2],$p[4]], 'deeply nodes 3';
232 2     2   1825 lives_and { is scalar($p->nodes), 3 } 'scalar context nodes';
  2         30  
233 2         747 @e = $p->relationships;
234 2         30 is_deeply [@e], [$p[1],$p[3]], 'deeply rel 2';
235 2     2   1630 lives_and { is scalar($p->relationships), 2 } 'scalar context relationships';
  2         29  
236            
237 2         737 $p = $new->($path_class, []);
238 2         20 @e = $p->elements;
239 2         21 is scalar(@e), 0, 'no elements gigo';
240 2     2   716 lives_and { is scalar($p->elements), 0 } 'scalar context no elements';
  2         31  
241 2         744 @e = $p->nodes;
242 2         24 is scalar(@e), 0, 'no nodes 0 gigo';
243 2     2   709 lives_and { is scalar($p->nodes), 0 } 'scalar context no nodes';
  2         37  
244 2         733 @e = $p->relationships;
245 2         23 is scalar(@e), 0, 'no relationships 0 gigo';
246 2     2   722 lives_and { is scalar($p->relationships), 0 } 'scalar context no relationships';
  2         32  
247            
248 2         754 ok $p->DOES('Neo4j::Types::Path'), 'does role';
249             }
250              
251              
252             sub neo4j_path_ok {
253 2     2 1 2673 my ($class, $new, $name) = @_;
254 2   33     26 $name //= "neo4j_path_ok '$class'";
255 2     2   14 subtest $name, sub { _path_test($class, $new) };
  2         1398  
256             }
257              
258              
259             sub _point_test {
260 2     2   9 my ($point_class) = @_;
261            
262 2         8 plan tests => (9-6)+3 + (9-6)+3+3+3+2 + 6+6+6+6 + 1;
263            
264 2         1091 my (@c, $p);
265            
266            
267             # Simple point, location in real world
268 2         9 @c = ( 2.294, 48.858, 396 );
269 2         23 $p = $point_class->new( 4979, @c );
270 2         59 is $p->srid(), 4979, 'eiffel srid';
271             # is $p->X(), 2.294, 'eiffel X';
272             # is $p->Y(), 48.858, 'eiffel Y';
273             # is $p->Z(), 396, 'eiffel Z';
274             # is $p->longitude(), 2.294, 'eiffel lon';
275             # is $p->latitude(), 48.858, 'eiffel lat';
276             # is $p->height(), 396, 'eiffel ellipsoidal height';
277 2         718 is_deeply [$p->coordinates], [@c], 'eiffel coords';
278 2         1264 is scalar ($p->coordinates), 3, 'scalar context eiffel coords';
279            
280 2         769 @c = ( 2.294, 48.858 );
281 2         12 $p = $point_class->new( 4326, @c );
282 2         48 is $p->srid(), 4326, 'eiffel 2d srid';
283 2         714 is_deeply [$p->coordinates], [@c], 'eiffel 2d coords';
284 2         1161 is scalar ($p->coordinates), 2, 'scalar context eiffel 2d coords';
285            
286            
287             # Other SRSs, location not in real world
288 2         709 @c = ( 12, 34 );
289 2         11 $p = $point_class->new( 7203, @c );
290 2         37 is $p->srid(), 7203, 'plane srid';
291             # is $p->X(), 12, 'plane X';
292             # is $p->Y(), 34, 'plane Y';
293             # ok ! defined $p->Z(), 'plane Z';
294             # is $p->longitude(), 12, 'plane lon';
295             # is $p->latitude(), 34, 'plane lat';
296             # ok ! defined $p->height(), 'plane height';
297 2         708 is_deeply [$p->coordinates], [@c], 'plane coords';
298 2         1169 is scalar ($p->coordinates), 2, 'scalar context plane coords';
299            
300 2         709 @c = ( 56, 78, 90 );
301 2         9 $p = $point_class->new( 9157, @c );
302 2         40 is $p->srid(), 9157, 'space srid';
303 2         781 is_deeply [$p->coordinates], [@c], 'space coords';
304 2         1154 is scalar ($p->coordinates), 3, 'scalar context space coords';
305            
306 2         718 @c = ( 361, -91 );
307 2         12 $p = $point_class->new( 4326, @c );
308 2         36 is $p->srid(), 4326, 'ootw srid';
309 2         704 is_deeply [$p->coordinates], [@c], 'ootw coords';
310 2         1134 is scalar ($p->coordinates), 2, 'scalar context ootw coords';
311            
312 2         746 @c = ( 'what', 'ever' );
313 2         10 $p = $point_class->new( '4326', @c );
314 2         35 is $p->srid(), '4326', 'string srid';
315 2         707 is_deeply [$p->coordinates], [@c], 'string coords';
316 2         1221 is scalar ($p->coordinates), 2, 'scalar context string coords';
317            
318 2         707 @c = ( undef, 45 );
319 2         11 $p = $point_class->new( 7203, @c );
320 2         37 is_deeply [$p->coordinates], [@c], 'undef coord';
321 2         1130 is scalar ($p->coordinates), 2, 'scalar context undef coord';
322            
323            
324             # Failure behaviour for incorrect number of coordinates supplied to the constructor
325 2         707 @c = ( 42 );
326 2     2   28 throws_ok { $point_class->new( 4326, @c ) } qr/\bdimensions\b/i, 'new 4326 X fails';
  2         80  
327 2     2   1256 throws_ok { $point_class->new( 4979, @c ) } qr/\bdimensions\b/i, 'new 4979 X fails';
  2         68  
328 2     2   1106 throws_ok { $point_class->new( 7203, @c ) } qr/\bdimensions\b/i, 'new 7203 X fails';
  2         68  
329 2     2   1115 throws_ok { $point_class->new( 9157, @c ) } qr/\bdimensions\b/i, 'new 9157 X fails';
  2         66  
330 2     2   1070 throws_ok { $point_class->new( 12345, @c ) } qr/\bUnsupported\b/i, 'new 12345 X fails';
  2         98  
331 2     2   1072 throws_ok { $point_class->new( undef, @c ) } qr/\bSRID\b/i, 'new undef X fails';
  2         64  
332            
333 2         1089 @c = ( 2.294, 48.858 );
334 2         9 $p = $point_class->new( 4326, @c );
335 2         34 is_deeply [$p->coordinates], [@c[0..1]], 'new 4326';
336 2     2   1198 throws_ok { $point_class->new( 4979, @c ) } qr/\bdimensions\b/i, 'new 4979 XY fails';
  2         72  
337 2         1124 $p = $point_class->new( 7203, @c );
338 2         37 is_deeply [$p->coordinates], [@c[0..1]], 'new 7203';
339 2     2   1163 throws_ok { $point_class->new( 9157, @c ) } qr/\bdimensions\b/i, 'new 9157 XY fails';
  2         67  
340 2     2   1103 throws_ok { $point_class->new( 12345, @c ) } qr/\bUnsupported\b/i, 'new 12345 XY fails';
  2         66  
341 2     2   1097 throws_ok { $point_class->new( undef, @c ) } qr/\bSRID\b/i, 'new undef XY fails';
  2         68  
342            
343 2         1063 @c = ( 2.294, 48.858, 396 );
344 2         10 $p = $point_class->new( 4326, @c );
345 2         47 is_deeply [$p->coordinates], [@c[0..1]], 'new 4326 Z ignored';
346 2         1246 $p = $point_class->new( 4979, @c );
347 2         37 is_deeply [$p->coordinates], [@c[0..2]], 'new 4979';
348 2         1201 $p = $point_class->new( 7203, @c );
349 2         36 is_deeply [$p->coordinates], [@c[0..1]], 'new 7203 Z ignored';
350 2         1158 $p = $point_class->new( 9157, @c );
351 2         37 is_deeply [$p->coordinates], [@c[0..2]], 'new 9157';
352 2     2   1168 throws_ok { $point_class->new( 12345, @c ) } qr/\bUnsupported\b/i, 'new 12345 XYZ fails';
  2         69  
353 2     2   1132 throws_ok { $point_class->new( undef, @c ) } qr/\bSRID\b/i, 'new undef XYZ fails';
  2         74  
354            
355 2         1135 @c = ( 2.294, 48.858, 396, 13 );
356 2         11 $p = $point_class->new( 4326, @c );
357 2         38 is_deeply [$p->coordinates], [@c[0..1]], 'new 4326 ZM ignored';
358 2         1177 $p = $point_class->new( 4979, @c );
359 2         36 is_deeply [$p->coordinates], [@c[0..2]], 'new 4979 M ignored';
360 2         1315 $p = $point_class->new( 7203, @c );
361 2         38 is_deeply [$p->coordinates], [@c[0..1]], 'new 7203 ZM ignored';
362 2         1177 $p = $point_class->new( 9157, @c );
363 2         44 is_deeply [$p->coordinates], [@c[0..2]], 'new 9157 M ignored';
364 2     2   1205 throws_ok { $point_class->new( 12345, @c ) } qr/\bUnsupported\b/i, 'new 12345 XYZM fails';
  2         70  
365 2     2   1097 throws_ok { $point_class->new( undef, @c ) } qr/\bSRID\b/i, 'new undef XYZM fails';
  2         76  
366            
367            
368 2         1110 ok $p->DOES('Neo4j::Types::Point'), 'does role';
369             }
370              
371              
372             sub neo4j_point_ok {
373 2     2 1 2642 my ($class, $name) = @_;
374 2   33     21 $name //= "neo4j_point_ok '$class'";
375 2     2   13 subtest $name, sub { _point_test($class) };
  2         1411  
376             }
377              
378              
379             sub _datetime_test {
380 1     1   4 my ($datetime_class, $new) = @_;
381            
382 1         4 plan tests => 5 * 7 + 1;
383            
384 1         573 my ($dt, $p, $type);
385            
386 1         7 $dt = $new->($datetime_class, $p = {
387             days => 18645, # 2021-01-18
388             });
389 1         16 is $dt->days, $p->{days}, 'date: days';
390 1         368 is $dt->epoch, 1610928000, 'date: epoch';
391 1         356 is $dt->nanoseconds, $p->{nanoseconds}, 'date: no nanoseconds';
392 1         414 is $dt->seconds, $p->{seconds}, 'date: no seconds';
393 1         434 is $dt->type, 'DATE', 'date: type';
394 1         358 is $dt->tz_name, $p->{tz_name}, 'date: no tz_name';
395 1         472 is $dt->tz_offset, $p->{tz_offset}, 'date: no tz_offset';
396            
397 1         414 $type = lc 'LOCAL TIME';
398 1         7 $dt = $new->($datetime_class, $p = {
399             nanoseconds => 1,
400             seconds => 0,
401             });
402 1         15 is $dt->days, $p->{days}, 'local time: no days';
403 1         471 is $dt->epoch, 0, 'local time: epoch';
404 1         356 is $dt->nanoseconds, $p->{nanoseconds}, 'local time: nanoseconds';
405 1         364 is $dt->seconds, $p->{seconds}, 'local time: seconds';
406 1         371 is $dt->type, 'LOCAL TIME', 'local time: type';
407 1         353 is $dt->tz_name, $p->{tz_name}, 'local time: no tz_name';
408 1         438 is $dt->tz_offset, $p->{tz_offset}, 'local time: no tz_offset';
409            
410 1         406 $type = lc 'ZONED TIME';
411 1         6 $dt = $new->($datetime_class, $p = {
412             nanoseconds => 5e8, # 0.5 s
413             seconds => 86340, # 23:59
414             tz_offset => -28800, # -8 h
415             });
416 1         10 is $dt->days, $p->{days}, 'zoned time: no days';
417 1         409 is $dt->epoch, 86340, 'zoned time: epoch';
418 1         351 is $dt->nanoseconds, $p->{nanoseconds}, 'zoned time: nanoseconds';
419 1         354 is $dt->seconds, $p->{seconds}, 'zoned time: seconds';
420 1         351 is $dt->type, 'ZONED TIME', 'zoned time: type';
421 1         374 is $dt->tz_name, $p->{tz_name}, 'zoned time: no tz_name';
422 1         410 is $dt->tz_offset, $p->{tz_offset}, 'zoned time: tz_offset';
423            
424 1         388 $type = lc 'LOCAL DATETIME';
425 1         7 $dt = $new->($datetime_class, $p = {
426             days => -1,
427             nanoseconds => 999_999_999,
428             seconds => 86399,
429             });
430 1         10 is $dt->days, $p->{days}, 'local datetime: days';
431 1         351 is $dt->epoch, -1, 'local datetime: epoch';
432 1         350 is $dt->nanoseconds, $p->{nanoseconds}, 'local datetime: nanoseconds';
433 1         349 is $dt->seconds, $p->{seconds}, 'local datetime: seconds';
434 1         349 is $dt->type, 'LOCAL DATETIME', 'local datetime: type';
435 1         364 is $dt->tz_name, $p->{tz_name}, 'local datetime: no tz_name';
436 1         410 is $dt->tz_offset, $p->{tz_offset}, 'local datetime: no tz_offset';
437            
438 1         428 $type = lc 'ZONED DATETIME';
439 1         8 $dt = $new->($datetime_class, $p = {
440             days => 6560, # 1987-12-18
441             nanoseconds => 0,
442             seconds => 72000, # 20:00 UTC
443             tz_name => 'America/Los_Angeles',
444             });
445 1         8 is $dt->days, $p->{days}, 'zoned datetime: days';
446 1         349 is $dt->epoch, 566856000, 'zoned datetime: epoch';
447 1         349 is $dt->nanoseconds, $p->{nanoseconds}, 'zoned datetime: nanoseconds';
448 1         352 is $dt->seconds, $p->{seconds}, 'zoned datetime: seconds';
449 1         350 is $dt->type, 'ZONED DATETIME', 'zoned datetime: type';
450 1         367 is $dt->tz_name, $p->{tz_name}, 'zoned datetime: tz_name';
451 1         356 is $dt->tz_offset, $p->{tz_offset}, 'zoned datetime: no tz_offset';
452            
453 1         440 ok $dt->DOES('Neo4j::Types::DateTime'), 'does role';
454             }
455              
456              
457             sub neo4j_datetime_ok {
458 1     1 1 1392 my ($class, $new, $name) = @_;
459 1   33     10 $name //= "neo4j_datetime_ok '$class'";
460 1     1   6 subtest $name, sub { _datetime_test($class, $new) };
  1         804  
461             }
462              
463              
464             package # private
465             Test::Neo4j::Types::PathNode;
466 12     12   69 sub DOES { $_[1] eq 'Neo4j::Types::Node' }
467              
468              
469             package # private
470             Test::Neo4j::Types::PathRel;
471 6     6   18 sub DOES { $_[1] eq 'Neo4j::Types::Relationship' }
472              
473              
474             1;