commit e2f5e318e279d24d6730262221354da8e0a54976
parent d056f24f7b07910ac35c7d832bff517deaf66d9f
Author: Richard Ipsum <richardipsum@vx21.xyz>
Date:   Fri, 23 Oct 2020 23:53:36 +0200
err if last scenario line is not THEN
also err if last scenario has no THEN before FINALLY
Diffstat:
| M | tyarn.lua.in | | | 79 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------ | 
1 file changed, 55 insertions(+), 24 deletions(-)
diff --git a/tyarn.lua.in b/tyarn.lua.in
@@ -94,67 +94,102 @@ function parse_implementations(filepath, implementations)
 end
 
 function validate_scenario(steps_seen, scenario_name, scenario_line_no)
-    if not steps_seen["WHEN"] then
+    local seen_when = false
+    local seen_then = false
+    local i
+
+    for n, step_type in ipairs(steps_seen) do
+        if step_type == "WHEN" then
+            seen_when = true
+        elseif step_type == "THEN" then
+            seen_then = true
+        end
+    end
+
+    if not seen_when then
         io.stderr:write(string.format('Scenario "%s" (line %d) has no WHEN step\n',
                                       scenario_name, scenario_line_no))
         os.exit(1)
     end
 
-    if not steps_seen["THEN"] then
+    if not seen_then then
         io.stderr:write(string.format('Scenario "%s" (line %d) has no THEN step\n',
                                       scenario_name, scenario_line_no))
         os.exit(1)
     end
+
+    if steps_seen[#steps_seen] == "FINALLY" then
+        i = #steps_seen - 1
+        while steps_seen[i] == "FINALLY" do
+            i = i - 1
+        end
+
+        if steps_seen[i] ~= "THEN" then
+            errmsg = 'Scenario "%s" (line %d) does not have a THEN step before FINALLY step\n'
+            io.stderr:write(string.format(errmsg, scenario_name, scenario_line_no))
+            os.exit(1)
+        end
+    elseif steps_seen[#steps_seen] ~= "THEN" then
+        io.stderr:write(string.format('Scenario "%s" (line %d) does not end with THEN or FINALLY step\n',
+                                      scenario_name, scenario_line_no))
+        os.exit(1)
+    else
+        i = #steps_seen
+    end
+
+    while steps_seen[i] == "THEN" do
+        i = i - 1
+    end
+
+    if steps_seen[i] ~= "WHEN" then
+        errmsg = 'Scenario "%s" (line %d) does not have a WHEN step before THEN step\n'
+        io.stderr:write(string.format(errmsg, scenario_name, scenario_line_no))
+        os.exit(1)
+    end
 end
 
-function parse_scenario_line(scenario, scenario_name, steps_seen,
-                             line, line_no, last_step_type)
+function parse_scenario_line(scenario, scenario_name, steps_seen, line, line_no)
     stripped_line = lstrip(line)
 
     if tyarn.re_match(line, "^(    )[ \t]*GIVEN") then
         table.insert(scenario, normalise_scenario_line(stripped_line, "GIVEN"))
-        last_step_type = "GIVEN"
-        steps_seen["GIVEN"] = true
+        table.insert(steps_seen, "GIVEN")
     elseif tyarn.re_match(line, "^(    )[ \t]*WHEN") then
         table.insert(scenario, normalise_scenario_line(stripped_line, "WHEN"))
-        last_step_type = "WHEN"
-        steps_seen["WHEN"] = true
+        table.insert(steps_seen, "WHEN")
     elseif tyarn.re_match(line, "^(    )[ \t]*THEN") then
         table.insert(scenario, normalise_scenario_line(stripped_line, "THEN"))
-        last_step_type = "THEN"
-        steps_seen["THEN"] = true
+        table.insert(steps_seen, "THEN")
     elseif tyarn.re_match(line, "^(    )[ \t]*ASSUMING") then
         table.insert(scenario, normalise_scenario_line(stripped_line, "ASSUMING"))
-        last_step_type = "ASSUMING"
-        steps_seen["ASSUMING"] = true
+        table.insert(steps_seen, "ASSUMING")
     elseif tyarn.re_match(line, "^(    )[ \t]*AND") then
-        if last_step_type == nil then
+        if #steps_seen == 0 then
             io.stderr:write(string.format(
                 'Scenario "%s" (line %d) has AND as first step: %s\n',
                 scenario_name, line_no, stripped_line))
             os.exit(1)
         end
 
-        processed_line = string.gsub(stripped_line, "AND", last_step_type)
+        processed_line = string.gsub(stripped_line, "AND", steps_seen[#steps_seen])
+        table.insert(steps_seen, steps_seen[#steps_seen])
 
-        if last_step_type == "FINALLY" then
+        if steps_seen[#steps_seen - 1] == "FINALLY" then
             table.insert(scenario["FINALLY"], processed_line)
         else
             table.insert(scenario, processed_line)
         end
     elseif tyarn.re_match(line, "^(    )[ \t]*FINALLY") then
-        last_step_type = "FINALLY"
-        steps_seen["FINALLY"] = true
+        table.insert(steps_seen, "FINALLY")
         table.insert(scenario["FINALLY"], normalise_scenario_line(stripped_line, "FINALLY"))
     elseif tyarn.re_match(line, "^(    )[ \t]*\\.\\.\\.") then
-        if last_step_type == nil then
+        if #steps_seen == 0 then
             io.stderr:write(string.format(
                 'Scenario "%s" (line %d) has ... as first step: %s\n',
                 scenario_name, line_no, stripped_line))
             os.exit(1)
         end
 
-
         -- continuation of previous scenario line
         scenario[#scenario] = scenario[#scenario] .. ' ' .. lstrip(string.gsub(stripped_line, '^...', '', 1))
     elseif tyarn.re_match(line, "^(    )[ \t]*.+") then
@@ -163,14 +198,11 @@ function parse_scenario_line(scenario, scenario_name, steps_seen,
             scenario_name, line_no, stripped_line))
         os.exit(1)
     end
-
-    return last_step_type
 end
 
 function _parse_scenarios(scenario_list, scenarios, filepath,
                           file, scenario_name, scenario_line_no)
     debug('Parsing scenario', scenario_name)
-    last_step_type = nil
     scenario = {}
     scenario["FINALLY"] = {}
     line_no = scenario_line_no
@@ -193,8 +225,7 @@ function _parse_scenarios(scenario_list, scenarios, filepath,
         end
 
         if in_scenario then
-            last_step_type = parse_scenario_line(scenario, scenario_name, steps_seen,
-                                                 line, line_no, last_step_type)
+            parse_scenario_line(scenario, scenario_name, steps_seen, line, line_no)
         end
 
         -- ignore lines that aren't indented by one level