# ------------------------------------------------------------------------------ # Test the Gut object. # ------------------------------------------------------------------------------ extends GutTest class TestProperties: extends GutInternalTester var _gut = null func before_each(): # Can't use new_gut here because of default value checks _gut = autofree(Gut.new(GutUtils.GutLogger.new())) _gut.error_tracker = GutErrorTracker.new() _gut._should_print_versions = false var _backed_properties = ParameterFactory.named_parameters( ['property_name', 'default', 'new_value'], [ ['color_output', false, true], ['disable_strict_datatype_checks', false, true], ['disable_strict_datatype_checks', false, true], ['double_strategy', GutUtils.DOUBLE_STRATEGY.SCRIPT_ONLY, GutUtils.DOUBLE_STRATEGY.INCLUDE_NATIVE], ['export_path', '', 'res://somewhere/cool'], ['ignore_pause_before_teardown', false, true], ['include_subdirectories', false, true], ['inner_class_name', '', 'TestSomeInnerClass'], ['junit_xml_file', '', 'user://somewhere.json'], ['junit_xml_timestamp', false, true], ['log_level', 1, 3], ['parameter_handler', null, GutUtils.ParameterHandler.new([])], ['post_run_script', '', 'res://something_else.gd'], ['pre_run_script', '', 'res://something.gd'], ['unit_test_name', '', 'test_something_cool'], ]) func test_check_backed_properties(p=use_parameters(_backed_properties)): assert_property_with_backing_variable(_gut, p.property_name, p.default, p.new_value) var _basic_properties = ParameterFactory.named_parameters( ['property_name', 'default', 'new_value'], [ ['paint_after', .1, 1.5] ]) func test_basic_properties(p = use_parameters(_basic_properties)): assert_property(_gut, p.property_name, p.default, p.new_value) # This must be its own test since _gut will not be anything at # the time _backed_properties is assigned func test_property_add_children_to_backed(): assert_property_with_backing_variable(_gut, 'add_children_to', _gut, self) func test_logger_backed_property(): assert_property_with_backing_variable(_gut, 'logger', _gut._lgr, GutUtils.GutLogger.new(), '_lgr') func test_setting_logger_sets_gut_for_logger(): var new_logger = GutUtils.GutLogger.new() _gut.logger = new_logger assert_eq(new_logger.get_gut(), _gut) func test_get_current_script_object_returns_null_by_default(): assert_eq(_gut.get_current_script_object(), null) # I don't know how to test this in other situations func test_set_double_strategy_does_not_accept_invalid_values(): var default = _gut.double_strategy _gut.double_strategy = -1 assert_eq(_gut.double_strategy, default, 'did not accept -1') _gut.double_strategy = 22 assert_eq(_gut.double_strategy, default, 'did not accept 22') class TestSimulate: extends GutInternalTester var _test_gut = null func before_each(): _test_gut = autofree(new_gut(verbose)) class WithoutProcess: extends Node class WithProcess: extends Node var call_count = 0 var delta_sum = 0.0 func _process(delta): call_count += 1 delta_sum += delta class WithoutPhysicsProcess: extends Node class WithPhysicsProcess: extends Node var call_count = 0 var delta_sum = 0.0 func _physics_process(delta): call_count += 1 delta_sum += delta func test_simulate_calls_process_if_object_has_method(): var with_method = autofree(WithProcess.new()) _test_gut.simulate(with_method, 5, 0.2) assert_eq(with_method.call_count, 5, '_process should have been called 5 times') assert_eq(with_method.delta_sum, 1.0, 'The delta value should have been passed in and summed') func test_simulate_does_not_error_when_object_does_not_have_process(): var without_method = autofree(WithoutProcess.new()) _test_gut.simulate(without_method, 5, 0.2) pass_test('We got here') func test_simulate_calls_process_on_child_objects_of_child_objects(): var objs = [] for i in range(5): objs.append(autofree(WithProcess.new())) if(i > 0): objs[i - 1].add_child(objs[i]) _test_gut.simulate(objs[0], 5, 0.2) for i in range(objs.size()): assert_eq(objs[i].call_count, 5, '_process should have been called on object # ' + str(i)) assert_eq(objs[i].delta_sum, 1, 'The delta value should have been summed on object # ' + str(i)) func test_simulate_checks_process_on_all_nodes(): var objs = [ autofree(WithProcess.new()), autofree(WithoutProcess.new()), autofree(WithProcess.new()), autofree(WithoutProcess.new()), ] for i in range(1, 4): objs[i - 1].add_child(objs[i]) _test_gut.simulate(objs[0], 5, 0.2) assert_eq(objs[0].call_count, 5, '_process should have been called 5 times') assert_eq(objs[0].delta_sum, 1.0, 'The delta value should have been passed in and summed') assert_eq(objs[2].call_count, 5, '_process should have been called 5 times') assert_eq(objs[2].delta_sum, 1.0, 'The delta value should have been passed in and summed') func test_simulate_calls_process_if_object_is_processing_and_check_is_true(): var with_processing = autofree(WithProcess.new()) with_processing.set_process(true) _test_gut.simulate(with_processing, 5, 0.2, true) # check_is_processing=false assert_eq(with_processing.call_count, 5, '_process should have been called 5 times') assert_eq(with_processing.delta_sum, 1.0, 'The delta value should have been passed in and summed') func test_simulate_does_not_call_process_if_object_is_not_processing_and_check_is_true(): var without_processing = autofree(WithProcess.new()) without_processing.set_process(false) _test_gut.simulate(without_processing, 5, 0.2, true) # check_is_processing=true assert_eq(without_processing.call_count, 0, '_process should not have been called') func test_simulate_does_not_error_if_object_is_processing_but_has_no_method(): var with_processing_but_without_method = autofree(WithoutProcess.new()) with_processing_but_without_method.set_process(true) _test_gut.simulate(with_processing_but_without_method, 5, 0.2, true) # check_is_processing=true pass_test('We got here') func test_simulate_calls_process_on_descendents_if_objects_are_processing(): var objs = [ autofree(WithProcess.new()), autofree(WithoutProcess.new()), autofree(WithProcess.new()), autofree(WithoutProcess.new()), ] for i in range(1, 4): objs[i - 1].add_child(objs[i]) objs[0].set_process(false) objs[1].set_process(false) objs[2].set_process(true) objs[3].set_process(true) _test_gut.simulate(objs[0], 5, 0.2, true) # check_is_processing=true assert_eq(objs[0].call_count, 0, '_process should not have been called') assert_eq(objs[2].call_count, 5, '_process should have been called 5 times') assert_eq(objs[2].delta_sum, 1.0, 'The delta value should have been passed in and summed') func test_simulate_calls_physics_process_if_object_has_method(): var with_method = autofree(WithPhysicsProcess.new()) _test_gut.simulate(with_method, 5, 0.2) assert_eq(with_method.call_count, 5, '_physics_process should have been called 5 times') assert_eq(with_method.delta_sum, 1.0, 'The delta value should have been passed in and summed') func test_simulate_does_not_error_when_object_does_not_have_physics_process(): var without_method = autofree(WithoutPhysicsProcess.new()) _test_gut.simulate(without_method, 5, 0.2) pass_test('We got here') func test_simulate_calls_physics_process_on_child_objects_of_child_objects(): var objs = [] for i in range(5): objs.append(autofree(WithPhysicsProcess.new())) if(i > 0): objs[i - 1].add_child(objs[i]) _test_gut.simulate(objs[0], 5, 0.2) for i in range(objs.size()): assert_eq(objs[i].call_count, 5, '_physics_process should have been called on object # ' + str(i)) assert_eq(objs[i].delta_sum, 1, 'The delta value should have been summed on object # ' + str(i)) func test_simulate_calls_physics_process_on_descendents_if_objects_have_method(): var objs = [ autofree(WithPhysicsProcess.new()), autofree(WithoutPhysicsProcess.new()), autofree(WithPhysicsProcess.new()), autofree(WithoutPhysicsProcess.new()), ] for i in range(1, 4): objs[i - 1].add_child(objs[i]) _test_gut.simulate(objs[0], 5, 0.2) assert_eq(objs[0].call_count, 5, '_physics_process should have been called 5 times') assert_eq(objs[0].delta_sum, 1.0, 'The delta value should have been passed in and summed') assert_eq(objs[2].call_count, 5, '_physics_process should have been called 5 times') assert_eq(objs[2].delta_sum, 1.0, 'The delta value should have been passed in and summed') func test_simulate_calls_physics_process_if_object_is_processing_and_check_is_true(): var with_processing = autofree(WithPhysicsProcess.new()) with_processing.set_physics_process(true) _test_gut.simulate(with_processing, 5, 0.2, true) # check_is_processing=false assert_eq(with_processing.call_count, 5, '_physics_process should have been called 5 times') assert_eq(with_processing.delta_sum, 1.0, 'The delta value should have been passed in and summed') func test_simulate_does_not_call_physics_process_if_object_is_not_processing_and_check_is_true(): var without_processing = autofree(WithPhysicsProcess.new()) without_processing.set_physics_process(false) _test_gut.simulate(without_processing, 5, 0.2, true) # check_is_processing=true assert_eq(without_processing.call_count, 0, '_physics_process should not have been called') func test_simulate_does_not_error_if_object_is_physics_processing_but_has_no_method(): var with_processing_but_without_method = autofree(WithoutPhysicsProcess.new()) with_processing_but_without_method.set_physics_process(true) _test_gut.simulate(with_processing_but_without_method, 5, 0.2, true) # check_is_processing=true pass_test('We got here') func test_simulate_calls_physics_process_on_descendents_if_objects_are_processing(): var objs = [ autofree(WithPhysicsProcess.new()), autofree(WithoutPhysicsProcess.new()), autofree(WithPhysicsProcess.new()), autofree(WithoutPhysicsProcess.new()), ] for i in range(1, 4): objs[i - 1].add_child(objs[i]) objs[0].set_physics_process(false) objs[1].set_physics_process(false) objs[2].set_physics_process(true) objs[3].set_physics_process(true) _test_gut.simulate(objs[0], 5, 0.2, true) # check_is_processing=true assert_eq(objs[0].call_count, 0, '_physics_process should not have been called') assert_eq(objs[2].call_count, 5, '_physics_process should have been called 5 times') assert_eq(objs[2].delta_sum, 1.0, 'The delta value should have been passed in and summed') class TestMisc: extends GutInternalTester func test_gut_does_not_make_orphans_when_added_to_scene(): var g = new_gut() add_child(g) g.free() assert_no_new_orphans() func test_gut_does_not_make_orphans_when_freed_before_in_tree(): var g = new_gut() g.free() await wait_physics_frames(2) assert_no_new_orphans() class TestEverythingElse: extends GutInternalTester #------------------------------ # Utility methods/variables #------------------------------ # When these tests are ran in the context of other tests then the setup and # teardown counts can get out of whack which causes the last test in here # to fail. These counts are used to adjust the values tested against. var starting_counts = { setup_count = 0, teardown_count = 0 } var counts = { setup_count = 0, teardown_count = 0, prerun_setup_count = 0, postrun_teardown_count = 0 } # GlobalReset(gr) variables to be used by tests. # The values of these are reset in the setup or # teardown methods. var gr = { test_gut = null, test_finished_called = false, signal_object = null, test = null } func callback_for_test_finished(): gr.test_finished_called = true # Returns a new gut object, all setup for testing. func get_a_gut(): var g = autofree(new_gut(verbose)) return g func run_tests(which = gr.test_gut): which.test_scripts() var signal_fired = await wait_for_signal(which.end_run, 2) if(signal_fired): await wait_seconds(.1) # ------------------------------ # Setup/Teardown # ------------------------------ func before_all(): starting_counts.setup_count = gut.get_test_count() starting_counts.teardown_count = gut.get_test_count() counts.prerun_setup_count += 1 func before_each(): counts.setup_count += 1 gr.test_finished_called = false gr.test_gut = get_a_gut() add_child_autoqfree(gr.test_gut) gr.test = autofree(Test.new()) gr.test.gut = gr.test_gut func after_each(): counts.teardown_count += 1 func after_all(): counts.postrun_teardown_count += 1 # can't verify that this ran, so do an assert. # Asserts in any of the setup/teardown methods # is a bad idea in general. assert_true(true, 'POSTTEARDOWN RAN') gut.directory_delete_files('user://') # ------------------------------ # Doubler # ------------------------------ func test_when_test_overrides_strategy_it_is_reset_after_test_finishes(): gr.test_gut.double_strategy = GutUtils.DOUBLE_STRATEGY.SCRIPT_ONLY gr.test_gut.add_script('res://test/samples/test_before_after.gd') gr.test_gut.get_doubler().set_strategy(GutUtils.DOUBLE_STRATEGY.INCLUDE_NATIVE) await run_tests() assert_eq(gr.test_gut.double_strategy, GutUtils.DOUBLE_STRATEGY.SCRIPT_ONLY) func test_clears_ignored_methods_between_tests(): gr.test_gut.get_doubler().add_ignored_method('ignore_script', 'ignore_method') gr.test_gut.add_script('res://test/samples/test_sample_one.gd') gr.test_gut.unit_test_name = 'test_assert_eq_number_not_equal' await run_tests() assert_eq(gr.test_gut.get_doubler().get_ignored_methods().size(), 0) pause_before_teardown() # ------------------------------ # disable strict datatype comparisons # ------------------------------ func test_when_strict_enabled_you_can_compare_int_and_float(): gr.test.assert_eq(1.0, 1) assert_pass(gr.test) func test_when_strict_disabled_can_compare_int_and_float(): gr.test_gut.disable_strict_datatype_checks = true gr.test.assert_eq(1.0, 1) assert_pass(gr.test) # ------------------------------ # File utilities # ------------------------------ func test_file_touch_creates_file(): var path = 'user://gut_test_touch.txt' gut.file_touch(path) gr.test.assert_file_exists(path) assert_pass(gr.test) func test_file_delete_kills_file(): var path = 'user://gut_test_file_delete.txt' gr.test_gut.file_touch(path) gr.test_gut.file_delete(path) gr.test.assert_file_does_not_exist(path) assert_pass(gr.test) func test_delete_all_files_in_a_directory(): var path = 'user://gut_dir_tests' var d = DirAccess.open('user://') if(d != null): d.make_dir('gut_dir_tests') gr.test_gut.file_touch(path + '/helloworld.txt') gr.test_gut.file_touch(path + '/file2.txt') gr.test_gut.directory_delete_files(path) gr.test.assert_file_does_not_exist(path + '/helloworld.txt') gr.test.assert_file_does_not_exist(path + '/file2.txt') gut.directory_delete_files('user://gut_dir_tests') gut.file_delete('user://gut_dir_tests') assert_pass(gr.test, 2, 'both files should not exist') # ------------------------------ # No Assert Warning # ------------------------------ # no assert was moved to risky, so this test changed to make sure the warning # was no longer generated. func test_when_a_test_has_no_asserts_risky_count_and_no_warning(): gr.test_gut.add_script('res://test/resources/per_test_assert_tracking.gd') gr.test_gut.unit_test_name = 'test_no_asserts' await run_tests() assert_logger_warn(gr.test_gut, 0) var risky_count = gr.test_gut.get_test_collector().scripts[0].get_risky_count() assert_eq(risky_count, 1, 'Risky count') func test_with_passing_assert_no_assert_warning_is_not_generated(): gr.test_gut.add_script('res://test/resources/per_test_assert_tracking.gd') gr.test_gut.unit_test_name = 'test_passing_assert' await run_tests() assert_logger_warn(gr.test_gut, 0) func test_with_failing_assert_no_assert_warning_is_not_generated(): gr.test_gut.add_script('res://test/resources/per_test_assert_tracking.gd') gr.test_gut.unit_test_name = 'test_failing_assert' await run_tests() assert_logger_warn(gr.test_gut, 0) func test_with_pass_test_call_no_assert_warning_is_not_generated(): gr.test_gut.add_script('res://test/resources/per_test_assert_tracking.gd') gr.test_gut.unit_test_name = 'test_use_pass_test' await run_tests() assert_logger_warn(gr.test_gut, 0) func test_with_fail_test_call_no_assert_warning_is_not_generated(): gr.test_gut.add_script('res://test/resources/per_test_assert_tracking.gd') gr.test_gut.unit_test_name = 'test_use_fail_test' await run_tests() assert_logger_warn(gr.test_gut, 0) func test_with_pending_call_no_assert_warning_is_no_generated(): gr.test_gut.add_script('res://test/resources/per_test_assert_tracking.gd') gr.test_gut.unit_test_name = 'test_use_pending' await run_tests() assert_logger_warn(gr.test_gut, 0) # ------------------------------ # Setting test to run # ------------------------------ const SAMPLES_DIR = 'res://test/samples/' func test_setting_name_will_run_only_matching_tests(): gr.test_gut.add_script(SAMPLES_DIR + 'test_sample_all_passed.gd') gr.test_gut.unit_test_name = 'test_works' await run_tests() assert_eq(gr.test_gut.get_test_count(), 1) func test_setting_name_matches_partial(): gr.test_gut.add_script(SAMPLES_DIR + 'test_sample_all_passed.gd') gr.test_gut.unit_test_name = 'two' await run_tests() assert_eq(gr.test_gut.get_test_count(), 1) # These should all pass, just making sure there aren't any syntax errors. func test_asserts_on_test_object(): assert_eq(1, 1, 'text') assert_ne(1, 2, 'text') assert_almost_eq(5, 5, 0, 'text') assert_almost_ne(5, 6, 0, 'text') assert_gt(10, 5, 'text') assert_lt(1, 2, 'text') assert_true(true, 'text') assert_false(false, 'text') assert_between(5, 1, 10, 'text') assert_file_does_not_exist('res://doesnotexist') var path = 'user://gut_test_file.txt' var f = FileAccess.open(path, FileAccess.WRITE) f = null assert_file_exists(path) path = 'user://gut_test_empty.txt' f = FileAccess.open(path, FileAccess.WRITE) assert_file_empty(path) f = null path = 'user://gut_test_not_empty.txt' f = FileAccess.open(path, FileAccess.WRITE) f.store_8(100) f.flush() f = null assert_file_not_empty(path) func test_gut_clears_test_instances_between_runs(): gr.test_gut.add_script(SAMPLES_DIR + 'test_sample_all_passed.gd') gr.test_gut.test_scripts() await run_tests() assert_eq(gr.test_gut._test_script_objects.size(), 1, 'The should only be one test script after a second run') # There might not be an easy way to free this orphan. # ------------------------------ # Signal tests # ------------------------------ func test_when_moving_to_next_test_watched_signals_are_cleared(): gr.test_gut.add_script('res://test/unit/verify_signal_watches_are_cleared.gd') await run_tests() assert_eq(gr.test_gut.get_pass_count(), 1, 'One test should have passed.') assert_eq(gr.test_gut.get_fail_count(), 1, 'One failure for not watching anymore.') assert_eq(gr.test_gut.get_test_count(), 2, 'should have ran two tests') # ------------------------------ # Inner Class # ------------------------------ func test_when_set_only_inner_class_tests_run(): gr.test_gut.inner_class_name = 'TestClass1' gr.test_gut.add_script('res://test/resources/parsing_and_loading_samples/has_inner_class.gd') await run_tests() # count should be 4, 2 from TestClass1 and 2 from TestExtendsTestClass1 # which extends TestClass1 so it gets its two tests as well. assert_eq(gr.test_gut.get_summary().get_totals().tests, 4) func test_when_script_has_const_that_starts_with_Test_it_ignores_it(): gr.test_gut.add_script('res://test/resources/parsing_and_loading_samples/const_object.gd') pass_test('we got here') # ------------------------------ # Setup/before and teardown/after # ------------------------------ func test_after_running_script_everything_checks_out(): gr.test_gut.add_script('res://test/samples/test_before_after.gd') gr.test_gut.run_tests() var instance = gr.test_gut.get_current_script_object() assert_eq(instance.counts.before_all, 1, 'before_all') assert_eq(instance.counts.before_each, 3, 'before_each') assert_eq(instance.counts.after_all, 1, 'after_all') assert_eq(instance.counts.after_each, 3, 'after_each') await wait_seconds(1) func test_when_inner_class_skipped_none_of_the_before_after_are_called(): gr.test_gut.add_script('res://test/resources/parsing_and_loading_samples/inner_classes_check_before_after.gd') gr.test_gut.inner_class_name = 'Inner1' gr.test_gut.run_tests() var instances = gr.test_gut._test_script_objects var inner1_inst = null var inner2_inst = null # order in which the inner classes will be run is unknown so we # have to go looking for them. for i in range(instances.size()): var dict = inst_to_dict(instances[i]) var subpath = str(dict['@subpath']) if(subpath == 'TestInner1'): inner1_inst = instances[i] elif(subpath == 'TestInner2'): inner2_inst = instances[i] assert_eq(inner1_inst.before_all_calls, 1, 'TestInner1 before_all calls') assert_eq(inner1_inst.after_all_calls, 1, 'TestInner1 after_all calls') assert_eq(inner1_inst.before_each_calls, 1, 'TestInner1 before_each_calls') assert_eq(inner1_inst.after_each_calls, 1, 'TestInner1 after_each calls') assert_eq(inner2_inst.before_all_calls, 0, 'TestInner2 before_all calls') assert_eq(inner2_inst.after_all_calls, 0, 'TestInner2 after_all calls') assert_eq(inner2_inst.before_each_calls, 0, 'TestInner2 before_each_calls') assert_eq(inner2_inst.after_each_calls, 0, 'TestInner2 after_each calls') await wait_seconds(1) if(is_failing()): gut.p('These sometimes fail due to the order tests are run.') # ------------------------------ # Pre and post hook tests # ------------------------------ func test_when_pre_hook_set_script_instance_is_is_retrievable(): var PreRunScript = load('res://test/resources/pre_run_script.gd') gr.test_gut.pre_run_script = 'res://test/resources/pre_run_script.gd' gr.test_gut.add_script(SAMPLES_DIR + 'test_sample_all_passed.gd') await run_tests() assert_is(gr.test_gut.get_pre_run_script_instance(), PreRunScript) func test_when_pre_hook_set_run_method_is_called(): var PreRunScript = load('res://test/resources/pre_run_script.gd') gr.test_gut.pre_run_script = 'res://test/resources/pre_run_script.gd' gr.test_gut.add_script(SAMPLES_DIR + 'test_sample_all_passed.gd') await run_tests() assert_true(gr.test_gut.get_pre_run_script_instance().run_called) func test_when_pre_hook_set_to_invalid_script_no_tests_are_ran(): gr.test_gut.pre_run_script = 'res://does_not_exist.gd' gr.test_gut.add_script(SAMPLES_DIR + 'test_sample_all_passed.gd') await run_tests() assert_eq(gr.test_gut.get_test_count(), 0, 'test should not be run') assert_tracked_gut_error(gr.test_gut, 2) func test_pre_hook_sets_gut_instance(): gr.test_gut.pre_run_script = 'res://test/resources/pre_run_script.gd' gr.test_gut.add_script(SAMPLES_DIR + 'test_sample_all_passed.gd') await run_tests() assert_eq(gr.test_gut.get_pre_run_script_instance().gut, gr.test_gut) func test_pre_hook_accesses_global_lifecycle_signals(): gr.test_gut.pre_run_script = 'res://test/resources/pre_run_script_lifecycle_hooks.gd' gr.test_gut.add_script(SAMPLES_DIR + 'test_sample_all_passed.gd') await run_tests() var retrieved_data = gr.test_gut.get_meta('pre_run_script_lifecycle_hooks_data') assert_eq(retrieved_data[0], "test run started") assert_eq(retrieved_data[1], "res://test/samples/test_sample_all_passed.gd loaded from collected script") assert_eq(retrieved_data[2], "starting test test_works") assert_eq(retrieved_data[3], "test_works passed") assert_eq(retrieved_data[4], "starting test test_two") assert_eq(retrieved_data[5], "test_two passed") assert_eq(retrieved_data[6], "starting test test_3") assert_eq(retrieved_data[7], "test_3 passed") assert_eq(retrieved_data[8], "res://test/samples/test_sample_all_passed.gd passed") assert_eq(retrieved_data[9], "test run ended") func test_pre_hook_does_not_accept_non_hook_scripts(): gr.test_gut.pre_run_script = 'res://test/resources/non_hook_script.gd' gr.test_gut.add_script(SAMPLES_DIR + 'test_sample_all_passed.gd') await run_tests() assert_eq(gr.test_gut.get_test_count(), 0, 'test should not be run') assert_tracked_gut_error(gr.test_gut, 2) func test_post_hook_is_run_after_tests(): var PostRunScript = load('res://test/resources/post_run_script.gd') gr.test_gut.post_run_script = 'res://test/resources/post_run_script.gd' gr.test_gut.add_script(SAMPLES_DIR + 'test_sample_all_passed.gd') await run_tests() await wait_seconds(1) assert_is(gr.test_gut._post_run_script_instance, PostRunScript, 'Instance is set') assert_true(gr.test_gut._post_run_script_instance.run_called, 'run was called') func test_when_post_hook_set_to_invalid_script_no_tests_are_ran(): watch_signals(gr.test_gut) gr.test_gut.post_run_script = 'res://does_not_exist.gd' gr.test_gut.add_script(SAMPLES_DIR + 'test_sample_all_passed.gd') await run_tests() assert_eq(gr.test_gut.get_test_count(), 0, 'test should not be run') assert_tracked_gut_error(gr.test_gut, 2) func test_awaiting_in_the_pre_hook_script(): var pre_run_script = load("res://test/resources/awaiting_pre_run_script.gd") gr.test_gut.pre_run_script = "res://test/resources/awaiting_pre_run_script.gd" gr.test_gut.add_script(SAMPLES_DIR + 'test_sample_all_passed.gd') gr.test_gut.test_scripts() await wait_for_signal(gr.test_gut.start_run, 3, "It should take exactly 1 second.") assert_true(gr.test_gut.get_pre_run_script_instance().awaited, "Pre-run script awaited.") await wait_seconds(1) func test_awaiting_in_the_post_hook_script(): var pre_run_script = load("res://test/resources/awaiting_post_run_script.gd") gr.test_gut.post_run_script = "res://test/resources/awaiting_post_run_script.gd" gr.test_gut.add_script(SAMPLES_DIR + 'test_sample_all_passed.gd') gr.test_gut.test_scripts() await wait_for_signal(gr.test_gut.end_run, 3, "It should take exactly 1 second.") assert_true(gr.test_gut.get_post_run_script_instance().awaited, "Post-run script awaited.") await wait_seconds(.1) # ------------------------------ # Parameterized Test Tests # ------------------------------ const TEST_WITH_PARAMETERS = 'res://test/resources/parsing_and_loading_samples/test_with_parameters.gd' func _get_test_script_object_of_type(the_gut, the_type): var objs = gr.test_gut._test_script_objects var obj = null for i in range(objs.size()): if(is_instance_of(objs[i], the_type)): obj = objs[i] print('- ', _str(objs[i])) return obj func test_can_run_tests_with_parameters(): gr.test_gut.add_script(TEST_WITH_PARAMETERS) gr.test_gut.unit_test_name = 'test_has_one_defaulted_parameter' await run_tests() assert_eq(gr.test_gut.get_pass_count(), 1, 'pass count') assert_eq(gr.test_gut.get_test_count(), 1, 'test count') func test_too_many_parameters_generates_an_error(): gr.test_gut.add_script(TEST_WITH_PARAMETERS) gr.test_gut.unit_test_name = 'test_has_two_parameters' await run_tests() assert_tracked_gut_error(gr.test_gut, 1) assert_eq(gr.test_gut.get_test_count(), 0, 'test count') func test_parameterized_tests_are_called_multiple_times(): gr.test_gut.add_script(TEST_WITH_PARAMETERS) gr.test_gut.unit_test_name = 'test_has_three_values_for_parameters' await run_tests() assert_eq(gr.test_gut.get_pass_count(), 3) func test_when_use_parameters_is_not_called_then_error_is_generated(): gr.test_gut.add_script(TEST_WITH_PARAMETERS) gr.test_gut.unit_test_name = 'test_does_not_use_use_parameters' await run_tests() assert_tracked_gut_error(gr.test_gut) assert_tracked_gut_error(gr.test_gut, 1) assert_eq(gr.test_gut.get_fail_count(), 1) # if you really think about this, it is a very very inception like test. func test_parameterized_test_that_yield_are_called_correctly(): gr.test_gut.add_script(TEST_WITH_PARAMETERS) gr.test_gut.unit_test_name = 'test_three_values_and_a_yield' await run_tests() assert_eq(gr.test_gut.get_pass_count(), 3) func test_parameterized_test_calls_before_each_before_each_test(): gr.test_gut.add_script(TEST_WITH_PARAMETERS) gr.test_gut.inner_class_name = 'TestWithBeforeEach' gr.test_gut.run_tests() assert_eq(gr.test_gut.get_pass_count(), 3) var obj = _get_test_script_object_of_type(gr.test_gut, load(TEST_WITH_PARAMETERS).TestWithBeforeEach) assert_eq(obj.before_count, 3, 'test class: before_count') await wait_seconds(1) func test_parameterized_test_calls_after_each_after_each_test(): gr.test_gut.add_script(TEST_WITH_PARAMETERS) gr.test_gut.inner_class_name = 'TestWithAfterEach' gr.test_gut.run_tests() assert_eq(gr.test_gut.get_pass_count(), 3) var obj = _get_test_script_object_of_type(gr.test_gut, load(TEST_WITH_PARAMETERS).TestWithAfterEach) assert_eq(obj.after_count, 3, 'test class: after_count') await wait_seconds(1) # ------------------------------ # Asserting in before_all and after_all # ------------------------------ func test_passing_asserts_made_in_before_all_are_counted(): gr.test_gut.add_script('res://test/resources/has_asserts_in_beforeall_and_afterall.gd') gr.test_gut.inner_class_name = 'TestPassingBeforeAllAssertNoOtherTests' await run_tests() assert_eq(gr.test_gut.get_assert_count(), 1, 'assert count') assert_eq(gr.test_gut.get_pass_count(), 1, 'pass count') func test_failing_asserts_made_in_after_all_are_counted(): gr.test_gut.add_script('res://test/resources/has_asserts_in_beforeall_and_afterall.gd') gr.test_gut.inner_class_name = 'TestFailingAfterAllAssertNoOtherTests' await run_tests() assert_eq(gr.test_gut.get_assert_count(), 1, 'assert count') assert_eq(gr.test_gut.get_fail_count(), 1, 'fail count') func test_before_all_after_all_printing(): gr.test_gut.add_script('res://test/resources/has_asserts_in_beforeall_and_afterall.gd') gr.test_gut.inner_class_name = 'TestHasBeforeAllAfterAllAndSomeTests' await run_tests() assert_eq(gr.test_gut.get_pass_count(), 4, 'pass count') assert_eq(gr.test_gut.get_fail_count(), 4, 'fail count') assert_eq(gr.test_gut.get_assert_count(), 8, 'assert count`') func test_before_all_after_all_printing_all_classes_in_script(): gr.test_gut.add_script('res://test/resources/has_asserts_in_beforeall_and_afterall.gd') await run_tests() assert_eq(gr.test_gut.get_pass_count(), 10, 'pass count') assert_eq(gr.test_gut.get_fail_count(), 10, 'fail count') assert_eq(gr.test_gut.get_assert_count(), 20, 'assert count`') class TestReworkedEverythingElse: extends GutInternalTester var _gut = null func before_all(): verbose = false DynamicGutTest.should_print_source = verbose func before_each(): _gut = add_child_autofree(new_gut(verbose)) func test_passing_asserts_made_in_after_all_are_counted(): var src = """ func after_all(): assert_true(true) func test_nothing(): assert_eq(1, 1) """ var s = autofree(DynamicGutTest.new()) s.add_source(src) var t = await s.run_tests_in_gut_await(_gut) assert_eq(t.passing, 2, 'passing asserts') func test_failing_asserts_made_in_before_all_are_counted(): var src = """ func after_all(): assert_true(false) func test_nothing(): assert_eq(1, 1) pending() """ var s = autofree(DynamicGutTest.new()) s.add_source(src) var t = await s.run_tests_in_gut_await(_gut) assert_eq(t.failing, 1, 'one failing') func test_failing_asserts_made_in_before_all_are_in_the_summary(): var src = """ func before_all(): assert_true(false) func test_nothing(): assert_eq(1, 1) """ var s = autofree(DynamicGutTest.new()) s.add_source(src) var t = await s.run_tests_in_gut_await(_gut) _gut.get_summary().log_end_run() assert_eq(t.failing, 1, 'one failing') assert_has(_gut.get_logger().get_log_entries('failed'), "before_all/after_all assert failed") func test_failing_asserts_made_in_after_all_are_in_the_summary(): var src = """ func after_all(): assert_true(false) func test_nothing(): assert_eq(1, 1) """ var s = autofree(DynamicGutTest.new()) s.add_source(src) var t = await s.run_tests_in_gut_await(_gut) _gut.get_summary().log_end_run() assert_eq(t.failing, 1, 'one failing') assert_has(_gut.get_logger().get_log_entries('failed'), "before_all/after_all assert failed") func test_failing_asserts_made_in_before_each_cause_test_it_is_before_to_fail(): var src = """ func before_each(): assert_true(false, 'before_each_assert') func test_nothing(): assert_eq(1, 1) func test_something(): assert_eq(1, 1) """ var s = autofree(DynamicGutTest.new()) s.add_source(src) var t = await s.run_tests_in_gut_await(_gut) assert_eq(t.failing, 2, 'failing asserts') assert_eq(t.failing_tests, 2, 'failing tests') func test_failing_asserts_made_in_after_each_cause_test_it_is_after_to_fail(): var src = """ func after_each(): assert_true(false, 'after_each assert') func test_nothing(): assert_eq(1, 1) func test_something(): assert_eq(1, 1) """ var s = autofree(DynamicGutTest.new()) s.add_source(src) var t = await s.run_tests_in_gut_await(_gut) assert_eq(t.failing, 2, 'failing asserts') assert_eq(t.failing_tests, 2, 'failing tests') class TestGutHookOrder: extends GutInternalTester var _gut = null func before_each(): _gut = add_child_autofree(new_gut(verbose)) func test_signal_order(): var events: Array[String] = [] _gut.set_meta("test_signal_order", events) _gut.start_script.connect(func(_x): events.append("signal start_script")) _gut.start_test.connect(func(_x): events.append("signal start_test")) _gut.end_test.connect(func(): events.append("signal end_test")) _gut.end_script.connect(func(): events.append("signal end_script")) var src = """ func before_all(): gut.get_meta("test_signal_order").append("hook before_all") func before_each(): gut.get_meta("test_signal_order").append("hook before_each") func after_all(): gut.get_meta("test_signal_order").append("hook after_all") func after_each(): gut.get_meta("test_signal_order").append("hook after_each") func test_nothing(): pass_test("") """ var s = autofree(DynamicGutTest.new()) s.add_source(src) await s.run_tests_in_gut_await(_gut) assert_eq(_gut.get_meta("test_signal_order"), [ "signal start_script", "hook before_all", "hook before_each", "signal start_test", "hook after_each", "signal end_test", "hook after_all", "signal end_script", ])