extends SceneTree ## Test suite for ValueStepper component ## ## Tests data loading, value navigation, and input handling. const TestHelperClass = preload("res://tests/helpers/TestHelper.gd") var stepper_scene: PackedScene var stepper_instance: Control var test_viewport: SubViewport var original_language: 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("ValueStepper Component") # Store original settings var settings_manager = root.get_node("SettingsManager") original_language = settings_manager.get_setting("language") # Setup test environment setup_test_environment() # Run test suites test_basic_functionality() test_data_source_loading() test_value_navigation() test_custom_values() test_input_handling() test_visual_feedback() test_settings_integration() test_boundary_conditions() test_error_handling() # Cleanup cleanup_tests() TestHelperClass.print_test_footer("ValueStepper Component") func setup_test_environment(): TestHelperClass.print_step("Test Environment Setup") # Load ValueStepper scene stepper_scene = load("res://scenes/ui/components/ValueStepper.tscn") TestHelperClass.assert_not_null( stepper_scene, "ValueStepper scene loads successfully" ) # Create test viewport for isolated testing test_viewport = SubViewport.new() test_viewport.size = Vector2i(400, 200) root.add_child(test_viewport) # Instance ValueStepper in test viewport if stepper_scene: stepper_instance = stepper_scene.instantiate() test_viewport.add_child(stepper_instance) TestHelperClass.assert_not_null( stepper_instance, "ValueStepper instance created successfully" ) # Wait for initialization await process_frame await process_frame func test_basic_functionality(): TestHelperClass.print_step("Basic Functionality") if not stepper_instance: TestHelperClass.assert_true( false, "ValueStepper instance not available for testing" ) return # Test that ValueStepper has expected properties var expected_properties = [ "data_source", "custom_format_function", "values", "display_names", "current_index" ] for prop in expected_properties: TestHelperClass.assert_true( prop in stepper_instance, "ValueStepper has property: " + prop ) # Test that ValueStepper has expected methods var expected_methods = [ "change_value", "setup_custom_values", "get_current_value", "set_current_value", "set_highlighted", "handle_input_action", "get_control_name" ] TestHelperClass.assert_has_methods( stepper_instance, expected_methods, "ValueStepper component methods" ) # Test signals TestHelperClass.assert_true( stepper_instance.has_signal("value_changed"), "ValueStepper has value_changed signal" ) # Test UI components TestHelperClass.assert_not_null( stepper_instance.left_button, "Left button is available" ) TestHelperClass.assert_not_null( stepper_instance.right_button, "Right button is available" ) TestHelperClass.assert_not_null( stepper_instance.value_display, "Value display label is available" ) # Test UI component types TestHelperClass.assert_true( stepper_instance.left_button is Button, "Left button is Button type" ) TestHelperClass.assert_true( stepper_instance.right_button is Button, "Right button is Button type" ) TestHelperClass.assert_true( stepper_instance.value_display is Label, "Value display is Label type" ) func test_data_source_loading(): TestHelperClass.print_step("Data Source Loading") if not stepper_instance: return # Test default language data source TestHelperClass.assert_equal( "language", stepper_instance.data_source, "Default data source is language" ) # Test that values are loaded TestHelperClass.assert_not_null( stepper_instance.values, "Values array is initialized" ) TestHelperClass.assert_not_null( stepper_instance.display_names, "Display names array is initialized" ) TestHelperClass.assert_true( stepper_instance.values is Array, "Values is Array type" ) TestHelperClass.assert_true( stepper_instance.display_names is Array, "Display names is Array type" ) # Test that language data is loaded correctly if stepper_instance.data_source == "language": TestHelperClass.assert_true( stepper_instance.values.size() > 0, "Language values loaded" ) TestHelperClass.assert_true( stepper_instance.display_names.size() > 0, "Language display names loaded" ) TestHelperClass.assert_equal( stepper_instance.values.size(), stepper_instance.display_names.size(), "Values and display names arrays have same size" ) # Test that current language is properly selected var current_lang = root.get_node("SettingsManager").get_setting( "language" ) var expected_index = stepper_instance.values.find(current_lang) if expected_index >= 0: TestHelperClass.assert_equal( expected_index, stepper_instance.current_index, "Current language index set correctly" ) # Test resolution data source var resolution_stepper = stepper_scene.instantiate() resolution_stepper.data_source = "resolution" test_viewport.add_child(resolution_stepper) await process_frame TestHelperClass.assert_true( resolution_stepper.values.size() > 0, "Resolution values loaded" ) TestHelperClass.assert_contains( resolution_stepper.values, "1920x1080", "Resolution data contains expected value" ) resolution_stepper.queue_free() # Test difficulty data source var difficulty_stepper = stepper_scene.instantiate() difficulty_stepper.data_source = "difficulty" test_viewport.add_child(difficulty_stepper) await process_frame TestHelperClass.assert_true( difficulty_stepper.values.size() > 0, "Difficulty values loaded" ) TestHelperClass.assert_contains( difficulty_stepper.values, "normal", "Difficulty data contains expected value" ) TestHelperClass.assert_equal( 1, difficulty_stepper.current_index, "Difficulty defaults to normal" ) difficulty_stepper.queue_free() func test_value_navigation(): TestHelperClass.print_step("Value Navigation") if not stepper_instance: return # Store original state var original_index = stepper_instance.current_index var original_value = stepper_instance.get_current_value() # Test forward navigation var initial_value = stepper_instance.get_current_value() stepper_instance.change_value(1) var next_value = stepper_instance.get_current_value() TestHelperClass.assert_not_equal( initial_value, next_value, "Forward navigation changes value" ) # Test backward navigation stepper_instance.change_value(-1) var back_value = stepper_instance.get_current_value() TestHelperClass.assert_equal( initial_value, back_value, "Backward navigation returns to original value" ) # Test wrap-around forward var max_index = stepper_instance.values.size() - 1 stepper_instance.current_index = max_index stepper_instance.change_value(1) TestHelperClass.assert_equal( 0, stepper_instance.current_index, "Forward navigation wraps to beginning" ) # Test wrap-around backward stepper_instance.current_index = 0 stepper_instance.change_value(-1) TestHelperClass.assert_equal( max_index, stepper_instance.current_index, "Backward navigation wraps to end" ) # Restore original state stepper_instance.current_index = original_index # Display updates automatically when value changes func test_custom_values(): TestHelperClass.print_step("Custom Values") if not stepper_instance: return # Store original state var original_values = stepper_instance.values.duplicate() var original_display_names = stepper_instance.display_names.duplicate() var original_index = stepper_instance.current_index # Test custom values without display names var custom_values = ["apple", "banana", "cherry"] stepper_instance.setup_custom_values(custom_values) TestHelperClass.assert_equal( 3, stepper_instance.values.size(), "Custom values set correctly" ) TestHelperClass.assert_equal( "apple", stepper_instance.values[0], "First custom value correct" ) TestHelperClass.assert_equal( 0, stepper_instance.current_index, "Index reset to 0 for custom values" ) TestHelperClass.assert_equal( "apple", stepper_instance.get_current_value(), "Current value matches first custom value" ) # Test custom values with display names var custom_display_names = ["Red Apple", "Yellow Banana", "Red Cherry"] stepper_instance.setup_custom_values(custom_values, custom_display_names) TestHelperClass.assert_equal( 3, stepper_instance.display_names.size(), "Custom display names set correctly" ) TestHelperClass.assert_equal( "Red Apple", stepper_instance.display_names[0], "First display name correct" ) # Test navigation with custom values stepper_instance.change_value(1) TestHelperClass.assert_equal( "banana", stepper_instance.get_current_value(), "Navigation works with custom values" ) # Test set_current_value stepper_instance.set_current_value("cherry") TestHelperClass.assert_equal( "cherry", stepper_instance.get_current_value(), "set_current_value works correctly" ) TestHelperClass.assert_equal( 2, stepper_instance.current_index, "Index updated correctly by set_current_value" ) # Test invalid value stepper_instance.set_current_value("grape") TestHelperClass.assert_equal( "cherry", stepper_instance.get_current_value(), "Invalid value doesn't change current value" ) # Restore original state stepper_instance.values = original_values stepper_instance.display_names = original_display_names stepper_instance.current_index = original_index # Display updates automatically when value changes func test_input_handling(): TestHelperClass.print_step("Input Handling") if not stepper_instance: return # Store original state var original_value = stepper_instance.get_current_value() # Test left input action var left_handled = stepper_instance.handle_input_action("move_left") TestHelperClass.assert_true(left_handled, "Left input action handled") TestHelperClass.assert_not_equal( original_value, stepper_instance.get_current_value(), "Left action changes value" ) # Test right input action var right_handled = stepper_instance.handle_input_action("move_right") TestHelperClass.assert_true(right_handled, "Right input action handled") TestHelperClass.assert_equal( original_value, stepper_instance.get_current_value(), "Right action returns to original value" ) # Test invalid input action var invalid_handled = stepper_instance.handle_input_action("invalid_action") TestHelperClass.assert_false( invalid_handled, "Invalid input action not handled" ) # Test button press simulation if stepper_instance.left_button: var before_left = stepper_instance.get_current_value() stepper_instance.handle_input_action("move_left") TestHelperClass.assert_not_equal( before_left, stepper_instance.get_current_value(), "Left button press changes value" ) if stepper_instance.right_button: var before_right = stepper_instance.get_current_value() stepper_instance.handle_input_action("move_right") TestHelperClass.assert_equal( original_value, stepper_instance.get_current_value(), "Right button press returns to original" ) func test_visual_feedback(): TestHelperClass.print_step("Visual Feedback") if not stepper_instance: return # Store original visual properties var original_scale = stepper_instance.scale var original_modulate = stepper_instance.modulate # Test highlighting stepper_instance.set_highlighted(true) TestHelperClass.assert_true( stepper_instance.is_highlighted, "Highlighted state set correctly" ) TestHelperClass.assert_true( stepper_instance.scale.x > original_scale.x, "Scale increased when highlighted" ) # Test unhighlighting stepper_instance.set_highlighted(false) TestHelperClass.assert_false( stepper_instance.is_highlighted, "Highlighted state cleared correctly" ) TestHelperClass.assert_equal( original_scale, stepper_instance.scale, "Scale restored when unhighlighted" ) TestHelperClass.assert_equal( original_modulate, stepper_instance.modulate, "Modulate restored when unhighlighted" ) # Test display update if stepper_instance.value_display: var current_text = stepper_instance.value_display.text TestHelperClass.assert_true( current_text.length() > 0, "Value display has text content" ) TestHelperClass.assert_not_equal( "N/A", current_text, "Value display shows valid content" ) func test_settings_integration(): TestHelperClass.print_step("Settings Integration") if not stepper_instance or stepper_instance.data_source != "language": return # Store original language var original_lang = root.get_node("SettingsManager").get_setting("language") # Test that changing language stepper updates settings var available_languages = stepper_instance.values if available_languages.size() > 1: # Find a different language var target_lang = null for lang in available_languages: if lang != original_lang: target_lang = lang break if target_lang: stepper_instance.set_current_value(target_lang) # Value change is applied automatically through set_current_value # Verify setting was updated var updated_lang = root.get_node("SettingsManager").get_setting( "language" ) TestHelperClass.assert_equal( target_lang, updated_lang, "Language setting updated correctly" ) # Restore original language root.get_node("SettingsManager").set_setting( "language", original_lang ) func test_boundary_conditions(): TestHelperClass.print_step("Boundary Conditions") if not stepper_instance: return # Test empty values array var empty_stepper = stepper_scene.instantiate() empty_stepper.data_source = "unknown" # Will result in empty arrays test_viewport.add_child(empty_stepper) await process_frame TestHelperClass.assert_equal( "", empty_stepper.get_current_value(), "Empty values array returns empty string" ) # Test change_value with empty array empty_stepper.change_value(1) # Should not crash TestHelperClass.assert_true( true, "change_value handles empty array gracefully" ) empty_stepper.queue_free() # Test index bounds if stepper_instance.values.size() > 0: # Test negative index handling stepper_instance.current_index = -1 # Display updates automatically when value changes TestHelperClass.assert_equal( "N/A", stepper_instance.value_display.text, "Negative index shows N/A" ) # Test out-of-bounds index handling stepper_instance.current_index = stepper_instance.values.size() # Display updates automatically when value changes TestHelperClass.assert_equal( "N/A", stepper_instance.value_display.text, "Out-of-bounds index shows N/A" ) # Restore valid index stepper_instance.current_index = 0 # Display updates automatically when value changes func test_error_handling(): TestHelperClass.print_step("Error Handling") if not stepper_instance: return # Test unknown data source var unknown_stepper = stepper_scene.instantiate() unknown_stepper.data_source = "invalid_source" test_viewport.add_child(unknown_stepper) await process_frame # Should not crash and should handle gracefully TestHelperClass.assert_true(true, "Unknown data source handled gracefully") unknown_stepper.queue_free() # Test get_control_name var control_name = stepper_instance.get_control_name() TestHelperClass.assert_true( control_name.ends_with("_stepper"), "Control name has correct suffix" ) TestHelperClass.assert_true( control_name.begins_with(stepper_instance.data_source), "Control name includes data source" ) # Test custom values with mismatched arrays var values_3 = ["a", "b", "c"] var names_2 = ["A", "B"] stepper_instance.setup_custom_values(values_3, names_2) # Should handle gracefully - display_names should be duplicated from values TestHelperClass.assert_equal( 3, stepper_instance.values.size(), "Values array size preserved" ) TestHelperClass.assert_equal( 2, stepper_instance.display_names.size(), "Display names size preserved as provided" ) # Test navigation with mismatched arrays stepper_instance.current_index = 2 # Index where display_names doesn't exist # Display updates automatically when value changes TestHelperClass.assert_equal( "c", stepper_instance.value_display.text, "Falls back to value when display name missing" ) func cleanup_tests(): TestHelperClass.print_step("Cleanup") # Restore original language setting root.get_node("SettingsManager").set_setting("language", original_language) # Clean up stepper instance if stepper_instance and is_instance_valid(stepper_instance): stepper_instance.queue_free() # Clean up test viewport if test_viewport and is_instance_valid(test_viewport): test_viewport.queue_free() # Wait for cleanup await process_frame TestHelperClass.assert_true(true, "Test cleanup completed")