2 * Copyright (c) 2016, Facebook, Inc.
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the "hack" directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
11 module EditableTrivia
= Full_fidelity_editable_trivia
12 module SourceText
= Full_fidelity_source_text
13 module SyntaxTree
= Full_fidelity_syntax_tree
14 .WithSyntax
(Full_fidelity_positioned_syntax
)
15 module PositionedTree
= Full_fidelity_syntax_tree
16 .WithSyntax
(Full_fidelity_positioned_syntax
)
17 module ParserErrors
= Full_fidelity_parser_errors
18 .WithSyntax
(Full_fidelity_positioned_syntax
)
19 module SyntaxError
= Full_fidelity_syntax_error
20 module TestUtils
= Full_fidelity_test_utils
21 module TriviaKind
= Full_fidelity_trivia_kind
27 let test_files_dir = "./hphp/hack/test/full_fidelity/cases"
30 (** Source files is loaded from <name>.php in the <cwd>/<test_files_dir>/ *)
34 test_function
: string -> string;
35 value_mapper
: string -> string;
40 let write_file name contents
=
41 let path = Filename.concat
test_files_dir name
in
42 let oc = open_out
path in
43 Printf.fprintf
oc "%s" contents
;
46 let write_expectation_to_file name expected
=
47 write_file (name ^
".out") expected
50 let path = Filename.concat
test_files_dir name
in
51 let raw = Sys_utils.cat
path in
52 (** cat adds an extra newline at the end. *)
53 if (String.length
raw > 0) &&
54 (String.get
raw (String.length
raw - 1)) == '
\n'
then
55 String.sub
raw 0 (String.length
raw - 1)
59 (** Create a test_case by reading input from <cwd>/<test_files_dir>/name.php
61 let make_test_case_from_files ?
(value_mapper
=ident) name test_function
=
62 let source = cat_file (name ^
".php") in
63 let expected = cat_file (name ^
".exp") in
68 test_function
= test_function
;
72 let remove_whitespace text
=
73 let length = String.length text
in
74 let buffer = Buffer.create
length in
77 Buffer.contents
buffer
79 let ch = String.get text i
in
81 | ' '
| '
\n'
| '
\r'
| '
\t'
-> aux (i
+ 1)
82 | _
-> begin Buffer.add_char
buffer ch; aux (i
+ 1) end in
86 let test_minimal source =
87 let file_path = Relative_path.(create Dummy
"<test_minimal>") in
88 let source_text = SourceText.make
file_path source in
89 let syntax_tree = SyntaxTree.make
source_text in
90 TestUtils.to_formatted_sexp_string
(SyntaxTree.root
syntax_tree)
92 let test_trivia source =
93 let file_path = Relative_path.(create Dummy
"<test_trivia>") in
94 let source_text = SourceText.make
file_path source in
95 let syntax_tree = SyntaxTree.make
source_text in
96 let editable = SyntaxTransforms.editable_from_positioned
syntax_tree in
97 let (no_trivia_tree
, trivia
) = TestUtils.rewrite_editable_tree_no_trivia
editable in
98 let pretty_no_trivia = Full_fidelity_pretty_printer.pretty_print no_trivia_tree
in
99 let formatted_trivia = List.map trivia
101 Printf.sprintf
"%s: (%s)"
102 (TriviaKind.to_string
@@ EditableTrivia.kind t
)
103 (EditableTrivia.text t
)
105 Printf.sprintf
"%s\n%s" (String.trim
pretty_no_trivia) (String.concat
"\n" formatted_trivia)
107 let test_mode source =
108 let file_path = Relative_path.(create Dummy
"<test_mode>") in
109 let source_text = SourceText.make
file_path source in
110 let syntax_tree = SyntaxTree.make
source_text in
111 let lang = SyntaxTree.language
syntax_tree in
112 let mode = SyntaxTree.mode syntax_tree in
113 let is_strict = SyntaxTree.is_strict syntax_tree in
114 let is_hack = SyntaxTree.is_hack syntax_tree in
115 let is_php = SyntaxTree.is_php syntax_tree in
116 Printf.sprintf
"Lang:%sMode:%sStrict:%bHack:%bPhp:%b"
117 lang mode is_strict is_hack is_php
119 let test_errors source =
120 let file_path = Relative_path.(create Dummy
"<test_errors>") in
121 let source_text = SourceText.make
file_path source in
122 let offset_to_position = SourceText.offset_to_position source_text in
123 let syntax_tree = PositionedTree.make
source_text in
124 let errors = ParserErrors.parse_errors
syntax_tree in
125 let mapper err
= SyntaxError.to_positioned_string err
offset_to_position in
126 let errors = List.map
errors ~f
:mapper in
127 Printf.sprintf
"%s" (String.concat
"\n" errors)
130 [make_test_case_from_files "test_trivia" test_trivia]
133 let mapper testname
=
134 make_test_case_from_files
135 ~value_mapper
:remove_whitespace testname
test_minimal in
139 (* TODO: This test is temporarily disabled because
141 does not parse in the FF parser as it did in the original Hack parser,
142 due to a precedence issue. Re-enable this test once we either fix that,
143 or decide to take the breaking change.
144 "test_conditional"; *)
146 "test_for_statements";
147 "test_try_statement";
148 "test_list_precedence";
149 "test_list_expression";
150 "test_foreach_statements";
151 "test_types_type_const";
152 "test_function_call";
153 "test_array_expression";
154 "test_varray_darray_expressions";
155 "test_varray_darray_types";
156 "test_attribute_spec";
157 "test_array_key_value_precedence";
159 "test_class_with_attributes";
160 "test_class_with_qualified_name";
163 "test_class_method_declaration";
164 "test_constructor_destructor";
171 "test_global_constant";
173 "test_inclusion_directive";
174 "test_awaitable_creation";
176 "test_variadic_type_hint";
177 "test_tuple_type_keyword";
178 "test_trailing_commas";
179 "context/test_extra_error_trivia";
180 "test_funcall_with_type_arguments";
181 "test_nested_namespace_declarations";
182 "test_xhp_attributes";
184 "test_spaces_preserved_in_string_containing_expression";
186 "test_degenerate_ternary";
190 let mapper testname
=
191 make_test_case_from_files testname
test_errors in
194 "is_expression/test_callable_hint";
195 "is_expression/test_soft_hint";
196 "test_default_param_errors";
198 "test_method_modifier_errors";
199 "test_errors_not_strict";
200 "test_errors_strict";
201 "test_no_errors_strict";
202 "test_statement_errors";
203 "test_expression_errors";
204 "test_errors_method";
205 "test_declaration_errors";
207 "test_errors_array_type";
208 "test_errors_variadic_param";
209 "test_errors_variadic_param_default";
210 "test_errors_statements";
211 "test_implements_errors";
212 "test_object_creation_errors";
213 "test_classish_inside_function_errors";
214 "test_list_expression_errors";
215 "test_interface_method_errors";
216 "test_abstract_classish_errors";
217 "test_abstract_methodish_errors";
219 "test_visibility_modifier_errors";
221 "context/test_missing_name_in_expression";
222 "context/test_nested_function_lite";
223 "context/test_nested_function";
224 "context/test_method_decl_extra_token";
225 "context/test_recovery_to_classish1";
226 "context/test_recovery_to_classish2";
227 "context/test_recovery_to_classish3";
228 "context/test_single_extra_token_recovery";
229 "context/test_missing_foreach_value";
230 "test_namespace_error_recovery";
231 "test_correct_code1";
232 "test_misspelling_recovery";
233 "test_misspelling_recovery2";
234 "test_group_use_errors";
235 "test_abstract_initializers";
236 "test_mixed_bracketed_unbracketed_namespaces1";
237 "test_mixed_bracketed_unbracketed_namespaces2";
241 "test_xhp_attribute_enum_errors";
243 "test_abstract_final_errors";
244 "test_content_before_header";
245 "test_valid_php_no_markup_errors";
246 "test_question_mark_end_tag_errors";
247 "test_php_blocks_errors";
248 "test_inout_params_errors";
249 "test_variadic_ref_decorators";
250 "test_lambda_variadic_errors";
251 "test_lambda_no_typehints_errors";
254 let test_data = minimal_tests @ trivia_tests @ error_tests @
257 name
= "test_mode_1";
259 expected = "Lang:hhMode:Strict:falseHack:truePhp:false";
260 test_function
= test_mode;
261 value_mapper
= ident;
264 name
= "test_mode_2";
266 expected = "Lang:phpMode:Strict:falseHack:falsePhp:true";
267 test_function
= test_mode;
268 value_mapper
= ident;
271 name
= "test_mode_3";
272 source = "<?hh // strict ";
273 expected = "Lang:hhMode:strictStrict:trueHack:truePhp:false";
274 test_function
= test_mode;
275 value_mapper
= ident;
278 name
= "test_mode_4";
279 source = "<?php // strict "; (* Not strict! *)
280 expected = "Lang:phpMode:strictStrict:falseHack:falsePhp:true";
281 test_function
= test_mode;
282 value_mapper
= ident;
285 name
= "test_mode_5";
287 expected = "Lang:hhMode:Strict:falseHack:truePhp:false";
288 test_function
= test_mode;
289 value_mapper
= ident;
292 name
= "test_mode_6";
294 expected = "Lang:hhMode:Strict:falseHack:truePhp:false";
295 test_function
= test_mode;
296 value_mapper
= ident;
301 let actual = test
.test_function test
.source in
303 let expected = test
.value_mapper test
.expected in
304 let actual = test
.value_mapper
actual in
305 assert_equal
expected actual
308 write_expectation_to_file test
.name
actual;
312 test
.name
>:: (driver test
)
314 let run_tests tests
=
315 Printf.printf
"%s" (Sys.getcwd
());
316 List.map tests ~f
:run_test
319 "Full_fidelity_suite" >::: (run_tests test_data)
322 run_test_tt_main
test_suite