26 datatype test_params = Test_Params of {default_type: typ list, expect : expectation}; |
26 datatype test_params = Test_Params of {default_type: typ list, expect : expectation}; |
27 val test_params_of : Proof.context -> test_params |
27 val test_params_of : Proof.context -> test_params |
28 val map_test_params : (typ list * expectation -> typ list * expectation) |
28 val map_test_params : (typ list * expectation -> typ list * expectation) |
29 -> Context.generic -> Context.generic |
29 -> Context.generic -> Context.generic |
30 val add_generator: |
30 val add_generator: |
31 string * (Proof.context -> term -> int -> term list option * report option) |
31 string * (Proof.context -> term * term list -> int -> term list option * report option) |
32 -> Context.generic -> Context.generic |
32 -> Context.generic -> Context.generic |
33 val add_batch_generator: |
33 val add_batch_generator: |
34 string * (Proof.context -> term list -> (int -> term list option) list) |
34 string * (Proof.context -> term list -> (int -> term list option) list) |
35 -> Context.generic -> Context.generic |
35 -> Context.generic -> Context.generic |
36 (* testing terms and proof states *) |
36 (* testing terms and proof states *) |
37 val test_term: Proof.context -> bool * bool -> term -> |
37 val test_term: Proof.context -> bool * bool -> term * term list -> |
38 (string * term) list option * ((string * int) list * ((int * report) list) option) |
38 (string * term) list option * ((string * int) list * ((int * report) list) option) |
39 val test_goal_terms: |
39 val test_goal_terms: |
40 Proof.context -> bool * bool -> (string * typ) list -> term list |
40 Proof.context -> bool * bool -> (string * typ) list -> (term * term list) list |
41 -> (string * term) list option * ((string * int) list * ((int * report) list) option) list |
41 -> (string * term) list option * ((string * int) list * ((int * report) list) option) list |
42 val quickcheck: (string * string list) list -> int -> Proof.state -> (string * term) list option |
42 val quickcheck: (string * string list) list -> int -> Proof.state -> (string * term) list option |
43 (* testing a batch of terms *) |
43 (* testing a batch of terms *) |
44 val test_terms: Proof.context -> term list -> (string * term) list option list option |
44 val test_terms: Proof.context -> term list -> (string * term) list option list option |
45 end; |
45 end; |
107 (merge (op =) (default_type1, default_type2), merge_expectation (expect1, expect2)); |
107 (merge (op =) (default_type1, default_type2), merge_expectation (expect1, expect2)); |
108 |
108 |
109 structure Data = Generic_Data |
109 structure Data = Generic_Data |
110 ( |
110 ( |
111 type T = |
111 type T = |
112 ((string * (Proof.context -> term -> int -> term list option * report option)) list |
112 ((string * (Proof.context -> term * term list -> int -> term list option * report option)) list |
113 * (string * (Proof.context -> term list -> (int -> term list option) list)) list) |
113 * (string * (Proof.context -> term list -> (int -> term list option) list)) list) |
114 * test_params; |
114 * test_params; |
115 val empty = (([], []), Test_Params {default_type = [], expect = No_Expectation}); |
115 val empty = (([], []), Test_Params {default_type = [], expect = No_Expectation}); |
116 val extend = I; |
116 val extend = I; |
117 fun merge (((generators1, batch_generators1), params1), ((generators2, batch_generators2), params2)) : T = |
117 fun merge (((generators1, batch_generators1), params1), ((generators2, batch_generators2), params2)) : T = |
180 handle TimeLimit.TimeOut => |
180 handle TimeLimit.TimeOut => |
181 if is_interactive then exc () else raise TimeLimit.TimeOut |
181 if is_interactive then exc () else raise TimeLimit.TimeOut |
182 else |
182 else |
183 f () |
183 f () |
184 |
184 |
185 fun test_term ctxt (limit_time, is_interactive) t = |
185 fun test_term ctxt (limit_time, is_interactive) (t, eval_terms) = |
186 let |
186 let |
187 val (names, t') = apfst (map fst) (prep_test_term t); |
187 val (names, t') = apfst (map fst) (prep_test_term t); |
188 val current_size = Unsynchronized.ref 0 |
188 val current_size = Unsynchronized.ref 0 |
189 fun excipit s = |
189 fun excipit s = |
190 "Quickcheck " ^ s ^ " while testing at size " ^ string_of_int (!current_size) |
190 "Quickcheck " ^ s ^ " while testing at size " ^ string_of_int (!current_size) |
191 val (test_fun, comp_time) = cpu_time "quickcheck compilation" (fn () => mk_tester ctxt t'); |
191 val (test_fun, comp_time) = cpu_time "quickcheck compilation" |
|
192 (fn () => mk_tester ctxt (t', eval_terms)); |
192 fun with_size test_fun k reports = |
193 fun with_size test_fun k reports = |
193 if k > Config.get ctxt size then |
194 if k > Config.get ctxt size then |
194 (NONE, reports) |
195 (NONE, reports) |
195 else |
196 else |
196 let |
197 let |
236 (* In the end there is probably no generic quickcheck interface left... *) |
237 (* In the end there is probably no generic quickcheck interface left... *) |
237 |
238 |
238 fun test_term_with_increasing_cardinality ctxt (limit_time, is_interactive) ts = |
239 fun test_term_with_increasing_cardinality ctxt (limit_time, is_interactive) ts = |
239 let |
240 let |
240 val thy = ProofContext.theory_of ctxt |
241 val thy = ProofContext.theory_of ctxt |
|
242 val (ts, eval_terms) = split_list ts |
241 val (freess, ts') = split_list (map prep_test_term ts) |
243 val (freess, ts') = split_list (map prep_test_term ts) |
242 val Ts = map snd (hd freess) |
244 val Ts = map snd (hd freess) |
243 val (test_funs, comp_time) = cpu_time "quickcheck compilation" |
245 val (test_funs, comp_time) = cpu_time "quickcheck compilation" |
244 (fn () => map (mk_tester ctxt) ts') |
246 (fn () => map (mk_tester ctxt) (ts' ~~ eval_terms)) |
245 fun test_card_size (card, size) = |
247 fun test_card_size (card, size) = |
246 (* FIXME: why decrement size by one? *) |
248 (* FIXME: why decrement size by one? *) |
247 case fst (the (nth test_funs (card - 1)) (size - 1)) of |
249 case fst (the (nth test_funs (card - 1)) (size - 1)) of |
248 SOME ts => SOME (map fst (nth freess (card - 1)) ~~ ts) |
250 SOME ts => SOME (map fst (nth freess (card - 1)) ~~ ts) |
249 | NONE => NONE |
251 | NONE => NONE |
288 Syntax.string_of_sort_global thy S)) |
290 Syntax.string_of_sort_global thy S)) |
289 end |
291 end |
290 | subst T = T; |
292 | subst T = T; |
291 in (map_types o map_atyps) subst end; |
293 in (map_types o map_atyps) subst end; |
292 |
294 |
293 datatype wellsorted_error = Wellsorted_Error of string | Term of term |
295 datatype wellsorted_error = Wellsorted_Error of string | Term of term * term list |
294 |
296 |
295 fun test_goal_terms lthy (limit_time, is_interactive) insts check_goals = |
297 fun test_goal_terms lthy (limit_time, is_interactive) insts check_goals = |
296 let |
298 let |
|
299 fun map_goal_and_eval_terms f (check_goal, eval_terms) = (f check_goal, map f eval_terms) |
297 val thy = ProofContext.theory_of lthy |
300 val thy = ProofContext.theory_of lthy |
298 val default_insts = |
301 val default_insts = |
299 if Config.get lthy finite_types then (get_finite_types lthy) else (default_type lthy) |
302 if Config.get lthy finite_types then (get_finite_types lthy) else (default_type lthy) |
300 val inst_goals = |
303 val inst_goals = |
301 map (fn check_goal => |
304 map (fn (check_goal, eval_terms) => |
302 if not (null (Term.add_tfree_names check_goal [])) then |
305 if not (null (Term.add_tfree_names check_goal [])) then |
303 map (fn T => |
306 map (fn T => |
304 (pair (SOME T) o Term o Object_Logic.atomize_term thy o monomorphic_term thy insts T) |
307 (pair (SOME T) o Term o apfst (Object_Logic.atomize_term thy)) |
305 check_goal |
308 (map_goal_and_eval_terms (monomorphic_term thy insts T) (check_goal, eval_terms)) |
306 handle WELLSORTED s => (SOME T, Wellsorted_Error s)) default_insts |
309 handle WELLSORTED s => (SOME T, Wellsorted_Error s)) default_insts |
307 else |
310 else |
308 [(NONE, Term (Object_Logic.atomize_term thy check_goal))]) check_goals |
311 [(NONE, Term (Object_Logic.atomize_term thy check_goal, eval_terms))]) check_goals |
309 val error_msg = |
312 val error_msg = |
310 cat_lines |
313 cat_lines |
311 (maps (map_filter (fn (_, Term t) => NONE | (_, Wellsorted_Error s) => SOME s)) inst_goals) |
314 (maps (map_filter (fn (_, Term t) => NONE | (_, Wellsorted_Error s) => SOME s)) inst_goals) |
312 fun is_wellsorted_term (T, Term t) = SOME (T, t) |
315 fun is_wellsorted_term (T, Term t) = SOME (T, t) |
313 | is_wellsorted_term (_, Wellsorted_Error s) = NONE |
316 | is_wellsorted_term (_, Wellsorted_Error s) = NONE |
330 collect_results test_term' [] correct_inst_goals |
333 collect_results test_term' [] correct_inst_goals |
331 else |
334 else |
332 collect_results (test_term lthy (limit_time, is_interactive)) [] (maps (map snd) correct_inst_goals) |
335 collect_results (test_term lthy (limit_time, is_interactive)) [] (maps (map snd) correct_inst_goals) |
333 end; |
336 end; |
334 |
337 |
335 fun test_goal (time_limit, is_interactive) insts i state = |
338 fun test_goal (time_limit, is_interactive) (insts, eval_terms) i state = |
336 let |
339 let |
337 val lthy = Proof.context_of state; |
340 val lthy = Proof.context_of state; |
338 val thy = Proof.theory_of state; |
341 val thy = Proof.theory_of state; |
339 fun strip (Const ("all", _) $ Abs (_, _, t)) = strip t |
342 fun strip (Const ("all", _) $ Abs (_, _, t)) = strip t |
340 | strip t = t; |
343 | strip t = t; |
347 val assms = if Config.get lthy no_assms then [] else case some_locale |
350 val assms = if Config.get lthy no_assms then [] else case some_locale |
348 of NONE => Assumption.all_assms_of lthy |
351 of NONE => Assumption.all_assms_of lthy |
349 | SOME locale => Assumption.local_assms_of lthy (Locale.init locale thy); |
352 | SOME locale => Assumption.local_assms_of lthy (Locale.init locale thy); |
350 val proto_goal = Logic.list_implies (map Thm.term_of assms, subst_bounds (frees, strip gi)); |
353 val proto_goal = Logic.list_implies (map Thm.term_of assms, subst_bounds (frees, strip gi)); |
351 val check_goals = case some_locale |
354 val check_goals = case some_locale |
352 of NONE => [proto_goal] |
355 of NONE => [(proto_goal, eval_terms)] |
353 | SOME locale => map (fn (_, phi) => Morphism.term phi proto_goal) |
356 | SOME locale => |
354 (Locale.registrations_of (Context.Theory thy) (*FIXME*) locale); |
357 map (fn (_, phi) => (Morphism.term phi proto_goal, map (Morphism.term phi) eval_terms)) |
|
358 (Locale.registrations_of (Context.Theory thy) (*FIXME*) locale); |
355 in |
359 in |
356 test_goal_terms lthy (time_limit, is_interactive) insts check_goals |
360 test_goal_terms lthy (time_limit, is_interactive) insts check_goals |
357 end |
361 end |
358 |
362 |
359 (* pretty printing *) |
363 (* pretty printing *) |
396 let |
400 let |
397 val ctxt = Proof.context_of state; |
401 val ctxt = Proof.context_of state; |
398 val res = |
402 val res = |
399 state |
403 state |
400 |> Proof.map_context (Config.put report false #> Config.put quiet true) |
404 |> Proof.map_context (Config.put report false #> Config.put quiet true) |
401 |> try (test_goal (false, false) [] 1); |
405 |> try (test_goal (false, false) ([], []) 1); |
402 in |
406 in |
403 case res of |
407 case res of |
404 NONE => (false, state) |
408 NONE => (false, state) |
405 | SOME (NONE, report) => (false, state) |
409 | SOME (NONE, report) => (false, state) |
406 | SOME (cex, report) => (true, Proof.goal_message (K (Pretty.chunks [Pretty.str "", |
410 | SOME (cex, report) => (true, Proof.goal_message (K (Pretty.chunks [Pretty.str "", |
469 fun quickcheck_params_cmd args = Context.theory_map (fold parse_test_param args); |
473 fun quickcheck_params_cmd args = Context.theory_map (fold parse_test_param args); |
470 |
474 |
471 fun gen_quickcheck args i state = |
475 fun gen_quickcheck args i state = |
472 state |
476 state |
473 |> Proof.map_context_result (fn ctxt => fold parse_test_param_inst args (([], []), ctxt)) |
477 |> Proof.map_context_result (fn ctxt => fold parse_test_param_inst args (([], []), ctxt)) |
474 |> (fn ((insts, eval_terms), state') => test_goal (true, true) insts i state' |
478 |> (fn ((insts, eval_terms), state') => test_goal (true, true) (insts, eval_terms) i state' |
475 |> tap (fn (SOME x, _) => if expect (Proof.context_of state') = No_Counterexample then |
479 |> tap (fn (SOME x, _) => if expect (Proof.context_of state') = No_Counterexample then |
476 error ("quickcheck expected to find no counterexample but found one") else () |
480 error ("quickcheck expected to find no counterexample but found one") else () |
477 | (NONE, _) => if expect (Proof.context_of state') = Counterexample then |
481 | (NONE, _) => if expect (Proof.context_of state') = Counterexample then |
478 error ("quickcheck expected to find a counterexample but did not find one") else ())) |
482 error ("quickcheck expected to find a counterexample but did not find one") else ())) |
479 |
483 |