Indicate "OK" for expected errors
[tiger.ml.git] / compiler / src / lib / tiger / tiger_test.ml
CommitLineData
e69e4e8b
SK
1(* "exe" is for status of execution (whether any exceptions were raised)
2 * "out" is for status of output comparison (whether what was outputted is
3 * what was expected)
4 *
d3bdde4b
SK
5 * code |> pass_a_exe |> pass_a_out |> ... |> pass_z_exe |> pass_z_out
6 *
7 * pass a:
8 * exe: OK
9 * out: n/a
10 * pass b:
11 * exe: OK
12 * out: OK
13 * pass c:
14 * exe: OK
15 * out: ERROR
16 * ...
17 *
18 * name | pass a | ... | pass z
19 * ---------+--------+-----+--------
20 * exe foo | OK | ... | OK
21 * out foo | OK | ... | ERROR
22 *
23 * *)
24
25open Printf
26
27module List = ListLabels
28module String = StringLabels
29
30module Option : sig
31 type 'a t = 'a option
32
33 val map : 'a t -> ('a -> 'b) -> 'b t
34end = struct
35 type 'a t = 'a option
36
37 let map t f =
38 match t with
39 | None -> None
40 | Some x -> Some (f x)
41end
42
43type t =
44 { name : string
45 ; code : string
46 ; out_lexing : (Tiger_parser.token list) option
47 ; out_parsing : Tiger_absyn.t option
e69e4e8b 48 ; is_error_expected : (Tiger_error.t -> bool)
d3bdde4b
SK
49 }
50
51type color =
52 | Red
53 | Yellow
54 | Green
55
56
57let color_to_ansi_code = function
58 | Red -> "\027[0;31m"
59 | Yellow -> "\027[0;33m"
60 | Green -> "\027[0;32m"
61
62let color color string =
63 let color_on = color_to_ansi_code color in
64 let color_off = "\027[0m" in
65 sprintf "%s%s%s" color_on string color_off
66
e69e4e8b
SK
67let case
68 ?(out_lexing)
69 ?(out_parsing)
70 ?(is_error_expected=(fun _ -> false))
71 ~code
72 name
73 =
d3bdde4b
SK
74 { name
75 ; code
76 ; out_lexing
77 ; out_parsing
e69e4e8b 78 ; is_error_expected
d3bdde4b
SK
79 }
80
81let bar_sep = String.make 80 '-'
82let bar_end = String.make 80 '='
83
84let indent =
85 let unit_spaces = 2 in
86 fun n ->
87 String.make (n * unit_spaces) ' '
88
89let pass_lexing code : (Tiger_parser.token list, string) result =
90 let lexbuf = Lexing.from_string code in
91 let rec tokens () =
92 let token = Tiger_lexer.token lexbuf in
93 (* Avoiding fragile pattern-matching *)
94 if token = Tiger_parser.EOF then [] else token :: tokens ()
95 in
96 match tokens () with
97 | exception e -> Error (Printexc.to_string e)
98 | tokens -> Ok tokens
99
e69e4e8b 100let pass_parsing code : (Tiger_absyn.t, string) result =
d3bdde4b
SK
101 let lb = Lexing.from_string code in
102 match Tiger_parser.program Tiger_lexer.token lb with
103 | exception Parsing.Parse_error ->
104 let module L = Lexing in
105 let L.({lex_curr_p = {pos_lnum=l; pos_bol=b; pos_cnum=c; _}; _}) = lb in
106 let msg = sprintf "Syntax error around line: %d, column: %d" l (c - b) in
107 Error msg
108 | ast ->
109 Ok ast
110
111let s = sprintf
112let p = printf
113let p_ln = print_newline
114let p_indent n = p "%s" (indent n)
115
116let run tests =
117 let error_count = ref 0 in
e69e4e8b
SK
118 let run_pass ~f ~input ~expect_output ~is_error_expected =
119 let output_status = "n/a" in
120 let output_value = None in
d3bdde4b
SK
121 match f input with
122 | exception e ->
df637739 123 let status_text, error_text =
e69e4e8b
SK
124 (match e with
125 | Tiger_error.T e when is_error_expected e ->
df637739 126 ((color Green "OK"), Tiger_error.to_string e)
e69e4e8b
SK
127 | Tiger_error.T e ->
128 incr error_count;
df637739 129 ((color Red "ERROR"), Tiger_error.to_string e)
e69e4e8b
SK
130 | e ->
131 incr error_count;
df637739 132 ((color Red "ERROR"), Printexc.to_string e)
e69e4e8b
SK
133 )
134 in
df637739 135 ( s "%s: %s" status_text error_text
e69e4e8b
SK
136 , output_status
137 , output_value
d3bdde4b
SK
138 )
139 | Error msg ->
140 incr error_count;
141 ( s "%s: %s" (color Red "ERROR") msg
e69e4e8b
SK
142 , output_status
143 , output_value
d3bdde4b
SK
144 )
145 | Ok produced ->
e69e4e8b
SK
146 let execution_status = s "%s" (color Green "OK") in
147 let output_status =
d3bdde4b 148 match
e69e4e8b 149 Option.map expect_output (fun expected -> expected = produced)
d3bdde4b
SK
150 with
151 | None ->
e69e4e8b 152 s "%s" (color Yellow "expected output not provided")
d3bdde4b
SK
153 | Some true ->
154 s "%s" (color Green "OK")
155 | Some false ->
156 incr error_count;
157 s "%s" (color Red "ERROR")
158 in
e69e4e8b
SK
159 let output_value = Some produced in
160 (execution_status, output_status, output_value)
d3bdde4b
SK
161 in
162 List.iter tests ~f:(
e69e4e8b
SK
163 fun {name; code; out_lexing; out_parsing; is_error_expected} ->
164 let (stat_lex_exe, stat_lex_out_cmp, _) =
165 run_pass
166 ~f:pass_lexing
167 ~input:code
168 ~expect_output:out_lexing
169 ~is_error_expected
170 in
171 let (stat_pars_exe, stat_pars_out_cmp, _) =
172 run_pass
173 ~f:pass_parsing
174 ~input:code
175 ~expect_output:out_parsing
176 ~is_error_expected
177 in
d3bdde4b
SK
178 p "%s" bar_sep; p_ln ();
179 p "Test: %S" name; p_ln ();
180 p_indent 1; p "Lexing:"; p_ln ();
e69e4e8b
SK
181 p_indent 2; p "exe: %s" stat_lex_exe ; p_ln ();
182 p_indent 2; p "out: %s" stat_lex_out_cmp; p_ln ();
d3bdde4b 183 p_indent 1; p "Parsing:"; p_ln ();
e69e4e8b
SK
184 p_indent 2; p "exe: %s" stat_pars_exe ; p_ln ();
185 p_indent 2; p "out: %s" stat_pars_out_cmp; p_ln ();
d3bdde4b
SK
186 );
187 p "%s" bar_end; p_ln ();
188 let failures = !error_count in
189 let clr = (if failures = 0 then Green else Red) in
190 p "Failures: %s" (color clr (string_of_int failures)); p_ln ();
191 p "%s" bar_end; p_ln ();
192 exit failures
This page took 0.031715 seconds and 4 git commands to generate.