(* Copyright (C) 2004, HELM Team. * * This file is part of HELM, an Hypertextual, Electronic * Library of Mathematics, developed at the Computer Science * Department, University of Bologna, Italy. * * HELM 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. * * HELM 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 General Public License * along with HELM; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. * * For details, see the HELM World-Wide-Web page, * http://helm.cs.unibo.it/ *) open Printf let argc = Array.length Sys.argv let rawsep = "###" let sep = Pcre.regexp (sprintf "^%s" rawsep) let msg_prefix = "*** REGTEST *** " let print_msg s = prerr_endline (msg_prefix ^ s) type state = Term | EMetasenv | ETerm | EType | EReduced (* regtest file format * < cic term in concrete syntax > * separator (* see sep above *) * < expected metasenv after disambiguation (CicMetaSubst.ppmetasenv) > * separator (* see sep above *) * < expected cic term after disambiguation (CicPp.ppterm) > * separator (* see sep above *) * < expected cic type as per type_of (CicPp.ppterm) > * separator (* see sep above *) * < expected reduced cic term as (CicPp.ppterm) > *) type regtest = { term: string; (* raw cic term *) emetasenv : string; (* expected metasenv *) eterm: string; (* expected term *) etype: string; (* expected type *) ereduced: string; (* expected reduced term *) } let print_test test fname = let oc = open_out fname in output_string oc (String.concat "" [ test.term; sprintf "%s (* METASENV after disambiguation *)\n" rawsep; test.emetasenv; sprintf "%s (* TERM after disambiguation *)\n" rawsep; test.eterm; sprintf "%s (* TYPE_OF the disambiguated term *)\n" rawsep; test.etype; sprintf "%s (* REDUCED disambiguated term *)\n" rawsep; test.ereduced ]); close_out oc let parse_regtest = let term = Buffer.create 1024 in (* raw term *) let emetasenv = Buffer.create 1024 in (* expected metasenv *) let eterm = Buffer.create 1024 in (* raw expected term *) let etype = Buffer.create 1024 in (* raw expected type *) let ereduced = Buffer.create 1024 in (* raw expected reducted term *) let state = ref Term in let bump_state () = match !state with | Term -> state := EMetasenv | EMetasenv -> state := ETerm | ETerm -> state := EType | EType -> state := EReduced | EReduced -> assert false in let buffer_of_state = function | Term -> term | EMetasenv -> emetasenv | ETerm -> eterm | EType -> etype | EReduced -> ereduced in let clear_buffers () = List.iter Buffer.clear [ term; emetasenv; eterm; etype; ereduced ] in fun fname -> state := Term; clear_buffers (); let ic = open_in fname in (try while true do let line = input_line ic in match line with | l when Pcre.pmatch ~rex:sep l -> bump_state () | l -> Buffer.add_string (buffer_of_state !state) (line ^ "\n") done with End_of_file -> ()); { term = Buffer.contents term; emetasenv = Buffer.contents emetasenv; eterm = Buffer.contents eterm; etype = Buffer.contents etype; ereduced = Buffer.contents ereduced } let as_expected expected found = (* ignores "term" field *) let outcome = ref true in if expected.eterm <> found.eterm then begin print_msg "Term mismatch"; print_msg " expected:"; print_msg (" " ^ expected.eterm); print_msg " found:"; print_msg (" " ^ found.eterm); outcome := false; end; if expected.emetasenv <> found.emetasenv then begin print_msg "Metasenv mismatch"; print_msg " expected:"; print_msg (" " ^ expected.emetasenv); print_msg " found:"; print_msg (" " ^ found.emetasenv); outcome := false; end; if expected.etype <> found.etype then begin print_msg "Type mismatch"; print_msg " expected:"; print_msg (" " ^ expected.etype); print_msg " found:"; print_msg (" " ^ found.etype); outcome := false; end; if expected.ereduced <> found.ereduced then begin print_msg "Reduced term mismatch"; print_msg " expected:"; print_msg (" " ^ expected.ereduced); print_msg " found:"; print_msg (" " ^ found.ereduced); outcome := false; end; !outcome let test_this raw_term = let empty_context = [] in let (metasenv, cic_term) = BatchParser.parse raw_term in let etype = try CicPp.ppterm (CicTypeChecker.type_of_aux' metasenv empty_context cic_term) with _ -> "MALFORMED" in let ereduced = try CicPp.ppterm (CicReduction.whd empty_context cic_term) with _ -> "MALFORMED" in { term = raw_term; (* useless *) emetasenv = CicMetaSubst.ppmetasenv metasenv [] ^ "\n"; eterm = CicPp.ppterm cic_term ^ "\n"; etype = etype ^ "\n"; ereduced = ereduced ^ "\n"; } let dump_environment filename = try let oc = open_out filename in CicEnvironment.dump_to_channel oc; close_out oc with exc -> prerr_endline ("DUMP_ENVIRONMENT FAILURE, uncaught excecption " ^ Printexc.to_string exc) ; raise exc ;; let restore_environment filename = if Sys.file_exists filename then begin try let ic = open_in filename in CicEnvironment.restore_from_channel ic; close_in ic with exc -> prerr_endline ("RESTORE_ENVIRONMENT FAILURE, uncaught excecption " ^ Printexc.to_string exc) ; raise exc end else CicEnvironment.empty () ;; let main generate dump fnames = if generate then begin (* gen mode *) print_msg "[ Gen mode ]"; List.iter (function fname -> let test_fname = fname ^ ".test" in let env_fname = fname ^ ".env" in print_msg (sprintf "Generating regtest %s -> %s\n ..." fname test_fname); let raw_term = (parse_regtest fname).term in let result = test_this raw_term in print_test result test_fname ; if dump then dump_environment env_fname ; ) fnames end else begin (* regtest mode *) print_msg "[ Regtest mode ]"; let (ok, nok) = (ref 0, ref []) in List.iter (function fname -> let env_fname = fname ^ ".env" in let test_fname = fname ^ ".test" in restore_environment env_fname ; prerr_endline ("# " ^ fname); try let expected = parse_regtest test_fname in let actual = test_this expected.term in if dump then dump_environment env_fname ; if as_expected expected actual then incr ok else nok := fname :: !nok; with e -> nok := fname :: !nok ) fnames ; print_msg "Regtest completed:"; print_msg (sprintf "Succeeded: %d" !ok); print_msg (sprintf "Failed: %d" (List.length !nok)); List.iter (fun fname -> print_msg (sprintf " %s failed :-(" fname)) (List.rev !nok) end ;; let _ = let fnames = ref [] in let gen = ref false in let dump = ref false in let nodump = ref false in let usage = "regtest [OPTION] ... test1 ..." in let spec = ["-gen", Arg.Set gen, "generate the tests; implies -dump (unless -nodump is specified)" ; "--gen", Arg.Set gen, "generate the tests; implies -dump (unless -nodump is specified)" ; "-dump", Arg.Set dump, "dumps the final environment" ; "--dump", Arg.Set dump, "dumps the final environment" ; "-nodump", Arg.Set dump, "do not dump the final environment" ; "--nodump", Arg.Set dump, "do not dump the final environment" ] in Arg.parse spec (function filename -> fnames := filename::!fnames ) usage ; if !fnames = [] then Arg.usage spec (Sys.argv.(0) ^ ": missing argument test. You must provide at least one test file.\n" ^ usage) ; main !gen ((!gen || !dump) && (not !nodump)) !fnames ;;