diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/dup_cases.ml | 10 | ||||
-rw-r--r-- | test/dynamics.ml | 93 | ||||
-rw-r--r-- | test/get_type.ml | 68 | ||||
-rw-r--r-- | test/literals.ml | 15 | ||||
-rw-r--r-- | test/location.ml | 14 | ||||
-rw-r--r-- | test/make_checkTest.ml | 91 | ||||
-rw-r--r-- | test/qsp_parser_test.ml | 1 | ||||
-rw-r--r-- | test/syntax.ml | 7 | ||||
-rw-r--r-- | test/syntax_error.ml | 34 | ||||
-rw-r--r-- | test/type_of.ml | 2 |
10 files changed, 252 insertions, 83 deletions
diff --git a/test/dup_cases.ml b/test/dup_cases.ml index 8b9f846..76a1157 100644 --- a/test/dup_cases.ml +++ b/test/dup_cases.ml @@ -28,8 +28,7 @@ elseif rnd: end |} [] -(** The same test in two differents block shall be considered as a duplicate. - *) +(** The same test in two differents block shall be considered as a duplicate. *) let ok_act () = _test_instruction {| @@ -61,14 +60,13 @@ end { level = Warn; loc = _position; - message = "This case is duplicated line(s) 5"; + message = "This case is duplicated line(s) 4"; }; ] let duplicate_root_test () = _test_instruction - {| -if args[0] = 1: + {|if args[0] = 1: 0 end if args[0] = 1: @@ -81,7 +79,7 @@ end { level = Warn; loc = _position; - message = "This case is duplicated line(s) 6"; + message = "This case is duplicated line(s) 4"; }; ] diff --git a/test/dynamics.ml b/test/dynamics.ml new file mode 100644 index 0000000..ad980f4 --- /dev/null +++ b/test/dynamics.ml @@ -0,0 +1,93 @@ +module Check = Make_checkTest.M (Qsp_checks.Dynamics) +module S = Qsp_syntax.S + +let position = (Lexing.dummy_pos, Lexing.dummy_pos) + +module Testable = struct + type pos = S.pos + + let pp_pos = Qsp_syntax.Report.pp_pos + let equal_pos : pos -> pos -> bool = fun _ _ -> true + + type t = Qsp_checks.Dynamics.text = { content : string; position : pos } + [@@deriving show, eq] + + let v = Alcotest.list (Alcotest.testable pp equal) +end + +let _parse : string -> Testable.t list -> unit = + fun literal expected -> + let context = Qsp_checks.Dynamics.initialize () in + (* The result of the parsing can be discarded, the usefull information is in + the context *) + let result = + Check._parse ~context Qparser.Analyzer.Dynamic (literal ^ "\n") + in + match result with + | Ok _ -> + let actual : Qsp_checks.Dynamics.text List.t = + Qsp_checks.Dynamics.dynamics_string context |> List.of_seq + in + let msg = literal in + Alcotest.(check' Testable.v ~msg ~expected ~actual) + | Error _ -> raise (Failure "Syntax error") + +let test_direct () = + _parse "dynamic '$a = 1'" + [ { Qsp_checks.Dynamics.content = "$a = 1"; position } ] + +let test_indirect () = + _parse "$test = '$a = 1' & dynamic $test" + [ { Qsp_checks.Dynamics.content = "$a = 1"; position } ] + +let test_indirect_array () = + _parse "$test[0] = '$a = 1' & dynamic $test[0]" + [ { Qsp_checks.Dynamics.content = "$a = 1"; position } ]; + + _parse "$test['a'] = '$a = 1' & dynamic $test['a']" + [ { Qsp_checks.Dynamics.content = "$a = 1"; position } ]; + + _parse "$test[0] = '$a = 1' & dynamic $test[1]" [] + +(** If a variable is identified as dynamic, check all the differents values this + variable can have *) +let test_reassignation () = + _parse + {|$test = '$a = 1' + $test = '$a = 2' + dynamic $test|} + [ + { Qsp_checks.Dynamics.content = "$a = 1"; position }; + { Qsp_checks.Dynamics.content = "$a = 2"; position }; + ] + +(** If the variable contains a dynamic assignation, blacklist it from being + checkable*) +let test_blacklist () = + _parse {|$test = '$a = 1' + $test = $b + '' + dynamic $test|} [] + +(** Ignore string template because this can be anything *) +let test_template_str () = _parse "dynamic '$a = <<$other>>'" [] + +let test_template_str2 () = + _parse {|dynamic '$a = <<"other">>'|} + [ { Qsp_checks.Dynamics.content = "$a = other"; position } ] + +let test_template_int () = + _parse "dynamic '$a = <<other>>'" + [ { Qsp_checks.Dynamics.content = "$a = 0"; position } ] + +let test = + ( "Dynamic evaluation checker", + [ + Alcotest.test_case "direct" `Quick test_direct; + Alcotest.test_case "indirect" `Quick test_indirect; + Alcotest.test_case "indirect array" `Quick test_indirect_array; + Alcotest.test_case "template" `Quick test_template_str; + Alcotest.test_case "template" `Quick test_template_str2; + Alcotest.test_case "template int" `Quick test_template_int; + Alcotest.test_case "reassignation" `Quick test_reassignation; + Alcotest.test_case "blacklist" `Quick test_blacklist; + ] ) diff --git a/test/get_type.ml b/test/get_type.ml index 55f087e..56b4689 100644 --- a/test/get_type.ml +++ b/test/get_type.ml @@ -3,79 +3,84 @@ module T = Qsp_syntax.T let _position = (Lexing.dummy_pos, Lexing.dummy_pos) -let type_of : Get_type.t Alcotest.testable = - Alcotest.testable Get_type.pp Get_type.equal +let type_of : Get_type.Expression.t Alcotest.testable = + Alcotest.testable Get_type.Expression.pp Get_type.Expression.equal + +let ctx = Qsp_syntax.S.{ f = (fun _ -> None) } let add_number () = let actual = - Get_type.boperator _position T.Plus - (Get_type.integer _position "0") - (Get_type.integer _position "1") + Get_type.Expression.boperator ~ctx _position T.Plus + (Get_type.Expression.integer ~ctx _position "0") + (Get_type.Expression.integer ~ctx _position "1") in - let expected = Get_type.(Raw Integer) in + let expected = Get_type.Expression.(Raw Integer) in let msg = "Adding integer" in Alcotest.(check' type_of ~msg ~expected ~actual) let add_literal_number () = let actual = - Get_type.boperator _position T.Plus - (Get_type.literal _position [ T.Text "2" ]) - (Get_type.integer _position "1") + Get_type.Expression.boperator ~ctx _position T.Plus + (Get_type.Expression.literal ~ctx _position [ T.Text "2" ]) + (Get_type.Expression.integer ~ctx _position "1") in - let expected = Get_type.(Raw Integer) in + let expected = Get_type.Expression.(Raw Integer) in let msg = "A string containing integer is considered as integer" in Alcotest.(check' type_of ~msg ~expected ~actual) let concat_text () = let actual = - Get_type.boperator _position T.Plus - (Get_type.literal _position [ T.Text "a" ]) - (Get_type.integer _position "1") + Get_type.Expression.boperator ~ctx _position T.Plus + (Get_type.Expression.literal ~ctx _position [ T.Text "a" ]) + (Get_type.Expression.integer ~ctx _position "1") in - let expected = Get_type.(Raw String) in + let expected = Get_type.Expression.(Raw String) in let msg = "Concatenate" in Alcotest.(check' type_of ~msg ~expected ~actual) let literal_1 () = let actual = - Get_type.literal _position [ T.Expression (Get_type.Raw Integer) ] - and expected = Get_type.(Raw NumericString) in + Get_type.Expression.literal ~ctx _position + [ T.Expression (Get_type.Expression.Raw Integer) ] + and expected = Get_type.Expression.(Raw NumericString) in let msg = "" in Alcotest.(check' type_of ~msg ~expected ~actual) let literal_2 () = let actual = - Get_type.literal _position - Get_type.[ T.Text "1"; T.Expression (Raw Integer) ] - and expected = Get_type.(Raw NumericString) in + Get_type.Expression.literal ~ctx _position + Get_type.Expression.[ T.Text "1"; T.Expression (Raw Integer) ] + and expected = Get_type.Expression.(Raw NumericString) in let msg = "" in Alcotest.(check' type_of ~msg ~expected ~actual) let literal_3 () = let actual = - Get_type.literal _position - Get_type.[ T.Text "b"; T.Expression (Raw Integer) ] - and expected = Get_type.(Raw String) in + Get_type.Expression.literal ~ctx _position + Get_type.Expression.[ T.Text "b"; T.Expression (Raw Integer) ] + and expected = Get_type.Expression.(Raw String) in let msg = "" in Alcotest.(check' type_of ~msg ~expected ~actual) let literal_4 () = let actual = - Get_type.literal _position [ T.Expression (Get_type.Variable Integer) ] - and expected = Get_type.(Variable NumericString) in + Get_type.Expression.literal ~ctx _position + Get_type.Expression.[ T.Expression (Variable Integer) ] + and expected = Get_type.Expression.(Variable NumericString) in let msg = "" in Alcotest.(check' type_of ~msg ~expected ~actual) let min () = - let actual = Get_type.function_ _position T.Min [] in - let expected = Get_type.(Raw Bool) in + let actual = Get_type.Expression.function_ ~ctx _position T.Min [] in + let expected = Get_type.Expression.(Raw Bool) in let msg = "The function min without argument return a default value" in Alcotest.(check' type_of ~msg ~expected ~actual); let actual = - Get_type.function_ _position T.Min [ Get_type.literal _position [] ] + Get_type.Expression.function_ ~ctx _position T.Min + [ Get_type.Expression.literal ~ctx _position [] ] in - let expected = Get_type.(Variable NumericString) in + let expected = Get_type.Expression.(Variable NumericString) in let msg = "The function min with a literal will take the literal as the name of an \ array" @@ -83,10 +88,11 @@ let min () = Alcotest.(check' type_of ~msg ~expected ~actual); let actual = - Get_type.function_ _position T.Min - [ Get_type.integer _position ""; Get_type.integer _position "" ] + Get_type.Expression.function_ ~ctx _position T.Min + Get_type.Expression. + [ integer ~ctx _position ""; integer ~ctx _position "" ] in - let expected = Get_type.(Raw Integer) in + let expected = Get_type.Expression.(Raw Integer) in let msg = "With two or more arguments, return the type of the first one" in Alcotest.(check' type_of ~msg ~expected ~actual) diff --git a/test/literals.ml b/test/literals.ml index f98fa8f..2685538 100644 --- a/test/literals.ml +++ b/test/literals.ml @@ -107,6 +107,20 @@ let multiple_expression () = ] )); ] +let int_expression () = + _test_instruction {|"<<expr2>>"|} + [ + Tree.Ast.Expression + (Tree.Ast.Literal + ( _position, + [ + T.Expression + (Tree.Ast.Ident + { Tree.Ast.pos = _position; name = "EXPR2"; index = None }); + T.Text ""; + ] )); + ] + let test = ( "Literals", [ @@ -127,4 +141,5 @@ let test = Alcotest.test_case "elements_sequence" `Quick elements_sequence; Alcotest.test_case "expression" `Quick expression; Alcotest.test_case "multiple_expression" `Quick multiple_expression; + Alcotest.test_case "multiple_expression" `Quick int_expression; ] ) diff --git a/test/location.ml b/test/location.ml index a1939f4..decf270 100644 --- a/test/location.ml +++ b/test/location.ml @@ -5,7 +5,7 @@ let _position = (Lexing.dummy_pos, Lexing.dummy_pos) let error_message = [ ( "Location", - Check. + Make_checkTest. { level = Error; loc = _position; @@ -18,11 +18,21 @@ let ok_upper () = Check.global_check "gt 'LOCATION'" [] let missing_gt () = Check.global_check "gt 'unknown_place'" error_message let missing_gs () = Check.global_check "gs 'unknown_place'" error_message +let act_missing_gs () = + Check.global_check {| +act "test": gs 'unknown_place'|} error_message + +let if_missing_gs () = + Check.global_check {| + if 0: gs 'unknown_place'|} error_message + let test = - ( "Locations", + ( __FILE__, [ Alcotest.test_case "Ok" `Quick ok; Alcotest.test_case "Ok upper" `Quick ok_upper; Alcotest.test_case "Missing GT" `Quick missing_gt; Alcotest.test_case "Missing GS" `Quick missing_gs; + Alcotest.test_case "Missing GS in block" `Quick act_missing_gs; + Alcotest.test_case "Missing GS in block'" `Quick if_missing_gs; ] ) diff --git a/test/make_checkTest.ml b/test/make_checkTest.ml index d3ad358..7ffd17c 100644 --- a/test/make_checkTest.ml +++ b/test/make_checkTest.ml @@ -1,69 +1,92 @@ -(** Build a parser for a specific check module *) -module M (Check : Qsp_syntax.S.Analyzer) = struct - module S = Qsp_syntax.S +module S = Qsp_syntax.S + +type pos = S.pos - let pp_pos = Qsp_syntax.Report.pp_pos +let pp_pos = Qsp_syntax.Report.pp_pos +let equal_pos : pos -> pos -> bool = fun _ _ -> true - type pos = S.pos +type t = Qsp_syntax.Report.t = { + level : Qsp_syntax.Report.level; + loc : pos; + message : string; +} +[@@deriving show, eq] - let equal_pos : pos -> pos -> bool = fun _ _ -> true +let report : t list Alcotest.testable = + Alcotest.list @@ Alcotest.testable Qsp_syntax.Report.pp equal - type t = Qsp_syntax.Report.t = { - level : Qsp_syntax.Report.level; - loc : pos; - message : string; - } - [@@deriving show, eq] +let report_global : (string * t) list Alcotest.testable = + Alcotest.list + @@ Alcotest.pair Alcotest.string + (Alcotest.testable Qsp_syntax.Report.pp equal) - let report : t list Alcotest.testable = - Alcotest.list @@ Alcotest.testable Qsp_syntax.Report.pp equal +(** Build a parser for a specific check module *) +module M + (Checkable : Qsp_syntax.Analyzer.T with type ex = Qsp_syntax.Identifier.t) = +struct + let context_id = Type.Id.make () - let report_global : (string * t) list Alcotest.testable = - Alcotest.list - @@ Alcotest.pair Alcotest.string - (Alcotest.testable Qsp_syntax.Report.pp equal) + (* Build the test module with a single test inside. *) + module Check = Qsp_checks.Check.Make (struct + let t = [| Qsp_syntax.Identifier.build ~context_id (module Checkable) |] + end) - let parse : - ?context:Check.context -> + let _parse : + ?context:Checkable.context -> + Qparser.Analyzer.lexer -> string -> (Check.Location.t Qparser.Analyzer.result, t) result = - fun ?context content -> + fun ?context lexer content -> let lexing = Sedlexing.Latin1.from_string content |> Qparser.Lexbuf.from_lexbuf in - let context = Option.value context ~default:(Check.initialize ()) in - Qparser.Analyzer.parse (module Check) lexing context + (* Initialize the context *inside* the Check module. This works by + editing the context we created. + + We have the context id (created at the begining of the module), which is + required to get the value. *) + let context = + match context with + | None -> Check.initialize () + | Some c -> ( + let init = Check.initialize () in + match Qsp_checks.Check.set context_id init.(0) c with + | None -> raise Not_found + | Some v -> + init.(0) <- v; + init) + in + Qparser.Analyzer.parse (module Check) lexer lexing context let get_report : (Check.Location.t Qparser.Analyzer.result, Qsp_syntax.Report.t) result -> Qsp_syntax.Report.t list = function | Ok v -> v.report - | Error _ -> failwith "Error" + | Error msg -> failwith msg.message let _test_instruction : string -> t list -> unit = fun literal expected -> - let _location = Printf.sprintf {|# Location -%s -------- |} literal in - let actual = get_report @@ parse _location and msg = literal in + let actual = get_report @@ _parse Qparser.Analyzer.Dynamic literal + and msg = literal in Alcotest.(check' report ~msg ~expected ~actual) - (** Run a test over the whole file. - The parsing of the content shall not report any error. - *) + (** Run a test over the whole file. The parsing of the content shall not + report any error. *) let global_check : string -> (string * t) list -> unit = fun literal expected -> let _location = Printf.sprintf {|# Location %s ------- |} literal in - let context = Check.initialize () in - let actual = get_report @@ parse ~context _location in + let context = Checkable.initialize () in + let actual = + get_report @@ _parse ~context Qparser.Analyzer.Location _location + in let () = Alcotest.( check' report ~msg:"Error reported during parsing" ~expected:[] ~actual) in let msg = literal in - let actual = Check.finalize context in + let actual = Checkable.finalize context in Alcotest.(check' report_global ~msg ~expected ~actual) end diff --git a/test/qsp_parser_test.ml b/test/qsp_parser_test.ml index 43f9cb3..4ae5a4c 100644 --- a/test/qsp_parser_test.ml +++ b/test/qsp_parser_test.ml @@ -11,4 +11,5 @@ let () = Nested_string.test; Location.test; Dup_cases.test; + Dynamics.test; ] diff --git a/test/syntax.ml b/test/syntax.ml index db449b1..ce3e89e 100644 --- a/test/syntax.ml +++ b/test/syntax.ml @@ -4,7 +4,8 @@ module Check = Qsp_checks.Check module S = Qsp_syntax.S module T = Qsp_syntax.T -let location_id, e1 = Qsp_syntax.Catalog.build (module Tree) +let location_id = Type.Id.make () +let e1 = Qsp_syntax.Identifier.build ~location_id (module Tree) module Parser = Check.Make (struct let t = [| e1 |] @@ -28,7 +29,9 @@ let parse : string -> (S.pos location, Qsp_syntax.Report.t) result = Sedlexing.Latin1.from_string content |> Qparser.Lexbuf.from_lexbuf in let context = Parser.initialize () in - Qparser.Analyzer.parse (module Parser) lexing context + Qparser.Analyzer.parse + (module Parser) + Qparser.Analyzer.Location lexing context |> Result.map (fun v -> (* Uncatched excteptions here, but we are in the tests… If it’s fail here I have an error in the code. *) diff --git a/test/syntax_error.ml b/test/syntax_error.ml index b92cf28..9d51cf3 100644 --- a/test/syntax_error.ml +++ b/test/syntax_error.ml @@ -57,14 +57,15 @@ let elseif_no_column () = } let unclosed_paren () = - _test_instruction - {|(1 - |} + let expected = { level = Error; loc = _position; message = "Unexpected '('. Did you forgot a function before ?"; } + in + _test_instruction "(1" expected; + _test_instruction "'<<(1>>'" expected let act_no_column () = _test_instruction @@ -113,8 +114,12 @@ let missing_operand () = () let unknow_function () = - _test_instruction "a = ran(1, 2)" + let expected = { level = Error; loc = _position; message = "Unexpected expression here." } + in + _test_instruction "ran(1, 2)" expected; + _test_instruction "'<<ran(1, 2)>>'" expected; + _test_instruction "rand(1,2))" expected let inline_elif () = _test_instruction {| @@ -194,9 +199,8 @@ let missing_comparable () = _test_instruction "1 <= or 0" result; _test_instruction "1 = or 0" result -(** This code looks like a new location, but is actualy invalid. - The application should report the old location. - *) +(** This code looks like a new location, but is actualy invalid. The application + should report the old location. *) let location_change () = let result = { @@ -272,6 +276,20 @@ let nested_string_mess () = |} { level = Error; loc = _position; message = "Unclosed string" } +let unexpected_bracket () = + let expected = + { level = Error; loc = _position; message = "Unbalanced paren" } + in + _test_instruction {|a[]]|} expected; + _test_instruction {|"<<a[]]>>"|} expected; + _test_instruction "'<<rand(1,2))>>'" expected + +let missing_operator () = + _test_instruction {| +'' + $func('f', '') '' +|} + { level = Error; loc = _position; message = "Missing operator before text" } + let test = ( "Syntax Errors", [ @@ -295,4 +313,6 @@ let test = Alcotest.test_case "act: else" `Quick unclosed_act; Alcotest.test_case "+ =" `Quick unknown_operator; Alcotest.test_case "'<<''>>'" `Quick nested_string_mess; + Alcotest.test_case "a[]]" `Quick unexpected_bracket; + Alcotest.test_case "Missing +" `Quick missing_operator; ] ) diff --git a/test/type_of.ml b/test/type_of.ml index e816bc7..1b84faa 100644 --- a/test/type_of.ml +++ b/test/type_of.ml @@ -78,7 +78,7 @@ let concat_text () = _test_instruction {|$a = 'A' + 1|} [] let increment_string () = _test_instruction {|$a += 1|} (message' Error) let test = - ( "Typechecking", + ( __FILE__, [ Alcotest.test_case "Assign str to int" `Quick type_mismatch; Alcotest.test_case "$str = int" `Quick assign_int_str; |