1/* Part of SWI-Prolog 2 3 Author: Jan Wielemaker 4 E-mail: J.Wielemaker@vu.nl 5 WWW: http://www.swi-prolog.org 6 Copyright (c) 2009-2015, University of Amsterdam 7 VU University Amsterdam 8 All rights reserved. 9 10 Redistribution and use in source and binary forms, with or without 11 modification, are permitted provided that the following conditions 12 are met: 13 14 1. Redistributions of source code must retain the above copyright 15 notice, this list of conditions and the following disclaimer. 16 17 2. Redistributions in binary form must reproduce the above copyright 18 notice, this list of conditions and the following disclaimer in 19 the documentation and/or other materials provided with the 20 distribution. 21 22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 POSSIBILITY OF SUCH DAMAGE. 34*/ 35 36:- module(test_turtle, 37 [ test_turtle/0, 38 test_turtle/1 % +Test 39 ]). 40:- include(local_test). 41 42fix_load_path :- 43 prolog_load_context(directory, Dir), 44 file_base_name(Dir, LocalDir), 45 LocalDir \== semweb, 46 !, 47 asserta(system:term_expansion((:- use_module(library(semweb/X))), 48 (:- use_module(library(LocalDir/X))))). 49fix_load_path. 50 51:- fix_load_path. 52 53:- use_module(library(semweb/turtle)). 54:- use_module(library(semweb/rdf_db)). 55:- use_module(library(semweb/rdf_compare)). 56:- use_module('../RDF/w3c_ntdata'). % From package RDF 57:- use_module(library(apply)). 58:- use_module(library(debug)). 59:- use_module(library(aggregate)). 60 61:- dynamic 62 error/1, 63 passed/1, 64 this_dir/1. 65 66:- retractall(this_dir(_)), 67 prolog_load_context(directory, Dir), 68 asserta(this_dir(Dir)). 69 70 71test_turtle :- 72 retractall(error(_)), 73 retractall(passed(_)), 74 this_dir(Dir), 75 atom_concat(Dir, '/Tests/Turtle', TestDir), 76 test_dir(TestDir), 77 garbage_collect_atoms, % leak checks 78 ( error(_) 79 -> fail 80 ; aggregate_all(count, passed(_), Passed), 81 aggregate_all(count, blocked(_), Blocked), 82 format('~NAll ~D Turtle tests passed (~D blocked)~n', 83 [Passed, Blocked]) 84 ). 85 86test_turtle(File) :- 87 this_dir(Here), 88 atomic_list_concat([Here, '/Tests/Turtle/', File], FullFile), 89 test_file(FullFile). 90 91%! blocked(?Test) 92% 93% True if Test is blocked. 94 95:- dynamic 96 blocked/1. 97 98% test-18.ttl uses Unicode characters > 2**16. 99blocked('test-18.ttl') :- \+ catch(char_code(_, 100 000), _, fail). 100 101%:- debug(test_turtle). 102 103/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 104Handle the test-cases provided with the Turtle language definition. 105- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 106 107test_dir(Dir) :- 108 atom_concat(Dir, '/*.ttl', Pattern), 109 expand_file_name(Pattern, Files), 110 maplist(test_file, Files). 111 112test_file(File) :- 113 file_base_name(File, BaseName), 114 blocked(BaseName), 115 !, 116 print_message(informational, test_turtle(blocked, BaseName)). 117test_file(File) :- 118 file_base_name(File, Base), 119 atom_concat(bad, _, Base), 120 !, 121 file_base_name(File, BaseName), 122 debug(test_turtle, 'Negative test ~w ...', [BaseName]), 123 catch(load_turtle(File, _Triples), E, true), 124 ( nonvar(E) 125 -> test_passed(BaseName) 126 ; print_message(error, test_turtle(false, BaseName)) 127 ). 128test_file(File) :- 129 file_base_name(File, BaseName), 130 file_name_extension(Base, ttl, File), 131 file_name_extension(Base, out, OkFile), 132 exists_file(OkFile), 133 !, 134 debug(test_turtle, 'Test ~w ...', [BaseName]), 135 load_turtle(File, Triples), 136 load_rdf_ntriples(OkFile, OkTriples0), 137 maplist(canonical_triple, OkTriples0, OkTriples), 138 sort(Triples, Turtle), 139 sort(OkTriples, OK), 140 ( rdf_equal_graphs(OK, Turtle, _) 141 -> test_passed(BaseName) 142 ; print_message(error, test_turtle(false, BaseName)), 143 ( debugging(test_turtle) 144 -> report_diff(OK, Turtle) 145 ; true 146 ) 147 ). 148test_file(_). % not a test 149 150load_turtle(File, Triples) :- 151 file_base_name(File, Base), 152 atom_concat('http://www.w3.org/2001/sw/DataAccess/df1/tests/', 153 Base, 154 BaseURI), 155 rdf_read_turtle(File, Triples, 156 [ base_uri(BaseURI), 157 anon_prefix(node(_)), 158 on_error(error) 159 ]). 160 161canonical_triple(rdf(S0, P0, O0), 162 rdf(S, P, O)) :- 163 canonical_node(S0, S), 164 canonical_node(P0, P), 165 canonical_node(O0, O). 166 167canonical_node(node(GenId), node(N)) :- 168 atom_concat(genid, AN, GenId), 169 !, 170 atom_number(AN, N). 171canonical_node(Node, Node). 172 173report_diff(OK, Result) :- 174 rdf_equal_graphs(OK, Result, _), 175 !. 176report_diff(OK, Result) :- 177 subtract(OK, Result, Missing), 178 subtract(Result, OK, TooMany), 179 ( Missing \== [] 180 -> length(Missing, NM), 181 format('**************** ~D Omitted results:~n', [NM]), 182 write_list(Missing) 183 ; true 184 ), 185 ( TooMany \== [] 186 -> length(TooMany, TM), 187 format('**************** ~D Overcomplete results:~n', [TM]), 188 write_list(TooMany) 189 ; true 190 ). 191 192write_list([]). 193write_list([H|T]) :- 194 ( H =.. [row|Cols] 195 -> write_cols(Cols), 196 format(' .~n') 197 ; H = rdf(S,P,O) 198 -> write_cell(S), put(' '), 199 write_cell(P), put(' '), 200 write_cell(O), write(' .\n') 201 ; format('~p~n', [H]) 202 ), 203 write_list(T). 204 205 206write_cols([]). 207write_cols([H|T]) :- 208 write_cell(H), 209 ( T == [] 210 -> true 211 ; put(' '), 212 write_cols(T) 213 ). 214 215write_cell(literal(X)) :- 216 !, 217 format('"~w"', [X]). 218write_cell(R) :- 219 atom(R), 220 rdf_global_id(NS:Id, R), 221 !, 222 format('<~w:~w>', [NS, Id]). 223write_cell('$null$') :- 224 !, 225 write('NULL'). 226write_cell(R) :- 227 atom(R), 228 !, 229 format('<!~w>', [R]). 230write_cell(X) :- 231 format('~p', [X]). 232 233 234 /******************************* 235 * MESSAGES * 236 *******************************/ 237 238test_passed(Test) :- 239 print_message(informational, test_turtle(true, Test)), 240 ( current_prolog_flag(verbose, silent) 241 -> put_char(user_error, '.') 242 ; true 243 ). 244 245:- multifile 246 prolog:message//1. 247 248prolog:message(test_turtle(true, Test)) --> 249 { assert(passed(Test)) }, 250 [ 'Turtle test ~q: ~tpassed~42|'-[Test] ]. 251prolog:message(test_turtle(false, Test)) --> 252 { assert(error(Test)) }, 253 [ 'Turtle test ~q: ~tFAILED~42|'-[Test], nl, 254 'Re-run with "?- debug(test_turtle)." to see more details'-[] 255 ]. 256prolog:message(test_turtle(blocked, Test)) --> 257 [ 'Turtle test ~q: ~t(blocked)~42|'-[Test] ]. 258