247 lines
6.7 KiB
Perl
247 lines
6.7 KiB
Perl
|
/* $Id$
|
||
|
|
||
|
Part of SWI-Prolog
|
||
|
|
||
|
Author: Jan Wielemaker
|
||
|
E-mail: J.Wielemaker@cs.vu.nl
|
||
|
WWW: http://www.swi-prolog.org
|
||
|
Copyright (C): 1985-2009, University of Amsterdam
|
||
|
|
||
|
This program is free software; you can redistribute it and/or
|
||
|
modify it under the terms of the GNU General Public License
|
||
|
as published by the Free Software Foundation; either version 2
|
||
|
of the License, or (at your option) any later version.
|
||
|
|
||
|
This program is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
GNU General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU Lesser General Public
|
||
|
License along with this library; if not, write to the Free Software
|
||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
|
||
|
As a special exception, if you link this library with other files,
|
||
|
compiled with a Free Software compiler, to produce an executable, this
|
||
|
library does not by itself cause the resulting executable to be covered
|
||
|
by the GNU General Public License. This exception does not however
|
||
|
invalidate any other reasons why the executable file might be covered by
|
||
|
the GNU General Public License.
|
||
|
*/
|
||
|
|
||
|
:- module(test_turtle,
|
||
|
[ test_turtle/0,
|
||
|
test_turtle/1 % +Test
|
||
|
]).
|
||
|
:- asserta(user:file_search_path(library, '..')).
|
||
|
:- asserta(user:file_search_path(library, '../clib')).
|
||
|
:- asserta(user:file_search_path(library, '../sgml')).
|
||
|
:- asserta(user:file_search_path(library, '../RDF')).
|
||
|
:- asserta(user:file_search_path(foreign, '.')).
|
||
|
:- asserta(user:file_search_path(foreign, '../sgml')).
|
||
|
:- asserta(user:file_search_path(foreign, '../clib')).
|
||
|
|
||
|
:- use_module(library(semweb/rdf_turtle)).
|
||
|
:- use_module(library(semweb/rdf_db)).
|
||
|
:- use_module(library(semweb/rdf_compare)).
|
||
|
:- use_module(library(rdf_ntriples)).
|
||
|
:- use_module(library(apply)).
|
||
|
:- use_module(library(debug)).
|
||
|
:- use_module(library(aggregate)).
|
||
|
|
||
|
:- dynamic
|
||
|
error/1,
|
||
|
passed/1,
|
||
|
this_dir/1.
|
||
|
|
||
|
:- retractall(this_dir(_)),
|
||
|
prolog_load_context(directory, Dir),
|
||
|
asserta(this_dir(Dir)).
|
||
|
|
||
|
|
||
|
test_turtle :-
|
||
|
retractall(error(_)),
|
||
|
retractall(passed(_)),
|
||
|
this_dir(Dir),
|
||
|
atom_concat(Dir, '/Tests/Turtle', TestDir),
|
||
|
test_dir(TestDir),
|
||
|
( error(_)
|
||
|
-> fail
|
||
|
; aggregate_all(count, passed(_), Passed),
|
||
|
aggregate_all(count, blocked(_), Blocked),
|
||
|
format('~NAll ~D Turtle tests passed (~D blocked)~n',
|
||
|
[Passed, Blocked])
|
||
|
).
|
||
|
|
||
|
test_turtle(File) :-
|
||
|
this_dir(Here),
|
||
|
atomic_list_concat([Here, '/Tests/Turtle/', File], FullFile),
|
||
|
test_file(FullFile).
|
||
|
|
||
|
%% blocked(?Test)
|
||
|
%
|
||
|
% True if Test is blocked. Currently blocked:
|
||
|
%
|
||
|
% $ test-29.ttl :
|
||
|
% URI test. Contains ...%&... Should or shouldn't we
|
||
|
% do %-decoding!? Surely there are datasets our there
|
||
|
% that expect us to do so.
|
||
|
%
|
||
|
% $ test-28.ttl :
|
||
|
% Test numbers. I don't understand this test and I don't
|
||
|
% understand the *three* files: test-28.ttl, test-28.out
|
||
|
% and test-28.out.ttl.
|
||
|
|
||
|
blocked('test-28.ttl').
|
||
|
blocked('test-29.ttl').
|
||
|
|
||
|
|
||
|
%:- debug(test_turtle).
|
||
|
|
||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
Handle the test-cases provided with the Turtle language definition.
|
||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||
|
|
||
|
test_dir(Dir) :-
|
||
|
atom_concat(Dir, '/*.ttl', Pattern),
|
||
|
expand_file_name(Pattern, Files),
|
||
|
maplist(test_file, Files).
|
||
|
|
||
|
test_file(File) :-
|
||
|
file_base_name(File, BaseName),
|
||
|
blocked(BaseName), !,
|
||
|
print_message(informational, test_turtle(blocked, BaseName)).
|
||
|
test_file(File) :-
|
||
|
file_base_name(File, Base),
|
||
|
atom_concat(bad, _, Base), !,
|
||
|
file_base_name(File, BaseName),
|
||
|
debug(test_turtle, 'Negative test ~w ...', [BaseName]),
|
||
|
catch(load_turtle(File, _Triples), E, true),
|
||
|
( nonvar(E)
|
||
|
-> test_passed(BaseName)
|
||
|
; print_message(error, test_turtle(false, BaseName))
|
||
|
).
|
||
|
test_file(File) :-
|
||
|
file_base_name(File, BaseName),
|
||
|
file_name_extension(Base, ttl, File),
|
||
|
file_name_extension(Base, out, OkFile),
|
||
|
exists_file(OkFile), !,
|
||
|
debug(test_turtle, 'Test ~w ...', [BaseName]),
|
||
|
load_turtle(File, Triples),
|
||
|
load_rdf_ntriples(OkFile, OkTriples0),
|
||
|
maplist(canonical_triple, OkTriples0, OkTriples),
|
||
|
sort(Triples, Turtle),
|
||
|
sort(OkTriples, OK),
|
||
|
( rdf_equal_graphs(OK, Turtle, _)
|
||
|
-> test_passed(BaseName)
|
||
|
; print_message(error, test_turtle(false, BaseName)),
|
||
|
( debugging(test_turtle)
|
||
|
-> report_diff(OK, Turtle)
|
||
|
; true
|
||
|
)
|
||
|
).
|
||
|
test_file(_). % not a test
|
||
|
|
||
|
load_turtle(File, Triples) :-
|
||
|
file_base_name(File, Base),
|
||
|
atom_concat('http://www.w3.org/2001/sw/DataAccess/df1/tests/',
|
||
|
Base,
|
||
|
BaseURI),
|
||
|
rdf_read_turtle(File, Triples,
|
||
|
[ base_uri(BaseURI),
|
||
|
anon_prefix(node(_)),
|
||
|
on_error(error)
|
||
|
]).
|
||
|
|
||
|
canonical_triple(rdf(S0, P0, O0),
|
||
|
rdf(S, P, O)) :-
|
||
|
canonical_node(S0, S),
|
||
|
canonical_node(P0, P),
|
||
|
canonical_node(O0, O).
|
||
|
|
||
|
canonical_node(node(GenId), node(N)) :-
|
||
|
atom_concat(genid, AN, GenId), !,
|
||
|
atom_number(AN, N).
|
||
|
canonical_node(Node, Node).
|
||
|
|
||
|
report_diff(OK, Result) :-
|
||
|
rdf_equal_graphs(OK, Result, _), !.
|
||
|
report_diff(OK, Result) :-
|
||
|
subtract(OK, Result, Missing),
|
||
|
subtract(Result, OK, TooMany),
|
||
|
( Missing \== []
|
||
|
-> length(Missing, NM),
|
||
|
format('**************** ~D Omitted results:~n', [NM]),
|
||
|
write_list(Missing)
|
||
|
; true
|
||
|
),
|
||
|
( TooMany \== []
|
||
|
-> length(TooMany, TM),
|
||
|
format('**************** ~D Overcomplete results:~n', [TM]),
|
||
|
write_list(TooMany)
|
||
|
; true
|
||
|
).
|
||
|
|
||
|
write_list([]).
|
||
|
write_list([H|T]) :-
|
||
|
( H =.. [row|Cols]
|
||
|
-> write_cols(Cols),
|
||
|
format(' .~n')
|
||
|
; H = rdf(S,P,O)
|
||
|
-> write_cell(S), put(' '),
|
||
|
write_cell(P), put(' '),
|
||
|
write_cell(O), write(' .\n')
|
||
|
; format('~p~n', [H])
|
||
|
),
|
||
|
write_list(T).
|
||
|
|
||
|
|
||
|
write_cols([]).
|
||
|
write_cols([H|T]) :-
|
||
|
write_cell(H),
|
||
|
( T == []
|
||
|
-> true
|
||
|
; put(' '),
|
||
|
write_cols(T)
|
||
|
).
|
||
|
|
||
|
write_cell(literal(X)) :- !,
|
||
|
format('"~w"', [X]).
|
||
|
write_cell(R) :-
|
||
|
atom(R),
|
||
|
rdf_global_id(NS:Id, R), !,
|
||
|
format('<~w:~w>', [NS, Id]).
|
||
|
write_cell('$null$') :- !,
|
||
|
write('NULL').
|
||
|
write_cell(R) :-
|
||
|
atom(R), !,
|
||
|
format('<!~w>', [R]).
|
||
|
write_cell(X) :-
|
||
|
format('~p', [X]).
|
||
|
|
||
|
|
||
|
/*******************************
|
||
|
* MESSAGES *
|
||
|
*******************************/
|
||
|
|
||
|
test_passed(Test) :-
|
||
|
print_message(informational, test_turtle(true, Test)),
|
||
|
( current_prolog_flag(verbose, silent)
|
||
|
-> put_char(user_error, '.')
|
||
|
; true
|
||
|
).
|
||
|
|
||
|
:- multifile
|
||
|
prolog:message//1.
|
||
|
|
||
|
prolog:message(test_turtle(true, Test)) -->
|
||
|
{ assert(passed(Test)) },
|
||
|
[ 'Turtle test ~q: ~tpassed~42|'-[Test] ].
|
||
|
prolog:message(test_turtle(false, Test)) -->
|
||
|
{ assert(error(Test)) },
|
||
|
[ 'Turtle test ~q: ~tFAILED~42|'-[Test], nl,
|
||
|
'Re-run with "?- debug(test_turtle)." to see more details'-[]
|
||
|
].
|
||
|
prolog:message(test_turtle(blocked, Test)) -->
|
||
|
[ 'Turtle test ~q: ~t(blocked)~42|'-[Test] ].
|