#-- 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);