#-- test suite use strict; use warnings; # change 'tests => 1' to 'tests => last_test_to_print'; use Test::More qw(no_plan); use Data::Dumper; $Data::Dumper::Indent = 1; sub _chomp { my $s = shift; chomp $s; return $s; } my $warn = shift @ARGV; unless ($warn) { close STDERR; open (STDERR, ">/dev/null"); select (STDERR); $| = 1; } #== TESTS ===================================================================== use XML::Simple; $XML::Simple::PREFERRED_PARSER = 'XML::LibXML::SAX'; use XML::LibXML::SAX; my $tests = XMLin('t/tmql-use-cases.xml', KeyAttr => { database => 'title' }, ForceArray => [ 'database', 'query', 'use-case', 'solution', 'axiom' ]); use TM::Literal; use TM::Index::Match; require_ok ('TM::QL::TS'); require_ok ('TM::QL::PE'); require_ok ('TM::QL'); #warn "# no tests activated"; my $UC = shift @ARGV; foreach my $testdb (map { $tests->{database}->{$_} } ( # 'PE Database', 'TMQL Database' ) ) { use TM::Materialized::AsTMa; my $tm = new TM::Materialized::AsTMa (inline => $testdb->{data}->{content}); $tm->sync_in; # my $idx1 = new TM::Index::Match ($tm); #warn Dumper $tm; exit; foreach my $u (sort { $a->{qid} cmp $b->{qid} } @{$testdb->{'use-case'}}) { # warn "testing '".$u->{qid} ."'"; next if $u->{qid} =~ /^\*/; next if (defined $UC and $u->{qid} ne $UC); # next unless $u->{qid} =~ /^s/; my $d = $u->{title} || ""; $d =~ s/\n//g; my $sol_ctr = 0; foreach my $q (@{$u->{query}}) { my $expected = $q->{interface}->{output}; $expected->{content} ||= ''; if ($expected->{type} eq 'list' || $expected->{type} eq 'set') { $expected->{content} =~ s/^\s*\n+//s; $expected->{content} =~ s/\n+\s*$//s; } elsif ($expected->{type} eq 'xml') { # ok } elsif ($expected->{type} eq 'xpath') { $expected->{content} =~ s/^\s*\n+//s; $expected->{content} =~ s/\n+\s*$//s; } else { die; } #warn "query ".Dumper $q; my @only_tests = (); # assume that there is none foreach my $s (@{$q->{solution}}) { #warn "test ".Dumper $s; push @only_tests, $s if $s->{operational} eq "tyes"; } #warn Dumper \@only_tests; foreach my $s (@only_tests ? @only_tests : @{$q->{solution}}) { # take only_tests or fall back to complete list $sol_ctr++; if ($s->{operational} eq 'TODO') { TODO: { local $TODO = $d."/".$q->{title}.": ".$u->{qid}."/$sol_ctr: "; ok (0, $TODO); # $s->{code} } } elsif ($s->{operational} =~ /yes/) { #warn "working on solution $sol_ctr".Dumper $s; if ($expected->{type} eq 'list' || $expected->{type} eq 'set') { my $exp; if ($expected->{content} =~ /\[\.\.\.\]/) { $exp = [ map { [ $_->[TM->LID] ] } $tm->toplets ]; } elsif ($expected->{content} =~ /^$/) { $exp = []; } elsif ($expected->{content} =~ /\[\.\.\.\.\.\.\]/) { my @ts = map { $_->[TM->LID] } $tm->toplets; $exp = [ map { my $x = $_; map { [ $x, $_ ] } @ts } @ts ]; } else { my @s = map { $_ =~ s/\s+// or $_ } split (/\n/, $expected->{content}); @$exp = (); foreach my $s (@s) { push @$exp, [ map { $_ =~ /^\w+:/ and $_ or $_ =~ /(true|false)/ and new TM::Literal ($1, 'xsd:boolean') or $_ =~ /\[(.*)\]/ and $tm->tids ($1) #or (warn $_ and 0) or $_ =~ /\[([a-f0-9]{32})\]/ and $1 or $_ =~ /"(http:.*)"/ and $_ = $1 and new TM::Literal ($_, 'xsd:anyURI') or $_ =~ /"(urn:.*)"/ and $_ = $1 and new TM::Literal ($_, 'xsd:anyURI') or $_ =~ /"(.*)"/ and $_ = $1 and new TM::Literal ($_, 'xsd:string') or $_ =~ /(\-?\d+(\.\d+))/ and new TM::Literal ($1, 'xsd:decimal') or $_ =~ /(\-?\d+)/ and new TM::Literal ($1, 'xsd:integer') or $_ =~ /null/ and undef } split (/\s*,\s*/, $s) ]; } #warn "expectation is: ".Dumper ($exp); exit; } _check_list ($tm, $d."/".$q->{title}.": ".$u->{qid}."/$sol_ctr: ", $expected->{type} eq 'list', $s->{code}, $exp, $s->{language}); # ordered or not } elsif ($expected->{type} eq 'xml') { my $exp = $expected->{content}; # $exp =~ s/^\n+//; $exp =~ s/\n+$//; # warn "EXPECTING XML $exp"; my $res = _eval_q ($tm, $s->{code}, $s->{language}); # warn "GOT $res". Dumper $res; my $xml = $res->[0]->[0]->[0]; my $s = $xml->toString (0); is ($s, $exp, $d."/".$q->{title}.": ".$u->{qid}."/$sol_ctr: "); } elsif ($expected->{type} eq 'xpath') { my $res = _eval_q ($tm, $s->{code}, $s->{language}); # warn "GOT $res". Dumper $res; my $doc = XML::LibXML::Document->new; my $frag = $res->[0]->[0]->[0]; $doc->setDocumentElement( ($frag->childNodes)[1]); # warn "serialized: $doc".$doc->toString (0); foreach my $xp (split (/\n/, $expected->{content})) { ok ($doc->findnodes( $xp ), $d."/".$q->{title}.": ".$u->{qid}. " $xp"); } } else { die; } } } } foreach my $a (@{$u->{axiom}}) { $sol_ctr++; next unless $a->{operational} =~ /yes/; #warn "working on axiom $sol_ctr".Dumper $a; my ($left, $right) = split (/===/, $a->{code}); _check_list ($tm, $d."/axiom: ".$u->{qid}."/a$sol_ctr", 0, $left, $right, $a->{language}); } } } sub _eval_q { my $tm = shift; my $code = shift; my $lang = shift; #warn "in eval_q $code"; if ($lang eq 'tmql') { # #warn "compiling $code"; use TM::QL; my $q = new TM::QL ($code); # #warn "path compiled ".Dumper $q; return $q->eval ({'%_' => $tm}); } elsif ($lang eq 'tau') { my $pe = new TM::QL::PE ($code); my $pec = $pe; #### TODO my $pec = TM::QL::PE::optimize ($pe); return TM::QL::PE::eval ({'%_' => $tm}, $pec); } } sub _check_list { my $tm = shift; my $desc = shift; my $ordered= shift; my $left = shift; my $right = shift; my $lang = shift; $left = _eval_q ($tm, $left, $lang) unless ref ($left); #warn scalar @$left; #warn "left ".Dumper $left; $right = _eval_q ($tm, $right, $lang) unless ref ($right); #warn "right ".Dumper $right; ok ($ordered ? TM::QL::TS::ts_identical ($left, $right) : TM::QL::TS::ts_uo_eq ($left, $right), $desc) or die "got: ".Dumper ($left). "but expected ".Dumper ($right); } __END__ do_xml_test (' function test (map $m) as xml return { forall $t [ $a (sss) ] in $m return { forall $bn in $t/bn return {$bn} } sort by $a desc } ', { '$m' => $tm }, [ '/aaaa/bbb/ccc[text() = "MMM"]', '/aaaa/bbb/ccc[text() = "NNN"]' ], 'xml:', 0); do_xml_test (' function test () as xml return { forall in ("aaa", "bbb", "ccc") return " yyy" } ', { }, '/element/text()', 'xml:', 0); do_xml_test (' function test (map $m, string $a := "xxx") as xml return { let string $b := {$a} let string $c := {$b} $c } ', { }, '/element', 'xml:', 0); do_xml_test (' function test (map $m, string $a := "xxx") as xml return {$a}yyy{$a} ', { }, '/element[text() = "xxxyyyxxx"]', 'xml:', 0); do_xml_test (' function test (string $a := "xxx") as xml return huhu ', { }, '/elemxxxent', 'xml:', 0); do_string_test (' function test () as string return "xxx{ forall in ("aaa", "bbb", "ccc") return " yyy" } zzz" ', {}, 'xxx yyy yyy yyy zzz', 'forall:', 0); do_xml_test (' function test (string $a := "xxx") as xml return huhu ', {}, '//mentel[@www="ccc"]', 'xml:', 0); do_xml_test (' function test (string $a := "xxx") as xml return huhu ', {}, '//@uuu', 'xml:', 0);