use strict; # 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; } use TM; use TM::PSI; sub _parse { my $text = shift; my $ms = new TM (baseuri => 'tm:'); my $p = new TM::AsTMa::Fact (store => $ms); my $i = $p->parse ("$text\n"); return $ms; } sub _q_players { my $ms = shift; # my @res = $ms->match (TM->FORALL, @_); # warn "res no filter ".Dumper \@res; my @res = grep ($_ !~ m|^tm:|, map { ref($_) ? $_->[0] : $_ } map { @{$_->[TM->PLAYERS]} } $ms->match (TM->FORALL, @_)); # warn "res ".Dumper \@res; return \@res; } ##=================================================================================== #== TESTS =========================================================================== require_ok( 'TM::AsTMa::Fact' ); { # class ok my $p = new TM::AsTMa::Fact; ok (ref($p) eq 'TM::AsTMa::Fact', 'class ok'); } { #-- structural my $ms = _parse ('aaa (bbb) ccc (bbb) '); #warn Dumper $ms; exit; is (scalar $ms->match_forall (type => 'isa', irole => 'class', iplayer => 'tm:bbb'), 2, 'two types for bbb'); ok (eq_array ([ $ms->mids ('aaa', 'bbb', 'ccc') ], [ 'tm:aaa', 'tm:bbb', 'tm:ccc' ]), 'aaa, bbb, ccc internalized'); } { #-- structural my $ms = _parse ('aaa (bbb) '); #warn Dumper $ms; is (scalar $ms->match (TM->FORALL, type => 'isa', arole => 'instance', aplayer => 'tm:aaa', brole => 'class', bplayer => 'tm:bbb'), 1, 'one type for aaa'); ok (eq_array ([ $ms->mids ('aaa', 'bbb') ], [ 'tm:aaa', 'tm:bbb' ]), 'aaa, bbb internalized'); } { my $ms = _parse ('aaa '); #warn Dumper $ms; is ($ms->mids ('aaa'), 'tm:aaa', 'aaa implicitely internalized'); } { # structural topic my $ms = _parse (q| aaa is-a bbb bn: AAA oc: http://BBB in: blabla bla |); #warn Dumper $ms; is (scalar $ms->match (TM->FORALL, type => 'isa', irole => 'instance', iplayer => 'tm:aaa' ), 1, 'one type for aaa'); is (scalar $ms->match (TM->FORALL, irole => 'thing', iplayer => 'tm:aaa' ), 4, 'chars for aaa'); is (scalar $ms->match (TM->FORALL, type => 'name', irole => 'thing', iplayer => 'tm:aaa' ), 1, 'basenames for aaa'); is (scalar $ms->match (TM->FORALL, type => 'occurrence', irole => 'thing', iplayer => 'tm:aaa' ), 2, 'occurrences for aaa 1'); } { # dangerous IDs my $ms = _parse (q| in-a is-a oc-a in: aaaa rd-b is-a ex-a rd: bbbb this.is.a.valid.topic.name this.is.even-more.so.a_topic in-line-with-policy bn: goals of backup system must be in line with corp policies in: eg: no backup of desktops ex-suggested bn: ex-suggested: (is-a-variant-of) in-a : in-line-with-policy rd-b : ex-suggested |); #warn Dumper $ms; foreach (qw(in-a oc-a rd-b ex-a this.is.a.valid.topic.name this.is.even-more.so.a_topic in-line-with-policy ex-suggested is-a-variant-of)) { is ($ms->mids ($_), "tm:$_", "dangerous $_"); } } #-- syntactic issues ---------------------------------------------------------------- my $npa = scalar keys %{$TM::infrastructure->{assertions}}; my $npt = scalar keys %{$TM::infrastructure->{mid2iid}}; { my $ms = _parse (q| # this is AsTMa |); #warn Dumper $ms; is (scalar $ms->match(), $npa, 'empty map 1 (assertions)'); is ($ms->toplets, $npt, 'empty map 2 (toplets)'); } { # empty line with blanks my $ms = _parse (q| topic1 topic2 |); ##warn Dumper $ms; is (scalar $ms->toplets(), $npt+2, 'empty line contains blanks'); } { # empty lines with \r my $ms = _parse (q| topic1 topic2 topic3 |); is (scalar $ms->toplets(), $npt+3, 'empty line \r contains blanks'); } { # using TABs as separators my $ms = _parse (q| topic1 ( topic2 ) # comment |); #warn Dumper $ms; is (scalar $ms->toplets, $npt+2, 'using TABs as separators'); } { my $ms = _parse (q| # comment1 aaa (bbbbb cccc dddd) #comment2 #comment4 ccc (bbb) #comment3 #comment4 ddd (xxxx) #comment5 |); ##warn Dumper $ms; is (scalar $ms->toplets, $npt+8, 'test comment/separation'); is (scalar $ms->match (TM->FORALL, type => 'isa', irole => 'instance', iplayer => 'tm:aaa' ), 3, 'types for aaa'); is (scalar $ms->match (TM->FORALL, type => 'isa', irole => 'instance', iplayer => 'tm:ccc' ), 1, 'type for ccc'); is (scalar $ms->match (TM->FORALL, type => 'isa', irole => 'instance', iplayer => 'tm:ddd' ), 1, 'type for ddd'); } { # line continuation with comments my $ms = _parse (q| topic1 # comment \ topic2 |); is (scalar $ms->toplets, $npt+1, 'continuation in comment'); } { # line continuation with comments my $ms = _parse (q| topic1 # comment \ topic2 |); is (scalar $ms->toplets, $npt+2, 'continuation in comment, not 1'); } { # line continuation with comments my $ms = _parse (q| topic1 # comment \ topic2 |); is (scalar $ms->toplets, $npt+2, 'continuation in comment, not 2'); } { # line continuation my $ms = _parse (q| aaa (bbbbb \ cccc \ dddd) | ); is (scalar $ms->toplets, $npt+4, 'line continuation'); is (scalar $ms->match (TM->FORALL, type => 'isa', irole => 'instance', iplayer => 'tm:aaa' ), 3, 'types for aaa'); } { # line continuation, not my $ms = _parse (q| aaa bn: AAA in: a \ within the text is ok in: also one with a \\ followed by a blank: \\ in: this is a new one \\ in: this is not a new one |); ##warn Dumper $ms; my @res = $ms->match (TM->FORALL, type => 'occurrence', irole => 'thing', iplayer => 'tm:aaa' ); is (scalar @res, 3, 'ins for aaa'); ##warn Dumper \@res; ##warn Dumper [ map { ${$_->[TM->PLAYERS]->[1]}} @res ]; ok (eq_set ([ map { $_->[0] } map { $_->[TM->PLAYERS]->[1] } @res ], [ 'a \ within the text is ok', 'also one with a \ followed by a blank: \\', # blank is gone now 'this is a new one in: this is not a new one']), 'same text'); } { # line continuation, not \\ my $ms = _parse (q| aaa (bbbb \ ) # this is a continuation bn: but not this \\\\ in: should be separate | ); ##warn Dumper $ms; is (scalar $ms->match, $npa+3, 'line continuation, =3'); } { # string detection my $ms = _parse (q| aaa in: AAA bbb in: <<< xxxxxxxxxxxxx yyyyyyyyyy zzzzzz <<< ccc in: <match, $npa+3, 'string detection'); my @res = $ms->match (TM->FORALL, type => 'occurrence', irole => 'thing', iplayer => 'tm:bbb' ); ok (eq_set ([ map { $_->[0] } map { $_->[TM->PLAYERS]->[1] } @res ], [ 'xxxxxxxxxxxxx yyyyyyyyyy zzzzzz', ]), 'same text [<<<]'); @res = $ms->match (TM->FORALL, type => 'occurrence', irole => 'thing', iplayer => 'tm:ccc' ); ok (eq_set ([ map { $_->[0] } map { $_->[TM->PLAYERS]->[1] } @res ], [ 'rumsti ramsti romsti', ]), 'same text [<match, $npa+5, '~ separation: assertion'); ok (eq_set ([ map { $_->[0] } map { $_->[TM->PLAYERS]->[1] } $ms->match (TM->FORALL, type => 'name', iplayer => 'tm:aaa' ) ] , [ 'AAA' ]), '~ separation: AAA basename'); } { # line no separation my $ms = _parse (q| aaa (bbb) ~ bn: AAA ~ in: rumsti is using ~~ in: text |); ## warn Dumper $ms; is (scalar $ms->match, $npa+3, '~~ no-separation: assertions'); ok (eq_set ([ map { $_->[0] } map { $_->[TM->PLAYERS]->[1] } $ms->match (TM->FORALL, type => 'occurrence', iplayer => 'tm:aaa' ) ] , [ 'rumsti is using ~ in: text' ]), 'getting back ~ text'); } { # inline comments my $ms = _parse (q| aaa bn: AAA # comment bn: AAA# no-comment oc: http://rumsti#no-comment in: a hash-bang path like \#!/bin/bash in: a hash-bang path like \\\\#!/bin/bash |); #warn Dumper $ms; is (scalar $ms->match, $npa+5, 'comment + assertions'); ok (eq_set ([ map { $_->[0] } map { $_->[TM->PLAYERS]->[1] } $ms->match (TM->FORALL, type => 'name', iplayer => 'tm:aaa' ) ] , [ 'AAA', 'AAA# no-comment' ]), 'getting back commented basename'); ok (eq_set ([ map { $_->[0] } map { $_->[TM->PLAYERS]->[1] } $ms->match (TM->FORALL, type => 'occurrence', iplayer => 'tm:aaa' ) ] , [ 'http://rumsti#no-comment', 'a hash-bang path like #!/bin/bash', 'a hash-bang path like \\\\#!/bin/bash']), 'getting back commented occ'); } #-- structural: assocs ---------------------------------------------------------- { my $ms = _parse (q| (xxx) role : player |); ##warn Dumper $ms; is (scalar $ms->match, $npa+1, 'basic association'); is (scalar $ms->match (TM->FORALL, iplayer => 'tm:player' ), 1, 'finding basic association 1'); is (scalar $ms->match (TM->FORALL, type => 'tm:xxx', iplayer => 'tm:player' ), 1, 'finding basic association 2'); is (scalar $ms->match (TM->FORALL, type => 'tm:xxx', irole => 'tm:role', iplayer => 'tm:player' ), 1, 'finding basic association 3'); } { my $ms = _parse (q| (xxx) role : p1 p2 p3 |); ## warn Dumper $ms; is (scalar $ms->match, $npa+1, 'basic association'); is (scalar $ms->match (TM->FORALL, iplayer => 'tm:p1' ), 1, 'finding basic association 4'); is (scalar $ms->match (TM->FORALL, type => 'tm:xxx', iplayer => 'tm:p2' ), 1, 'finding basic association 5'); is (scalar $ms->match (TM->FORALL, type => 'tm:xxx', irole => 'tm:role', iplayer => 'tm:p3' ), 1, 'finding basic association 6'); } { my $ms = _parse (q| (xxx) role : aaa bbb (xxx) role : aaa |); ## warn Dumper $ms; is (scalar $ms->match, $npa+2, 'basic association'); is (scalar $ms->match (TM->FORALL, iplayer => 'tm:aaa' ), 2, 'finding basic association 7'); is (scalar $ms->match (TM->FORALL, type => 'tm:xxx', iplayer => 'tm:bbb' ), 1, 'finding basic association 8'); } { my $ms = _parse (q| (xxx) role1 : aaa bbb role2 : ccc |); ##warn Dumper $ms; is (scalar $ms->match, $npa+1, 'basic association'); is (scalar $ms->match (TM->FORALL, iplayer => 'tm:aaa' ), 1, 'finding basic association 10'); is (scalar $ms->match (TM->FORALL, type => 'tm:xxx', iplayer => 'tm:ccc' ), 1, 'finding basic association 11'); is (scalar $ms->match (TM->FORALL, type => 'tm:xxx', irole => 'tm:role2', iplayer => 'tm:ccc' ), 1, 'finding basic association 12'); } { my $ms = _parse (q| (aaa) @ sss role : player |); #warn Dumper $ms; # ok ($ms->is_subclass ('aaa', 'association'), 'association: subclassed'); # is (scalar $ms->match (TM->FORALL, type=> 'isa', iplayer => 'tm:sss' ), 1, 'association scoped 1'); is (scalar $ms->match, $npa+2, 'association scoped'); is (scalar $ms->match (TM->FORALL, iplayer => 'tm:player' ), 1, 'association scoped 2'); is (scalar $ms->match (TM->FORALL, scope => 'tm:sss', iplayer => 'tm:player' ), 1, 'association scoped 3'); } #-- reification -------------------------------------- { my $ms = _parse (q| http://rumsti.com/ is-a website urn:x-rumsti:xxx is-a rumsti |); #warn Dumper $ms; ok (eq_array ([ $ms->mids ('http://rumsti.com/','urn:x-rumsti:xxx') ], [ 'tm:uuid-0000000000', 'tm:uuid-0000000001' ]), 'reification: identifiers'); is (scalar $ms->match, $npa+2, 'external reification: association'); is (scalar $ms->match (TM->FORALL, iplayer => 'tm:uuid-0000000001' ), 1, 'reification: finding'); is (scalar $ms->match (TM->FORALL, type => 'isa', iplayer => 'tm:uuid-0000000000' ), 1, 'finding basic association'); } { my $ms = _parse (q| cpan reifies http://cpan.org/ (xxx) aaa: cpan bbb: ccc |); #warn Dumper $ms; is (scalar $ms->match, $npa+1, 'reification: association'); is (scalar $ms->match (TM->FORALL, type => 'tm:xxx', iplayer => $ms->mids ('http://cpan.org/') ), 1, 'reification: finding basic association'); is (scalar $ms->match (TM->FORALL, type => 'tm:xxx', iplayer => 'tm:cpan' ), 1, 'reification: finding basic association'); ok (eq_set ( [ $ms->match (TM->FORALL, type => 'tm:xxx', iplayer => $ms->mids ('http://cpan.org/') ) ], [ $ms->match (TM->FORALL, type => 'tm:xxx', iplayer => 'tm:cpan' ) ] ), 'reification: finding, same'); } { my $ms = _parse (q| (http://xxx) http://role1 : aaa http://bbb http://role2 : ccc |); #warn Dumper $ms; is (scalar $ms->match, $npa+1, 'reification: association'); is (scalar $ms->match (TM->FORALL, type => $ms->mids('http://xxx'), roles => [ $ms->mids ('http://role1', 'http://role2', 'http://role1') ], players => [ $ms->mids ('tm:aaa', undef, 'http://bbb') ] ), 1, 'reification: association'); } { # reification explicit my $ms = _parse (q| xxx (http://www.topicmaps.org/xtm/1.0/#psi-topic) |); #warn Dumper $ms; is (scalar $ms->match, $npa+1, 'reification: type'); ok ($ms->is_asserted (Assertion->new (scope => 'us', type => 'isa', roles => [ 'class', 'instance' ], players => [ 'http://www.topicmaps.org/xtm/1.0/#psi-topic', 'tm:xxx' ])), 'xxx is-a found'); my $m = $ms->tids ('http://www.topicmaps.org/xtm/1.0/#psi-topic'); ok ($ms->is_asserted (Assertion->new (scope => 'us', type => 'isa', roles => [ 'class', 'instance' ], players => [ $m, 'tm:xxx' ])), 'xxx is-a found (via mids)'); } { my $ms = _parse (q| (xxx) is-reified-by aaa role : player |); #warn Dumper $ms; my ($a) = $ms->match (TM->FORALL, type => 'tm:xxx'); is_deeply ([ $ms->is_reified ($a) ], [ 'tm:aaa' ], 'assoc reified: regained'); is ($ms->reifies ('tm:aaa'), $a, 'assoc reified: regained 2'); } { my $ms = _parse (q| (xxx) is-reified-by is-a.some-thing.which-ex-strange role : player |); my ($a) = $ms->match (TM->FORALL, type => 'tm:xxx'); is_deeply ([ $ms->is_reified ($a) ], [ 'tm:is-a.some-thing.which-ex-strange' ], 'assoc reified: regained'); is ($ms->reifies ('tm:is-a.some-thing.which-ex-strange'), $a, 'assoc reified: regained 2'); }; eval { my $ms = _parse (q| (xxx) reifies aaa role : player |); }; like ($@, qr/must be a URI/i, _chomp($@)); #{ # my $ms = _parse (q| #(xxx) reifies http://rumsti/ # role : player #|); ##warn Dumper $ms; # # my ($a) = $ms->match (TM->FORALL, type => 'tm:xxx'); # is ($ms->reified_by ($a->[TM->LID]), 'http://rumsti/', 'assoc reified: regained 3'); #} eval { my $ms = _parse (q| (xxx) is-reified-by http://aaa/ role : player |); }; like ($@, qr/local identifier/i, _chomp($@)); #-- syntax errors ------------------------------------------------------------------- eval { my $ms = _parse (q| (xxx zzz) member : aaa |); }; like ($@, qr/syntax error/i, _chomp($@)); eval { my $ms = _parse (q| (xxx) |); }; like ($@, qr/syntax error/i, _chomp($@)); eval { my $ms = _parse (q| (xxx) role : aaa role2 : |); }; like ($@, qr/syntax error/i, _chomp($@)); eval { my $ms = _parse (q| (xxx) rumsti |); }; like ($@, qr/syntax error/i, _chomp($@)); eval { my $ms = _parse (q| () role : player |); }; like ($@, qr/syntax error/i, _chomp($@)); #-- autogenerating ids { my $ms = _parse (q| * (aaa) * (aaa) |); ## warn Dumper $ms; is (scalar $ms->match, $npa+2, 'autogenerating ids'); is (scalar ( grep /tm:uuid-\d{10}/, map {$_->[TM->PLAYERS]->[1] } $ms->match (TM->FORALL, type => 'isa', iplayer => 'tm:aaa' ) ), 2, 'generated ids ok'); } #-- structural: toplets/characteristics ----------------------------------------- #- negative tests eval { my $ms = _parse (q| ttt bn: |); warn Dumper $ms; }; ok ($@, "raises except on empty bn:"); eval { my $ms = _parse (q| ttt oc: |); }; ok ($@, "raises except on empty oc:"); eval { my $ms = _parse (q| ttt in: |); }; ok ($@, "raises except on empty in:"); eval { my $ms = _parse (q| (aaa) aaa : |); fail ("raises except on empty role"); }; ok ($@, "raises except on empty role"); eval { my $ms = _parse (q| (aaa) aaa:bbb |); fail ("raises except on empty role 2"); }; ok ($@, "raises except on empty role 2"); eval { my $ms = _parse (q| (ddd) bbb:aaa:ccc |); fail ("raises except on empty role 3"); }; ok ($@, "raises except on empty role 3"); eval { my $ms = _parse (q| aaa sin (ttt): urn:xxx |); fail ("raises except on subject indicator"); }; ok ($@, "raises except on subject indicator"); eval { my $ms = _parse (q| aaa sin @ sss : urn:xxx |); fail ("raises except on subject indicator"); }; ok ($@, "raises except on subject indicator"); #-- positive tests ----------------------------------- { # testing toplets with characteristics my $ms = _parse (q| xxx bn: XXX |); ##warn Dumper $ms; is (scalar $ms->match (TM->FORALL, type => 'name', roles => [ 'value', 'thing' ], players => [ undef, 'tm:xxx' ]), 1, 'basename characteristics'); } { # testing toplets with URI my $ms = _parse (q| http://xxx bn: XXX |); ##warn Dumper $ms; is (scalar $ms->match (TM->FORALL, type => 'name', roles => [ 'value', 'thing' ], players => [ $ms->mids (undef, 'http://xxx') ]), 1, 'basename characterisistics (reification)'); } { my $ms = _parse (q| aaa (bbbbb) bn: AAA in: blabla |); ##warn Dumper $ms; ok (eq_set ([ map { map { $_->[0] } $_->[TM->PLAYERS]->[1] } $ms->match (TM->FORALL, type => 'occurrence', iplayer => 'tm:aaa' ) ] , [ 'blabla' ]), 'test blanks in resourceData 1'); } { my $ms = _parse (q| xxx bn: XXX oc: http://xxx.com ex: http://yyy.com |); ##warn Dumper $ms; ok (eq_set ([ map { $_->[0] } map { $_->[TM->PLAYERS]->[1] } $ms->match (TM->FORALL, type => 'occurrence', iplayer => 'tm:xxx' ) ] , [ 'http://yyy.com', 'http://xxx.com' ]), 'occurrence char, value ok'); } #- adding types { my $ms = _parse (q| aaa bn: AAA bn (rumsti) : AAAT in: III in (bumsti) : IIIT oc: http://xxx/ oc (ramsti) : http://xxxt/ oc (rimsti) : http://yyy/ bn (remsti) : http://zzz/ in (remsti) : bla |); #warn Dumper $ms; #warn "occurrences of aaa ".Dumper [ $ms->match (TemplateIPlayerType->new ( type => 'tm:occurrence', iplayer => 'tm:aaa' )) ]; ok (eq_set ([ map { $_->[0] } map { $_->[TM->PLAYERS]->[1] } grep ($_->[TM->TYPE] eq 'name', $ms->match (TM->FORALL, type => 'name', iplayer => 'tm:aaa' )) ] , [ 'AAA' ]), 'basename untyped char, value ok'); ok (eq_set ([ map { $_->[0] } map { $_->[TM->PLAYERS]->[1] } $ms->match (TM->FORALL, type => 'tm:rumsti', iplayer => 'tm:aaa' ) ] , [ 'AAAT' ]), 'basename typed char, value ok'); ok (eq_set ([ map { $_->[0] } map { $_->[TM->PLAYERS]->[1] } $ms->match (TM->FORALL, type => 'occurrence', iplayer => 'tm:aaa' ) ] , [ 'http://xxxt/', 'http://yyy/', 'http://zzz/', # yes, this is also now an occurrence, since remsti is that too! 'III', 'IIIT', 'bla', 'http://xxx/' ]), 'occurr typed char, value ok'); ok (eq_set ([ map { $_->[0] } map { $_->[TM->PLAYERS]->[1] } $ms->match (TM->FORALL, type => 'tm:bumsti', iplayer => 'tm:aaa' ) ] , [ 'IIIT' ]), 'occurr typed char, value ok'); ok (eq_set (_q_players ($ms, type => 'tm:ramsti', iplayer => 'tm:aaa' ) , [ 'http://xxxt/' ]), 'occurr typed char, value ok'); ok (eq_set (_q_players ($ms, type => 'tm:remsti', iplayer => 'tm:aaa' ) , [ 'http://zzz/', 'bla' ]), 'occurr typed char, value ok'); } { # subject indication my $ms = _parse (q| aaa bn: AAA sin: http://AAA sin: http://BBB |); #warn Dumper $ms; my $t = $ms->midlet ('tm:aaa'); ok (eq_set ( $t->[TM->INDICATORS], [ 'http://AAA', 'http://BBB', ]), 'indicators'); is (scalar $ms->match (TM->FORALL, type => 'name', irole => 'thing', iplayer => $ms->mids (\ 'http://AAA') ), 1, 'names for aaa via indication'); is (scalar $ms->match (TM->FORALL, type => 'name', irole => 'thing', iplayer => $ms->mids (\ 'http://BBB') ), 1, 'names for aaa via indication'); } #-- associations with URIs { my $ms = _parse (q| (aaa) aaa:bbb : ccc (ddd) bbb: aaa:ccc |); ## warn Dumper $ms; ok (eq_set ([ map { $_->[TM->PLAYERS]->[0] } $ms->match (TM->FORALL, type => 'tm:aaa', irole => $ms->mids ('aaa:bbb') ) ] , [ 'tm:ccc' ]), 'assoc with URIs 1'); ok (eq_set ([ map { $_->[TM->PLAYERS]->[0] } $ms->match (TM->FORALL, type => 'tm:ddd', irole => 'tm:bbb' ) ] , [ $ms->mids ('aaa:ccc') ]), 'assoc with URIs 2'); } #- adding scopes { my $ms = _parse (q| aaa bn: AAA bn @ sss : AAAS in: III in @ sss : IIIS oc: http://xxx/ oc @ sss : http://xxxs/ |); ## warn Dumper $ms; ok (eq_set (_q_players ($ms, type => 'name', iplayer => 'tm:aaa' ), [ 'AAA', 'AAAS' ]), 'basename untyped, scoped, value ok'); ok (eq_set (_q_players ($ms, scope => 'us', type => 'name', iplayer => 'tm:aaa' ), [ 'AAA' ]), 'basename untyped, scoped, value ok'); ok (eq_set (_q_players ($ms, scope => 'tm:sss', type => 'name', iplayer => 'tm:aaa' ), [ 'AAAS' ]), 'basename untyped, scoped, value ok'); ok (eq_set (_q_players ($ms, type => 'occurrence', iplayer => 'tm:aaa' ), [ 'III', 'IIIS', 'http://xxx/', 'http://xxxs/' ]), 'occurrences untyped, mixscoped, value ok'); ok (eq_set (_q_players ($ms, scope => 'tm:sss', type => 'occurrence', iplayer => 'tm:aaa' ), [ 'IIIS', 'http://xxxs/' ]), 'occurrences untyped, scoped, value ok'); } { # typed and scoped characteristics my $ms = _parse (q| aaa bn (ramsti): AAA bn @ sss (rumsti): AAAS in: III in @ sss (ramsti): IIIS oc: http://xxx/ oc @ sss (ramsti): http://xxxs/ xxx (yyy) |); # warn Dumper $ms; ok (eq_set (_q_players ($ms, type => 'tm:ramsti', iplayer => 'tm:aaa' ), [ 'AAA', 'IIIS', 'http://xxxs/' ]), 'basename typed, mixscoped, value ok'); ok (eq_set (_q_players ($ms, scope => 'us', type => 'tm:ramsti', iplayer => 'tm:aaa' ), [ 'AAA' ]), 'basename untyped, scoped, value ok'); ok (eq_set (_q_players ($ms, scope => 'tm:sss', type => 'tm:rumsti', iplayer => 'tm:aaa' ), [ 'AAAS' ]), 'basename untyped, scoped, value ok'); ok (eq_set (_q_players ($ms, type => 'name', iplayer => 'tm:aaa' ), [ 'http://xxxs/', 'AAA', 'IIIS', 'AAAS' ]), 'basenames typed, mixscoped, value ok'); ok (eq_set (_q_players ($ms, type => 'occurrence', iplayer => 'tm:aaa' ), [ 'http://xxxs/', 'http://xxx/', 'AAA', 'IIIS', 'III' ]), 'occurrences typed, mixscoped, value ok'); ok (eq_set (_q_players ($ms, kind => TM->OCC, type => 'occurrence', iplayer => 'tm:aaa' ), [ 'http://xxx/', 'http://xxxs/', 'IIIS', 'III' ]), 'occurrences untyped, mixscoped, value ok'); } #-- inlined { # checking inlined subclassing my $ms = _parse (q| aaa is-subclass-of bbb (is-subclass-of) superclass: ddd subclass: ccc eee is-subclass-of fff is-subclass-of ggg hhh subclasses iii is-subclass-of jjj |); ##warn Dumper $ms; is (scalar $ms->match(TM->FORALL, type => 'is-subclass-of', roles => [ 'subclass', 'superclass' ], players => [ 'tm:aaa', 'tm:bbb' ] ), 1, 'intrinsic is-subclass-of, different forms 1'); is (scalar $ms->match(TM->FORALL, type => 'is-subclass-of', roles => [ 'subclass', 'superclass' ], players => [ 'tm:ccc', 'tm:ddd' ] ), 1, 'intrinsic is-subclass-of, different forms 2'); is (scalar $ms->match(TM->FORALL, type => 'is-subclass-of', roles => [ 'subclass', 'superclass' ], players => [ 'tm:eee', 'tm:fff' ] ), 1, 'intrinsic is-subclass-of, different forms 3'); is (scalar $ms->match(TM->FORALL, type => 'is-subclass-of', roles => [ 'subclass', 'superclass' ], players => [ 'tm:eee', 'tm:ggg' ] ), 1, 'intrinsic is-subclass-of, different forms 4'); is (scalar $ms->match(TM->FORALL, type => 'is-subclass-of', roles => [ 'subclass', 'superclass' ], players => [ 'tm:hhh', 'tm:iii' ] ), 1, 'intrinsic is-subclass-of, different forms 5'); is (scalar $ms->match(TM->FORALL, type => 'is-subclass-of', roles => [ 'subclass', 'superclass' ], players => [ 'tm:hhh', 'tm:jjj' ] ), 1, 'intrinsic is-subclass-of, different forms 6'); } { my $ms = _parse (q| aaa bbb is-a thing bbb is-a ccc ddd ( ) eee is-a bbb is-a ccc is-a ddd xxx has-a aaa |); ##warn Dumper $ms; is (scalar $ms->match(TM->FORALL, type => 'isa', roles => [ 'class', 'instance' ], players => [ 'tm:xxx', 'tm:aaa' ] ), 1, 'explicit is-a'); is (scalar $ms->match(TM->FORALL, type => 'isa', roles => [ 'class', 'instance' ], players => [ 'tm:ccc', 'tm:bbb' ] ), 1, 'explicit is-a 2'); is (scalar $ms->match(TM->FORALL, type => 'isa', roles => [ 'class', 'instance' ], players => [ 'tm:ddd', 'tm:eee' ] ), 1, 'explicit is-a 3'); is (scalar $ms->match(TM->FORALL, type => 'isa', roles => [ 'class', 'instance' ], players => [ 'tm:ccc', 'tm:eee' ] ), 1, 'explicit is-a 4'); is (scalar $ms->match(TM->FORALL, type => 'isa', roles => [ 'class', 'instance' ], players => [ 'tm:bbb', 'tm:eee' ] ), 1, 'explicit is-a 5'); } #-- templates -------------------- eval { my $ms = _parse (q| xxx bbb zzz |); }; ok ($@, "raises except on undefined inline assoc"); { my $ms = _parse (q| [ (bbb) ccc: ddd eee: fff ] xxx bbb zzz uuu bbb vvv |); #warn Dumper $ms; is (scalar $ms->match(TM->FORALL, type => 'tm:bbb', roles => [ 'tm:ccc', 'tm:eee' ], players => [ 'tm:ddd', 'tm:fff' ] ), 1, 'template: static'); } { my $ms = _parse (q| [ (bbb) ccc: http://psi.tm.bond.edu.au/astma/1.0/#psi-left eee: fff ] xxx bbb zzz [ (bbb2) ccc: http://psi.tm.bond.edu.au/astma/1.0/#psi-left eee: http://psi.tm.bond.edu.au/astma/1.0/#psi-right ] xxx bbb2 zzz [ (bbb3) http://psi.tm.bond.edu.au/astma/1.0/#psi-left : ccc http://psi.tm.bond.edu.au/astma/1.0/#psi-right : eee ] xxx bbb3 zzz |); #warn Dumper $ms; is (scalar $ms->match(TM->FORALL, type => 'tm:bbb', roles => [ 'tm:ccc', 'tm:eee' ], players => [ 'tm:xxx', 'tm:fff' ] ), 1, 'template: dyn left'); is (scalar $ms->match(TM->FORALL, type => 'tm:bbb2', roles => [ 'tm:ccc', 'tm:eee' ], players => [ 'tm:xxx', 'tm:zzz' ] ), 1, 'template: dyn both, players'); is (scalar $ms->match(TM->FORALL, type => 'tm:bbb3', roles => [ 'tm:xxx', 'tm:zzz' ], players => [ 'tm:ccc', 'tm:eee' ] ), 1, 'template: dyn both, roles'); } #-- scopes as dates { my $ms = _parse (q| aaa bn : AAA bn @ 2004-01-12 : XXX bn @ 2004-01-12 12:23 : YYY |); # warn Dumper $ms; ok (eq_set (_q_players ($ms, scope => $ms->mids ('urn:x-date:2004-01-12:00:00'), type => 'name', iplayer => 'tm:aaa' ), [ 'XXX' ]), 'date scoped 1'); ok (eq_set (_q_players ($ms, scope => $ms->mids ('urn:x-date:2004-01-12:12:23'), type => 'name', iplayer => 'tm:aaa' ), [ 'YYY' ]), 'date scoped 2'); } #-- directives ------------------------------------------------------------ #-- encoding { #-- default my $ms = _parse (q| aaa in: Ich chan Glaas ässe, das tuet mir nöd weeh bbb in: Mohu jíst sklo, neublí?í mi |); ok (eq_set (_q_players ($ms, type => 'occurrence', iplayer => 'tm:aaa' ), [ 'Ich chan Glaas ässe, das tuet mir nöd weeh' ]), 'encoding: same text'); ok (eq_set (_q_players ($ms, type => 'occurrence', iplayer => 'tm:bbb' ), [ 'Mohu jíst sklo, neublí?í mi' ]), 'encoding: same text'); } { # -- explicit my $ms = _parse (q| %encoding iso-8859-1 aaa in: Ich chan Glaas ässe, das tuet mir nöd weeh |); ##warn Dumper $ms; ok (eq_set (_q_players ($ms, type => 'occurrence', iplayer => 'tm:aaa' ), [ 'Ich chan Glaas ässe, das tuet mir nöd weeh' ]), 'encoding: same text'); # ok (eq_set ([ $ms->toplets (new Toplet (characteristics => [ [ 'universal-scope', # 'xtm-psi-occurrence', # TM::Maplet::KIND_IN, # '\x{E4}sse' ]])) ], # [ 'aaa' ]), 'encoding: match in with umlaut'); } { #-- explicit different my $ms = _parse (q| %encoding iso-8859-2 aaa in: Ich chan Glaas ässe, das tuet mir nöd weeh |); ok (eq_set (_q_players ($ms, type => 'occurrence', iplayer => 'tm:aaa' ), [ 'Ich chan Glaas ässe, das tuet mir nöd weeh' ]), 'encoding: same text'); } my ($tmp); use IO::File; use POSIX qw(tmpnam); do { $tmp = tmpnam() ; } until IO::File->new ($tmp, O_RDWR|O_CREAT|O_EXCL); END { unlink ($tmp) ; } open (STDERR, ">$tmp"); { my $ms = _parse (q| aaa %cancel bbb |); is (scalar $ms->toplets, $npt+1, 'cancelling'); ERRexpect ("Cancelled"); ##warn Dumper $ms; } { # same, but with trailing blanks my $ms = _parse (q| aaa %cancel bbb |); is (scalar $ms->toplets, $npt+1, 'cancelling (blanks)'); ERRexpect ("Cancelled"); ##warn Dumper $ms; } { my $ms = _parse (q| aaa %log xxx bbb |); is (scalar $ms->toplets, $npt+2, 'logging'); ERRexpect ("Logging xxx"); } { my $ms = _parse (q| aaa %trace 1 bbb (ddd) eee : fff %trace 0 ccc |); ERRexpect ("start tracing: level 1"); ERRexpect ("added toplet"); ERRexpect ("added assertion"); ERRexpect ("start tracing: level 0"); } sub ERRexpect { my $expect = shift; open (ERR, $tmp); undef $/; my $s = ; like ($s, qr/$expect/, "STDERR: expected '$expect'"); close (ERR); } __END__ __END__ # testing corrupt TM # testing TNC my $text = ' aaa (bbb) bn: AAA '; foreach my $i (1..100) { $text .= " aaa$i (bbb) bn: AAA$i "; } $tm = new TM (tie => new TM::Driver::AsTMa (auto_complete => 0, text => $text)); warn "Parse RecDescent inclusive: $Parse::RecDescent::totincl"; warn "Parse RecDescent exclusive: $Parse::RecDescent::totexcl"; #warn "instartrule: $Parse::RecDescent::namespace000001::totincl"; warn "instartrule: $TM::Driver::AsTMa::Parser::totincl"; #warn "instartrule: $TM::AsTMa::Parser::totexcl"; warn "namespace0001 instartrule: $Parse::RecDescent::namespace000001::astma"; warn "namespace0001 cparserincl: $Parse::RecDescent::namespace000001::cparserincl"; __END__ TODO: { # assoc with multiple scope local $TODO = "assoc with multiple scope"; eval { my $tm = new TM (tie => new TM::Driver::AsTMa (text => ' @ aaa bbb (is-ramsti-of) ramsti : xxx rumsti : yyy; ')); }; ok (!$@); } __END__ ##=========================================================