dead_end.ml 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. module Dead_end = Qsp_syntax.Dead_end
  2. module S = Qsp_syntax.S
  3. let _position = (Lexing.dummy_pos, Lexing.dummy_pos)
  4. let pp_pos = Qsp_syntax.Report.pp_pos
  5. type pos = S.pos
  6. let equal_pos : pos -> pos -> bool = fun _ _ -> true
  7. type t = Qsp_syntax.Report.t = {
  8. level : Qsp_syntax.Report.level;
  9. loc : pos;
  10. message : string;
  11. }
  12. [@@deriving show, eq]
  13. let report : Qsp_syntax.Report.t list Alcotest.testable =
  14. Alcotest.list @@ Alcotest.testable Qsp_syntax.Report.pp equal
  15. let parse :
  16. string ->
  17. (Dead_end.Location.t * Qsp_syntax.Report.t list, Qsp_syntax.Report.t) result
  18. =
  19. fun content ->
  20. let lexing =
  21. Sedlexing.Latin1.from_string content |> Qparser.Lexbuf.from_lexbuf
  22. in
  23. Qparser.Analyzer.parse (module Dead_end) lexing
  24. let get_report :
  25. (Dead_end.Location.t * Qsp_syntax.Report.t list, Qsp_syntax.Report.t) result ->
  26. Qsp_syntax.Report.t list = function
  27. | Ok (_, report) -> report
  28. | Error _ -> failwith "Error"
  29. let _test_instruction : string -> Qsp_syntax.Report.t list -> unit =
  30. fun literal expected ->
  31. let _location = Printf.sprintf {|# Location
  32. %s
  33. ------- |} literal in
  34. let actual = get_report @@ parse _location and msg = literal in
  35. Alcotest.(check' report ~msg ~expected ~actual)
  36. (** This one is OK because act provide a solution in any case *)
  37. let ok () =
  38. _test_instruction {|
  39. if 0:
  40. act '': gt ''
  41. if 1:
  42. act '': gt ''
  43. end
  44. end
  45. |}
  46. []
  47. (** Ignore top level dead end*)
  48. let toplevel () =
  49. _test_instruction {|
  50. act 1:
  51. act '': gt ''
  52. end
  53. if 1: act '': gt ''
  54. |} []
  55. let else_branch () =
  56. _test_instruction
  57. {|
  58. if 0:
  59. if 1:
  60. act '': gt ''
  61. else
  62. act '': ''
  63. end
  64. end
  65. |}
  66. [
  67. {
  68. level = Warn;
  69. loc = _position;
  70. message = "Possible dead end (unmatched path)";
  71. };
  72. ]
  73. let elseif_branch () =
  74. _test_instruction
  75. {|
  76. if 0:
  77. if 1:
  78. act '': ''
  79. elseif 0:
  80. act '': gt ''
  81. end
  82. end
  83. |}
  84. [
  85. {
  86. level = Debug;
  87. loc = _position;
  88. message = "Possible dead end (no else fallback)";
  89. };
  90. ]
  91. let missing_else () =
  92. _test_instruction {|
  93. if 0:
  94. if 1: act '': gt ''
  95. end
  96. |}
  97. [
  98. {
  99. level = Debug;
  100. loc = _position;
  101. message = "Possible dead end (no else fallback)";
  102. };
  103. ]
  104. let nothing () = _test_instruction {|
  105. if 0:
  106. if 1: 0
  107. end
  108. |} []
  109. let test =
  110. ( "Dead end",
  111. [
  112. Alcotest.test_case "No dead_end" `Quick ok;
  113. Alcotest.test_case "top level" `Quick toplevel;
  114. Alcotest.test_case "Else branch" `Quick else_branch;
  115. Alcotest.test_case "ElseIf branch" `Quick elseif_branch;
  116. Alcotest.test_case "Missing else" `Quick missing_else;
  117. Alcotest.test_case "nothing" `Quick nothing;
  118. ] )