35
36:- module(test_wizard,
37 [ make_tests/3, 38 make_test/3 39 ]). 40:- autoload(library(apply),[maplist/2]). 41:- autoload(library(listing),[portray_clause/2]). 42:- autoload(library(lists),[member/2]). 43:- autoload(library(readutil),[read_file_to_terms/3]). 44:- autoload(library(time),[call_with_time_limit/2]).
54setting(max_time(5)).
55
56
57
66make_tests(Module, File, Out) :-
67 read_file_to_terms(File, Queries, []),
68 findall(Test, ( member(Q, Queries),
69 make_test(Q, Module, Test)), Tests),
70 ( Tests == []
71 -> true
72 ; format(Out, ':- begin_tests(~q).~n~n', [Module]),
73 maplist(portray_clause(Out), Tests),
74 format(Out, '~n:- end_tests(~q).~n', [Module])
75 ).
76
77
78
88make_test(Query0, Module, (test(Name, Options) :- Query)) :-
89 find_test_module(Query0, Module, Query),
90 pred_name(Query, Name),
91 setting(max_time(Max)),
92 test_result(Module:Query, Max, Options).
102find_test_module(Var, _, _) :-
103 var(Var), !, fail.
104find_test_module(M:Query, M0, Query) :-
105 !,
106 M0 = M.
107find_test_module(Query, M, Query) :-
108 current_predicate(_, M:Query),
109 \+ predicate_property(M:Query, imported_from(_M2)).
116pred_name(Callable, Name) :-
117 strip_module(Callable, _, Term),
118 functor(Term, Name, _Arity).
130test_result(Callable, Maxtime, Result) :-
131 term_variables(Callable, Vars),
132 make_template(Vars, Templ),
133 catch(call_with_time_limit(Maxtime,
134 findall(Templ-Det,
135 call_test(Callable, Det),
136 Bindings)),
137 E, true),
138 ( var(E)
139 -> success(Bindings, Templ, Result)
140 ; error(E, Result)
141 ).
147success([], _, [fail]) :- !.
148success([[]-true], _, []) :- !.
149success([S1-true], Templ, [ true(Templ == S1) ]) :- !.
150success([[]-false], _, [ nondet ]) :- !.
151success([S1-false], Templ, [ true(Templ == S1), nondet ]) :- !.
152success(ListDet, Templ, [all(Templ == List)]) :-
153 strip_det(ListDet, List).
154
155strip_det([], []).
156strip_det([H-_|T0], [H|T]) :-
157 strip_det(T0, T).
161error(Error0, [throws(Error)]) :-
162 generalise_error(Error0, Error).
163
164
165generalise_error(error(Formal, _), error(Formal, _)) :- !.
166generalise_error(Term, Term).
173make_template([], []) :- !.
174make_template([One], One) :- !.
175make_template([One, Two], One-Two) :- !.
176make_template(List, Vars) :-
177 Vars =.. [v|List].
184call_test(Goal, Det) :-
185 Goal,
186 deterministic(Det).
187
188
189 192
202
203:- multifile
204 user:message_hook/3. 205
206user:message_hook(toplevel_goal(Goal0, Bindings), _Level, _Lines) :-
207 open_query_log(Out),
208 bind_vars(Bindings),
209 clean_goal(Goal0, Goal),
210 call_cleanup(format(Out, '~W.~n', [Goal, [ numbervars(true),
211 quoted(true),
212 ignore_ops(true)
213 ]]), close(Out)),
214 fail.
215
216clean_goal(Var, _) :-
217 var(Var), !, fail.
218clean_goal(user:Goal, Goal) :- !.
219clean_goal(Goal, Goal).
220
221bind_vars([]).
222bind_vars([Name=Var|T]) :-
223 Var = '$VAR'(Name),
224 bind_vars(T).
225
226open_query_log(Out) :-
227 current_prolog_flag(log_query_file, File),
228 exists_file(File),
229 !,
230 open(File, append, Out,
231 [ encoding(utf8),
232 lock(write)
233 ]).
234open_query_log(Out) :-
235 current_prolog_flag(log_query_file, File),
236 access_file(File, write),
237 !,
238 open(File, write, Out,
239 [ encoding(utf8),
240 lock(write),
241 bom(true)
242 ]),
243 format(Out,
244 '/* SWI-Prolog query log. This file contains all syntactically\n \c
245 correct queries issued in this directory. It is used by the\n \c
246 test wizard to generate unit tests.\n\c
247 */~n~n', [])
Test Generation Wizard
Tasks
*/