|
75 | 75 | # 1. Extract source-test records (one JSON object per line, NDJSON): |
76 | 76 | # {"line_no":N,"task_id":N|null,"test_code":"..."} |
77 | 77 | # Reads the post-strip file so line numbers match what Factor reports. |
| 78 | +# A test runs from its first code line through the line that ends in a |
| 79 | +# test word (e.g. `unit-test`); accumulate the whole span so `test_code` |
| 80 | +# holds the full multi-line source, not just the closing `] unit-test`. |
| 81 | +# `line_no` stays the closing line, matching what Factor reports for |
| 82 | +# failures. Blank, comment, and TASK lines reset the buffer so they are |
| 83 | +# never folded into the next test. |
78 | 84 | src_tests=$(awk "${awk_json}"' |
79 | | - BEGIN { task = "null" } |
| 85 | + function reset() { |
| 86 | + n = 0 |
| 87 | + delete buf |
| 88 | + } |
| 89 | + function flush( i, code) { |
| 90 | + code = "" |
| 91 | + for (i = 1; i <= n; i++) code = code (i > 1 ? "\n" : "") buf[i] |
| 92 | + printf "{\"line_no\":%d,\"task_id\":%s,\"test_code\":%s}\n", NR, task, json_str(code) |
| 93 | + reset() |
| 94 | + } |
| 95 | + BEGIN { |
| 96 | + task = "null" |
| 97 | + n = 0 |
| 98 | + } |
80 | 99 | /^[[:space:]]*TASK:[[:space:]]+[0-9]+/ { |
81 | 100 | match($0, /TASK:[[:space:]]+[0-9]+/) |
82 | 101 | s = substr($0, RSTART, RLENGTH) |
83 | 102 | sub(/^TASK:[[:space:]]+/, "", s) |
84 | 103 | task = s |
| 104 | + reset() |
85 | 105 | next |
86 | 106 | } |
87 | | - /(unit-test|unit-test~|unit-test-v~|long-unit-test|must-fail-with|must-fail|must-not-fail|must-infer|must-infer-as)[[:space:]]*$/ { |
| 107 | + /^[[:space:]]*$/ { |
| 108 | + reset() |
| 109 | + next |
| 110 | + } |
| 111 | + /^[[:space:]]*!/ { |
| 112 | + reset() |
| 113 | + next |
| 114 | + } |
| 115 | + # A `"label" description` line names the test that follows; it is its own |
| 116 | + # statement, not part of the test form, so treat it as a boundary. |
| 117 | + /^[[:space:]]*"[^"]*"[[:space:]]+description[[:space:]]*$/ { |
| 118 | + reset() |
| 119 | + next |
| 120 | + } |
| 121 | + { |
88 | 122 | line = $0 |
89 | | - sub(/^[[:space:]]+/, "", line) |
90 | 123 | sub(/[[:space:]]+$/, "", line) |
91 | | - printf "{\"line_no\":%d,\"task_id\":%s,\"test_code\":%s}\n", NR, task, json_str(line) |
| 124 | + n++ |
| 125 | + buf[n] = line |
| 126 | + } |
| 127 | + /(unit-test|unit-test~|unit-test-v~|long-unit-test|must-fail-with|must-fail|must-not-fail|must-infer|must-infer-as)[[:space:]]*$/ { |
| 128 | + flush() |
92 | 129 | } |
93 | 130 | ' "${tmp_dir}/${slug}/${slug}-tests.factor") |
94 | 131 |
|
@@ -139,6 +176,17 @@ parsed=$(printf '%s\n' "${raw_output}" | awk "${awk_json}"' |
139 | 176 | delete seg |
140 | 177 | cur_name = pending_name |
141 | 178 | pending_name = "" |
| 179 | + # Factor pretty-prints a long test form across lines: the header |
| 180 | + # line is just "Unit Test: {" and the form body follows, indented, |
| 181 | + # up to a closing "}" at column 0. Those continuation lines are an |
| 182 | + # echo of the test, not program output, so skip them. |
| 183 | + rest = $0 |
| 184 | + sub(header_re, "", rest) |
| 185 | + if (rest == "{") state = "header_cont" |
| 186 | + next |
| 187 | + } |
| 188 | + state == "header_cont" { |
| 189 | + if ($0 ~ /^}[[:space:]]*$/) state = "inline" |
142 | 190 | next |
143 | 191 | } |
144 | 192 | # A generated "###DESC### <description>" line labels the test that |
|
0 commit comments