extends "res://tests/test_case.gd" # Task 6.3. The behaviour that matters is not "it parses a port" — it is the # precedence order an operator relies on, and the refusal to run on a typo. const ServerConfigScript = preload("res://scripts/server_config.gd") func _parse(args: Array) -> Variant: var argv := PackedStringArray() for a in args: argv.append(a) return ServerConfigScript.parse(argv) func _temp_config(body: String) -> String: var path := "user://test_server_%d.cfg" % Time.get_ticks_usec() var f := FileAccess.open(path, FileAccess.WRITE) f.store_string(body) f.close() return path func test_defaults_apply_when_nothing_is_given() -> void: var config = _parse([]) assert_true(config.is_valid(), "an empty command line is valid") assert_eq(config.get_value("port"), 7777, "default port") assert_eq(config.get_value("max-matches"), 0, "0 means run forever") assert_eq(config.get_value("log-level"), "info", "default log level") func test_command_line_values_are_typed_not_strings() -> void: var config = _parse(["--port=7000", "--match-length=90.5", "--fill-bots"]) assert_true(config.is_valid(), "valid: %s" % str(config.errors)) assert_eq(config.get_value("port"), 7000, "int stays an int") assert_almost_eq(config.get_value("match-length"), 90.5, 0.001, "float stays a float") assert_eq(config.get_value("fill-bots"), true, "a bare bool flag is true") func test_an_unknown_flag_is_an_error_not_a_shrug() -> void: # The whole reason this class exists: `--max-clientss=8` used to run a # server on the default cap and say nothing at all. var config = _parse(["--max-clientss=8"]) assert_true(not config.is_valid(), "a typo'd flag is rejected") assert_true("max-clientss" in " ".join(config.errors), "and the error names it: %s" % str(config.errors)) func test_a_value_that_is_not_the_declared_type_is_rejected() -> void: var config = _parse(["--port=seven"]) assert_true(not config.is_valid(), "a non-numeric port is rejected") var config_ok = _parse(["--port=7000"]) assert_true(config_ok.is_valid(), "control: a numeric port is accepted") func test_a_non_bool_flag_without_a_value_is_rejected() -> void: # Silently defaulting here would hide a shell-quoting mistake. var config = _parse(["--port"]) assert_true(not config.is_valid(), "--port with no value is an error") func test_no_prefix_turns_a_bool_off() -> void: var config = _parse(["--no-fill-bots"]) assert_true(config.is_valid(), "valid: %s" % str(config.errors)) assert_eq(config.get_value("fill-bots"), false, "--no- inverts it") # And it must not be listed separately, or --help doubles in length. var help: String = ServerConfigScript.help_text() assert_eq(help.count("--no-fill-bots"), 1, "--no- form appears once, in the default hint") func test_the_command_line_beats_the_config_file() -> void: var path := _temp_config("[server]\nport=8100\nmax-clients=4\n") var config = _parse(["--config=%s" % path, "--port=9200"]) assert_true(config.is_valid(), "valid: %s" % str(config.errors)) assert_eq(config.get_value("port"), 9200, "the command line wins") assert_eq(config.get_value("max-clients"), 4, "the file still supplies what the command line omits") DirAccess.remove_absolute(ProjectSettings.globalize_path(path)) func test_the_config_file_beats_the_default() -> void: var path := _temp_config("[server]\nport=8100\n") var config = _parse(["--config=%s" % path]) assert_true(config.is_valid(), "valid: %s" % str(config.errors)) assert_eq(config.get_value("port"), 8100, "the file overrides the default") DirAccess.remove_absolute(ProjectSettings.globalize_path(path)) func test_a_missing_or_malformed_config_file_is_an_error() -> void: var config = _parse(["--config=user://definitely_not_here_%d.cfg" % Time.get_ticks_usec()]) assert_true(not config.is_valid(), "a config file that cannot be read is an error, not silence") var path := _temp_config("[server]\nnonsense=1\n") var unknown_key = _parse(["--config=%s" % path]) assert_true(not unknown_key.is_valid(), "an unknown key in the file is rejected too") DirAccess.remove_absolute(ProjectSettings.globalize_path(path)) func test_out_of_range_values_are_rejected_with_their_own_message() -> void: assert_true(not _parse(["--port=0"]).is_valid(), "port 0 is out of range") assert_true(not _parse(["--port=70000"]).is_valid(), "port 70000 is out of range") assert_true(not _parse(["--max-clients=0"]).is_valid(), "a server for nobody is rejected") assert_true(not _parse(["--match-length=0"]).is_valid(), "a zero-length match is rejected") assert_true(not _parse(["--log-level=chatty"]).is_valid(), "an undefined log level is rejected") assert_true(not _parse(["--arena-rotation=spiral"]).is_valid(), "an undefined rotation mode is rejected") assert_true(not _parse(["--smoke-force-goal-after=-2"]).is_valid(), "only -1 disables the deterministic smoke goal") # Control: the same flags at legal values all pass together. var ok = _parse(["--port=7000", "--max-clients=6", "--match-length=90", "--log-level=warn", "--arena-rotation=random"]) assert_true(ok.is_valid(), "control: legal values pass (%s)" % str(ok.errors)) func test_a_repeated_flag_is_rejected_rather_than_last_wins() -> void: # Last-wins hides a duplicated line in a generated systemd unit. var config = _parse(["--port=7000", "--port=8000"]) assert_true(not config.is_valid(), "the same flag twice is an error") func test_help_documents_every_declared_flag() -> void: # The acceptance criterion is literally "--help documents every flag", so # assert it against the declaration rather than against a hand-kept list. var help: String = ServerConfigScript.help_text() for spec in ServerConfigScript.specs(): assert_true("--%s" % spec.key in help, "--%s appears in --help" % spec.key) assert_true(spec.help in help, "and so does its description") func test_help_is_requested_without_needing_a_valid_command_line() -> void: var config = _parse(["--help"]) assert_true(config.help_requested, "--help is recognised") var short = _parse(["-h"]) assert_true(short.help_requested, "-h too")