Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ RUN wget https://github.com/godotengine/godot/releases/download/4.4.1-stable/God
mv Godot_v4.4.1-stable_linux.x86_64 /usr/bin/godot && \
rm Godot_v4.4.1-stable_linux.x86_64.zip

WORKDIR /opt/test-runner
WORKDIR /opt/exercism/gdscript/test-runner
COPY . .
ENTRYPOINT ["/opt/test-runner/bin/run.sh"]
ENTRYPOINT ["/opt/exercism/gdscript/test-runner/bin/run.sh"]
8 changes: 4 additions & 4 deletions bin/run-tests-in-docker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ docker run \
--rm \
--network none \
--read-only \
--mount type=bind,src="${PWD}/tests",dst=/opt/test-runner/tests \
--mount type=bind,src="${PWD}/tests",dst=/opt/exercism/gdscript/test-runner/tests \
--mount type=tmpfs,dst=/tmp \
--volume "${PWD}/bin/run-tests.sh:/opt/test-runner/bin/run-tests.sh" \
--workdir /opt/test-runner \
--entrypoint /opt/test-runner/bin/run-tests.sh \
--volume "${PWD}/bin/run-tests.sh:/opt/exercism/gdscript/test-runner/bin/run-tests.sh" \
--workdir /opt/exercism/gdscript/test-runner \
--entrypoint /opt/exercism/gdscript/test-runner/bin/run-tests.sh \
exercism/test-runner
10 changes: 9 additions & 1 deletion bin/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,15 @@ mkdir -p "$XDG_CONFIG_HOME" "$XDG_DATA_HOME" "$XDG_CACHE_HOME"

echo "${slug}: testing..."

# Switch to where the script lives in case called from elsewhere
OLD_DIR=$(pwd)
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
cd "$SCRIPT_DIR" || exit 1

# Run the tests for the provided implementation file
godot --headless -s bin/test_runner.gd 2>/tmp/stderr -- "${slug}" "${solution_dir}" "${output_dir}"
godot --headless -s ./test_runner.gd 2>/tmp/stderr -- "${slug}" "${solution_dir}" "${output_dir}"

# Switch back to calling dir
cd "$OLD_DIR" || exit 1

echo "${slug}: done"
31 changes: 9 additions & 22 deletions bin/test-local-gdscript-solution.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,38 +12,25 @@ missing_gd_msg="Normally, the exercise subdirectory created by the exercism down
general_help_msg="Please see https://exercism.org/docs/tracks/gdscript/installation for details."
if [ ! -f "${slug//-/_}_test.gd" ]; then
echo "Missing test file: ${slug//-/_}_test.gd"
echo $missing_gd_msg
echo $general_help_msg
echo "$missing_gd_msg"
echo "$general_help_msg"
exit 1
fi
if [ ! -f "${slug//-/_}.gd" ]; then
echo "Missing solution file: ${slug//-/_}.gd"
echo $missing_gd_msg
echo $general_help_msg
echo "$missing_gd_msg"
echo "$general_help_msg"
exit 1
fi
if [ ! -f "/opt/exercism/gdscript/test-runner/bin/run.sh" ]; then
echo "Missing test runner file: /opt/exercism/gdscript/test-runner/bin/run.sh"
echo $general_help_msg
if [ ! -f "/opt/exercism/gdscript/test-runner/bin/test_runner.gd" ]; then
echo "Missing test runner file: /opt/exercism/gdscript/test-runner/bin/test_runner.gd"
echo "$general_help_msg"
exit 1
fi

solution_dir="$(pwd)"
output_dir="${solution_dir}/.test-output"
results_file="${output_dir}/results.json"
mkdir -p "${output_dir}"

(cd /opt/exercism/gdscript/test-runner && bin/run.sh "$slug" "$solution_dir" "$output_dir") || {
(cd /opt/exercism/gdscript/test-runner && godot --headless -s bin/test_runner.gd -- "$slug" "$solution_dir") || {
echo "Test runner script failed."
exit 1
}

test_status="$(jq -r '.status' "${results_file}")"
if [ "$test_status" != "pass" ]; then
echo "Tests for $slug have failed:"
cat "${results_file}"
exit 1
else
echo
echo "Tests for $slug passed!"
fi
}
17 changes: 11 additions & 6 deletions bin/test_runner.gd
Original file line number Diff line number Diff line change
Expand Up @@ -63,21 +63,26 @@ func parse_args() -> Error:
global variables, based on the given args:
* `solution_script_path`
* `test_suite_script_path`
* `output_dir_path`
* `output_dir_path` (optional for local test runner, required for standard JSON test runner behaviour)
"""
var args = OS.get_cmdline_user_args()

if len(args) != 3:
# This script still conforms to [1] but allows 2 arguments for a local test
# runner with non-JSON output to eliminate dependence on 'jq'
#
# [1] https://github.com/exercism/docs/blob/main/building/tooling/test-runners/interface.md#execution
if len(args) not in [2,3]:
push_error(
"The scrips needs exactly 3 arguments, was called with %s: %s" % [
"The script needs exactly 2 or exactly 3 arguments, was called with %s: %s" % [
len(args), str(args)
]
)
return ERR_INVALID_PARAMETER

var slug = args[0]
var solution_dir_path = args[1]
output_dir_path = args[2]
if len(args) == 3:
output_dir_path = args[2]

# Test folders use dashes, but test files use underscores
var gdscript_path = solution_dir_path.path_join(slug.replace("-", "_"))
Expand Down Expand Up @@ -127,7 +132,7 @@ func load_solution_script() -> Error:
"message": "The solution file could not be parsed.",
"tests": [],
}
file_utils.write_results_file(results, output_dir_path)
file_utils.output_results(results, output_dir_path)
return ERR_PARSE_ERROR

return OK
Expand Down Expand Up @@ -170,4 +175,4 @@ func run_tests() -> void:
results["status"] = "fail"
break

file_utils.write_results_file(results, output_dir_path)
file_utils.output_results(results, output_dir_path)
31 changes: 31 additions & 0 deletions bin/utils/file_utils.gd
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,37 @@ func load_script(script_path: String) -> Object:
return script


func output_results(results: Dictionary, output_dir_path: String) -> Error:
"""
If output_dir_path is empty, outputs friendly-formatted test results to
stdout.

Otherwise, writes JSON results to results.json in the given path.
"""
if output_dir_path == "":
return print_friendly_results(results)
else:
return write_results_file(results, output_dir_path)


func print_friendly_results(results: Dictionary) -> Error:
"""
Prints rich results to stdout.
"""
var rich_results = [""]
if results.status == "pass":
rich_results.push_back("[color=yellow]Exercise passed! Nicely done![/color]")
else:
rich_results.push_back("Exercise has at least one failed test:")
for test in results.tests:
if test.status == "pass":
rich_results.push_back(" %s [color=yellow]passed ✔[/color]" % test.name)
else:
rich_results.push_back(" %s [color=pink]failed: %s[/color]" % [test.name, test.message])
print_rich("\n".join(rich_results))
return OK


func write_results_file(results: Dictionary, output_dir_path: String) -> Error:
"""
Saves a dictionary as a `results.json` file in the output directory. The file
Expand Down
4 changes: 2 additions & 2 deletions tests/example-empty-file/expected_results.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
{
"name": "test_add_1_and_2",
"status": "error",
"message": "SCRIPT ERROR: Invalid call. Nonexistent function 'add_2_numbers' in base 'RefCounted (example_empty_file.gd)'.\n at: test_add_1_and_2 (res://tests/example-empty-file/example_empty_file_test.gd:2)\n"
"message": "SCRIPT ERROR: Invalid call. Nonexistent function 'add_2_numbers' in base 'RefCounted (example_empty_file.gd)'.\n at: test_add_1_and_2 (/opt/exercism/gdscript/test-runner/tests/example-empty-file/example_empty_file_test.gd:2)\n"
},
{
"name": "test_add_10_and_20",
"status": "error",
"message": "SCRIPT ERROR: Invalid call. Nonexistent function 'add_2_numbers' in base 'RefCounted (example_empty_file.gd)'.\n at: test_add_10_and_20 (res://tests/example-empty-file/example_empty_file_test.gd:6)\n"
"message": "SCRIPT ERROR: Invalid call. Nonexistent function 'add_2_numbers' in base 'RefCounted (example_empty_file.gd)'.\n at: test_add_10_and_20 (/opt/exercism/gdscript/test-runner/tests/example-empty-file/example_empty_file_test.gd:6)\n"
}
]
}
2 changes: 1 addition & 1 deletion tests/example-execution-error/expected_results.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
{
"name": "test_0",
"status": "error",
"message": "SCRIPT ERROR: Division by zero error in operator '/'.\n at: divide (res://tests/example-execution-error/example_execution_error.gd:2)\n"
"message": "SCRIPT ERROR: Division by zero error in operator '/'.\n at: divide (/opt/exercism/gdscript/test-runner/tests/example-execution-error/example_execution_error.gd:2)\n"
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
{
"name": "test_too_few_args",
"status": "error",
"message": "SCRIPT ERROR: Invalid call to function 'add_numbers' in base 'RefCounted (example_incorrect_number_of_arguments.gd)'. Expected 2 arguments.\n at: test_too_few_args (res://tests/example-incorrect-number-of-arguments/example_incorrect_number_of_arguments_test.gd:2)\n"
"message": "SCRIPT ERROR: Invalid call to function 'add_numbers' in base 'RefCounted (example_incorrect_number_of_arguments.gd)'. Expected 2 arguments.\n at: test_too_few_args (/opt/exercism/gdscript/test-runner/tests/example-incorrect-number-of-arguments/example_incorrect_number_of_arguments_test.gd:2)\n"
},
{
"name": "test_too_many_args",
"status": "error",
"message": "SCRIPT ERROR: Invalid call to function 'add_numbers' in base 'RefCounted (example_incorrect_number_of_arguments.gd)'. Expected 2 arguments.\n at: test_too_many_args (res://tests/example-incorrect-number-of-arguments/example_incorrect_number_of_arguments_test.gd:6)\n"
"message": "SCRIPT ERROR: Invalid call to function 'add_numbers' in base 'RefCounted (example_incorrect_number_of_arguments.gd)'. Expected 2 arguments.\n at: test_too_many_args (/opt/exercism/gdscript/test-runner/tests/example-incorrect-number-of-arguments/example_incorrect_number_of_arguments_test.gd:6)\n"
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
{
"name": "test_integer",
"status": "error",
"message": "SCRIPT ERROR: Invalid call. Nonexistent function 'ends_with' in base 'int'.\n at: check_something (res://tests/example-invalid-argument-type/example_invalid_argument_type.gd:3)\n"
"message": "SCRIPT ERROR: Invalid call. Nonexistent function 'ends_with' in base 'int'.\n at: check_something (/opt/exercism/gdscript/test-runner/tests/example-invalid-argument-type/example_invalid_argument_type.gd:3)\n"
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
{
"name": "test_hello",
"status": "error",
"message": "SCRIPT ERROR: Invalid call. Nonexistent function 'return_hello' in base 'RefCounted (example_multiple_methods_partial_fail.gd)'.\n at: test_hello (res://tests/example-multiple-methods-partial-fail/example_multiple_methods_partial_fail_test.gd:10)\n"
"message": "SCRIPT ERROR: Invalid call. Nonexistent function 'return_hello' in base 'RefCounted (example_multiple_methods_partial_fail.gd)'.\n at: test_hello (/opt/exercism/gdscript/test-runner/tests/example-multiple-methods-partial-fail/example_multiple_methods_partial_fail_test.gd:10)\n"
}
]
}
2 changes: 1 addition & 1 deletion tests/example-not-a-callable/expected_results.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
{
"name": "test_call_a_method",
"status": "error",
"message": "SCRIPT ERROR: Invalid call. Nonexistent function 'add_2_numbers' in base 'RefCounted (example_not_a_callable.gd)'.\n at: test_call_a_method (res://tests/example-not-a-callable/example_not_a_callable_test.gd:2)\n"
"message": "SCRIPT ERROR: Invalid call. Nonexistent function 'add_2_numbers' in base 'RefCounted (example_not_a_callable.gd)'.\n at: test_call_a_method (/opt/exercism/gdscript/test-runner/tests/example-not-a-callable/example_not_a_callable_test.gd:2)\n"
}
]
}
4 changes: 2 additions & 2 deletions tests/example-type-hints/expected_results.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
{
"name": "test_return_string_incorrect",
"status": "error",
"message": "SCRIPT ERROR: Trying to return value of type \"int\" from a function whose return type is \"String\".\n at: return_string (res://tests/example-type-hints/example_type_hints.gd:2)\n"
"message": "SCRIPT ERROR: Trying to return value of type \"int\" from a function whose return type is \"String\".\n at: return_string (/opt/exercism/gdscript/test-runner/tests/example-type-hints/example_type_hints.gd:2)\n"
},
{
"name": "test_accept_int_correct",
Expand All @@ -20,7 +20,7 @@
{
"name": "test_accept_int_incorrect",
"status": "error",
"message": "SCRIPT ERROR: Invalid type in function 'accept_int' in base 'RefCounted (example_type_hints.gd)'. Cannot convert argument 1 from String to int.\n at: test_accept_int_incorrect (res://tests/example-type-hints/example_type_hints_test.gd:14)\n"
"message": "SCRIPT ERROR: Invalid type in function 'accept_int' in base 'RefCounted (example_type_hints.gd)'. Cannot convert argument 1 from String to int.\n at: test_accept_int_incorrect (/opt/exercism/gdscript/test-runner/tests/example-type-hints/example_type_hints_test.gd:14)\n"
}
]
}
4 changes: 2 additions & 2 deletions tests/example-wrong-method-name/expected_results.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
{
"name": "test_1_and_2_equals_3",
"status": "error",
"message": "SCRIPT ERROR: Invalid call. Nonexistent function 'add_2_numbers' in base 'RefCounted (example_wrong_method_name.gd)'.\n at: test_1_and_2_equals_3 (res://tests/example-wrong-method-name/example_wrong_method_name_test.gd:2)\n"
"message": "SCRIPT ERROR: Invalid call. Nonexistent function 'add_2_numbers' in base 'RefCounted (example_wrong_method_name.gd)'.\n at: test_1_and_2_equals_3 (/opt/exercism/gdscript/test-runner/tests/example-wrong-method-name/example_wrong_method_name_test.gd:2)\n"
},
{
"name": "test_10_and_20_and_40_equals_70",
"status": "error",
"message": "SCRIPT ERROR: Invalid call. Nonexistent function 'add_3_numbers' in base 'RefCounted (example_wrong_method_name.gd)'.\n at: test_10_and_20_and_40_equals_70 (res://tests/example-wrong-method-name/example_wrong_method_name_test.gd:6)\n"
"message": "SCRIPT ERROR: Invalid call. Nonexistent function 'add_3_numbers' in base 'RefCounted (example_wrong_method_name.gd)'.\n at: test_10_and_20_and_40_equals_70 (/opt/exercism/gdscript/test-runner/tests/example-wrong-method-name/example_wrong_method_name_test.gd:6)\n"
}
]
}