1 BEGIN { do "./t/lib/ANFANG.pm" or die ( $@ || $! ) }
10 use DBIx::Class::_Util 'perlstring';
12 my $schema = DBICTest->init_schema(no_deploy => 1);
14 single_track.cd.artist.name
19 ($schema->source ('CD')->_mk_row_parser({
20 inflate_map => $infmap,
24 { single_track => ( ! defined( $_->[0]) )
45 'Simple 1:1 descending non-collapsing parser',
49 single_track.cd.artist.cds.tracks.title
50 single_track.cd.artist.artistid
52 single_track.cd.artist.cds.cdid
58 ($schema->source ('CD')->_mk_row_parser({
59 inflate_map => $infmap,
62 { artist => $_->[5], title => $_->[4], year => $_->[2] },
64 single_track => ( (! defined $_->[0] ) && (! defined $_->[1]) && (! defined $_->[3] ) )
72 { artistid => $_->[1] },
74 cds => ( (! defined $_->[0] ) && ( ! defined $_->[3] ) )
78 tracks => ( ! defined $_->[0] )
79 ? bless ( [{ title => $_->[0] }], __NBC__ )
80 : [{ title => $_->[0] }]
86 tracks => ( ! defined $_->[0] )
87 ? bless ( [{ title => $_->[0] }], __NBC__ )
88 : [{ title => $_->[0] }]
104 { artistid => $_->[1] },
106 cds => ( (! defined $_->[0] ) && ( ! defined $_->[3] ) )
110 tracks => ( ! defined $_->[0] )
111 ? bless ( [{ title => $_->[0] }], __NBC__ )
112 : [{ title => $_->[0] }]
118 tracks => ( ! defined $_->[0] )
119 ? bless ( [{ title => $_->[0] }], __NBC__ )
120 : [{ title => $_->[0] }]
131 '1:1 descending non-collapsing parser terminating with chained 1:M:M',
135 ($schema->source ('CD')->_mk_row_parser({
136 prune_null_branches => 1,
137 inflate_map => $infmap,
140 { artist => $_->[5], title => $_->[4], year => $_->[2] },
142 single_track => ( (! defined $_->[0] ) && (! defined $_->[1]) && (! defined $_->[3] ) ) ? undef : [
149 { artistid => $_->[1] },
151 cds => ( (! defined $_->[0] ) && ( ! defined $_->[3] ) ) ? undef : [
154 tracks => ( ! defined $_->[0] ) ? undef : [
155 { title => $_->[0] },
167 '1:1 descending non-collapsing pruning parser terminating with chained 1:M:M',
171 ($schema->source ('CD')->_mk_row_parser({
173 prune_null_branches => 1,
174 inflate_map => $infmap,
177 artist => $_->[5], title => $_->[4], year => $_->[2],
179 ( single_track => ( (! defined $_->[0] ) && (! defined $_->[1]) && (! defined $_->[3] ) )
186 ( cds => ( (! defined $_->[0] ) && ( ! defined $_->[3] ) )
190 ( tracks => ( ! defined $_->[0] )
192 : { title => $_->[0] }
201 '1:1 descending non-collapsing HRI-direct parser terminating with chained 1:M:M',
207 ($schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} })),
209 -identifying_columns => [ 4, 5 ],
212 -identifying_columns => [ 1, 4, 5 ],
217 -identifying_columns => [ 1, 4, 5 ],
221 -identifying_columns => [ 1, 4, 5 ],
225 -identifying_columns => [ 1, 3, 4, 5 ],
229 -identifying_columns => [ 0, 1, 3, 4, 5 ],
237 'Correct collapse map for 1:1 descending chain terminating with chained 1:M:M'
241 ($schema->source ('CD')->_mk_row_parser({
242 inflate_map => $infmap,
246 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
248 while ($cur_row_data = (
255 ( ($rows_pos = -1), undef )
259 ( $_[1] and $_[1]->() )
264 # mandatory => { 4 => 1, 5 => 1 }
265 # from_first_encounter => [ [ 1, 3, 0 ] ]
267 ( defined( $cur_row_data->[4] ) or $_[3]->{4} = 1 ),
269 ( defined( $cur_row_data->[5] ) or $_[3]->{5} = 1 ),
272 ( not defined $cur_row_data->[1] )
274 ( not defined $cur_row_data->[3] )
276 ( not defined $cur_row_data->[0] )
280 : ( not defined $cur_row_data->[3] )
282 ( not defined $cur_row_data->[0] )
289 ( keys %{$_[3]} and (
290 ( @{$_[2]} = $cur_row_data ),
296 ( @cur_row_ids{0,1,3,4,5} = (
297 ( $cur_row_data->[0] // "\0NULL\xFF$rows_pos\xFF0\0" ),
298 ( $cur_row_data->[1] // "\0NULL\xFF$rows_pos\xFF1\0" ),
299 ( $cur_row_data->[3] // "\0NULL\xFF$rows_pos\xFF3\0" ),
300 ( $cur_row_data->[4] ),
301 ( $cur_row_data->[5] ),
304 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
305 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} and (unshift @{$_[2]}, $cur_row_data) and last ),
307 # the rowdata itself for root node
308 ( $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} //= $_[0][$result_pos++] = [{ artist => $cur_row_data->[5], title => $cur_row_data->[4], year => $cur_row_data->[2] }] ),
310 # prefetch data of single_track (placed in root)
311 ( $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{single_track} //= $collapse_idx[1]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}} = [] ),
312 ( defined($cur_row_data->[1]) or bless( $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{single_track}, __NBC__ ) ),
314 # prefetch data of cd (placed in single_track)
315 ( $collapse_idx[1]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{cd} //= $collapse_idx[2]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}} = [] ),
317 # prefetch data of artist ( placed in single_track->cd)
318 ( $collapse_idx[2]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{artist} //= $collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}} = [{ artistid => $cur_row_data->[1] }] ),
320 # prefetch data of cds (if available)
322 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
324 push @{$collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{cds}}, (
325 $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} = [{ cdid => $cur_row_data->[3] }]
328 ( defined($cur_row_data->[3]) or bless( $collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{cds}, __NBC__ ) ),
330 # prefetch data of tracks (if available)
332 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
334 push @{$collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{tracks}}, (
335 $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} = [{ title => $cur_row_data->[0] }]
338 ( defined($cur_row_data->[0]) or bless( $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{tracks}, __NBC__ ) ),
341 $#{$_[0]} = $result_pos - 1;
343 'Same 1:1 descending terminating with chained 1:M:M but with collapse',
347 ($schema->source ('CD')->_mk_row_parser({
348 inflate_map => $infmap,
351 prune_null_branches => 1,
354 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
356 while ($cur_row_data = (
363 ( ($rows_pos = -1), undef )
367 ( $_[1] and $_[1]->() )
372 # mandatory => { 4 => 1, 5 => 1 }
373 # from_first_encounter => [ [ 1, 3, 0 ] ]
375 ( defined( $cur_row_data->[4] ) or $_[3]->{4} = 1 ),
377 ( defined( $cur_row_data->[5] ) or $_[3]->{5} = 1 ),
380 ( not defined $cur_row_data->[1] )
382 ( not defined $cur_row_data->[3] )
384 ( not defined $cur_row_data->[0] )
388 : ( not defined $cur_row_data->[3] )
390 ( not defined $cur_row_data->[0] )
397 ( keys %{$_[3]} and (
398 ( @{$_[2]} = $cur_row_data ),
404 ( @cur_row_ids{0, 1, 3, 4, 5} = @{$cur_row_data}[0, 1, 3, 4, 5] ),
406 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
407 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} and (unshift @{$_[2]}, $cur_row_data) and last ),
409 # the rowdata itself for root node
410 ( $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} //= $_[0][$result_pos++] = { artist => $cur_row_data->[5], title => $cur_row_data->[4], year => $cur_row_data->[2] } ),
412 # prefetch data of single_track (placed in root)
413 ( (! defined($cur_row_data->[1]) ) ? $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}{single_track} = undef : do {
414 ( $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}{single_track} //= $collapse_idx[1]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}} = {} ),
416 # prefetch data of cd (placed in single_track)
417 ( $collapse_idx[1]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}{cd} //= $collapse_idx[2]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}} = {} ),
419 # prefetch data of artist ( placed in single_track->cd)
420 ( $collapse_idx[2]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}{artist} //= $collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}} = { artistid => $cur_row_data->[1] } ),
422 # prefetch data of cds (if available)
423 ( (! defined $cur_row_data->[3] ) ? $collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}{cds} = [] : do {
426 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
428 push @{$collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}{cds}}, (
429 $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} = { cdid => $cur_row_data->[3] }
433 # prefetch data of tracks (if available)
434 (( ! defined $cur_row_data->[0] ) ? $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}{tracks} = [] : do {
437 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
439 push @{$collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}{tracks}}, (
440 $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} = { title => $cur_row_data->[0] }
447 $#{$_[0]} = $result_pos - 1;
449 'Same 1:1 descending terminating with chained 1:M:M but with collapse, HRI-direct',
453 tracks.lyrics.existing_lyric_versions.text
454 existing_single_track.cd.artist.artistid
455 existing_single_track.cd.artist.cds.year
459 existing_single_track.cd.artist.cds.cdid
461 existing_single_track.cd.artist.cds.tracks.title
462 existing_single_track.cd.artist.cds.genreid
463 tracks.lyrics.existing_lyric_versions.lyric_id
467 $schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} }),
469 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
471 existing_single_track => {
472 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
476 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
480 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
484 -identifying_columns => [ 1, 6 ], # existing_single_track.cd.artist.cds.cdid
488 -identifying_columns => [ 1, 6, 8 ], # existing_single_track.cd.artist.cds.cdid, existing_single_track.cd.artist.cds.tracks.title
496 -identifying_columns => [ 1, 5 ], # existing_single_track.cd.artist.artistid, tracks.title
500 -identifying_columns => [ 1, 5, 10 ], # existing_single_track.cd.artist.artistid, tracks.title, tracks.lyrics.existing_lyric_versions.lyric_id
504 existing_lyric_versions => {
505 -identifying_columns => [ 0, 1, 5, 10 ], # tracks.lyrics.existing_lyric_versions.text, existing_single_track.cd.artist.artistid, tracks.title, tracks.lyrics.existing_lyric_versions.lyric_id
510 'Correct collapse map constructed',
514 ($schema->source ('CD')->_mk_row_parser({
515 inflate_map => $infmap,
519 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
521 while ($cur_row_data = (
528 ( ($rows_pos = -1), undef )
532 ( $_[1] and $_[1]->() )
537 # mandatory => { 1 => 1 }
538 # from_first_encounter => [ [6, 8], [5, 10, 0] ],
540 ( defined( $cur_row_data->[1] ) or $_[3]->{1} = 1 ),
543 ( not defined $cur_row_data->[6] )
545 ( not defined $cur_row_data->[8] )
553 ( not defined $cur_row_data->[5] )
555 ( not defined $cur_row_data->[10] )
557 ( not defined $cur_row_data->[0] )
561 : ( not defined $cur_row_data->[10] )
563 ( not defined $cur_row_data->[0] )
570 ( keys %{$_[3]} and (
571 ( @{$_[2]} = $cur_row_data ),
577 ( @cur_row_ids{0, 1, 5, 6, 8, 10} = (
578 $cur_row_data->[0] // "\0NULL\xFF$rows_pos\xFF0\0",
580 $cur_row_data->[5] // "\0NULL\xFF$rows_pos\xFF5\0",
581 $cur_row_data->[6] // "\0NULL\xFF$rows_pos\xFF6\0",
582 $cur_row_data->[8] // "\0NULL\xFF$rows_pos\xFF8\0",
583 $cur_row_data->[10] // "\0NULL\xFF$rows_pos\xFF10\0",
586 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
587 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{1}} and (unshift @{$_[2]}, $cur_row_data) and last ),
589 ( $collapse_idx[0]{$cur_row_ids{1}} //= $_[0][$result_pos++] = [{ genreid => $cur_row_data->[4], latest_cd => $cur_row_data->[7], year => $cur_row_data->[3] }] ),
591 ( $collapse_idx[0]{$cur_row_ids{1}}[1]{existing_single_track} //= $collapse_idx[1]{$cur_row_ids{1}} = [] ),
592 ( $collapse_idx[1]{$cur_row_ids{1}}[1]{cd} //= $collapse_idx[2]{$cur_row_ids{1}} = [] ),
593 ( $collapse_idx[2]{$cur_row_ids{1}}[1]{artist} //= $collapse_idx[3]{$cur_row_ids{1}} = [{ artistid => $cur_row_data->[1] }] ),
596 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}} )
598 push @{ $collapse_idx[3]{$cur_row_ids{1}}[1]{cds} }, (
599 $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}} = [{ cdid => $cur_row_data->[6], genreid => $cur_row_data->[9], year => $cur_row_data->[2] }]
602 ( defined($cur_row_data->[6]) or bless( $collapse_idx[3]{$cur_row_ids{1}}[1]{cds}, __NBC__ ) ),
605 (! $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} )
607 push @{ $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks} }, (
608 $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} = [{ title => $cur_row_data->[8] }]
611 ( defined($cur_row_data->[8]) or bless( $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks}, __NBC__ ) ),
614 (! $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} )
616 push @{ $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks} }, (
617 $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} = [{ title => $cur_row_data->[5] }]
620 ( defined($cur_row_data->[5]) or bless( $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks}, __NBC__ ) ),
622 ( $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics} //= $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} = [] ),
623 ( defined($cur_row_data->[10]) or bless( $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics}, __NBC__ ) ),
626 (! $collapse_idx[8]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} )
628 push @{ $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}}[1]{existing_lyric_versions} }, (
629 $collapse_idx[8]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} = [{ lyric_id => $cur_row_data->[10], text => $cur_row_data->[0] }]
634 $#{$_[0]} = $result_pos - 1;
636 'Multiple has_many on multiple branches torture test',
640 ($schema->source ('CD')->_mk_row_parser({
641 inflate_map => $infmap,
643 prune_null_branches => 1,
646 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
648 while ($cur_row_data = (
655 ( ($rows_pos = -1), undef )
659 ( $_[1] and $_[1]->() )
664 # mandatory => { 1 => 1 }
665 # from_first_encounter => [ [6, 8], [5, 10, 0] ],
667 ( defined( $cur_row_data->[1] ) or $_[3]->{1} = 1 ),
670 ( not defined $cur_row_data->[6] )
672 ( not defined $cur_row_data->[8] )
680 ( not defined $cur_row_data->[5] )
682 ( not defined $cur_row_data->[10] )
684 ( not defined $cur_row_data->[0] )
688 : ( not defined $cur_row_data->[10] )
690 ( not defined $cur_row_data->[0] )
697 ( keys %{$_[3]} and (
698 ( @{$_[2]} = $cur_row_data ),
704 ( @cur_row_ids{( 0, 1, 5, 6, 8, 10 )} = @{$cur_row_data}[( 0, 1, 5, 6, 8, 10 )] ),
706 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
707 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{1}} and (unshift @{$_[2]}, $cur_row_data) and last ),
709 ( $collapse_idx[0]{$cur_row_ids{1}} //= $_[0][$result_pos++] = [{ genreid => $cur_row_data->[4], latest_cd => $cur_row_data->[7], year => $cur_row_data->[3] }] ),
711 ( $collapse_idx[0]{$cur_row_ids{1}}[1]{existing_single_track} //= $collapse_idx[1]{$cur_row_ids{1}} = [] ),
712 ( $collapse_idx[1]{$cur_row_ids{1}}[1]{cd} //= $collapse_idx[2]{$cur_row_ids{1}} = [] ),
713 ( $collapse_idx[2]{$cur_row_ids{1}}[1]{artist} //= $collapse_idx[3]{$cur_row_ids{1}} = [{ artistid => $cur_row_data->[1] }] ),
715 ( (! defined($cur_row_data->[6])) ? $collapse_idx[3]{$cur_row_ids{1}}[1]{cds} = [] : do {
717 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}} )
719 push @{ $collapse_idx[3]{$cur_row_ids{1}}[1]{cds} }, (
720 $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}} = [{ cdid => $cur_row_data->[6], genreid => $cur_row_data->[9], year => $cur_row_data->[2] }]
724 ( (! defined($cur_row_data->[8]) ) ? $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks} = [] : do {
726 (! $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} )
728 push @{ $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks} }, (
729 $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} = [{ title => $cur_row_data->[8] }]
735 ( (! defined($cur_row_data->[5]) ) ? $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks} = [] : do {
738 (! $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} )
740 push @{ $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks} }, (
741 $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} = [{ title => $cur_row_data->[5] }]
745 ( (! defined($cur_row_data->[10]) ) ? $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics} = [] : do {
747 ( $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics} //= $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} = [] ),
750 (! $collapse_idx[8]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} )
752 push @{ $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}}[1]{existing_lyric_versions} }, (
753 $collapse_idx[8]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} = [{ lyric_id => $cur_row_data->[10], text => $cur_row_data->[0] }]
760 $#{$_[0]} = $result_pos - 1;
762 'Multiple has_many on multiple branches with branch pruning torture test',
766 'single_track.trackid', # (0) definitive link to root from 1:1:1:1:M:M chain
767 'year', # (1) non-unique
768 'tracks.cd', # (2) \ together both uniqueness for second multirel
769 'tracks.title', # (3) / and definitive link back to root
770 'single_track.cd.artist.cds.cdid', # (4) to give uniquiness to ...tracks.title below
771 'single_track.cd.artist.cds.year', # (5) non-unique
772 'single_track.cd.artist.artistid', # (6) uniqufies entire parental chain
773 'single_track.cd.artist.cds.genreid', # (7) nullable
774 'single_track.cd.artist.cds.tracks.title',# (8) unique when combined with ...cds.cdid above
778 $schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} }),
780 -identifying_columns => [],
781 -identifying_columns_variants => [
785 -identifying_columns => [ 0 ],
789 -identifying_columns => [ 0 ],
792 -identifying_columns => [ 0 ],
795 -identifying_columns => [ 0, 4 ],
798 -identifying_columns => [ 0, 4, 8 ],
806 -identifying_columns => [ 2, 3 ],
810 'Correct underdefined root collapse map constructed'
814 ($schema->source ('CD')->_mk_row_parser({
815 inflate_map => $infmap,
819 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
821 while ($cur_row_data = (
828 ( ($rows_pos = -1), undef )
832 ( $_[1] and $_[1]->() )
838 # from_first_encounter => [ [0, 4, 8] ]
839 # all_or_nothing => [ { 2 => 1, 3 => 1 } ]
841 ( not defined $cur_row_data->[0] )
843 ( not defined $cur_row_data->[4] )
845 ( not defined $cur_row_data->[8] )
849 : ( not defined $cur_row_data->[4] )
851 ( not defined $cur_row_data->[8] )
860 ( not defined $cur_row_data->[2] )
862 ( not defined $cur_row_data->[3] )
866 ( defined($cur_row_data->[2]) or $_[3]->{2} = 1 ),
867 ( defined($cur_row_data->[3]) or $_[3]->{3} = 1 ),
871 ( keys %{$_[3]} and (
872 ( @{$_[2]} = $cur_row_data ),
878 ( @cur_row_ids{( 0, 2, 3, 4, 8 )} = (
879 $cur_row_data->[0] // "\0NULL\xFF$rows_pos\xFF0\0",
880 $cur_row_data->[2] // "\0NULL\xFF$rows_pos\xFF2\0",
881 $cur_row_data->[3] // "\0NULL\xFF$rows_pos\xFF3\0",
882 $cur_row_data->[4] // "\0NULL\xFF$rows_pos\xFF4\0",
883 $cur_row_data->[8] // "\0NULL\xFF$rows_pos\xFF8\0",
886 # cache expensive set of ops in a non-existent rowid slot
887 ( $cur_row_ids{10} = (
888 ( ( defined $cur_row_data->[0] ) && (join "\xFF", q{}, $cur_row_ids{0}, q{} ))
890 ( ( defined $cur_row_data->[2] ) && (join "\xFF", q{}, $cur_row_ids{2}, q{} ))
895 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
896 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{10}} and (unshift @{$_[2]}, $cur_row_data) and last ),
898 ( $collapse_idx[0]{$cur_row_ids{10}} //= $_[0][$result_pos++] = [{ year => $$cur_row_data[1] }] ),
900 ( $collapse_idx[0]{$cur_row_ids{10}}[1]{single_track} //= ($collapse_idx[1]{$cur_row_ids{0}} = [{ trackid => $cur_row_data->[0] }]) ),
901 ( defined($cur_row_data->[0]) or bless ( $collapse_idx[0]{$cur_row_ids{10}}[1]{single_track}, __NBC__ ) ),
903 ( $collapse_idx[1]{$cur_row_ids{0}}[1]{cd} //= $collapse_idx[2]{$cur_row_ids{0}} = [] ),
905 ( $collapse_idx[2]{$cur_row_ids{0}}[1]{artist} //= ($collapse_idx[3]{$cur_row_ids{0}} = [{ artistid => $cur_row_data->[6] }]) ),
908 (! $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}} )
910 push @{$collapse_idx[3]{$cur_row_ids{0}}[1]{cds}}, (
911 $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}} = [{ cdid => $cur_row_data->[4], genreid => $cur_row_data->[7], year => $cur_row_data->[5] }]
914 ( defined($cur_row_data->[4]) or bless ( $collapse_idx[3]{$cur_row_ids{0}}[1]{cds}, __NBC__ ) ),
917 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} )
919 push @{$collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}[1]{tracks}}, (
920 $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} = [{ title => $cur_row_data->[8] }]
923 ( defined($cur_row_data->[8]) or bless ( $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}[1]{tracks}, __NBC__ ) ),
926 (! $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} )
928 push @{$collapse_idx[0]{$cur_row_ids{10}}[1]{tracks}}, (
929 $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} = [{ cd => $$cur_row_data[2], title => $cur_row_data->[3] }]
932 ( defined($cur_row_data->[2]) or bless ( $collapse_idx[0]{$cur_row_ids{10}}[1]{tracks}, __NBC__ ) ),
935 $#{$_[0]} = $result_pos - 1;
937 'Multiple has_many on multiple branches with underdefined root torture test',
941 ($schema->source ('CD')->_mk_row_parser({
942 inflate_map => $infmap,
945 prune_null_branches => 1,
948 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
950 while ($cur_row_data = (
957 ( ($rows_pos = -1), undef )
961 ( $_[1] and $_[1]->() )
967 # from_first_encounter => [ [0, 4, 8] ]
968 # all_or_nothing => [ { 2 => 1, 3 => 1 } ]
970 ( not defined $cur_row_data->[0] )
972 ( not defined $cur_row_data->[4] )
974 ( not defined $cur_row_data->[8] )
978 : ( not defined $cur_row_data->[4] )
980 ( not defined $cur_row_data->[8] )
989 ( not defined $cur_row_data->[2] )
991 ( not defined $cur_row_data->[3] )
995 ( defined($cur_row_data->[2]) or $_[3]->{2} = 1 ),
996 ( defined($cur_row_data->[3]) or $_[3]->{3} = 1 ),
1000 ( keys %{$_[3]} and (
1001 ( @{$_[2]} = $cur_row_data ),
1002 ( $result_pos = 0 ),
1007 # do not care about nullability here
1008 ( @cur_row_ids{( 0, 2, 3, 4, 8 )} = @{$cur_row_data}[( 0, 2, 3, 4, 8 )] ),
1010 # cache expensive set of ops in a non-existent rowid slot
1011 ( $cur_row_ids{10} = (
1012 ( ( defined $cur_row_data->[0] ) && (join "\xFF", q{}, $cur_row_ids{0}, q{} ))
1014 ( ( defined $cur_row_data->[2] ) && (join "\xFF", q{}, $cur_row_ids{2}, q{} ))
1019 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
1020 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{10}} and (unshift @{$_[2]}, $cur_row_data) and last ),
1022 ( $collapse_idx[0]{$cur_row_ids{10}} //= $_[0][$result_pos++] = { year => $$cur_row_data[1] } ),
1024 ( (! defined $cur_row_data->[0] ) ? $collapse_idx[0]{$cur_row_ids{10}}{single_track} = undef : do {
1026 ( $collapse_idx[0]{$cur_row_ids{10}}{single_track} //= ($collapse_idx[1]{$cur_row_ids{0}} = { trackid => $$cur_row_data[0] }) ),
1028 ( $collapse_idx[1]{$cur_row_ids{0}}{cd} //= $collapse_idx[2]{$cur_row_ids{0}} = {} ),
1030 ( $collapse_idx[2]{$cur_row_ids{0}}{artist} //= ($collapse_idx[3]{$cur_row_ids{0}} = { artistid => $$cur_row_data[6] }) ),
1032 ( (! defined $cur_row_data->[4] ) ? $collapse_idx[3]{$cur_row_ids{0}}{cds} = [] : do {
1035 (! $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}} )
1037 push @{$collapse_idx[3]{$cur_row_ids{0}}{cds}}, (
1038 $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}} = { cdid => $$cur_row_data[4], genreid => $$cur_row_data[7], year => $$cur_row_data[5] }
1042 ( (! defined $cur_row_data->[8] ) ? $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}{tracks} = [] : do {
1044 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} )
1046 push @{$collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}{tracks}}, (
1047 $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} = { title => $$cur_row_data[8] }
1053 ( (! defined $cur_row_data->[2] ) ? $collapse_idx[0]{$cur_row_ids{10}}{tracks} = [] : do {
1055 (! $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} )
1057 push @{$collapse_idx[0]{$cur_row_ids{10}}{tracks}}, (
1058 $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} = { cd => $$cur_row_data[2], title => $$cur_row_data[3] }
1064 $#{$_[0]} = $result_pos - 1;
1066 'Multiple has_many on multiple branches with underdefined root, HRI-direct torture test',
1071 'single_track.lyrics.track_id', # (0) random optional 1:1:1 chain
1072 'year', # (1) non-unique
1073 'tracks.cd', # (2) \ together both uniqueness for second multirel
1074 'tracks.title', # (3) / and definitive link back to root
1075 'single_track.cd.artist.cds.cdid', # (4) to give uniquiness to ...tracks.title below
1076 'single_track.cd.artist.cds.year', # (5) non-unique
1077 'single_track.cd.artist.artistid', # (6) uniqufies entire parental chain
1078 'single_track.cd.artist.cds.genreid', # (7) nullable
1079 'single_track.cd.artist.cds.tracks.title', # (8) unique when combined with ...cds.cdid above
1080 'single_track.lyrics.lyric_versions.text', # (9) unique combined with the single_track.lyrics 1:1:1
1084 $schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} }),
1086 -identifying_columns => [],
1087 -identifying_columns_variants => [
1091 -identifying_columns => [ 6 ],
1095 -identifying_columns => [ 6 ],
1098 -identifying_columns => [ 6 ],
1101 -identifying_columns => [ 4, 6 ],
1104 -identifying_columns => [ 4, 6, 8 ],
1111 -identifying_columns => [ 0, 6 ],
1115 -identifying_columns => [ 0, 6, 9 ],
1121 -identifying_columns => [ 2, 3 ],
1125 'Correct underdefined root tripple-has-many-torture collapse map constructed'
1129 ($schema->source ('CD')->_mk_row_parser({
1130 inflate_map => $infmap,
1133 prune_null_branches => 1,
1136 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
1138 while ($cur_row_data = (
1145 ( ($rows_pos = -1), undef )
1149 ( $_[1] and $_[1]->() )
1154 # from_first_encounter => [ [6, 4, 8], [6, 0, 9] ]
1155 # all_or_nothing => [ { 2 => 1, 3 => 1 } ]
1157 ( not defined $cur_row_data->[6] )
1159 ( not defined $cur_row_data->[4] )
1161 ( not defined $cur_row_data->[8] )
1165 : ( not defined $cur_row_data->[4] )
1167 ( not defined $cur_row_data->[8] )
1175 ( not defined $cur_row_data->[6] )
1177 ( not defined $cur_row_data->[0] )
1179 ( not defined $cur_row_data->[9] )
1183 : ( not defined $cur_row_data->[0] )
1185 ( not defined $cur_row_data->[9] )
1194 ( not defined $cur_row_data->[2] )
1196 ( not defined $cur_row_data->[3] )
1200 ( defined($cur_row_data->[2]) or $_[3]->{2} = 1 ),
1201 ( defined($cur_row_data->[3]) or $_[3]->{3} = 1 ),
1205 ( keys %{$_[3]} and (
1206 ( @{$_[2]} = $cur_row_data ),
1207 ( $result_pos = 0 ),
1212 # do not care about nullability here
1213 ( @cur_row_ids{( 0, 2, 3, 4, 6, 8, 9 )} = @{$cur_row_data}[( 0, 2, 3, 4, 6, 8, 9 )] ),
1215 # cache expensive set of ops in a non-existent rowid slot
1216 ( $cur_row_ids{11} = (
1217 ( ( defined $cur_row_data->[2] ) && (join "\xFF", q{}, $cur_row_ids{2}, q{} ))
1219 ( ( defined $cur_row_data->[6] ) && (join "\xFF", q{}, $cur_row_ids{6}, q{} ))
1224 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
1225 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{11}} and (unshift @{$_[2]}, $cur_row_data) and last ),
1227 ( $collapse_idx[0]{$cur_row_ids{11}} //= $_[0][$result_pos++] = { year => $$cur_row_data[1] } ),
1229 ( (! defined $cur_row_data->[6] ) ? $collapse_idx[0]{$cur_row_ids{11}}{single_track} = undef : do {
1231 ( $collapse_idx[0]{$cur_row_ids{11}}{single_track} //= ( $collapse_idx[1]{$cur_row_ids{6}} = {} ) ),
1233 ( $collapse_idx[1]{$cur_row_ids{6}}{cd} //= $collapse_idx[2]{$cur_row_ids{6}} = {} ),
1235 ( $collapse_idx[2]{$cur_row_ids{6}}{artist} //= ($collapse_idx[3]{$cur_row_ids{6}} = { artistid => $$cur_row_data[6] }) ),
1237 ( (! defined $cur_row_data->[4] ) ? $collapse_idx[3]{$cur_row_ids{6}}{cds} = [] : do {
1240 (! $collapse_idx[4]{$cur_row_ids{4}}{$cur_row_ids{6}} )
1242 push @{$collapse_idx[3]{$cur_row_ids{6}}{cds}}, (
1243 $collapse_idx[4]{$cur_row_ids{4}}{$cur_row_ids{6}} = { cdid => $$cur_row_data[4], genreid => $$cur_row_data[7], year => $$cur_row_data[5] }
1247 ( (! defined $cur_row_data->[8] ) ? $collapse_idx[4]{$cur_row_ids{4}}{$cur_row_ids{6}}{tracks} = [] : do {
1249 (! $collapse_idx[5]{$cur_row_ids{4}}{$cur_row_ids{6}}{$cur_row_ids{8}} )
1251 push @{$collapse_idx[4]{$cur_row_ids{4}}{$cur_row_ids{6}}{tracks}}, (
1252 $collapse_idx[5]{$cur_row_ids{4}}{$cur_row_ids{6}}{$cur_row_ids{8}} = { title => $$cur_row_data[8] }
1257 ( ( ! defined $cur_row_data->[0] ) ? $collapse_idx[1]{ $cur_row_ids{6} }{"lyrics"} = undef : do {
1259 ( $collapse_idx[1]{ $cur_row_ids{6} }{"lyrics"} //= ( $collapse_idx[6]{ $cur_row_ids{0} }{ $cur_row_ids{6} } = { "track_id" => $cur_row_data->[0] } ) ),
1261 ( ( ! defined $cur_row_data->[9] ) ? $collapse_idx[6]{ $cur_row_ids{0} }{ $cur_row_ids{6} }{"lyric_versions"} = [] : do {
1263 (! $collapse_idx[7]{ $cur_row_ids{0} }{ $cur_row_ids{6} }{ $cur_row_ids{9} })
1265 push @{$collapse_idx[6]{ $cur_row_ids{0} }{ $cur_row_ids{6} }{"lyric_versions"}}, (
1266 $collapse_idx[7]{ $cur_row_ids{0} }{ $cur_row_ids{6} }{ $cur_row_ids{9} } = { "text" => $cur_row_data->[9] }
1273 ( (! defined $cur_row_data->[2] ) ? $collapse_idx[0]{$cur_row_ids{11}}{tracks} = [] : do {
1275 (! $collapse_idx[8]{$cur_row_ids{2}}{$cur_row_ids{3}} )
1277 push @{$collapse_idx[0]{$cur_row_ids{11}}{tracks}}, (
1278 $collapse_idx[8]{$cur_row_ids{2}}{$cur_row_ids{3}} = { cd => $$cur_row_data[2], title => $$cur_row_data[3] }
1284 $#{$_[0]} = $result_pos - 1;
1286 'Tripple multiple has_many on multiple branches with underdefined root, HRI-direct torture test',
1290 ($schema->source ('Owners')->_mk_row_parser({
1291 inflate_map => [qw( books.title books.owner )],
1293 prune_null_branches => 1,
1296 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids );
1298 while ($cur_row_data = (
1305 ( ($rows_pos = -1), undef )
1309 ( $_[1] and $_[1]->() )
1312 ( @cur_row_ids{0,1} = @{$cur_row_data}[0,1] ),
1314 ( $cur_row_ids{3} = (
1315 ( ( defined $cur_row_data->[1] ) && (join "\xFF", q{}, $cur_row_ids{1}, q{} ))
1320 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{3}} and (unshift @{$_[2]}, $cur_row_data) and last ),
1322 # empty data for the root node
1323 ( $collapse_idx[0]{$cur_row_ids{3}} //= $_[0][$result_pos++] = [] ),
1325 ( ( ! defined $cur_row_data->[0] ) ? $collapse_idx[0]{$cur_row_ids{3}}[1]{"books"} = [] : do {
1326 ( ! $collapse_idx[1]{$cur_row_ids{0}} )
1328 push @{$collapse_idx[0]{$cur_row_ids{3}}[1]{books}},
1329 $collapse_idx[1]{$cur_row_ids{0}} = [ { owner => $cur_row_data->[1], title => $cur_row_data->[0] } ]
1333 $#{$_[0]} = $result_pos - 1; # truncate the passed in array to where we filled it with results
1335 'Non-premultiplied implicit collapse with missing join columns',
1339 ($schema->source('Artist')->_mk_row_parser({
1340 inflate_map => [qw( artistid cds.artist cds.title cds.tracks.title )],
1342 prune_null_branches => 1,
1345 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids );
1347 while ($cur_row_data = (
1354 ( ($rows_pos = -1), undef )
1358 ( $_[1] and $_[1]->() )
1363 # mandatory => { 0 => 1 }
1364 # from_first_encounter => [ [1, 2, 3] ]
1365 # all_or_nothing => [ { 1 => 1, 2 => 1 } ]
1367 ( defined( $cur_row_data->[0] ) or $_[3]->{0} = 1 ),
1370 ( not defined $cur_row_data->[1] )
1372 ( not defined $cur_row_data->[2] )
1374 ( not defined $cur_row_data->[3] )
1378 : ( not defined $cur_row_data->[2] )
1380 ( not defined $cur_row_data->[3] )
1389 ( not defined $cur_row_data->[1] )
1391 ( not defined $cur_row_data->[2] )
1395 ( defined($cur_row_data->[1]) or $_[3]->{1} = 1 ),
1396 ( defined($cur_row_data->[2]) or $_[3]->{2} = 1 ),
1400 ( keys %{$_[3]} and (
1401 ( @{$_[2]} = $cur_row_data ),
1402 ( $result_pos = 0 ),
1407 ( @cur_row_ids{( 0, 1, 2, 3 )} = @{$cur_row_data}[ 0, 1, 2, 3 ] ),
1409 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{0}} and (unshift @{$_[2]}, $cur_row_data) and last ),
1411 ( $collapse_idx[0]{ $cur_row_ids{0} }
1412 //= $_[0][$result_pos++] = [ { "artistid" => $cur_row_data->[0] } ]
1415 ( ( ! defined $cur_row_data->[1] ) ? $collapse_idx[0]{ $cur_row_ids{0} }[1]{"cds"} = [] : do {
1418 ! $collapse_idx[1]{ $cur_row_ids{0} }{ $cur_row_ids{1} }{ $cur_row_ids{2} }
1420 push @{$collapse_idx[0]{ $cur_row_ids{0} }[1]{"cds"}},
1421 $collapse_idx[1]{ $cur_row_ids{0} }{ $cur_row_ids{1} }{ $cur_row_ids{2} }
1422 = [ { "artist" => $cur_row_data->[1], "title" => $cur_row_data->[2] } ]
1425 ( ( ! defined $cur_row_data->[3] ) ? $collapse_idx[1]{ $cur_row_ids{0} }{ $cur_row_ids{1} }{ $cur_row_ids{2} }[1]{"tracks"} = [] : do {
1427 ! $collapse_idx[2]{ $cur_row_ids{0} }{ $cur_row_ids{1} }{ $cur_row_ids{2} }{ $cur_row_ids{3} }
1429 push @{$collapse_idx[1]{ $cur_row_ids{0} }{ $cur_row_ids{1} }{ $cur_row_ids{2} }[1]{"tracks"}},
1430 $collapse_idx[2]{ $cur_row_ids{0} }{ $cur_row_ids{1} }{ $cur_row_ids{2} }{ $cur_row_ids{3} }
1431 = [ { "title" => $cur_row_data->[3] } ]
1437 $#{$_[0]} = $result_pos - 1
1439 'A rolled out version of inflate map of misled_rowparser.t'
1445 sub is_same_src { SKIP: {
1447 skip "Skipping comparison of unicode-poisoned source", 1
1448 if DBIx::Class::_ENV_::STRESSTEST_UTF8_UPGRADE_GENERATED_COLLAPSER_SOURCE;
1450 $deparser ||= B::Deparse->new;
1451 local $Test::Builder::Level = $Test::Builder::Level + 1;
1453 my ($got, $expect) = @_;
1455 skip "Not testing equality of source containing defined-or operator on this perl $]", 1
1456 if ( "$]" < 5.010 and $expect =~ m!\Q//=! );
1458 $expect =~ s/__NBC__/perlstring($DBIx::Class::ResultSource::RowParser::Util::null_branch_class)/ge;
1460 $expect = "sub { use strict; use warnings FATAL => 'uninitialized';\n$expect\n }";
1462 my @normalized = map {
1463 my $cref = eval "sub { $_ }" or do {
1464 fail "Coderef does not compile!\n\n$@\n\n$_";
1467 $deparser->coderef2text($cref);
1470 &is (@normalized, $_[2]||() ) or do {
1471 eval { require Test::Differences }
1472 ? &Test::Differences::eq_or_diff( @normalized, $_[2]||() )
1473 : note ("Original sources:\n\n$got\n\n$expect\n")