diff --git a/Dockerfile b/Dockerfile index 42dca5e..b79e6fc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -41,8 +41,8 @@ RUN rm -rf .git build vm src misc Factor.app \ GNUmakefile Nmakefile LICENSE.txt README.md \ build.sh build.cmd unmaintained -# Keep only the extra/ source that sequences.extras needs to compile on demand: -# itself plus extra/assocs.extras and extra/shuffle. +# Keep only the extra/ source needed to compile sequences.extras and +# assocs.extras on demand: those two plus extra/shuffle. RUN find extra -mindepth 1 -maxdepth 1 \ ! -name sequences ! -name assocs ! -name shuffle \ -exec rm -rf {} + && \ diff --git a/bin/run.sh b/bin/run.sh index 6f069de..f45edc9 100755 --- a/bin/run.sh +++ b/bin/run.sh @@ -47,7 +47,11 @@ tmp_dir=$(mktemp -d -t "factor-runner-${slug}-XXXXX") trap 'rm -rf "${tmp_dir}"' EXIT cp -r "${solution_dir}/." "${tmp_dir}" stripped_tests="${tmp_dir}/${slug}/${slug}-tests.factor" -awk '!/^STOP-HERE$/' "${stripped_tests}" > "${stripped_tests}.new" +# Blank each STOP-HERE line rather than deleting it: a blank line is a no-op +# to Factor, and keeping the line count intact means the line numbers Factor +# reports for failures still match the file the student submitted. +awk '{ if ($0 ~ /^STOP-HERE$/) print ""; else print }' \ + "${stripped_tests}" > "${stripped_tests}.new" mv "${stripped_tests}.new" "${stripped_tests}" # Run Factor; capture combined stdout/stderr. @@ -131,7 +135,7 @@ src_tests=$(awk "${awk_json}"' # 2. Parse Factor stdout into NDJSON segments and failures: # segments: {"type":"segment","idx":N,"failed":bool,"name":"...","output":"..."} -# failures: {"type":"failure","line_no":N,"message":"..."} +# failures: {"type":"failure","line_no":N,"location":"...","message":"..."} parsed=$(printf '%s\n' "${raw_output}" | awk "${awk_json}"' function close_segment( out, i) { if (idx == 0) return @@ -147,8 +151,8 @@ parsed=$(printf '%s\n' "${raw_output}" | awk "${awk_json}"' for (i = 1; i <= fail_n; i++) body = body (i > 1 ? "\n" : "") fail[i] sub(/^\n+/, "", body) sub(/\n+$/, "", body) - printf "{\"type\":\"failure\",\"line_no\":%d,\"message\":%s}\n", - fail_line, json_str(body) + printf "{\"type\":\"failure\",\"line_no\":%d,\"location\":%s,\"message\":%s}\n", + fail_line, json_str(fail_loc), json_str(body) } # Factor renders each test-word name into a title, e.g.: # unit-test → "Unit Test:" @@ -221,8 +225,14 @@ parsed=$(printf '%s\n' "${raw_output}" | awk "${awk_json}"' n = substr($0, RSTART, RLENGTH) gsub(/[^0-9]/, "", n) fail_line = n + 0 + # exercism-tools prints ": "; collapse it to the + # conventional ":" so the student can paste it + # into an editor. The path is already relative to the solution + # root, so it is safe to show as-is. + fail_loc = substr($0, 1, RSTART - 1) ":" fail_line } else { fail_line = 0 + fail_loc = "" } fail_n = 0 delete fail @@ -276,7 +286,7 @@ jq -n \ --argjson segs "$(printf '%s\n' "${segments}" | jq -s '.')" \ --argjson fails "$(printf '%s\n' "${failures}" | jq -s '.')" \ ' - ($fails | map({(.line_no|tostring): .message}) | add // {}) as $fail_by_line + ($fails | map({(.line_no|tostring): .}) | add // {}) as $fail_by_line | $segs | sort_by(.idx) | to_entries | map( @@ -284,7 +294,8 @@ jq -n \ | (.key) as $i | ($srcs[$i] // null) as $src | ($src.line_no | tostring) as $ln - | ($fail_by_line[$ln] // null) as $msg + | ($fail_by_line[$ln] // null) as $fail + | ($fail.message // null) as $msg | ( if $seg.failed then if ($msg // "" | startswith("=== Expected:")) then "fail" @@ -300,7 +311,11 @@ jq -n \ test_code: ($src.test_code // ""), } + (if $src.task_id then {task_id: $src.task_id} else {} end) - + (if $seg.failed then {message: ($msg // "test failed")} else {} end) + + (if $seg.failed then + {message: (if $msg == null then "test failed" + elif ($fail.location // "") == "" then $msg + else $fail.location + "\n" + $msg end)} + else {} end) + (if $seg.output != "" then {output: ($seg.output[0:500])} else {} end) ) | (if all(.status == "pass") then "pass" else "fail" end) as $top diff --git a/tests/all-fail/exercism-tools/exercism-tools.factor b/tests/all-fail/exercism-tools/exercism-tools.factor index 428c2d3..df5f692 100644 --- a/tests/all-fail/exercism-tools/exercism-tools.factor +++ b/tests/all-fail/exercism-tools/exercism-tools.factor @@ -1,6 +1,7 @@ USING: accessors command-line continuations debugger io kernel - lexer namespaces sequences source-files.errors.debugger - system tools.test vocabs vocabs.loader ; + lexer namespaces prettyprint.config sequences + source-files.errors.debugger system tools.test vocabs + vocabs.loader ; IN: exercism-tools SYNTAX: STOP-HERE @@ -9,19 +10,15 @@ SYNTAX: STOP-HERE SYNTAX: TASK: lexer get next-line ; -! Label the test that follows with its description. The marker lets the -! wrapper strip this line from captured output and attach it to the next -! test as a name, rather than leaving it in the previous test's output. +! Label the test that follows with its description. : description ( str -- ) "###DESC### " write print ; -! Print one failure block in a stable, parser-friendly form. Bracketed by -! markers so a wrapper can split the stream reliably and avoid Factor's -! noisy callstack output (which is interleaved with subsequent failures). +! Print one failure block in a stable, parser-friendly form. :: print-failure ( failure -- ) "###FAIL_BEGIN###" print failure error-location print - failure error>> [ error. ] [ 2drop ] recover + [ failure error>> [ error. ] [ 2drop ] recover ] without-limits "###FAIL_END###" print flush ; @@ -29,6 +26,7 @@ SYNTAX: TASK: test-failures get [ print-failure ] each ; : run-exercism-tests ( -- ) + vocab-roots [ "." prefix ] change-global command-line get first [ require ] [ test ] bi test-failures get empty? diff --git a/tests/all-fail/expected_results.json b/tests/all-fail/expected_results.json index 07f910b..e6f9bb2 100644 --- a/tests/all-fail/expected_results.json +++ b/tests/all-fail/expected_results.json @@ -6,13 +6,13 @@ "name": "greet returns hello", "status": "fail", "test_code": "{ \"hello\" } [ greet ] unit-test", - "message": "=== Expected:\n\"hello\"\n=== Got:\n\"wrong\"" + "message": "all-fail/all-fail-tests.factor:5\n=== Expected:\n\"hello\"\n=== Got:\n\"wrong\"" }, { "name": "greet returns world", "status": "fail", "test_code": "{ \"world\" } [ greet ] unit-test", - "message": "=== Expected:\n\"world\"\n=== Got:\n\"wrong\"" + "message": "all-fail/all-fail-tests.factor:10\n=== Expected:\n\"world\"\n=== Got:\n\"wrong\"" } ] } diff --git a/tests/concept-concurrency/exercism-tools/exercism-tools.factor b/tests/concept-concurrency/exercism-tools/exercism-tools.factor index 428c2d3..df5f692 100644 --- a/tests/concept-concurrency/exercism-tools/exercism-tools.factor +++ b/tests/concept-concurrency/exercism-tools/exercism-tools.factor @@ -1,6 +1,7 @@ USING: accessors command-line continuations debugger io kernel - lexer namespaces sequences source-files.errors.debugger - system tools.test vocabs vocabs.loader ; + lexer namespaces prettyprint.config sequences + source-files.errors.debugger system tools.test vocabs + vocabs.loader ; IN: exercism-tools SYNTAX: STOP-HERE @@ -9,19 +10,15 @@ SYNTAX: STOP-HERE SYNTAX: TASK: lexer get next-line ; -! Label the test that follows with its description. The marker lets the -! wrapper strip this line from captured output and attach it to the next -! test as a name, rather than leaving it in the previous test's output. +! Label the test that follows with its description. : description ( str -- ) "###DESC### " write print ; -! Print one failure block in a stable, parser-friendly form. Bracketed by -! markers so a wrapper can split the stream reliably and avoid Factor's -! noisy callstack output (which is interleaved with subsequent failures). +! Print one failure block in a stable, parser-friendly form. :: print-failure ( failure -- ) "###FAIL_BEGIN###" print failure error-location print - failure error>> [ error. ] [ 2drop ] recover + [ failure error>> [ error. ] [ 2drop ] recover ] without-limits "###FAIL_END###" print flush ; @@ -29,6 +26,7 @@ SYNTAX: TASK: test-failures get [ print-failure ] each ; : run-exercism-tests ( -- ) + vocab-roots [ "." prefix ] change-global command-line get first [ require ] [ test ] bi test-failures get empty? diff --git a/tests/concept-multiline/exercism-tools/exercism-tools.factor b/tests/concept-multiline/exercism-tools/exercism-tools.factor index 428c2d3..df5f692 100644 --- a/tests/concept-multiline/exercism-tools/exercism-tools.factor +++ b/tests/concept-multiline/exercism-tools/exercism-tools.factor @@ -1,6 +1,7 @@ USING: accessors command-line continuations debugger io kernel - lexer namespaces sequences source-files.errors.debugger - system tools.test vocabs vocabs.loader ; + lexer namespaces prettyprint.config sequences + source-files.errors.debugger system tools.test vocabs + vocabs.loader ; IN: exercism-tools SYNTAX: STOP-HERE @@ -9,19 +10,15 @@ SYNTAX: STOP-HERE SYNTAX: TASK: lexer get next-line ; -! Label the test that follows with its description. The marker lets the -! wrapper strip this line from captured output and attach it to the next -! test as a name, rather than leaving it in the previous test's output. +! Label the test that follows with its description. : description ( str -- ) "###DESC### " write print ; -! Print one failure block in a stable, parser-friendly form. Bracketed by -! markers so a wrapper can split the stream reliably and avoid Factor's -! noisy callstack output (which is interleaved with subsequent failures). +! Print one failure block in a stable, parser-friendly form. :: print-failure ( failure -- ) "###FAIL_BEGIN###" print failure error-location print - failure error>> [ error. ] [ 2drop ] recover + [ failure error>> [ error. ] [ 2drop ] recover ] without-limits "###FAIL_END###" print flush ; @@ -29,6 +26,7 @@ SYNTAX: TASK: test-failures get [ print-failure ] each ; : run-exercism-tests ( -- ) + vocab-roots [ "." prefix ] change-global command-line get first [ require ] [ test ] bi test-failures get empty? diff --git a/tests/concept-multiline/expected_results.json b/tests/concept-multiline/expected_results.json index e4d3e49..f6a6e84 100644 --- a/tests/concept-multiline/expected_results.json +++ b/tests/concept-multiline/expected_results.json @@ -73,7 +73,7 @@ "status": "fail", "test_code": "{ 6 } [ 4 [ 6 roll-die ] play-seeded ] unit-test", "task_id": 5, - "message": "=== Expected:\n6\n=== Got:\n2" + "message": "concept-multiline/concept-multiline-tests.factor:62\n=== Expected:\n6\n=== Got:\n2" }, { "name": "Test 13", diff --git a/tests/concept-not-parsing/exercism-tools/exercism-tools.factor b/tests/concept-not-parsing/exercism-tools/exercism-tools.factor index 428c2d3..df5f692 100644 --- a/tests/concept-not-parsing/exercism-tools/exercism-tools.factor +++ b/tests/concept-not-parsing/exercism-tools/exercism-tools.factor @@ -1,6 +1,7 @@ USING: accessors command-line continuations debugger io kernel - lexer namespaces sequences source-files.errors.debugger - system tools.test vocabs vocabs.loader ; + lexer namespaces prettyprint.config sequences + source-files.errors.debugger system tools.test vocabs + vocabs.loader ; IN: exercism-tools SYNTAX: STOP-HERE @@ -9,19 +10,15 @@ SYNTAX: STOP-HERE SYNTAX: TASK: lexer get next-line ; -! Label the test that follows with its description. The marker lets the -! wrapper strip this line from captured output and attach it to the next -! test as a name, rather than leaving it in the previous test's output. +! Label the test that follows with its description. : description ( str -- ) "###DESC### " write print ; -! Print one failure block in a stable, parser-friendly form. Bracketed by -! markers so a wrapper can split the stream reliably and avoid Factor's -! noisy callstack output (which is interleaved with subsequent failures). +! Print one failure block in a stable, parser-friendly form. :: print-failure ( failure -- ) "###FAIL_BEGIN###" print failure error-location print - failure error>> [ error. ] [ 2drop ] recover + [ failure error>> [ error. ] [ 2drop ] recover ] without-limits "###FAIL_END###" print flush ; @@ -29,6 +26,7 @@ SYNTAX: TASK: test-failures get [ print-failure ] each ; : run-exercism-tests ( -- ) + vocab-roots [ "." prefix ] change-global command-line get first [ require ] [ test ] bi test-failures get empty? diff --git a/tests/concept-not-parsing/expected_results.json b/tests/concept-not-parsing/expected_results.json index 375be78..b18f740 100644 --- a/tests/concept-not-parsing/expected_results.json +++ b/tests/concept-not-parsing/expected_results.json @@ -1,5 +1,5 @@ { "version": 3, "status": "error", - "message": "/opt/test-runner/tests/concept-not-parsing/concept-not-parsing/concept-not-parsing.factor\n\n6: : cube ( n -- n^3 ) ?!?! ;\n ^\nNo word named '?!?!' found in current vocabulary search path" + "message": "concept-not-parsing/concept-not-parsing.factor\n\n6: : cube ( n -- n^3 ) ?!?! ;\n ^\nNo word named '?!?!' found in current vocabulary search path" } diff --git a/tests/concept-partial-fail/exercism-tools/exercism-tools.factor b/tests/concept-partial-fail/exercism-tools/exercism-tools.factor index 428c2d3..df5f692 100644 --- a/tests/concept-partial-fail/exercism-tools/exercism-tools.factor +++ b/tests/concept-partial-fail/exercism-tools/exercism-tools.factor @@ -1,6 +1,7 @@ USING: accessors command-line continuations debugger io kernel - lexer namespaces sequences source-files.errors.debugger - system tools.test vocabs vocabs.loader ; + lexer namespaces prettyprint.config sequences + source-files.errors.debugger system tools.test vocabs + vocabs.loader ; IN: exercism-tools SYNTAX: STOP-HERE @@ -9,19 +10,15 @@ SYNTAX: STOP-HERE SYNTAX: TASK: lexer get next-line ; -! Label the test that follows with its description. The marker lets the -! wrapper strip this line from captured output and attach it to the next -! test as a name, rather than leaving it in the previous test's output. +! Label the test that follows with its description. : description ( str -- ) "###DESC### " write print ; -! Print one failure block in a stable, parser-friendly form. Bracketed by -! markers so a wrapper can split the stream reliably and avoid Factor's -! noisy callstack output (which is interleaved with subsequent failures). +! Print one failure block in a stable, parser-friendly form. :: print-failure ( failure -- ) "###FAIL_BEGIN###" print failure error-location print - failure error>> [ error. ] [ 2drop ] recover + [ failure error>> [ error. ] [ 2drop ] recover ] without-limits "###FAIL_END###" print flush ; @@ -29,6 +26,7 @@ SYNTAX: TASK: test-failures get [ print-failure ] each ; : run-exercism-tests ( -- ) + vocab-roots [ "." prefix ] change-global command-line get first [ require ] [ test ] bi test-failures get empty? diff --git a/tests/concept-partial-fail/expected_results.json b/tests/concept-partial-fail/expected_results.json index 6a1c31c..ccea9fa 100644 --- a/tests/concept-partial-fail/expected_results.json +++ b/tests/concept-partial-fail/expected_results.json @@ -21,7 +21,7 @@ "status": "fail", "test_code": "{ 27 } [ \"cubing 3\" print 3 cube ] unit-test", "task_id": 2, - "message": "=== Expected:\n27\n=== Got:\n12", + "message": "concept-partial-fail/concept-partial-fail-tests.factor:12\n=== Expected:\n27\n=== Got:\n12", "output": "cubing 3" }, { @@ -29,42 +29,42 @@ "status": "fail", "test_code": "{ 64 } [ 4 cube ] unit-test", "task_id": 2, - "message": "=== Expected:\n64\n=== Got:\n20" + "message": "concept-partial-fail/concept-partial-fail-tests.factor:13\n=== Expected:\n64\n=== Got:\n20" }, { "name": "Test 5", "status": "error", "test_code": "{ { } } [ { } but-first ] unit-test", "task_id": 3, - "message": "Cannot create slice: from > to\nfrom 1\nto 0\nseq { }" + "message": "concept-partial-fail/concept-partial-fail-tests.factor:16\nCannot create slice: from > to\nfrom 1\nto 0\nseq { }" }, { "name": "Test 6", "status": "error", "test_code": "{ 0 } [ 4 0 / ] unit-test", "task_id": 4, - "message": "Division by zero\nx 4" + "message": "concept-partial-fail/concept-partial-fail-tests.factor:19\nDivision by zero\nx 4" }, { "name": "Test 7", "status": "error", "test_code": "{ 0 } [ 10 { 1 2 3 } nth ] unit-test", "task_id": 5, - "message": "Sequence index out of bounds\nindex 10\nseq { 1 2 3 }" + "message": "concept-partial-fail/concept-partial-fail-tests.factor:22\nSequence index out of bounds\nindex 10\nseq { 1 2 3 }" }, { "name": "Test 8", "status": "error", "test_code": "{ \"text\" } [ 5 label ] unit-test", "task_id": 6, - "message": "Generic word label does not define a method for the fixnum class.\nDispatching on object: 5" + "message": "concept-partial-fail/concept-partial-fail-tests.factor:25\nGeneric word label does not define a method for the fixnum class.\nDispatching on object: 5" }, { "name": "Test 9", "status": "error", "test_code": "{ 0 } [ 5 [ drop ] call( x -- x ) ] unit-test", "task_id": 7, - "message": "Quotation's stack effect does not match call site\nquot [ drop ]\ncall-site ( x -- x )" + "message": "concept-partial-fail/concept-partial-fail-tests.factor:28\nQuotation's stack effect does not match call site\nquot [ drop ]\ncall-site ( x -- x )" } ] } diff --git a/tests/concept-stub/exercism-tools/exercism-tools.factor b/tests/concept-stub/exercism-tools/exercism-tools.factor index 428c2d3..df5f692 100644 --- a/tests/concept-stub/exercism-tools/exercism-tools.factor +++ b/tests/concept-stub/exercism-tools/exercism-tools.factor @@ -1,6 +1,7 @@ USING: accessors command-line continuations debugger io kernel - lexer namespaces sequences source-files.errors.debugger - system tools.test vocabs vocabs.loader ; + lexer namespaces prettyprint.config sequences + source-files.errors.debugger system tools.test vocabs + vocabs.loader ; IN: exercism-tools SYNTAX: STOP-HERE @@ -9,19 +10,15 @@ SYNTAX: STOP-HERE SYNTAX: TASK: lexer get next-line ; -! Label the test that follows with its description. The marker lets the -! wrapper strip this line from captured output and attach it to the next -! test as a name, rather than leaving it in the previous test's output. +! Label the test that follows with its description. : description ( str -- ) "###DESC### " write print ; -! Print one failure block in a stable, parser-friendly form. Bracketed by -! markers so a wrapper can split the stream reliably and avoid Factor's -! noisy callstack output (which is interleaved with subsequent failures). +! Print one failure block in a stable, parser-friendly form. :: print-failure ( failure -- ) "###FAIL_BEGIN###" print failure error-location print - failure error>> [ error. ] [ 2drop ] recover + [ failure error>> [ error. ] [ 2drop ] recover ] without-limits "###FAIL_END###" print flush ; @@ -29,6 +26,7 @@ SYNTAX: TASK: test-failures get [ print-failure ] each ; : run-exercism-tests ( -- ) + vocab-roots [ "." prefix ] change-global command-line get first [ require ] [ test ] bi test-failures get empty? diff --git a/tests/concept-stub/expected_results.json b/tests/concept-stub/expected_results.json index 7f17360..1cdee9b 100644 --- a/tests/concept-stub/expected_results.json +++ b/tests/concept-stub/expected_results.json @@ -7,28 +7,28 @@ "status": "error", "test_code": "{ 9 } [ 3 square ] unit-test", "task_id": 1, - "message": "unimplemented" + "message": "concept-stub/concept-stub-tests.factor:5\nunimplemented" }, { "name": "Test 2", "status": "error", "test_code": "{ 16 } [ 4 square ] unit-test", "task_id": 1, - "message": "unimplemented" + "message": "concept-stub/concept-stub-tests.factor:9\nunimplemented" }, { "name": "Test 3", "status": "error", "test_code": "{ 27 } [ 3 cube ] unit-test", "task_id": 2, - "message": "unimplemented" + "message": "concept-stub/concept-stub-tests.factor:12\nunimplemented" }, { "name": "Test 4", "status": "error", "test_code": "{ 64 } [ 4 cube ] unit-test", "task_id": 2, - "message": "unimplemented" + "message": "concept-stub/concept-stub-tests.factor:13\nunimplemented" } ] } diff --git a/tests/concept-success/exercism-tools/exercism-tools.factor b/tests/concept-success/exercism-tools/exercism-tools.factor index 428c2d3..df5f692 100644 --- a/tests/concept-success/exercism-tools/exercism-tools.factor +++ b/tests/concept-success/exercism-tools/exercism-tools.factor @@ -1,6 +1,7 @@ USING: accessors command-line continuations debugger io kernel - lexer namespaces sequences source-files.errors.debugger - system tools.test vocabs vocabs.loader ; + lexer namespaces prettyprint.config sequences + source-files.errors.debugger system tools.test vocabs + vocabs.loader ; IN: exercism-tools SYNTAX: STOP-HERE @@ -9,19 +10,15 @@ SYNTAX: STOP-HERE SYNTAX: TASK: lexer get next-line ; -! Label the test that follows with its description. The marker lets the -! wrapper strip this line from captured output and attach it to the next -! test as a name, rather than leaving it in the previous test's output. +! Label the test that follows with its description. : description ( str -- ) "###DESC### " write print ; -! Print one failure block in a stable, parser-friendly form. Bracketed by -! markers so a wrapper can split the stream reliably and avoid Factor's -! noisy callstack output (which is interleaved with subsequent failures). +! Print one failure block in a stable, parser-friendly form. :: print-failure ( failure -- ) "###FAIL_BEGIN###" print failure error-location print - failure error>> [ error. ] [ 2drop ] recover + [ failure error>> [ error. ] [ 2drop ] recover ] without-limits "###FAIL_END###" print flush ; @@ -29,6 +26,7 @@ SYNTAX: TASK: test-failures get [ print-failure ] each ; : run-exercism-tests ( -- ) + vocab-roots [ "." prefix ] change-global command-line get first [ require ] [ test ] bi test-failures get empty? diff --git a/tests/empty-file/exercism-tools/exercism-tools.factor b/tests/empty-file/exercism-tools/exercism-tools.factor index 428c2d3..df5f692 100644 --- a/tests/empty-file/exercism-tools/exercism-tools.factor +++ b/tests/empty-file/exercism-tools/exercism-tools.factor @@ -1,6 +1,7 @@ USING: accessors command-line continuations debugger io kernel - lexer namespaces sequences source-files.errors.debugger - system tools.test vocabs vocabs.loader ; + lexer namespaces prettyprint.config sequences + source-files.errors.debugger system tools.test vocabs + vocabs.loader ; IN: exercism-tools SYNTAX: STOP-HERE @@ -9,19 +10,15 @@ SYNTAX: STOP-HERE SYNTAX: TASK: lexer get next-line ; -! Label the test that follows with its description. The marker lets the -! wrapper strip this line from captured output and attach it to the next -! test as a name, rather than leaving it in the previous test's output. +! Label the test that follows with its description. : description ( str -- ) "###DESC### " write print ; -! Print one failure block in a stable, parser-friendly form. Bracketed by -! markers so a wrapper can split the stream reliably and avoid Factor's -! noisy callstack output (which is interleaved with subsequent failures). +! Print one failure block in a stable, parser-friendly form. :: print-failure ( failure -- ) "###FAIL_BEGIN###" print failure error-location print - failure error>> [ error. ] [ 2drop ] recover + [ failure error>> [ error. ] [ 2drop ] recover ] without-limits "###FAIL_END###" print flush ; @@ -29,6 +26,7 @@ SYNTAX: TASK: test-failures get [ print-failure ] each ; : run-exercism-tests ( -- ) + vocab-roots [ "." prefix ] change-global command-line get first [ require ] [ test ] bi test-failures get empty? diff --git a/tests/empty-file/expected_results.json b/tests/empty-file/expected_results.json index 5b7846b..6586f1b 100644 --- a/tests/empty-file/expected_results.json +++ b/tests/empty-file/expected_results.json @@ -1,5 +1,5 @@ { "version": 3, "status": "error", - "message": "/opt/test-runner/tests/empty-file/empty-file/empty-file-tests.factor\n\n5: { \"hello\" } [ greet ] unit-test\n ^\nNo word named 'greet' found in current vocabulary search path" + "message": "empty-file/empty-file-tests.factor\n\n5: { \"hello\" } [ greet ] unit-test\n ^\nNo word named 'greet' found in current vocabulary search path" } diff --git a/tests/partial-fail/exercism-tools/exercism-tools.factor b/tests/partial-fail/exercism-tools/exercism-tools.factor index 428c2d3..df5f692 100644 --- a/tests/partial-fail/exercism-tools/exercism-tools.factor +++ b/tests/partial-fail/exercism-tools/exercism-tools.factor @@ -1,6 +1,7 @@ USING: accessors command-line continuations debugger io kernel - lexer namespaces sequences source-files.errors.debugger - system tools.test vocabs vocabs.loader ; + lexer namespaces prettyprint.config sequences + source-files.errors.debugger system tools.test vocabs + vocabs.loader ; IN: exercism-tools SYNTAX: STOP-HERE @@ -9,19 +10,15 @@ SYNTAX: STOP-HERE SYNTAX: TASK: lexer get next-line ; -! Label the test that follows with its description. The marker lets the -! wrapper strip this line from captured output and attach it to the next -! test as a name, rather than leaving it in the previous test's output. +! Label the test that follows with its description. : description ( str -- ) "###DESC### " write print ; -! Print one failure block in a stable, parser-friendly form. Bracketed by -! markers so a wrapper can split the stream reliably and avoid Factor's -! noisy callstack output (which is interleaved with subsequent failures). +! Print one failure block in a stable, parser-friendly form. :: print-failure ( failure -- ) "###FAIL_BEGIN###" print failure error-location print - failure error>> [ error. ] [ 2drop ] recover + [ failure error>> [ error. ] [ 2drop ] recover ] without-limits "###FAIL_END###" print flush ; @@ -29,6 +26,7 @@ SYNTAX: TASK: test-failures get [ print-failure ] each ; : run-exercism-tests ( -- ) + vocab-roots [ "." prefix ] change-global command-line get first [ require ] [ test ] bi test-failures get empty? diff --git a/tests/partial-fail/expected_results.json b/tests/partial-fail/expected_results.json index 9f73a6a..4cdac9f 100644 --- a/tests/partial-fail/expected_results.json +++ b/tests/partial-fail/expected_results.json @@ -12,8 +12,14 @@ "name": "greet returns world", "status": "fail", "test_code": "{ \"world\" } [ 2 . greet ] unit-test", - "message": "=== Expected:\n\"world\"\n=== Got:\n\"hello\"", + "message": "partial-fail/partial-fail-tests.factor:10\n=== Expected:\n\"world\"\n=== Got:\n\"hello\"", "output": "2" + }, + { + "name": "registering the same name twice throws", + "status": "error", + "test_code": "{ H{ { \"ada\" \"hello\" } } }\n[ H{ } clone \"hello\" \"ada\" register \"world\" \"ada\" register ] unit-test", + "message": "partial-fail/partial-fail-tests.factor:14\nkey-exists\nvalue \"ada\"\nkey H{ { \"ada\" \"hello\" } }\nassoc \"hello\"" } ] } diff --git a/tests/partial-fail/partial-fail/partial-fail-tests.factor b/tests/partial-fail/partial-fail/partial-fail-tests.factor index 5f7c85b..633fbb3 100644 --- a/tests/partial-fail/partial-fail/partial-fail-tests.factor +++ b/tests/partial-fail/partial-fail/partial-fail-tests.factor @@ -1,4 +1,4 @@ -USING: exercism-tools io partial-fail prettyprint tools.test ; +USING: exercism-tools io kernel partial-fail prettyprint tools.test ; IN: partial-fail.tests "greet returns hello" description @@ -8,3 +8,7 @@ STOP-HERE "greet returns world" description { "world" } [ 2 . greet ] unit-test + +"registering the same name twice throws" description +{ H{ { "ada" "hello" } } } +[ H{ } clone "hello" "ada" register "world" "ada" register ] unit-test diff --git a/tests/partial-fail/partial-fail/partial-fail.factor b/tests/partial-fail/partial-fail/partial-fail.factor index 427d1d1..3a33c63 100644 --- a/tests/partial-fail/partial-fail/partial-fail.factor +++ b/tests/partial-fail/partial-fail/partial-fail.factor @@ -1,4 +1,8 @@ -USING: kernel ; +USING: assocs.extras kernel ; IN: partial-fail : greet ( -- str ) "hello" ; + +! set-once-at throws key-exists when the key is already present +! (assocs.extras), so registering the same name twice fails at runtime. +: register ( assoc greeting name -- assoc ) pick set-once-at ; diff --git a/tests/practice-stub/exercism-tools/exercism-tools.factor b/tests/practice-stub/exercism-tools/exercism-tools.factor index 428c2d3..df5f692 100644 --- a/tests/practice-stub/exercism-tools/exercism-tools.factor +++ b/tests/practice-stub/exercism-tools/exercism-tools.factor @@ -1,6 +1,7 @@ USING: accessors command-line continuations debugger io kernel - lexer namespaces sequences source-files.errors.debugger - system tools.test vocabs vocabs.loader ; + lexer namespaces prettyprint.config sequences + source-files.errors.debugger system tools.test vocabs + vocabs.loader ; IN: exercism-tools SYNTAX: STOP-HERE @@ -9,19 +10,15 @@ SYNTAX: STOP-HERE SYNTAX: TASK: lexer get next-line ; -! Label the test that follows with its description. The marker lets the -! wrapper strip this line from captured output and attach it to the next -! test as a name, rather than leaving it in the previous test's output. +! Label the test that follows with its description. : description ( str -- ) "###DESC### " write print ; -! Print one failure block in a stable, parser-friendly form. Bracketed by -! markers so a wrapper can split the stream reliably and avoid Factor's -! noisy callstack output (which is interleaved with subsequent failures). +! Print one failure block in a stable, parser-friendly form. :: print-failure ( failure -- ) "###FAIL_BEGIN###" print failure error-location print - failure error>> [ error. ] [ 2drop ] recover + [ failure error>> [ error. ] [ 2drop ] recover ] without-limits "###FAIL_END###" print flush ; @@ -29,6 +26,7 @@ SYNTAX: TASK: test-failures get [ print-failure ] each ; : run-exercism-tests ( -- ) + vocab-roots [ "." prefix ] change-global command-line get first [ require ] [ test ] bi test-failures get empty? diff --git a/tests/practice-stub/expected_results.json b/tests/practice-stub/expected_results.json index 56de0c1..e9a10e6 100644 --- a/tests/practice-stub/expected_results.json +++ b/tests/practice-stub/expected_results.json @@ -6,13 +6,13 @@ "name": "greet returns hello", "status": "error", "test_code": "{ \"hello\" } [ greet ] unit-test", - "message": "unimplemented" + "message": "practice-stub/practice-stub-tests.factor:5\nunimplemented" }, { "name": "greet returns world", "status": "error", "test_code": "{ \"world\" } [ greet ] unit-test", - "message": "unimplemented" + "message": "practice-stub/practice-stub-tests.factor:10\nunimplemented" } ] } diff --git a/tests/success/exercism-tools/exercism-tools.factor b/tests/success/exercism-tools/exercism-tools.factor index 428c2d3..df5f692 100644 --- a/tests/success/exercism-tools/exercism-tools.factor +++ b/tests/success/exercism-tools/exercism-tools.factor @@ -1,6 +1,7 @@ USING: accessors command-line continuations debugger io kernel - lexer namespaces sequences source-files.errors.debugger - system tools.test vocabs vocabs.loader ; + lexer namespaces prettyprint.config sequences + source-files.errors.debugger system tools.test vocabs + vocabs.loader ; IN: exercism-tools SYNTAX: STOP-HERE @@ -9,19 +10,15 @@ SYNTAX: STOP-HERE SYNTAX: TASK: lexer get next-line ; -! Label the test that follows with its description. The marker lets the -! wrapper strip this line from captured output and attach it to the next -! test as a name, rather than leaving it in the previous test's output. +! Label the test that follows with its description. : description ( str -- ) "###DESC### " write print ; -! Print one failure block in a stable, parser-friendly form. Bracketed by -! markers so a wrapper can split the stream reliably and avoid Factor's -! noisy callstack output (which is interleaved with subsequent failures). +! Print one failure block in a stable, parser-friendly form. :: print-failure ( failure -- ) "###FAIL_BEGIN###" print failure error-location print - failure error>> [ error. ] [ 2drop ] recover + [ failure error>> [ error. ] [ 2drop ] recover ] without-limits "###FAIL_END###" print flush ; @@ -29,6 +26,7 @@ SYNTAX: TASK: test-failures get [ print-failure ] each ; : run-exercism-tests ( -- ) + vocab-roots [ "." prefix ] change-global command-line get first [ require ] [ test ] bi test-failures get empty? diff --git a/tests/syntax-error/exercism-tools/exercism-tools.factor b/tests/syntax-error/exercism-tools/exercism-tools.factor index 428c2d3..df5f692 100644 --- a/tests/syntax-error/exercism-tools/exercism-tools.factor +++ b/tests/syntax-error/exercism-tools/exercism-tools.factor @@ -1,6 +1,7 @@ USING: accessors command-line continuations debugger io kernel - lexer namespaces sequences source-files.errors.debugger - system tools.test vocabs vocabs.loader ; + lexer namespaces prettyprint.config sequences + source-files.errors.debugger system tools.test vocabs + vocabs.loader ; IN: exercism-tools SYNTAX: STOP-HERE @@ -9,19 +10,15 @@ SYNTAX: STOP-HERE SYNTAX: TASK: lexer get next-line ; -! Label the test that follows with its description. The marker lets the -! wrapper strip this line from captured output and attach it to the next -! test as a name, rather than leaving it in the previous test's output. +! Label the test that follows with its description. : description ( str -- ) "###DESC### " write print ; -! Print one failure block in a stable, parser-friendly form. Bracketed by -! markers so a wrapper can split the stream reliably and avoid Factor's -! noisy callstack output (which is interleaved with subsequent failures). +! Print one failure block in a stable, parser-friendly form. :: print-failure ( failure -- ) "###FAIL_BEGIN###" print failure error-location print - failure error>> [ error. ] [ 2drop ] recover + [ failure error>> [ error. ] [ 2drop ] recover ] without-limits "###FAIL_END###" print flush ; @@ -29,6 +26,7 @@ SYNTAX: TASK: test-failures get [ print-failure ] each ; : run-exercism-tests ( -- ) + vocab-roots [ "." prefix ] change-global command-line get first [ require ] [ test ] bi test-failures get empty? diff --git a/tests/syntax-error/expected_results.json b/tests/syntax-error/expected_results.json index 040ef79..7f0623f 100644 --- a/tests/syntax-error/expected_results.json +++ b/tests/syntax-error/expected_results.json @@ -1,5 +1,5 @@ { "version": 3, "status": "error", - "message": "/opt/test-runner/tests/syntax-error/syntax-error/syntax-error.factor\n\n4: : greet ( -- str ) @#$% ;\n ^\nNo word named '@#$%' found in current vocabulary search path" + "message": "syntax-error/syntax-error.factor\n\n4: : greet ( -- str ) @#$% ;\n ^\nNo word named '@#$%' found in current vocabulary search path" } diff --git a/tests/wishlist-vocabs/exercism-tools/exercism-tools.factor b/tests/wishlist-vocabs/exercism-tools/exercism-tools.factor index 428c2d3..df5f692 100644 --- a/tests/wishlist-vocabs/exercism-tools/exercism-tools.factor +++ b/tests/wishlist-vocabs/exercism-tools/exercism-tools.factor @@ -1,6 +1,7 @@ USING: accessors command-line continuations debugger io kernel - lexer namespaces sequences source-files.errors.debugger - system tools.test vocabs vocabs.loader ; + lexer namespaces prettyprint.config sequences + source-files.errors.debugger system tools.test vocabs + vocabs.loader ; IN: exercism-tools SYNTAX: STOP-HERE @@ -9,19 +10,15 @@ SYNTAX: STOP-HERE SYNTAX: TASK: lexer get next-line ; -! Label the test that follows with its description. The marker lets the -! wrapper strip this line from captured output and attach it to the next -! test as a name, rather than leaving it in the previous test's output. +! Label the test that follows with its description. : description ( str -- ) "###DESC### " write print ; -! Print one failure block in a stable, parser-friendly form. Bracketed by -! markers so a wrapper can split the stream reliably and avoid Factor's -! noisy callstack output (which is interleaved with subsequent failures). +! Print one failure block in a stable, parser-friendly form. :: print-failure ( failure -- ) "###FAIL_BEGIN###" print failure error-location print - failure error>> [ error. ] [ 2drop ] recover + [ failure error>> [ error. ] [ 2drop ] recover ] without-limits "###FAIL_END###" print flush ; @@ -29,6 +26,7 @@ SYNTAX: TASK: test-failures get [ print-failure ] each ; : run-exercism-tests ( -- ) + vocab-roots [ "." prefix ] change-global command-line get first [ require ] [ test ] bi test-failures get empty? diff --git a/tests/wishlist-vocabs/expected_results.json b/tests/wishlist-vocabs/expected_results.json index 625540c..b579b5f 100644 --- a/tests/wishlist-vocabs/expected_results.json +++ b/tests/wishlist-vocabs/expected_results.json @@ -36,6 +36,11 @@ "name": "pair-rocket builds an assoc", "status": "pass", "test_code": "{ H{ { \"ada\" 1 } { \"bob\" 2 } } } [ scores ] unit-test" + }, + { + "name": "assoc-invert swaps keys and values", + "status": "pass", + "test_code": "{ H{ { 1 \"ada\" } { 2 \"bob\" } } } [ H{ { \"ada\" 1 } { \"bob\" 2 } } invert-assoc ] unit-test" } ] } diff --git a/tests/wishlist-vocabs/wishlist-vocabs/wishlist-vocabs-tests.factor b/tests/wishlist-vocabs/wishlist-vocabs/wishlist-vocabs-tests.factor index fa4fb54..69ad50a 100644 --- a/tests/wishlist-vocabs/wishlist-vocabs/wishlist-vocabs-tests.factor +++ b/tests/wishlist-vocabs/wishlist-vocabs/wishlist-vocabs-tests.factor @@ -21,3 +21,6 @@ IN: wishlist-vocabs.tests "pair-rocket builds an assoc" description { H{ { "ada" 1 } { "bob" 2 } } } [ scores ] unit-test + +"assoc-invert swaps keys and values" description +{ H{ { 1 "ada" } { 2 "bob" } } } [ H{ { "ada" 1 } { "bob" 2 } } invert-assoc ] unit-test diff --git a/tests/wishlist-vocabs/wishlist-vocabs/wishlist-vocabs.factor b/tests/wishlist-vocabs/wishlist-vocabs/wishlist-vocabs.factor index 0abd2f8..3eff6ca 100644 --- a/tests/wishlist-vocabs/wishlist-vocabs/wishlist-vocabs.factor +++ b/tests/wishlist-vocabs/wishlist-vocabs/wishlist-vocabs.factor @@ -1,6 +1,6 @@ -USING: arrays circular hashtables infix interpolate kernel math - namespaces pair-rocket qw sequences sequences.extras - sequences.repeating ; +USING: arrays assocs.extras circular hashtables infix interpolate + kernel math namespaces pair-rocket qw sequences + sequences.extras sequences.repeating ; IN: wishlist-vocabs ! qw{ ... } reads a whitespace-separated literal sequence of strings (qw). @@ -25,3 +25,6 @@ INFIX:: add ( x y -- z ) x + y ; ! => pairs each key with the next value, building assoc literals (pair-rocket). : scores ( -- assoc ) { "ada" => 1 "bob" => 2 } >hashtable ; + +! assoc-invert swaps every key with its value (assocs.extras). +: invert-assoc ( assoc -- newassoc ) assoc-invert ;