1 | % (c) 2009-2013 Lehrstuhl fuer Softwaretechnik und Programmiersprachen, | |
2 | % Heinrich Heine Universitaet Duesseldorf | |
3 | % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html) | |
4 | ||
5 | :- module(test_typechecker,[run_typecheck_testcase/2]). | |
6 | ||
7 | :- use_module(library(codesio)). | |
8 | :- use_module(library(file_systems)). | |
9 | ||
10 | :- use_module(bsyntaxtree). | |
11 | :- use_module(btypechecker). | |
12 | :- use_module(bmachine_structure). | |
13 | :- use_module(bmachine_construction). | |
14 | :- use_module(parsercall). | |
15 | :- use_module(tools). | |
16 | :- use_module(translate,[pretty_type/2]). | |
17 | ||
18 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
19 | % typechecker-test framework | |
20 | ||
21 | run_typecheck_testcase(Filename,Type) :- | |
22 | run_testcase(Filename,Filename,Type,Verdicts), | |
23 | nl,print_verdicts(Verdicts,*), | |
24 | summarized_verdict(Verdicts,V), | |
25 | !, | |
26 | ( V==pass -> print('All tests passed\n') | |
27 | ; otherwise -> print('Test failed\n'),fail). | |
28 | ||
29 | print_verdicts([],_). | |
30 | print_verdicts([verdict(Testname,Subname,Verdict)|Rest],Before) :- | |
31 | ( Before=Testname -> true | |
32 | ; otherwise -> write(Testname),write(':'),nl), | |
33 | format('~t~q~10|: ~q~n',[Subname,Verdict]), | |
34 | print_verdicts(Rest,Testname). | |
35 | ||
36 | summarized_verdict(Vs,Sum) :- summarized_verdict2(Vs,pass,Sum). | |
37 | summarized_verdict2([],V,V). | |
38 | summarized_verdict2([verdict(_,_,V)|Rest],Old,New) :- | |
39 | ( V==pass -> summarized_verdict2(Rest,Old,New) | |
40 | ; otherwise -> New=fail). | |
41 | ||
42 | :- use_module(b_global_sets,[b_clear_global_set_type_definitions/0]). | |
43 | run_testcase(Filename,Testname,Type,Verdict) :- | |
44 | b_clear_global_set_type_definitions, | |
45 | catch(( absolute_file_name(Filename,AbsFilename), | |
46 | load_b_machine_as_term(AbsFilename,Machine) -> | |
47 | ( run_testcase2(Type,Testname,Machine,Verdict) -> true | |
48 | ; otherwise -> Verdict = [verdict(Testname,*,error('run_testcase2 failed'))]) | |
49 | ; otherwise -> Verdict = [verdict(Testname,*,error('unable to load testfile'))]), | |
50 | X, | |
51 | Verdict = [verdict(Testname,*,error(X))]). | |
52 | ||
53 | run_testcase2(Type, Testname, complete_machine(Main, Machines, _), Verdict) :- | |
54 | ( extract_tests(Main,Machines,Test) -> | |
55 | ( \+ ground(Test) -> | |
56 | Verdict = [verdict(Testname,*,error('testcases not ground'))] | |
57 | ; check_machine(Main, Machines, Typed, Errors) -> | |
58 | ( run_testcase3(Type,Testname,Typed,Errors,Test,Verdict) -> true | |
59 | ; otherwise -> Verdict = [verdict(Testname,*,error('run_testcase3 failed'))]) | |
60 | ; otherwise -> | |
61 | Verdict = [verdict(Testname,*,fail('type checker failed'))]) | |
62 | ; otherwise -> | |
63 | Verdict = [verdict(Testname,*,error('extracting tests failed'))]). | |
64 | ||
65 | extract_tests(Main,Machines,Tests) :- | |
66 | findall(test(Name,T), | |
67 | ( get_secs(Main,Machines,Secs), | |
68 | member(definitions(_,Defs),Secs), | |
69 | member(expression_definition(_,Fullname,[],string(_,TestAtom)),Defs), | |
70 | atom_chars(Fullname,CFullname), | |
71 | append(['T','E','S','T','_'],CName,CFullname), | |
72 | atom_chars(Name,CName), | |
73 | name(TestAtom,TestCodes1),append(TestCodes1,".",TestCodes), | |
74 | read_from_codes(TestCodes,T)), | |
75 | Tests). | |
76 | get_secs(Name,Machines,Secs) :- | |
77 | member(abstract_machine(_,_ModelType,machine_header(_,Name,_),Secs),Machines). | |
78 | get_secs(Name,Machines,Secs) :- | |
79 | member(refinement_machine(_,machine_header(_,Name,_),_Refines,Secs),Machines). | |
80 | ||
81 | ||
82 | run_testcase3(typesok, Testname, Typed, Errors, Tests, Verdict) :- | |
83 | ( Errors = [] -> | |
84 | Verdict = [verdict(Testname,typecheck,pass)|Verdict1], | |
85 | run_checks(Tests,Testname,Typed,Verdict1) | |
86 | ; otherwise -> | |
87 | Verdict = [verdict(Testname,*,fail('unexpected errors from type-checker', Errors))]). | |
88 | ||
89 | run_checks([],_,_,[]). | |
90 | run_checks([test(Name,Test)|Rest],Testname,Typed,[verdict(Testname,Name,Verdict)|VRest]) :- | |
91 | run_check(Test,Typed,Verdict), | |
92 | run_checks(Rest,Testname,Typed,VRest). | |
93 | ||
94 | run_check(ElemPos:ExpectedType, Typed, Verdict) :- | |
95 | ( slashes_to_list(ElemPos,ElemPosL), | |
96 | get_element(ElemPosL,Typed,Element) -> | |
97 | ( get_texpr_type(Element,Type) -> | |
98 | ( Type == ExpectedType -> | |
99 | Verdict = pass | |
100 | ; otherwise -> | |
101 | safe_pretty_type(ExpectedType, PExp), | |
102 | safe_pretty_type(Type, PType), | |
103 | ajoin(['expected ',PExp,', but was ', PType],Msg), | |
104 | Verdict = fail(Msg)) | |
105 | ; otherwise -> | |
106 | Verdict = fail('got ill-formed expression')) | |
107 | ; otherwise -> | |
108 | write_to_codes(ElemPos,ElemStr), | |
109 | name(ElemAtom,ElemStr), | |
110 | ajoin(['element ',ElemAtom,' not found'], Msg), | |
111 | Verdict = fail(Msg)). | |
112 | ||
113 | safe_pretty_type(Type,Text) :- | |
114 | ( pretty_type(Type,Text) -> true | |
115 | ; otherwise -> Text = '<failed to pretty type>'). | |
116 | ||
117 | slashes_to_list(A/B,List) :- | |
118 | !,slashes_to_list(A,AList), | |
119 | slashes_to_list(B,BList), | |
120 | append(AList,BList,List). | |
121 | slashes_to_list(X,[X]). | |
122 | ||
123 | get_element([Section|Path],M,Elem) :- | |
124 | get_section(Section,M,Content), | |
125 | get_element2(Content,Path,Elem),!. | |
126 | get_element2([H|T],Path,Elem) :- !, | |
127 | member(Sub,[H|T]),get_element2(Sub,Path,Elem). | |
128 | get_element2(TExpr,Path,Elem) :- | |
129 | is_texpr(TExpr), | |
130 | get_texpr_expr(TExpr,Expr), | |
131 | ( Path = [] -> | |
132 | Elem=TExpr | |
133 | ; Expr = identifier(op(ID)) -> | |
134 | get_element3(Path,ID,TExpr,Elem) | |
135 | ; Expr = identifier(ID) -> | |
136 | get_element3(Path,ID,TExpr,Elem) | |
137 | ; Expr = operation(OpId,_,_,_),get_texpr_id(OpId,op(ID)) -> | |
138 | get_element3(Path,ID,TExpr,Elem) | |
139 | ; functor(Expr,Functor,_) -> | |
140 | get_element3(Path,Functor,TExpr,Elem)). | |
141 | get_element3([Path],Path,TExpr,TExpr). | |
142 | get_element3([Head|Rest],Head,TExpr,Elem) :- | |
143 | Rest=[_|_], | |
144 | syntaxtraversion(TExpr,_,_,_,Subs,_), | |
145 | get_element2(Subs,Rest,Elem). | |
146 | get_element3([*|Rest],Pattern,TExpr,Elem) :- | |
147 | Rest=[_|_],get_element3(Rest,Pattern,TExpr,Elem). | |
148 | get_element3([*|Rest],_Pattern,TExpr,Elem) :- | |
149 | Rest=[_|_], | |
150 | syntaxtraversion(TExpr,_,_,_,Subs,_), | |
151 | get_element2(Subs,[*|Rest],Elem). |