extends SceneTree ## Test suite for GameManager ## ## Tests scene transitions, input validation, and gameplay modes. const TestHelperClass = preload("res://tests/helpers/TestHelper.gd") var game_manager: Node var original_scene: Node var test_scenes_created: Array[String] = [] func _initialize(): # Wait for autoloads to initialize await process_frame await process_frame run_tests() # Exit after tests complete quit() func run_tests(): TestHelperClass.print_test_header("GameManager") # Get reference to GameManager game_manager = root.get_node("GameManager") if not game_manager: TestHelperClass.assert_true(false, "GameManager autoload not found") TestHelperClass.print_test_footer("GameManager") return # Store original scene reference original_scene = current_scene # Run test suites test_basic_functionality() test_scene_constants() test_input_validation() test_race_condition_protection() test_gameplay_mode_validation() test_scene_transition_safety() test_error_handling() test_scene_method_validation() test_pending_mode_management() # Cleanup cleanup_tests() TestHelperClass.print_test_footer("GameManager") func test_basic_functionality(): TestHelperClass.print_step("Basic Functionality") # Test that GameManager has expected properties TestHelperClass.assert_has_properties( game_manager, ["pending_gameplay_mode", "is_changing_scene"], "GameManager properties" ) # Test that GameManager has expected methods var expected_methods = [ "start_new_game", "continue_game", "start_match3_game", "start_clickomania_game", "start_game_with_mode", "save_game", "exit_to_main_menu" ] TestHelperClass.assert_has_methods( game_manager, expected_methods, "GameManager methods" ) # Test initial state TestHelperClass.assert_equal( "match3", game_manager.pending_gameplay_mode, "Default pending gameplay mode" ) TestHelperClass.assert_false( game_manager.is_changing_scene, "Initial scene change flag" ) func test_scene_constants(): TestHelperClass.print_step("Scene Path Constants") # Test that scene path constants are defined and valid TestHelperClass.assert_true( "GAME_SCENE_PATH" in game_manager, "GAME_SCENE_PATH constant exists" ) TestHelperClass.assert_true( "MAIN_SCENE_PATH" in game_manager, "MAIN_SCENE_PATH constant exists" ) # Test path format validation var game_path = game_manager.GAME_SCENE_PATH var main_path = game_manager.MAIN_SCENE_PATH TestHelperClass.assert_true( game_path.begins_with("res://"), "Game scene path uses res:// protocol" ) TestHelperClass.assert_true( game_path.ends_with(".tscn"), "Game scene path has .tscn extension" ) TestHelperClass.assert_true( main_path.begins_with("res://"), "Main scene path uses res:// protocol" ) TestHelperClass.assert_true( main_path.ends_with(".tscn"), "Main scene path has .tscn extension" ) # Test that scene files exist TestHelperClass.assert_true( ResourceLoader.exists(game_path), "Game scene file exists at path" ) TestHelperClass.assert_true( ResourceLoader.exists(main_path), "Main scene file exists at path" ) func test_input_validation(): TestHelperClass.print_step("Input Validation") # Store original state var original_changing = game_manager.is_changing_scene var original_mode = game_manager.pending_gameplay_mode # Test empty string validation game_manager.start_game_with_mode("") TestHelperClass.assert_equal( original_mode, game_manager.pending_gameplay_mode, "Empty string mode rejected" ) TestHelperClass.assert_false( game_manager.is_changing_scene, "Scene change flag unchanged after empty mode" ) # Test null validation - GameManager expects String, so this tests the type safety # Note: In Godot 4.4, passing null to String parameter causes script error as expected # The function properly validates empty strings instead TestHelperClass.assert_equal( original_mode, game_manager.pending_gameplay_mode, "Mode preserved after empty string test" ) TestHelperClass.assert_false( game_manager.is_changing_scene, "Scene change flag unchanged after validation tests" ) # Test invalid mode validation game_manager.start_game_with_mode("invalid_mode") TestHelperClass.assert_equal( original_mode, game_manager.pending_gameplay_mode, "Invalid mode rejected" ) TestHelperClass.assert_false( game_manager.is_changing_scene, "Scene change flag unchanged after invalid mode" ) # Test case sensitivity game_manager.start_game_with_mode("MATCH3") TestHelperClass.assert_equal( original_mode, game_manager.pending_gameplay_mode, "Case-sensitive mode validation" ) TestHelperClass.assert_false( game_manager.is_changing_scene, "Scene change flag unchanged after wrong case" ) func test_race_condition_protection(): TestHelperClass.print_step("Race Condition Protection") # Store original state var original_mode = game_manager.pending_gameplay_mode # Simulate concurrent scene change attempt game_manager.is_changing_scene = true game_manager.start_game_with_mode("match3") # Verify second request was rejected TestHelperClass.assert_equal( original_mode, game_manager.pending_gameplay_mode, "Concurrent scene change blocked" ) TestHelperClass.assert_true( game_manager.is_changing_scene, "Scene change flag preserved" ) # Test exit to main menu during scene change game_manager.exit_to_main_menu() TestHelperClass.assert_true( game_manager.is_changing_scene, "Exit request blocked during scene change" ) # Reset state game_manager.is_changing_scene = false func test_gameplay_mode_validation(): TestHelperClass.print_step("Gameplay Mode Validation") # Test valid modes var valid_modes = ["match3", "clickomania"] for mode in valid_modes: var original_changing = game_manager.is_changing_scene # We'll test the validation logic without actually changing scenes # by checking if the function would accept the mode # Create a temporary mock to test validation var test_mode_valid = mode in ["match3", "clickomania"] TestHelperClass.assert_true( test_mode_valid, "Valid mode accepted: " + mode ) # Test whitelist enforcement var invalid_modes = ["puzzle", "arcade", "adventure", "rpg", "action"] for mode in invalid_modes: var test_mode_invalid = not (mode in ["match3", "clickomania"]) TestHelperClass.assert_true( test_mode_invalid, "Invalid mode rejected: " + mode ) func test_scene_transition_safety(): TestHelperClass.print_step("Scene Transition Safety") # Test scene loading validation (without actually changing scenes) var game_scene_path = game_manager.GAME_SCENE_PATH var main_scene_path = game_manager.MAIN_SCENE_PATH # Test scene resource loading var game_scene = load(game_scene_path) TestHelperClass.assert_not_null( game_scene, "Game scene resource loads successfully" ) TestHelperClass.assert_true( game_scene is PackedScene, "Game scene is PackedScene type" ) var main_scene = load(main_scene_path) TestHelperClass.assert_not_null( main_scene, "Main scene resource loads successfully" ) TestHelperClass.assert_true( main_scene is PackedScene, "Main scene is PackedScene type" ) # Test that current scene exists TestHelperClass.assert_not_null(current_scene, "Current scene exists") func test_error_handling(): TestHelperClass.print_step("Error Handling") # Store original state var original_changing = game_manager.is_changing_scene var original_mode = game_manager.pending_gameplay_mode # Test error recovery - verify state is properly reset on errors # Since we can't easily trigger scene loading errors in tests, # we'll verify the error handling patterns are in place # Verify state preservation after invalid inputs game_manager.start_game_with_mode("") TestHelperClass.assert_equal( original_changing, game_manager.is_changing_scene, "State preserved after empty mode error" ) TestHelperClass.assert_equal( original_mode, game_manager.pending_gameplay_mode, "Mode preserved after empty mode error" ) game_manager.start_game_with_mode("invalid") TestHelperClass.assert_equal( original_changing, game_manager.is_changing_scene, "State preserved after invalid mode error" ) TestHelperClass.assert_equal( original_mode, game_manager.pending_gameplay_mode, "Mode preserved after invalid mode error" ) func test_scene_method_validation(): TestHelperClass.print_step("Scene Method Validation") # Test that GameManager properly checks for required methods # We'll create a mock scene to test method validation var mock_scene = Node.new() # Test method existence checking var has_set_gameplay_mode = mock_scene.has_method("set_gameplay_mode") var has_set_global_score = mock_scene.has_method("set_global_score") var has_get_global_score = mock_scene.has_method("get_global_score") TestHelperClass.assert_false( has_set_gameplay_mode, "Mock scene lacks set_gameplay_mode method" ) TestHelperClass.assert_false( has_set_global_score, "Mock scene lacks set_global_score method" ) TestHelperClass.assert_false( has_get_global_score, "Mock scene lacks get_global_score method" ) # Clean up mock scene mock_scene.queue_free() func test_pending_mode_management(): TestHelperClass.print_step("Pending Mode Management") # Store original mode var original_mode = game_manager.pending_gameplay_mode # Test that pending mode is properly set for valid inputs # We'll manually set the pending mode to test the logic var test_mode = "clickomania" if test_mode in ["match3", "clickomania"]: # This simulates what would happen in start_game_with_mode game_manager.pending_gameplay_mode = test_mode TestHelperClass.assert_equal( test_mode, game_manager.pending_gameplay_mode, "Pending mode set correctly" ) # Test mode preservation during errors game_manager.pending_gameplay_mode = "match3" var preserved_mode = game_manager.pending_gameplay_mode # Attempt invalid operation (this should not change pending mode) # The actual start_game_with_mode with invalid input won't change pending_gameplay_mode TestHelperClass.assert_equal( preserved_mode, game_manager.pending_gameplay_mode, "Mode preserved during invalid operations" ) # Restore original mode game_manager.pending_gameplay_mode = original_mode func cleanup_tests(): TestHelperClass.print_step("Cleanup") # Reset GameManager state game_manager.is_changing_scene = false game_manager.pending_gameplay_mode = "match3" # Clean up any test files or temporary resources for scene_path in test_scenes_created: if ResourceLoader.exists(scene_path): # Note: Can't actually delete from res:// in tests, just track for manual cleanup pass TestHelperClass.assert_true(true, "Test cleanup completed")