Add gdlint and gdformat scripts
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
extends RefCounted
|
||||
class_name TestHelper
|
||||
extends RefCounted
|
||||
|
||||
## Common test utilities and assertions for Skelly project testing
|
||||
##
|
||||
@@ -7,13 +7,13 @@ class_name TestHelper
|
||||
## to ensure consistent test behavior across all test files.
|
||||
|
||||
## Test result tracking
|
||||
static var tests_run := 0
|
||||
static var tests_passed := 0
|
||||
static var tests_failed := 0
|
||||
static var tests_run = 0
|
||||
static var tests_passed = 0
|
||||
static var tests_failed = 0
|
||||
|
||||
## Performance tracking
|
||||
static var test_start_time := 0.0
|
||||
static var performance_data := {}
|
||||
static var test_start_time = 0.0
|
||||
static var performance_data = {}
|
||||
|
||||
## Print test section header with consistent formatting
|
||||
static func print_test_header(test_name: String):
|
||||
|
||||
@@ -12,6 +12,7 @@ var audio_manager: Node
|
||||
var original_music_volume: float
|
||||
var original_sfx_volume: float
|
||||
|
||||
|
||||
func _initialize():
|
||||
# Wait for autoloads to initialize
|
||||
await process_frame
|
||||
@@ -22,6 +23,7 @@ func _initialize():
|
||||
# Exit after tests complete
|
||||
quit()
|
||||
|
||||
|
||||
func run_tests():
|
||||
TestHelper.print_test_header("AudioManager")
|
||||
|
||||
@@ -54,11 +56,16 @@ func run_tests():
|
||||
|
||||
TestHelper.print_test_footer("AudioManager")
|
||||
|
||||
|
||||
func test_basic_functionality():
|
||||
TestHelper.print_step("Basic Functionality")
|
||||
|
||||
# Test that AudioManager has expected properties
|
||||
TestHelper.assert_has_properties(audio_manager, ["music_player", "ui_click_player", "click_stream"], "AudioManager properties")
|
||||
TestHelper.assert_has_properties(
|
||||
audio_manager,
|
||||
["music_player", "ui_click_player", "click_stream"],
|
||||
"AudioManager properties"
|
||||
)
|
||||
|
||||
# Test that AudioManager has expected methods
|
||||
var expected_methods = ["update_music_volume", "play_ui_click"]
|
||||
@@ -66,7 +73,10 @@ func test_basic_functionality():
|
||||
|
||||
# Test that AudioManager has expected constants
|
||||
TestHelper.assert_true("MUSIC_PATH" in audio_manager, "MUSIC_PATH constant exists")
|
||||
TestHelper.assert_true("UI_CLICK_SOUND_PATH" in audio_manager, "UI_CLICK_SOUND_PATH constant exists")
|
||||
TestHelper.assert_true(
|
||||
"UI_CLICK_SOUND_PATH" in audio_manager, "UI_CLICK_SOUND_PATH constant exists"
|
||||
)
|
||||
|
||||
|
||||
func test_audio_constants():
|
||||
TestHelper.print_step("Audio File Constants")
|
||||
@@ -76,7 +86,9 @@ func test_audio_constants():
|
||||
var click_path = audio_manager.UI_CLICK_SOUND_PATH
|
||||
|
||||
TestHelper.assert_true(music_path.begins_with("res://"), "Music path uses res:// protocol")
|
||||
TestHelper.assert_true(click_path.begins_with("res://"), "Click sound path uses res:// protocol")
|
||||
TestHelper.assert_true(
|
||||
click_path.begins_with("res://"), "Click sound path uses res:// protocol"
|
||||
)
|
||||
|
||||
# Test file extensions
|
||||
var valid_audio_extensions = [".wav", ".ogg", ".mp3"]
|
||||
@@ -96,22 +108,39 @@ func test_audio_constants():
|
||||
TestHelper.assert_true(ResourceLoader.exists(music_path), "Music file exists at path")
|
||||
TestHelper.assert_true(ResourceLoader.exists(click_path), "Click sound file exists at path")
|
||||
|
||||
|
||||
func test_audio_player_initialization():
|
||||
TestHelper.print_step("Audio Player Initialization")
|
||||
|
||||
# Test music player initialization
|
||||
TestHelper.assert_not_null(audio_manager.music_player, "Music player is initialized")
|
||||
TestHelper.assert_true(audio_manager.music_player is AudioStreamPlayer, "Music player is AudioStreamPlayer type")
|
||||
TestHelper.assert_true(audio_manager.music_player.get_parent() == audio_manager, "Music player is child of AudioManager")
|
||||
TestHelper.assert_true(
|
||||
audio_manager.music_player is AudioStreamPlayer, "Music player is AudioStreamPlayer type"
|
||||
)
|
||||
TestHelper.assert_true(
|
||||
audio_manager.music_player.get_parent() == audio_manager,
|
||||
"Music player is child of AudioManager"
|
||||
)
|
||||
|
||||
# Test UI click player initialization
|
||||
TestHelper.assert_not_null(audio_manager.ui_click_player, "UI click player is initialized")
|
||||
TestHelper.assert_true(audio_manager.ui_click_player is AudioStreamPlayer, "UI click player is AudioStreamPlayer type")
|
||||
TestHelper.assert_true(audio_manager.ui_click_player.get_parent() == audio_manager, "UI click player is child of AudioManager")
|
||||
TestHelper.assert_true(
|
||||
audio_manager.ui_click_player is AudioStreamPlayer,
|
||||
"UI click player is AudioStreamPlayer type"
|
||||
)
|
||||
TestHelper.assert_true(
|
||||
audio_manager.ui_click_player.get_parent() == audio_manager,
|
||||
"UI click player is child of AudioManager"
|
||||
)
|
||||
|
||||
# Test audio bus assignment
|
||||
TestHelper.assert_equal("Music", audio_manager.music_player.bus, "Music player assigned to Music bus")
|
||||
TestHelper.assert_equal("SFX", audio_manager.ui_click_player.bus, "UI click player assigned to SFX bus")
|
||||
TestHelper.assert_equal(
|
||||
"Music", audio_manager.music_player.bus, "Music player assigned to Music bus"
|
||||
)
|
||||
TestHelper.assert_equal(
|
||||
"SFX", audio_manager.ui_click_player.bus, "UI click player assigned to SFX bus"
|
||||
)
|
||||
|
||||
|
||||
func test_stream_loading_and_validation():
|
||||
TestHelper.print_step("Stream Loading and Validation")
|
||||
@@ -119,12 +148,16 @@ func test_stream_loading_and_validation():
|
||||
# Test music stream loading
|
||||
TestHelper.assert_not_null(audio_manager.music_player.stream, "Music stream is loaded")
|
||||
if audio_manager.music_player.stream:
|
||||
TestHelper.assert_true(audio_manager.music_player.stream is AudioStream, "Music stream is AudioStream type")
|
||||
TestHelper.assert_true(
|
||||
audio_manager.music_player.stream is AudioStream, "Music stream is AudioStream type"
|
||||
)
|
||||
|
||||
# Test click stream loading
|
||||
TestHelper.assert_not_null(audio_manager.click_stream, "Click stream is loaded")
|
||||
if audio_manager.click_stream:
|
||||
TestHelper.assert_true(audio_manager.click_stream is AudioStream, "Click stream is AudioStream type")
|
||||
TestHelper.assert_true(
|
||||
audio_manager.click_stream is AudioStream, "Click stream is AudioStream type"
|
||||
)
|
||||
|
||||
# Test stream resource loading directly
|
||||
var loaded_music = load(audio_manager.MUSIC_PATH)
|
||||
@@ -135,6 +168,7 @@ func test_stream_loading_and_validation():
|
||||
TestHelper.assert_not_null(loaded_click, "Click resource loads successfully")
|
||||
TestHelper.assert_true(loaded_click is AudioStream, "Loaded click sound is AudioStream type")
|
||||
|
||||
|
||||
func test_audio_bus_configuration():
|
||||
TestHelper.print_step("Audio Bus Configuration")
|
||||
|
||||
@@ -147,10 +181,17 @@ func test_audio_bus_configuration():
|
||||
|
||||
# Test player bus assignments match actual AudioServer buses
|
||||
if music_bus_index >= 0:
|
||||
TestHelper.assert_equal("Music", audio_manager.music_player.bus, "Music player correctly assigned to Music bus")
|
||||
TestHelper.assert_equal(
|
||||
"Music", audio_manager.music_player.bus, "Music player correctly assigned to Music bus"
|
||||
)
|
||||
|
||||
if sfx_bus_index >= 0:
|
||||
TestHelper.assert_equal("SFX", audio_manager.ui_click_player.bus, "UI click player correctly assigned to SFX bus")
|
||||
TestHelper.assert_equal(
|
||||
"SFX",
|
||||
audio_manager.ui_click_player.bus,
|
||||
"UI click player correctly assigned to SFX bus"
|
||||
)
|
||||
|
||||
|
||||
func test_volume_management():
|
||||
TestHelper.print_step("Volume Management")
|
||||
@@ -162,33 +203,49 @@ func test_volume_management():
|
||||
|
||||
# Test volume update to valid range
|
||||
audio_manager.update_music_volume(0.5)
|
||||
TestHelper.assert_float_equal(linear_to_db(0.5), audio_manager.music_player.volume_db, 0.001, "Music volume set correctly")
|
||||
TestHelper.assert_float_equal(
|
||||
linear_to_db(0.5), audio_manager.music_player.volume_db, 0.001, "Music volume set correctly"
|
||||
)
|
||||
|
||||
# Test volume update to zero (should stop music)
|
||||
audio_manager.update_music_volume(0.0)
|
||||
TestHelper.assert_equal(linear_to_db(0.0), audio_manager.music_player.volume_db, "Zero volume set correctly")
|
||||
TestHelper.assert_equal(
|
||||
linear_to_db(0.0), audio_manager.music_player.volume_db, "Zero volume set correctly"
|
||||
)
|
||||
# Note: We don't test playing state as it depends on initialization conditions
|
||||
|
||||
# Test volume update to maximum
|
||||
audio_manager.update_music_volume(1.0)
|
||||
TestHelper.assert_equal(linear_to_db(1.0), audio_manager.music_player.volume_db, "Maximum volume set correctly")
|
||||
TestHelper.assert_equal(
|
||||
linear_to_db(1.0), audio_manager.music_player.volume_db, "Maximum volume set correctly"
|
||||
)
|
||||
|
||||
# Test volume range validation
|
||||
var test_volumes = [0.0, 0.25, 0.5, 0.75, 1.0]
|
||||
for volume in test_volumes:
|
||||
audio_manager.update_music_volume(volume)
|
||||
var expected_db = linear_to_db(volume)
|
||||
TestHelper.assert_float_equal(expected_db, audio_manager.music_player.volume_db, 0.001, "Volume %f converts correctly to dB" % volume)
|
||||
TestHelper.assert_float_equal(
|
||||
expected_db,
|
||||
audio_manager.music_player.volume_db,
|
||||
0.001,
|
||||
"Volume %f converts correctly to dB" % volume
|
||||
)
|
||||
|
||||
# Restore original volume
|
||||
audio_manager.update_music_volume(original_volume)
|
||||
|
||||
|
||||
func test_music_playback_control():
|
||||
TestHelper.print_step("Music Playback Control")
|
||||
|
||||
# Test that music player exists and has a stream
|
||||
TestHelper.assert_not_null(audio_manager.music_player, "Music player exists for playback testing")
|
||||
TestHelper.assert_not_null(audio_manager.music_player.stream, "Music player has stream for playback testing")
|
||||
TestHelper.assert_not_null(
|
||||
audio_manager.music_player, "Music player exists for playback testing"
|
||||
)
|
||||
TestHelper.assert_not_null(
|
||||
audio_manager.music_player.stream, "Music player has stream for playback testing"
|
||||
)
|
||||
|
||||
# Test playback state management
|
||||
# Note: We test the control methods exist and can be called safely
|
||||
@@ -213,6 +270,7 @@ func test_music_playback_control():
|
||||
audio_manager.update_music_volume(0.0)
|
||||
TestHelper.assert_true(true, "Volume-based playback stop works")
|
||||
|
||||
|
||||
func test_ui_sound_effects():
|
||||
TestHelper.print_step("UI Sound Effects")
|
||||
|
||||
@@ -225,7 +283,11 @@ func test_ui_sound_effects():
|
||||
audio_manager.play_ui_click()
|
||||
|
||||
# Verify click stream was assigned to player
|
||||
TestHelper.assert_equal(audio_manager.click_stream, audio_manager.ui_click_player.stream, "Click stream assigned to player")
|
||||
TestHelper.assert_equal(
|
||||
audio_manager.click_stream,
|
||||
audio_manager.ui_click_player.stream,
|
||||
"Click stream assigned to player"
|
||||
)
|
||||
|
||||
# Test multiple rapid clicks (should not cause errors)
|
||||
for i in range(3):
|
||||
@@ -239,6 +301,7 @@ func test_ui_sound_effects():
|
||||
TestHelper.assert_true(true, "Null click stream handled safely")
|
||||
audio_manager.click_stream = backup_stream
|
||||
|
||||
|
||||
func test_stream_loop_configuration():
|
||||
TestHelper.print_step("Stream Loop Configuration")
|
||||
|
||||
@@ -250,7 +313,11 @@ func test_stream_loop_configuration():
|
||||
var has_loop_mode = "loop_mode" in music_stream
|
||||
TestHelper.assert_true(has_loop_mode, "WAV stream has loop_mode property")
|
||||
if has_loop_mode:
|
||||
TestHelper.assert_equal(AudioStreamWAV.LOOP_FORWARD, music_stream.loop_mode, "WAV stream set to forward loop")
|
||||
TestHelper.assert_equal(
|
||||
AudioStreamWAV.LOOP_FORWARD,
|
||||
music_stream.loop_mode,
|
||||
"WAV stream set to forward loop"
|
||||
)
|
||||
elif music_stream is AudioStreamOggVorbis:
|
||||
# For OGG files, check loop property
|
||||
var has_loop = "loop" in music_stream
|
||||
@@ -261,6 +328,7 @@ func test_stream_loop_configuration():
|
||||
# Test loop configuration for different stream types
|
||||
TestHelper.assert_true(true, "Stream loop configuration tested based on type")
|
||||
|
||||
|
||||
func test_error_handling():
|
||||
TestHelper.print_step("Error Handling")
|
||||
|
||||
@@ -268,11 +336,17 @@ func test_error_handling():
|
||||
# We can't actually break the resources in tests, but we can verify error handling patterns
|
||||
|
||||
# Test that AudioManager initializes even with potential issues
|
||||
TestHelper.assert_not_null(audio_manager, "AudioManager initializes despite potential resource issues")
|
||||
TestHelper.assert_not_null(
|
||||
audio_manager, "AudioManager initializes despite potential resource issues"
|
||||
)
|
||||
|
||||
# Test that players are still created even if streams fail to load
|
||||
TestHelper.assert_not_null(audio_manager.music_player, "Music player created regardless of stream loading")
|
||||
TestHelper.assert_not_null(audio_manager.ui_click_player, "UI click player created regardless of stream loading")
|
||||
TestHelper.assert_not_null(
|
||||
audio_manager.music_player, "Music player created regardless of stream loading"
|
||||
)
|
||||
TestHelper.assert_not_null(
|
||||
audio_manager.ui_click_player, "UI click player created regardless of stream loading"
|
||||
)
|
||||
|
||||
# Test null stream handling in play_ui_click
|
||||
var original_click_stream = audio_manager.click_stream
|
||||
@@ -292,6 +366,7 @@ func test_error_handling():
|
||||
audio_manager.update_music_volume(1.0)
|
||||
TestHelper.assert_true(true, "Maximum volume handled safely")
|
||||
|
||||
|
||||
func cleanup_tests():
|
||||
TestHelper.print_step("Cleanup")
|
||||
|
||||
@@ -303,4 +378,4 @@ func cleanup_tests():
|
||||
# Update AudioManager to original settings
|
||||
audio_manager.update_music_volume(original_music_volume)
|
||||
|
||||
TestHelper.assert_true(true, "Test cleanup completed")
|
||||
TestHelper.assert_true(true, "Test cleanup completed")
|
||||
|
||||
@@ -10,6 +10,7 @@ var game_manager: Node
|
||||
var original_scene: Node
|
||||
var test_scenes_created: Array[String] = []
|
||||
|
||||
|
||||
func _initialize():
|
||||
# Wait for autoloads to initialize
|
||||
await process_frame
|
||||
@@ -20,6 +21,7 @@ func _initialize():
|
||||
# Exit after tests complete
|
||||
quit()
|
||||
|
||||
|
||||
func run_tests():
|
||||
TestHelper.print_test_header("GameManager")
|
||||
|
||||
@@ -49,20 +51,34 @@ func run_tests():
|
||||
|
||||
TestHelper.print_test_footer("GameManager")
|
||||
|
||||
|
||||
func test_basic_functionality():
|
||||
TestHelper.print_step("Basic Functionality")
|
||||
|
||||
# Test that GameManager has expected properties
|
||||
TestHelper.assert_has_properties(game_manager, ["pending_gameplay_mode", "is_changing_scene"], "GameManager properties")
|
||||
TestHelper.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"]
|
||||
var expected_methods = [
|
||||
"start_new_game",
|
||||
"continue_game",
|
||||
"start_match3_game",
|
||||
"start_clickomania_game",
|
||||
"start_game_with_mode",
|
||||
"save_game",
|
||||
"exit_to_main_menu"
|
||||
]
|
||||
TestHelper.assert_has_methods(game_manager, expected_methods, "GameManager methods")
|
||||
|
||||
# Test initial state
|
||||
TestHelper.assert_equal("match3", game_manager.pending_gameplay_mode, "Default pending gameplay mode")
|
||||
TestHelper.assert_equal(
|
||||
"match3", game_manager.pending_gameplay_mode, "Default pending gameplay mode"
|
||||
)
|
||||
TestHelper.assert_false(game_manager.is_changing_scene, "Initial scene change flag")
|
||||
|
||||
|
||||
func test_scene_constants():
|
||||
TestHelper.print_step("Scene Path Constants")
|
||||
|
||||
@@ -83,6 +99,7 @@ func test_scene_constants():
|
||||
TestHelper.assert_true(ResourceLoader.exists(game_path), "Game scene file exists at path")
|
||||
TestHelper.assert_true(ResourceLoader.exists(main_path), "Main scene file exists at path")
|
||||
|
||||
|
||||
func test_input_validation():
|
||||
TestHelper.print_step("Input Validation")
|
||||
|
||||
@@ -92,24 +109,41 @@ func test_input_validation():
|
||||
|
||||
# Test empty string validation
|
||||
game_manager.start_game_with_mode("")
|
||||
TestHelper.assert_equal(original_mode, game_manager.pending_gameplay_mode, "Empty string mode rejected")
|
||||
TestHelper.assert_false(game_manager.is_changing_scene, "Scene change flag unchanged after empty mode")
|
||||
TestHelper.assert_equal(
|
||||
original_mode, game_manager.pending_gameplay_mode, "Empty string mode rejected"
|
||||
)
|
||||
TestHelper.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
|
||||
TestHelper.assert_equal(original_mode, game_manager.pending_gameplay_mode, "Mode preserved after empty string test")
|
||||
TestHelper.assert_false(game_manager.is_changing_scene, "Scene change flag unchanged after validation tests")
|
||||
TestHelper.assert_equal(
|
||||
original_mode, game_manager.pending_gameplay_mode, "Mode preserved after empty string test"
|
||||
)
|
||||
TestHelper.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")
|
||||
TestHelper.assert_equal(original_mode, game_manager.pending_gameplay_mode, "Invalid mode rejected")
|
||||
TestHelper.assert_false(game_manager.is_changing_scene, "Scene change flag unchanged after invalid mode")
|
||||
TestHelper.assert_equal(
|
||||
original_mode, game_manager.pending_gameplay_mode, "Invalid mode rejected"
|
||||
)
|
||||
TestHelper.assert_false(
|
||||
game_manager.is_changing_scene, "Scene change flag unchanged after invalid mode"
|
||||
)
|
||||
|
||||
# Test case sensitivity
|
||||
game_manager.start_game_with_mode("MATCH3")
|
||||
TestHelper.assert_equal(original_mode, game_manager.pending_gameplay_mode, "Case-sensitive mode validation")
|
||||
TestHelper.assert_false(game_manager.is_changing_scene, "Scene change flag unchanged after wrong case")
|
||||
TestHelper.assert_equal(
|
||||
original_mode, game_manager.pending_gameplay_mode, "Case-sensitive mode validation"
|
||||
)
|
||||
TestHelper.assert_false(
|
||||
game_manager.is_changing_scene, "Scene change flag unchanged after wrong case"
|
||||
)
|
||||
|
||||
|
||||
func test_race_condition_protection():
|
||||
TestHelper.print_step("Race Condition Protection")
|
||||
@@ -122,16 +156,21 @@ func test_race_condition_protection():
|
||||
game_manager.start_game_with_mode("match3")
|
||||
|
||||
# Verify second request was rejected
|
||||
TestHelper.assert_equal(original_mode, game_manager.pending_gameplay_mode, "Concurrent scene change blocked")
|
||||
TestHelper.assert_equal(
|
||||
original_mode, game_manager.pending_gameplay_mode, "Concurrent scene change blocked"
|
||||
)
|
||||
TestHelper.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()
|
||||
TestHelper.assert_true(game_manager.is_changing_scene, "Exit request blocked during scene change")
|
||||
TestHelper.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():
|
||||
TestHelper.print_step("Gameplay Mode Validation")
|
||||
|
||||
@@ -152,6 +191,7 @@ func test_gameplay_mode_validation():
|
||||
var test_mode_invalid = not (mode in ["match3", "clickomania"])
|
||||
TestHelper.assert_true(test_mode_invalid, "Invalid mode rejected: " + mode)
|
||||
|
||||
|
||||
func test_scene_transition_safety():
|
||||
TestHelper.print_step("Scene Transition Safety")
|
||||
|
||||
@@ -171,6 +211,7 @@ func test_scene_transition_safety():
|
||||
# Test that current scene exists
|
||||
TestHelper.assert_not_null(current_scene, "Current scene exists")
|
||||
|
||||
|
||||
func test_error_handling():
|
||||
TestHelper.print_step("Error Handling")
|
||||
|
||||
@@ -184,12 +225,23 @@ func test_error_handling():
|
||||
|
||||
# Verify state preservation after invalid inputs
|
||||
game_manager.start_game_with_mode("")
|
||||
TestHelper.assert_equal(original_changing, game_manager.is_changing_scene, "State preserved after empty mode error")
|
||||
TestHelper.assert_equal(original_mode, game_manager.pending_gameplay_mode, "Mode preserved after empty mode error")
|
||||
TestHelper.assert_equal(
|
||||
original_changing, game_manager.is_changing_scene, "State preserved after empty mode error"
|
||||
)
|
||||
TestHelper.assert_equal(
|
||||
original_mode, game_manager.pending_gameplay_mode, "Mode preserved after empty mode error"
|
||||
)
|
||||
|
||||
game_manager.start_game_with_mode("invalid")
|
||||
TestHelper.assert_equal(original_changing, game_manager.is_changing_scene, "State preserved after invalid mode error")
|
||||
TestHelper.assert_equal(original_mode, game_manager.pending_gameplay_mode, "Mode preserved after invalid mode error")
|
||||
TestHelper.assert_equal(
|
||||
original_changing,
|
||||
game_manager.is_changing_scene,
|
||||
"State preserved after invalid mode error"
|
||||
)
|
||||
TestHelper.assert_equal(
|
||||
original_mode, game_manager.pending_gameplay_mode, "Mode preserved after invalid mode error"
|
||||
)
|
||||
|
||||
|
||||
func test_scene_method_validation():
|
||||
TestHelper.print_step("Scene Method Validation")
|
||||
@@ -210,6 +262,7 @@ func test_scene_method_validation():
|
||||
# Clean up mock scene
|
||||
mock_scene.queue_free()
|
||||
|
||||
|
||||
func test_pending_mode_management():
|
||||
TestHelper.print_step("Pending Mode Management")
|
||||
|
||||
@@ -222,7 +275,9 @@ func test_pending_mode_management():
|
||||
if test_mode in ["match3", "clickomania"]:
|
||||
# This simulates what would happen in start_game_with_mode
|
||||
game_manager.pending_gameplay_mode = test_mode
|
||||
TestHelper.assert_equal(test_mode, game_manager.pending_gameplay_mode, "Pending mode set correctly")
|
||||
TestHelper.assert_equal(
|
||||
test_mode, game_manager.pending_gameplay_mode, "Pending mode set correctly"
|
||||
)
|
||||
|
||||
# Test mode preservation during errors
|
||||
game_manager.pending_gameplay_mode = "match3"
|
||||
@@ -230,11 +285,16 @@ func test_pending_mode_management():
|
||||
|
||||
# Attempt invalid operation (this should not change pending mode)
|
||||
# The actual start_game_with_mode with invalid input won't change pending_gameplay_mode
|
||||
TestHelper.assert_equal(preserved_mode, game_manager.pending_gameplay_mode, "Mode preserved during invalid operations")
|
||||
TestHelper.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():
|
||||
TestHelper.print_step("Cleanup")
|
||||
|
||||
@@ -248,4 +308,4 @@ func cleanup_tests():
|
||||
# Note: Can't actually delete from res:// in tests, just track for manual cleanup
|
||||
pass
|
||||
|
||||
TestHelper.assert_true(true, "Test cleanup completed")
|
||||
TestHelper.assert_true(true, "Test cleanup completed")
|
||||
|
||||
@@ -4,12 +4,14 @@ extends SceneTree
|
||||
# This script validates all log levels, filtering, and formatting functionality
|
||||
# Usage: Add to scene or autoload temporarily to run tests
|
||||
|
||||
|
||||
func _initialize():
|
||||
# Wait a frame for debug_manager to initialize
|
||||
await process_frame
|
||||
test_logging_system()
|
||||
quit()
|
||||
|
||||
|
||||
func test_logging_system():
|
||||
print("=== Starting Logging System Tests ===")
|
||||
|
||||
@@ -30,6 +32,7 @@ func test_logging_system():
|
||||
|
||||
print("=== Logging System Tests Complete ===")
|
||||
|
||||
|
||||
func test_basic_logging(debug_manager):
|
||||
print("\n--- Test 1: Basic Log Level Functionality ---")
|
||||
|
||||
@@ -43,6 +46,7 @@ func test_basic_logging(debug_manager):
|
||||
debug_manager.log_error("ERROR: This error should appear")
|
||||
debug_manager.log_fatal("FATAL: This fatal error should appear")
|
||||
|
||||
|
||||
func test_log_level_filtering(debug_manager):
|
||||
print("\n--- Test 2: Log Level Filtering ---")
|
||||
|
||||
@@ -64,6 +68,7 @@ func test_log_level_filtering(debug_manager):
|
||||
# Reset to INFO for remaining tests
|
||||
debug_manager.set_log_level(debug_manager.LogLevel.INFO)
|
||||
|
||||
|
||||
func test_category_logging(debug_manager):
|
||||
print("\n--- Test 3: Category Functionality ---")
|
||||
|
||||
@@ -73,6 +78,7 @@ func test_category_logging(debug_manager):
|
||||
debug_manager.log_warn("Warning with VALIDATION category", "VALIDATION")
|
||||
debug_manager.log_error("Error with SYSTEM category", "SYSTEM")
|
||||
|
||||
|
||||
func test_debug_mode_integration(debug_manager):
|
||||
print("\n--- Test 4: Debug Mode Integration ---")
|
||||
|
||||
@@ -99,6 +105,7 @@ func test_debug_mode_integration(debug_manager):
|
||||
debug_manager.set_debug_enabled(original_debug_state)
|
||||
debug_manager.set_log_level(debug_manager.LogLevel.INFO)
|
||||
|
||||
|
||||
# Helper function to validate log level enum values
|
||||
func test_log_level_enum(debug_manager):
|
||||
print("\n--- Log Level Enum Values ---")
|
||||
|
||||
@@ -10,6 +10,7 @@ var match3_scene: PackedScene
|
||||
var match3_instance: Node2D
|
||||
var test_viewport: SubViewport
|
||||
|
||||
|
||||
func _initialize():
|
||||
# Wait for autoloads to initialize
|
||||
await process_frame
|
||||
@@ -20,6 +21,7 @@ func _initialize():
|
||||
# Exit after tests complete
|
||||
quit()
|
||||
|
||||
|
||||
func run_tests():
|
||||
TestHelper.print_test_header("Match3 Gameplay")
|
||||
|
||||
@@ -43,6 +45,7 @@ func run_tests():
|
||||
|
||||
TestHelper.print_test_footer("Match3 Gameplay")
|
||||
|
||||
|
||||
func setup_test_environment():
|
||||
TestHelper.print_step("Test Environment Setup")
|
||||
|
||||
@@ -65,6 +68,7 @@ func setup_test_environment():
|
||||
await process_frame
|
||||
await process_frame
|
||||
|
||||
|
||||
func test_basic_functionality():
|
||||
TestHelper.print_step("Basic Functionality")
|
||||
|
||||
@@ -73,17 +77,26 @@ func test_basic_functionality():
|
||||
return
|
||||
|
||||
# Test that Match3 has expected properties
|
||||
var expected_properties = ["GRID_SIZE", "TILE_TYPES", "grid", "current_state", "selected_tile", "cursor_position"]
|
||||
var expected_properties = [
|
||||
"GRID_SIZE", "TILE_TYPES", "grid", "current_state", "selected_tile", "cursor_position"
|
||||
]
|
||||
for prop in expected_properties:
|
||||
TestHelper.assert_true(prop in match3_instance, "Match3 has property: " + prop)
|
||||
|
||||
# Test that Match3 has expected methods
|
||||
var expected_methods = ["_has_match_at", "_check_for_matches", "_get_match_line", "_clear_matches"]
|
||||
var expected_methods = [
|
||||
"_has_match_at", "_check_for_matches", "_get_match_line", "_clear_matches"
|
||||
]
|
||||
TestHelper.assert_has_methods(match3_instance, expected_methods, "Match3 gameplay methods")
|
||||
|
||||
# Test signals
|
||||
TestHelper.assert_true(match3_instance.has_signal("score_changed"), "Match3 has score_changed signal")
|
||||
TestHelper.assert_true(match3_instance.has_signal("grid_state_loaded"), "Match3 has grid_state_loaded signal")
|
||||
TestHelper.assert_true(
|
||||
match3_instance.has_signal("score_changed"), "Match3 has score_changed signal"
|
||||
)
|
||||
TestHelper.assert_true(
|
||||
match3_instance.has_signal("grid_state_loaded"), "Match3 has grid_state_loaded signal"
|
||||
)
|
||||
|
||||
|
||||
func test_constants_and_safety_limits():
|
||||
TestHelper.print_step("Constants and Safety Limits")
|
||||
@@ -94,26 +107,52 @@ func test_constants_and_safety_limits():
|
||||
# Test safety constants exist
|
||||
TestHelper.assert_true("MAX_GRID_SIZE" in match3_instance, "MAX_GRID_SIZE constant exists")
|
||||
TestHelper.assert_true("MAX_TILE_TYPES" in match3_instance, "MAX_TILE_TYPES constant exists")
|
||||
TestHelper.assert_true("MAX_CASCADE_ITERATIONS" in match3_instance, "MAX_CASCADE_ITERATIONS constant exists")
|
||||
TestHelper.assert_true(
|
||||
"MAX_CASCADE_ITERATIONS" in match3_instance, "MAX_CASCADE_ITERATIONS constant exists"
|
||||
)
|
||||
TestHelper.assert_true("MIN_GRID_SIZE" in match3_instance, "MIN_GRID_SIZE constant exists")
|
||||
TestHelper.assert_true("MIN_TILE_TYPES" in match3_instance, "MIN_TILE_TYPES constant exists")
|
||||
|
||||
# Test safety limit values are reasonable
|
||||
TestHelper.assert_equal(15, match3_instance.MAX_GRID_SIZE, "MAX_GRID_SIZE is reasonable")
|
||||
TestHelper.assert_equal(10, match3_instance.MAX_TILE_TYPES, "MAX_TILE_TYPES is reasonable")
|
||||
TestHelper.assert_equal(20, match3_instance.MAX_CASCADE_ITERATIONS, "MAX_CASCADE_ITERATIONS prevents infinite loops")
|
||||
TestHelper.assert_equal(
|
||||
20, match3_instance.MAX_CASCADE_ITERATIONS, "MAX_CASCADE_ITERATIONS prevents infinite loops"
|
||||
)
|
||||
TestHelper.assert_equal(3, match3_instance.MIN_GRID_SIZE, "MIN_GRID_SIZE is reasonable")
|
||||
TestHelper.assert_equal(3, match3_instance.MIN_TILE_TYPES, "MIN_TILE_TYPES is reasonable")
|
||||
|
||||
# Test current values are within safety limits
|
||||
TestHelper.assert_in_range(match3_instance.GRID_SIZE.x, match3_instance.MIN_GRID_SIZE, match3_instance.MAX_GRID_SIZE, "Grid width within safety limits")
|
||||
TestHelper.assert_in_range(match3_instance.GRID_SIZE.y, match3_instance.MIN_GRID_SIZE, match3_instance.MAX_GRID_SIZE, "Grid height within safety limits")
|
||||
TestHelper.assert_in_range(match3_instance.TILE_TYPES, match3_instance.MIN_TILE_TYPES, match3_instance.MAX_TILE_TYPES, "Tile types within safety limits")
|
||||
TestHelper.assert_in_range(
|
||||
match3_instance.GRID_SIZE.x,
|
||||
match3_instance.MIN_GRID_SIZE,
|
||||
match3_instance.MAX_GRID_SIZE,
|
||||
"Grid width within safety limits"
|
||||
)
|
||||
TestHelper.assert_in_range(
|
||||
match3_instance.GRID_SIZE.y,
|
||||
match3_instance.MIN_GRID_SIZE,
|
||||
match3_instance.MAX_GRID_SIZE,
|
||||
"Grid height within safety limits"
|
||||
)
|
||||
TestHelper.assert_in_range(
|
||||
match3_instance.TILE_TYPES,
|
||||
match3_instance.MIN_TILE_TYPES,
|
||||
match3_instance.MAX_TILE_TYPES,
|
||||
"Tile types within safety limits"
|
||||
)
|
||||
|
||||
# Test timing constants
|
||||
TestHelper.assert_true("CASCADE_WAIT_TIME" in match3_instance, "CASCADE_WAIT_TIME constant exists")
|
||||
TestHelper.assert_true("SWAP_ANIMATION_TIME" in match3_instance, "SWAP_ANIMATION_TIME constant exists")
|
||||
TestHelper.assert_true("TILE_DROP_WAIT_TIME" in match3_instance, "TILE_DROP_WAIT_TIME constant exists")
|
||||
TestHelper.assert_true(
|
||||
"CASCADE_WAIT_TIME" in match3_instance, "CASCADE_WAIT_TIME constant exists"
|
||||
)
|
||||
TestHelper.assert_true(
|
||||
"SWAP_ANIMATION_TIME" in match3_instance, "SWAP_ANIMATION_TIME constant exists"
|
||||
)
|
||||
TestHelper.assert_true(
|
||||
"TILE_DROP_WAIT_TIME" in match3_instance, "TILE_DROP_WAIT_TIME constant exists"
|
||||
)
|
||||
|
||||
|
||||
func test_grid_initialization():
|
||||
TestHelper.print_step("Grid Initialization")
|
||||
@@ -134,7 +173,9 @@ func test_grid_initialization():
|
||||
# Test each row has correct width
|
||||
for y in range(match3_instance.grid.size()):
|
||||
if y < expected_height:
|
||||
TestHelper.assert_equal(expected_width, match3_instance.grid[y].size(), "Grid row %d has correct width" % y)
|
||||
TestHelper.assert_equal(
|
||||
expected_width, match3_instance.grid[y].size(), "Grid row %d has correct width" % y
|
||||
)
|
||||
|
||||
# Test tiles are properly instantiated
|
||||
var tile_count = 0
|
||||
@@ -147,15 +188,25 @@ func test_grid_initialization():
|
||||
|
||||
if tile and is_instance_valid(tile):
|
||||
valid_tile_count += 1
|
||||
TestHelper.assert_true("tile_type" in tile, "Tile at (%d,%d) has tile_type property" % [x, y])
|
||||
TestHelper.assert_true("grid_position" in tile, "Tile at (%d,%d) has grid_position property" % [x, y])
|
||||
TestHelper.assert_true(
|
||||
"tile_type" in tile, "Tile at (%d,%d) has tile_type property" % [x, y]
|
||||
)
|
||||
TestHelper.assert_true(
|
||||
"grid_position" in tile, "Tile at (%d,%d) has grid_position property" % [x, y]
|
||||
)
|
||||
|
||||
# Test tile type is within valid range
|
||||
if "tile_type" in tile:
|
||||
TestHelper.assert_in_range(tile.tile_type, 0, match3_instance.TILE_TYPES - 1, "Tile type in valid range")
|
||||
TestHelper.assert_in_range(
|
||||
tile.tile_type,
|
||||
0,
|
||||
match3_instance.TILE_TYPES - 1,
|
||||
"Tile type in valid range"
|
||||
)
|
||||
|
||||
TestHelper.assert_equal(tile_count, valid_tile_count, "All grid positions have valid tiles")
|
||||
|
||||
|
||||
func test_grid_layout_calculation():
|
||||
TestHelper.print_step("Grid Layout Calculation")
|
||||
|
||||
@@ -164,7 +215,9 @@ func test_grid_layout_calculation():
|
||||
|
||||
# Test tile size calculation
|
||||
TestHelper.assert_true(match3_instance.tile_size > 0, "Tile size is positive")
|
||||
TestHelper.assert_true(match3_instance.tile_size <= 200, "Tile size is reasonable (not too large)")
|
||||
TestHelper.assert_true(
|
||||
match3_instance.tile_size <= 200, "Tile size is reasonable (not too large)"
|
||||
)
|
||||
|
||||
# Test grid offset
|
||||
TestHelper.assert_not_null(match3_instance.grid_offset, "Grid offset is set")
|
||||
@@ -173,10 +226,13 @@ func test_grid_layout_calculation():
|
||||
|
||||
# Test layout constants
|
||||
TestHelper.assert_equal(0.8, match3_instance.SCREEN_WIDTH_USAGE, "Screen width usage constant")
|
||||
TestHelper.assert_equal(0.7, match3_instance.SCREEN_HEIGHT_USAGE, "Screen height usage constant")
|
||||
TestHelper.assert_equal(
|
||||
0.7, match3_instance.SCREEN_HEIGHT_USAGE, "Screen height usage constant"
|
||||
)
|
||||
TestHelper.assert_equal(50.0, match3_instance.GRID_LEFT_MARGIN, "Grid left margin constant")
|
||||
TestHelper.assert_equal(50.0, match3_instance.GRID_TOP_MARGIN, "Grid top margin constant")
|
||||
|
||||
|
||||
func test_state_management():
|
||||
TestHelper.print_step("State Management")
|
||||
|
||||
@@ -196,7 +252,10 @@ func test_state_management():
|
||||
|
||||
# Test instance ID for debugging
|
||||
TestHelper.assert_true("instance_id" in match3_instance, "Instance ID exists for debugging")
|
||||
TestHelper.assert_true(match3_instance.instance_id.begins_with("Match3_"), "Instance ID has correct format")
|
||||
TestHelper.assert_true(
|
||||
match3_instance.instance_id.begins_with("Match3_"), "Instance ID has correct format"
|
||||
)
|
||||
|
||||
|
||||
func test_match_detection():
|
||||
TestHelper.print_step("Match Detection Logic")
|
||||
@@ -205,9 +264,15 @@ func test_match_detection():
|
||||
return
|
||||
|
||||
# Test match detection methods exist and can be called safely
|
||||
TestHelper.assert_true(match3_instance.has_method("_has_match_at"), "_has_match_at method exists")
|
||||
TestHelper.assert_true(match3_instance.has_method("_check_for_matches"), "_check_for_matches method exists")
|
||||
TestHelper.assert_true(match3_instance.has_method("_get_match_line"), "_get_match_line method exists")
|
||||
TestHelper.assert_true(
|
||||
match3_instance.has_method("_has_match_at"), "_has_match_at method exists"
|
||||
)
|
||||
TestHelper.assert_true(
|
||||
match3_instance.has_method("_check_for_matches"), "_check_for_matches method exists"
|
||||
)
|
||||
TestHelper.assert_true(
|
||||
match3_instance.has_method("_get_match_line"), "_get_match_line method exists"
|
||||
)
|
||||
|
||||
# Test boundary checking with invalid positions
|
||||
var invalid_positions = [
|
||||
@@ -227,7 +292,10 @@ func test_match_detection():
|
||||
for x in range(min(3, match3_instance.GRID_SIZE.x)):
|
||||
var pos = Vector2i(x, y)
|
||||
var result = match3_instance._has_match_at(pos)
|
||||
TestHelper.assert_true(result is bool, "Valid position (%d,%d) returns boolean" % [x, y])
|
||||
TestHelper.assert_true(
|
||||
result is bool, "Valid position (%d,%d) returns boolean" % [x, y]
|
||||
)
|
||||
|
||||
|
||||
func test_scoring_system():
|
||||
TestHelper.print_step("Scoring System")
|
||||
@@ -239,18 +307,17 @@ func test_scoring_system():
|
||||
# The scoring system uses: 3 gems = 3 points, 4+ gems = n + (n-2) points
|
||||
|
||||
# Test that the match3 instance can handle scoring (indirectly through clearing matches)
|
||||
TestHelper.assert_true(match3_instance.has_method("_clear_matches"), "Scoring system method exists")
|
||||
TestHelper.assert_true(
|
||||
match3_instance.has_method("_clear_matches"), "Scoring system method exists"
|
||||
)
|
||||
|
||||
# Test that score_changed signal exists
|
||||
TestHelper.assert_true(match3_instance.has_signal("score_changed"), "Score changed signal exists")
|
||||
TestHelper.assert_true(
|
||||
match3_instance.has_signal("score_changed"), "Score changed signal exists"
|
||||
)
|
||||
|
||||
# Test scoring formula logic (based on the documented formula)
|
||||
var test_scores = {
|
||||
3: 3, # 3 gems = exactly 3 points
|
||||
4: 6, # 4 gems = 4 + (4-2) = 6 points
|
||||
5: 8, # 5 gems = 5 + (5-2) = 8 points
|
||||
6: 10 # 6 gems = 6 + (6-2) = 10 points
|
||||
}
|
||||
var test_scores = {3: 3, 4: 6, 5: 8, 6: 10} # 3 gems = exactly 3 points # 4 gems = 4 + (4-2) = 6 points # 5 gems = 5 + (5-2) = 8 points # 6 gems = 6 + (6-2) = 10 points
|
||||
|
||||
for match_size in test_scores.keys():
|
||||
var expected_score = test_scores[match_size]
|
||||
@@ -260,7 +327,10 @@ func test_scoring_system():
|
||||
else:
|
||||
calculated_score = match_size + max(0, match_size - 2)
|
||||
|
||||
TestHelper.assert_equal(expected_score, calculated_score, "Scoring formula correct for %d gems" % match_size)
|
||||
TestHelper.assert_equal(
|
||||
expected_score, calculated_score, "Scoring formula correct for %d gems" % match_size
|
||||
)
|
||||
|
||||
|
||||
func test_input_validation():
|
||||
TestHelper.print_step("Input Validation")
|
||||
@@ -270,16 +340,25 @@ func test_input_validation():
|
||||
|
||||
# Test cursor position bounds
|
||||
TestHelper.assert_not_null(match3_instance.cursor_position, "Cursor position is initialized")
|
||||
TestHelper.assert_true(match3_instance.cursor_position is Vector2i, "Cursor position is Vector2i type")
|
||||
TestHelper.assert_true(
|
||||
match3_instance.cursor_position is Vector2i, "Cursor position is Vector2i type"
|
||||
)
|
||||
|
||||
# Test keyboard navigation flag
|
||||
TestHelper.assert_true("keyboard_navigation_enabled" in match3_instance, "Keyboard navigation flag exists")
|
||||
TestHelper.assert_true(match3_instance.keyboard_navigation_enabled is bool, "Keyboard navigation flag is boolean")
|
||||
TestHelper.assert_true(
|
||||
"keyboard_navigation_enabled" in match3_instance, "Keyboard navigation flag exists"
|
||||
)
|
||||
TestHelper.assert_true(
|
||||
match3_instance.keyboard_navigation_enabled is bool, "Keyboard navigation flag is boolean"
|
||||
)
|
||||
|
||||
# Test selected tile safety
|
||||
# selected_tile can be null initially, which is valid
|
||||
if match3_instance.selected_tile:
|
||||
TestHelper.assert_true(is_instance_valid(match3_instance.selected_tile), "Selected tile is valid if not null")
|
||||
TestHelper.assert_true(
|
||||
is_instance_valid(match3_instance.selected_tile), "Selected tile is valid if not null"
|
||||
)
|
||||
|
||||
|
||||
func test_memory_safety():
|
||||
TestHelper.print_step("Memory Safety")
|
||||
@@ -288,23 +367,33 @@ func test_memory_safety():
|
||||
return
|
||||
|
||||
# Test grid integrity validation
|
||||
TestHelper.assert_true(match3_instance.has_method("_validate_grid_integrity"), "Grid integrity validation method exists")
|
||||
TestHelper.assert_true(
|
||||
match3_instance.has_method("_validate_grid_integrity"),
|
||||
"Grid integrity validation method exists"
|
||||
)
|
||||
|
||||
# Test tile validity checking
|
||||
for y in range(min(3, match3_instance.grid.size())):
|
||||
for x in range(min(3, match3_instance.grid[y].size())):
|
||||
var tile = match3_instance.grid[y][x]
|
||||
if tile:
|
||||
TestHelper.assert_true(is_instance_valid(tile), "Grid tile at (%d,%d) is valid instance" % [x, y])
|
||||
TestHelper.assert_true(tile.get_parent() == match3_instance, "Tile properly parented to Match3")
|
||||
TestHelper.assert_true(
|
||||
is_instance_valid(tile), "Grid tile at (%d,%d) is valid instance" % [x, y]
|
||||
)
|
||||
TestHelper.assert_true(
|
||||
tile.get_parent() == match3_instance, "Tile properly parented to Match3"
|
||||
)
|
||||
|
||||
# Test position validation
|
||||
TestHelper.assert_true(match3_instance.has_method("_is_valid_grid_position"), "Position validation method exists")
|
||||
TestHelper.assert_true(
|
||||
match3_instance.has_method("_is_valid_grid_position"), "Position validation method exists"
|
||||
)
|
||||
|
||||
# Test safe tile access patterns exist
|
||||
# The Match3 code uses comprehensive bounds checking and null validation
|
||||
TestHelper.assert_true(true, "Memory safety patterns implemented in Match3 code")
|
||||
|
||||
|
||||
func test_performance_requirements():
|
||||
TestHelper.print_step("Performance Requirements")
|
||||
|
||||
@@ -316,12 +405,22 @@ func test_performance_requirements():
|
||||
TestHelper.assert_true(total_tiles <= 225, "Total tiles within performance limit (15x15=225)")
|
||||
|
||||
# Test cascade iteration limit prevents infinite loops
|
||||
TestHelper.assert_equal(20, match3_instance.MAX_CASCADE_ITERATIONS, "Cascade iteration limit prevents infinite loops")
|
||||
TestHelper.assert_equal(
|
||||
20,
|
||||
match3_instance.MAX_CASCADE_ITERATIONS,
|
||||
"Cascade iteration limit prevents infinite loops"
|
||||
)
|
||||
|
||||
# Test timing constants are reasonable for 60fps gameplay
|
||||
TestHelper.assert_true(match3_instance.CASCADE_WAIT_TIME >= 0.05, "Cascade wait time allows for smooth animation")
|
||||
TestHelper.assert_true(match3_instance.SWAP_ANIMATION_TIME <= 0.5, "Swap animation time is responsive")
|
||||
TestHelper.assert_true(match3_instance.TILE_DROP_WAIT_TIME <= 0.3, "Tile drop wait time is responsive")
|
||||
TestHelper.assert_true(
|
||||
match3_instance.CASCADE_WAIT_TIME >= 0.05, "Cascade wait time allows for smooth animation"
|
||||
)
|
||||
TestHelper.assert_true(
|
||||
match3_instance.SWAP_ANIMATION_TIME <= 0.5, "Swap animation time is responsive"
|
||||
)
|
||||
TestHelper.assert_true(
|
||||
match3_instance.TILE_DROP_WAIT_TIME <= 0.3, "Tile drop wait time is responsive"
|
||||
)
|
||||
|
||||
# Test grid initialization performance
|
||||
TestHelper.start_performance_test("grid_access")
|
||||
@@ -332,6 +431,7 @@ func test_performance_requirements():
|
||||
var tile_type = tile.tile_type
|
||||
TestHelper.end_performance_test("grid_access", 10.0, "Grid access performance within limits")
|
||||
|
||||
|
||||
func cleanup_tests():
|
||||
TestHelper.print_step("Cleanup")
|
||||
|
||||
@@ -346,4 +446,4 @@ func cleanup_tests():
|
||||
# Wait for cleanup
|
||||
await process_frame
|
||||
|
||||
TestHelper.assert_true(true, "Test cleanup completed")
|
||||
TestHelper.assert_true(true, "Test cleanup completed")
|
||||
|
||||
@@ -5,6 +5,7 @@ extends SceneTree
|
||||
|
||||
const TestHelper = preload("res://tests/helpers/TestHelper.gd")
|
||||
|
||||
|
||||
func _initialize():
|
||||
# Wait for autoloads to initialize
|
||||
await process_frame
|
||||
@@ -15,11 +16,13 @@ func _initialize():
|
||||
# Exit after tests complete
|
||||
quit()
|
||||
|
||||
|
||||
func run_tests():
|
||||
TestHelper.print_test_header("Migration Compatibility")
|
||||
test_migration_compatibility()
|
||||
TestHelper.print_test_footer("Migration Compatibility")
|
||||
|
||||
|
||||
func test_migration_compatibility():
|
||||
TestHelper.print_step("Old Save File Compatibility")
|
||||
var old_save_data = {
|
||||
@@ -28,7 +31,8 @@ func test_migration_compatibility():
|
||||
"current_score": 0,
|
||||
"games_played": 5,
|
||||
"total_score": 450,
|
||||
"grid_state": {
|
||||
"grid_state":
|
||||
{
|
||||
"grid_size": {"x": 8, "y": 8},
|
||||
"tile_types_count": 5,
|
||||
"active_gem_types": [0, 1, 2, 3, 4],
|
||||
@@ -53,7 +57,9 @@ func test_migration_compatibility():
|
||||
print("New checksum format: %s" % new_checksum)
|
||||
|
||||
# The checksums should be different (old system broken)
|
||||
TestHelper.assert_not_equal(old_checksum, new_checksum, "Old and new checksum formats should be different")
|
||||
TestHelper.assert_not_equal(
|
||||
old_checksum, new_checksum, "Old and new checksum formats should be different"
|
||||
)
|
||||
print("Old checksum: %s" % old_checksum)
|
||||
print("New checksum: %s" % new_checksum)
|
||||
|
||||
@@ -71,7 +77,11 @@ func test_migration_compatibility():
|
||||
|
||||
var second_checksum = _calculate_new_checksum(reloaded_data)
|
||||
|
||||
TestHelper.assert_equal(first_checksum, second_checksum, "New system should be self-consistent across save/load cycles")
|
||||
TestHelper.assert_equal(
|
||||
first_checksum,
|
||||
second_checksum,
|
||||
"New system should be self-consistent across save/load cycles"
|
||||
)
|
||||
print("Consistent checksum: %s" % first_checksum)
|
||||
|
||||
TestHelper.print_step("Migration Strategy Verification")
|
||||
@@ -80,6 +90,7 @@ func test_migration_compatibility():
|
||||
print("✓ Files with version < current: Recalculate checksum after migration")
|
||||
print("✓ Files with current version: Use new checksum validation")
|
||||
|
||||
|
||||
# Simulate old checksum calculation (before the fix)
|
||||
func _calculate_old_checksum(data: Dictionary) -> String:
|
||||
# Old broken checksum (without normalization)
|
||||
@@ -88,6 +99,7 @@ func _calculate_old_checksum(data: Dictionary) -> String:
|
||||
var old_string = JSON.stringify(data_copy) # Direct JSON without normalization
|
||||
return str(old_string.hash())
|
||||
|
||||
|
||||
# Implement new checksum calculation (the fixed version with normalization)
|
||||
func _calculate_new_checksum(data: Dictionary) -> String:
|
||||
# Calculate deterministic checksum EXCLUDING the checksum field itself
|
||||
@@ -97,6 +109,7 @@ func _calculate_new_checksum(data: Dictionary) -> String:
|
||||
var checksum_string = _create_deterministic_string(data_copy)
|
||||
return str(checksum_string.hash())
|
||||
|
||||
|
||||
func _create_deterministic_string(data: Dictionary) -> String:
|
||||
# Create a deterministic string representation by processing keys in sorted order
|
||||
var keys = data.keys()
|
||||
@@ -116,6 +129,7 @@ func _create_deterministic_string(data: Dictionary) -> String:
|
||||
parts.append(key_str + ":" + value_str)
|
||||
return "{" + ",".join(parts) + "}"
|
||||
|
||||
|
||||
func _create_deterministic_array_string(arr: Array) -> String:
|
||||
var parts = []
|
||||
for item in arr:
|
||||
@@ -128,6 +142,7 @@ func _create_deterministic_array_string(arr: Array) -> String:
|
||||
parts.append(_normalize_value_for_checksum(item))
|
||||
return "[" + ",".join(parts) + "]"
|
||||
|
||||
|
||||
func _normalize_value_for_checksum(value) -> String:
|
||||
"""
|
||||
CRITICAL FIX: Normalize values for consistent checksum calculation
|
||||
|
||||
@@ -10,6 +10,7 @@ const TestHelper = preload("res://tests/helpers/TestHelper.gd")
|
||||
var discovered_scenes: Array[String] = []
|
||||
var validation_results: Dictionary = {}
|
||||
|
||||
|
||||
func _initialize():
|
||||
# Wait for autoloads to initialize
|
||||
await process_frame
|
||||
@@ -20,6 +21,7 @@ func _initialize():
|
||||
# Exit after tests complete
|
||||
quit()
|
||||
|
||||
|
||||
func run_tests():
|
||||
TestHelper.print_test_header("Scene Validation")
|
||||
|
||||
@@ -34,14 +36,12 @@ func run_tests():
|
||||
|
||||
TestHelper.print_test_footer("Scene Validation")
|
||||
|
||||
|
||||
func test_scene_discovery():
|
||||
TestHelper.print_step("Scene Discovery")
|
||||
|
||||
# Discover scenes in key directories
|
||||
var scene_directories = [
|
||||
"res://scenes/",
|
||||
"res://examples/"
|
||||
]
|
||||
var scene_directories = ["res://scenes/", "res://examples/"]
|
||||
|
||||
for directory in scene_directories:
|
||||
discover_scenes_in_directory(directory)
|
||||
@@ -53,6 +53,7 @@ func test_scene_discovery():
|
||||
for scene_path in discovered_scenes:
|
||||
print(" - %s" % scene_path)
|
||||
|
||||
|
||||
func discover_scenes_in_directory(directory_path: String):
|
||||
var dir = DirAccess.open(directory_path)
|
||||
if not dir:
|
||||
@@ -74,12 +75,14 @@ func discover_scenes_in_directory(directory_path: String):
|
||||
|
||||
file_name = dir.get_next()
|
||||
|
||||
|
||||
func test_scene_loading():
|
||||
TestHelper.print_step("Scene Loading Validation")
|
||||
|
||||
for scene_path in discovered_scenes:
|
||||
validate_scene_loading(scene_path)
|
||||
|
||||
|
||||
func validate_scene_loading(scene_path: String):
|
||||
var scene_name = scene_path.get_file()
|
||||
|
||||
@@ -104,6 +107,7 @@ func validate_scene_loading(scene_path: String):
|
||||
validation_results[scene_path] = "Loading successful"
|
||||
TestHelper.assert_true(true, "%s - Scene loads successfully" % scene_name)
|
||||
|
||||
|
||||
func test_scene_instantiation():
|
||||
TestHelper.print_step("Scene Instantiation Testing")
|
||||
|
||||
@@ -112,6 +116,7 @@ func test_scene_instantiation():
|
||||
if validation_results.get(scene_path, "") == "Loading successful":
|
||||
validate_scene_instantiation(scene_path)
|
||||
|
||||
|
||||
func validate_scene_instantiation(scene_path: String):
|
||||
var scene_name = scene_path.get_file()
|
||||
|
||||
@@ -126,7 +131,9 @@ func validate_scene_instantiation(scene_path: String):
|
||||
return
|
||||
|
||||
# Validate the instance
|
||||
TestHelper.assert_not_null(scene_instance, "%s - Scene instantiation creates valid node" % scene_name)
|
||||
TestHelper.assert_not_null(
|
||||
scene_instance, "%s - Scene instantiation creates valid node" % scene_name
|
||||
)
|
||||
|
||||
# Clean up the instance
|
||||
scene_instance.queue_free()
|
||||
@@ -135,6 +142,7 @@ func validate_scene_instantiation(scene_path: String):
|
||||
if validation_results[scene_path] == "Loading successful":
|
||||
validation_results[scene_path] = "Full validation successful"
|
||||
|
||||
|
||||
func test_critical_scenes():
|
||||
TestHelper.print_step("Critical Scene Validation")
|
||||
|
||||
@@ -149,11 +157,15 @@ func test_critical_scenes():
|
||||
for scene_path in critical_scenes:
|
||||
if scene_path in discovered_scenes:
|
||||
var status = validation_results.get(scene_path, "Unknown")
|
||||
TestHelper.assert_equal("Full validation successful", status,
|
||||
"Critical scene %s must pass all validation" % scene_path.get_file())
|
||||
TestHelper.assert_equal(
|
||||
"Full validation successful",
|
||||
status,
|
||||
"Critical scene %s must pass all validation" % scene_path.get_file()
|
||||
)
|
||||
else:
|
||||
TestHelper.assert_false(true, "Critical scene missing: %s" % scene_path)
|
||||
|
||||
|
||||
func print_validation_summary():
|
||||
print("\n=== Scene Validation Summary ===")
|
||||
|
||||
@@ -176,4 +188,4 @@ func print_validation_summary():
|
||||
if failed_scenes == 0:
|
||||
print("✅ All scenes passed validation!")
|
||||
else:
|
||||
print("❌ %d scene(s) failed validation" % failed_scenes)
|
||||
print("❌ %d scene(s) failed validation" % failed_scenes)
|
||||
|
||||
@@ -10,6 +10,7 @@ var settings_manager: Node
|
||||
var original_settings: Dictionary
|
||||
var temp_files: Array[String] = []
|
||||
|
||||
|
||||
func _initialize():
|
||||
# Wait for autoloads to initialize
|
||||
await process_frame
|
||||
@@ -20,6 +21,7 @@ func _initialize():
|
||||
# Exit after tests complete
|
||||
quit()
|
||||
|
||||
|
||||
func run_tests():
|
||||
TestHelper.print_test_header("SettingsManager")
|
||||
|
||||
@@ -49,26 +51,36 @@ func run_tests():
|
||||
|
||||
TestHelper.print_test_footer("SettingsManager")
|
||||
|
||||
|
||||
func test_basic_functionality():
|
||||
TestHelper.print_step("Basic Functionality")
|
||||
|
||||
# Test that SettingsManager has expected properties
|
||||
TestHelper.assert_has_properties(settings_manager, ["settings", "default_settings", "languages_data"], "SettingsManager properties")
|
||||
TestHelper.assert_has_properties(
|
||||
settings_manager,
|
||||
["settings", "default_settings", "languages_data"],
|
||||
"SettingsManager properties"
|
||||
)
|
||||
|
||||
# Test that SettingsManager has expected methods
|
||||
var expected_methods = ["get_setting", "set_setting", "save_settings", "load_settings", "reset_settings_to_defaults"]
|
||||
var expected_methods = [
|
||||
"get_setting", "set_setting", "save_settings", "load_settings", "reset_settings_to_defaults"
|
||||
]
|
||||
TestHelper.assert_has_methods(settings_manager, expected_methods, "SettingsManager methods")
|
||||
|
||||
# Test default settings structure
|
||||
var expected_defaults = ["master_volume", "music_volume", "sfx_volume", "language"]
|
||||
for key in expected_defaults:
|
||||
TestHelper.assert_has_key(settings_manager.default_settings, key, "Default setting key: " + key)
|
||||
TestHelper.assert_has_key(
|
||||
settings_manager.default_settings, key, "Default setting key: " + key
|
||||
)
|
||||
|
||||
# Test getting settings
|
||||
var master_volume = settings_manager.get_setting("master_volume")
|
||||
TestHelper.assert_not_null(master_volume, "Can get master_volume setting")
|
||||
TestHelper.assert_true(master_volume is float, "master_volume is float type")
|
||||
|
||||
|
||||
func test_input_validation_security():
|
||||
TestHelper.print_step("Input Validation Security")
|
||||
|
||||
@@ -94,7 +106,9 @@ func test_input_validation_security():
|
||||
# Test valid volume range
|
||||
var valid_volume = settings_manager.set_setting("master_volume", 0.5)
|
||||
TestHelper.assert_true(valid_volume, "Valid volume values accepted")
|
||||
TestHelper.assert_equal(0.5, settings_manager.get_setting("master_volume"), "Volume value set correctly")
|
||||
TestHelper.assert_equal(
|
||||
0.5, settings_manager.get_setting("master_volume"), "Volume value set correctly"
|
||||
)
|
||||
|
||||
# Test string length validation for language
|
||||
var long_language = "a".repeat(20) # Exceeds MAX_SETTING_STRING_LENGTH
|
||||
@@ -109,11 +123,14 @@ func test_input_validation_security():
|
||||
var valid_lang = settings_manager.set_setting("language", "en")
|
||||
TestHelper.assert_true(valid_lang, "Valid language codes accepted")
|
||||
|
||||
|
||||
func test_file_io_security():
|
||||
TestHelper.print_step("File I/O Security")
|
||||
|
||||
# Test file size limits by creating oversized config
|
||||
var oversized_config_path = TestHelper.create_temp_file("oversized_settings.cfg", "x".repeat(70000)) # > 64KB
|
||||
var oversized_config_path = TestHelper.create_temp_file(
|
||||
"oversized_settings.cfg", "x".repeat(70000)
|
||||
) # > 64KB
|
||||
temp_files.append(oversized_config_path)
|
||||
|
||||
# Test that normal save/load operations work
|
||||
@@ -127,21 +144,30 @@ func test_file_io_security():
|
||||
# Test that settings file exists after save
|
||||
TestHelper.assert_file_exists("user://settings.cfg", "Settings file created after save")
|
||||
|
||||
|
||||
func test_json_parsing_security():
|
||||
TestHelper.print_step("JSON Parsing Security")
|
||||
|
||||
# Create invalid languages.json for testing
|
||||
var invalid_json_path = TestHelper.create_temp_file("invalid_languages.json", TestHelper.create_invalid_json())
|
||||
var invalid_json_path = TestHelper.create_temp_file(
|
||||
"invalid_languages.json", TestHelper.create_invalid_json()
|
||||
)
|
||||
temp_files.append(invalid_json_path)
|
||||
|
||||
# Create oversized JSON file
|
||||
var large_json_content = '{"languages": {"' + "x".repeat(70000) + '": "test"}}'
|
||||
var oversized_json_path = TestHelper.create_temp_file("oversized_languages.json", large_json_content)
|
||||
var oversized_json_path = TestHelper.create_temp_file(
|
||||
"oversized_languages.json", large_json_content
|
||||
)
|
||||
temp_files.append(oversized_json_path)
|
||||
|
||||
# Test that SettingsManager handles invalid JSON gracefully
|
||||
# This should fall back to default languages
|
||||
TestHelper.assert_true(settings_manager.languages_data.has("languages"), "Default languages loaded on JSON parse failure")
|
||||
TestHelper.assert_true(
|
||||
settings_manager.languages_data.has("languages"),
|
||||
"Default languages loaded on JSON parse failure"
|
||||
)
|
||||
|
||||
|
||||
func test_language_validation():
|
||||
TestHelper.print_step("Language Validation")
|
||||
@@ -164,6 +190,7 @@ func test_language_validation():
|
||||
var null_result = settings_manager.set_setting("language", null)
|
||||
TestHelper.assert_false(null_result, "Null language rejected")
|
||||
|
||||
|
||||
func test_volume_validation():
|
||||
TestHelper.print_step("Volume Validation")
|
||||
|
||||
@@ -171,16 +198,29 @@ func test_volume_validation():
|
||||
|
||||
for setting in volume_settings:
|
||||
# Test boundary values
|
||||
TestHelper.assert_true(settings_manager.set_setting(setting, 0.0), "Volume 0.0 accepted for " + setting)
|
||||
TestHelper.assert_true(settings_manager.set_setting(setting, 1.0), "Volume 1.0 accepted for " + setting)
|
||||
TestHelper.assert_true(
|
||||
settings_manager.set_setting(setting, 0.0), "Volume 0.0 accepted for " + setting
|
||||
)
|
||||
TestHelper.assert_true(
|
||||
settings_manager.set_setting(setting, 1.0), "Volume 1.0 accepted for " + setting
|
||||
)
|
||||
|
||||
# Test out of range values
|
||||
TestHelper.assert_false(settings_manager.set_setting(setting, -0.1), "Negative volume rejected for " + setting)
|
||||
TestHelper.assert_false(settings_manager.set_setting(setting, 1.1), "Volume > 1.0 rejected for " + setting)
|
||||
TestHelper.assert_false(
|
||||
settings_manager.set_setting(setting, -0.1), "Negative volume rejected for " + setting
|
||||
)
|
||||
TestHelper.assert_false(
|
||||
settings_manager.set_setting(setting, 1.1), "Volume > 1.0 rejected for " + setting
|
||||
)
|
||||
|
||||
# Test invalid types
|
||||
TestHelper.assert_false(settings_manager.set_setting(setting, "0.5"), "String volume rejected for " + setting)
|
||||
TestHelper.assert_false(settings_manager.set_setting(setting, null), "Null volume rejected for " + setting)
|
||||
TestHelper.assert_false(
|
||||
settings_manager.set_setting(setting, "0.5"), "String volume rejected for " + setting
|
||||
)
|
||||
TestHelper.assert_false(
|
||||
settings_manager.set_setting(setting, null), "Null volume rejected for " + setting
|
||||
)
|
||||
|
||||
|
||||
func test_error_handling_and_recovery():
|
||||
TestHelper.print_step("Error Handling and Recovery")
|
||||
@@ -198,12 +238,23 @@ func test_error_handling_and_recovery():
|
||||
|
||||
# Verify defaults are loaded
|
||||
var default_volume = settings_manager.default_settings["master_volume"]
|
||||
TestHelper.assert_equal(default_volume, settings_manager.get_setting("master_volume"), "Reset to defaults works correctly")
|
||||
TestHelper.assert_equal(
|
||||
default_volume,
|
||||
settings_manager.get_setting("master_volume"),
|
||||
"Reset to defaults works correctly"
|
||||
)
|
||||
|
||||
# Test fallback language loading
|
||||
TestHelper.assert_true(settings_manager.languages_data.has("languages"), "Fallback languages loaded")
|
||||
TestHelper.assert_has_key(settings_manager.languages_data["languages"], "en", "English fallback language available")
|
||||
TestHelper.assert_has_key(settings_manager.languages_data["languages"], "ru", "Russian fallback language available")
|
||||
TestHelper.assert_true(
|
||||
settings_manager.languages_data.has("languages"), "Fallback languages loaded"
|
||||
)
|
||||
TestHelper.assert_has_key(
|
||||
settings_manager.languages_data["languages"], "en", "English fallback language available"
|
||||
)
|
||||
TestHelper.assert_has_key(
|
||||
settings_manager.languages_data["languages"], "ru", "Russian fallback language available"
|
||||
)
|
||||
|
||||
|
||||
func test_reset_functionality():
|
||||
TestHelper.print_step("Reset Functionality")
|
||||
@@ -216,12 +267,21 @@ func test_reset_functionality():
|
||||
settings_manager.reset_settings_to_defaults()
|
||||
|
||||
# Verify reset worked
|
||||
TestHelper.assert_equal(settings_manager.default_settings["master_volume"], settings_manager.get_setting("master_volume"), "Volume reset to default")
|
||||
TestHelper.assert_equal(settings_manager.default_settings["language"], settings_manager.get_setting("language"), "Language reset to default")
|
||||
TestHelper.assert_equal(
|
||||
settings_manager.default_settings["master_volume"],
|
||||
settings_manager.get_setting("master_volume"),
|
||||
"Volume reset to default"
|
||||
)
|
||||
TestHelper.assert_equal(
|
||||
settings_manager.default_settings["language"],
|
||||
settings_manager.get_setting("language"),
|
||||
"Language reset to default"
|
||||
)
|
||||
|
||||
# Test that reset saves automatically
|
||||
TestHelper.assert_file_exists("user://settings.cfg", "Settings file exists after reset")
|
||||
|
||||
|
||||
func test_performance_benchmarks():
|
||||
TestHelper.print_step("Performance Benchmarks")
|
||||
|
||||
@@ -241,6 +301,7 @@ func test_performance_benchmarks():
|
||||
settings_manager.set_setting("master_volume", 0.5)
|
||||
TestHelper.end_performance_test("validation", 50.0, "100 validations within 50ms")
|
||||
|
||||
|
||||
func cleanup_tests():
|
||||
TestHelper.print_step("Cleanup")
|
||||
|
||||
@@ -253,4 +314,4 @@ func cleanup_tests():
|
||||
for temp_file in temp_files:
|
||||
TestHelper.cleanup_temp_file(temp_file)
|
||||
|
||||
TestHelper.assert_true(true, "Test cleanup completed")
|
||||
TestHelper.assert_true(true, "Test cleanup completed")
|
||||
|
||||
@@ -10,6 +10,7 @@ var tile_scene: PackedScene
|
||||
var tile_instance: Node2D
|
||||
var test_viewport: SubViewport
|
||||
|
||||
|
||||
func _initialize():
|
||||
# Wait for autoloads to initialize
|
||||
await process_frame
|
||||
@@ -20,6 +21,7 @@ func _initialize():
|
||||
# Exit after tests complete
|
||||
quit()
|
||||
|
||||
|
||||
func run_tests():
|
||||
TestHelper.print_test_header("Tile Component")
|
||||
|
||||
@@ -43,6 +45,7 @@ func run_tests():
|
||||
|
||||
TestHelper.print_test_footer("Tile Component")
|
||||
|
||||
|
||||
func setup_test_environment():
|
||||
TestHelper.print_step("Test Environment Setup")
|
||||
|
||||
@@ -65,6 +68,7 @@ func setup_test_environment():
|
||||
await process_frame
|
||||
await process_frame
|
||||
|
||||
|
||||
func test_basic_functionality():
|
||||
TestHelper.print_step("Basic Functionality")
|
||||
|
||||
@@ -73,16 +77,31 @@ func test_basic_functionality():
|
||||
return
|
||||
|
||||
# Test that Tile has expected properties
|
||||
var expected_properties = ["tile_type", "grid_position", "is_selected", "is_highlighted", "original_scale", "active_gem_types"]
|
||||
var expected_properties = [
|
||||
"tile_type",
|
||||
"grid_position",
|
||||
"is_selected",
|
||||
"is_highlighted",
|
||||
"original_scale",
|
||||
"active_gem_types"
|
||||
]
|
||||
for prop in expected_properties:
|
||||
TestHelper.assert_true(prop in tile_instance, "Tile has property: " + prop)
|
||||
|
||||
# Test that Tile has expected methods
|
||||
var expected_methods = ["set_active_gem_types", "get_active_gem_count", "add_gem_type", "remove_gem_type", "force_reset_visual_state"]
|
||||
var expected_methods = [
|
||||
"set_active_gem_types",
|
||||
"get_active_gem_count",
|
||||
"add_gem_type",
|
||||
"remove_gem_type",
|
||||
"force_reset_visual_state"
|
||||
]
|
||||
TestHelper.assert_has_methods(tile_instance, expected_methods, "Tile component methods")
|
||||
|
||||
# Test signals
|
||||
TestHelper.assert_true(tile_instance.has_signal("tile_selected"), "Tile has tile_selected signal")
|
||||
TestHelper.assert_true(
|
||||
tile_instance.has_signal("tile_selected"), "Tile has tile_selected signal"
|
||||
)
|
||||
|
||||
# Test sprite reference
|
||||
TestHelper.assert_not_null(tile_instance.sprite, "Sprite node is available")
|
||||
@@ -91,6 +110,7 @@ func test_basic_functionality():
|
||||
# Test group membership
|
||||
TestHelper.assert_true(tile_instance.is_in_group("tiles"), "Tile is in 'tiles' group")
|
||||
|
||||
|
||||
func test_tile_constants():
|
||||
TestHelper.print_step("Tile Constants")
|
||||
|
||||
@@ -102,8 +122,12 @@ func test_tile_constants():
|
||||
|
||||
# Test all_gem_textures array
|
||||
TestHelper.assert_not_null(tile_instance.all_gem_textures, "All gem textures array exists")
|
||||
TestHelper.assert_true(tile_instance.all_gem_textures is Array, "All gem textures is Array type")
|
||||
TestHelper.assert_equal(8, tile_instance.all_gem_textures.size(), "All gem textures has expected count")
|
||||
TestHelper.assert_true(
|
||||
tile_instance.all_gem_textures is Array, "All gem textures is Array type"
|
||||
)
|
||||
TestHelper.assert_equal(
|
||||
8, tile_instance.all_gem_textures.size(), "All gem textures has expected count"
|
||||
)
|
||||
|
||||
# Test that all gem textures are valid
|
||||
for i in range(tile_instance.all_gem_textures.size()):
|
||||
@@ -111,6 +135,7 @@ func test_tile_constants():
|
||||
TestHelper.assert_not_null(texture, "Gem texture %d is not null" % i)
|
||||
TestHelper.assert_true(texture is Texture2D, "Gem texture %d is Texture2D type" % i)
|
||||
|
||||
|
||||
func test_texture_management():
|
||||
TestHelper.print_step("Texture Management")
|
||||
|
||||
@@ -119,8 +144,12 @@ func test_texture_management():
|
||||
|
||||
# Test default gem types initialization
|
||||
TestHelper.assert_not_null(tile_instance.active_gem_types, "Active gem types is initialized")
|
||||
TestHelper.assert_true(tile_instance.active_gem_types is Array, "Active gem types is Array type")
|
||||
TestHelper.assert_true(tile_instance.active_gem_types.size() > 0, "Active gem types has content")
|
||||
TestHelper.assert_true(
|
||||
tile_instance.active_gem_types is Array, "Active gem types is Array type"
|
||||
)
|
||||
TestHelper.assert_true(
|
||||
tile_instance.active_gem_types.size() > 0, "Active gem types has content"
|
||||
)
|
||||
|
||||
# Test texture assignment for valid tile types
|
||||
var original_type = tile_instance.tile_type
|
||||
@@ -130,11 +159,14 @@ func test_texture_management():
|
||||
TestHelper.assert_equal(i, tile_instance.tile_type, "Tile type set correctly to %d" % i)
|
||||
|
||||
if tile_instance.sprite:
|
||||
TestHelper.assert_not_null(tile_instance.sprite.texture, "Sprite texture assigned for type %d" % i)
|
||||
TestHelper.assert_not_null(
|
||||
tile_instance.sprite.texture, "Sprite texture assigned for type %d" % i
|
||||
)
|
||||
|
||||
# Restore original type
|
||||
tile_instance.tile_type = original_type
|
||||
|
||||
|
||||
func test_gem_type_management():
|
||||
TestHelper.print_step("Gem Type Management")
|
||||
|
||||
@@ -147,17 +179,23 @@ func test_gem_type_management():
|
||||
# Test set_active_gem_types with valid array
|
||||
var test_gems = [0, 1, 2]
|
||||
tile_instance.set_active_gem_types(test_gems)
|
||||
TestHelper.assert_equal(3, tile_instance.get_active_gem_count(), "Active gem count set correctly")
|
||||
TestHelper.assert_equal(
|
||||
3, tile_instance.get_active_gem_count(), "Active gem count set correctly"
|
||||
)
|
||||
|
||||
# Test add_gem_type
|
||||
var add_result = tile_instance.add_gem_type(3)
|
||||
TestHelper.assert_true(add_result, "Valid gem type added successfully")
|
||||
TestHelper.assert_equal(4, tile_instance.get_active_gem_count(), "Gem count increased after addition")
|
||||
TestHelper.assert_equal(
|
||||
4, tile_instance.get_active_gem_count(), "Gem count increased after addition"
|
||||
)
|
||||
|
||||
# Test adding duplicate gem type
|
||||
var duplicate_result = tile_instance.add_gem_type(3)
|
||||
TestHelper.assert_false(duplicate_result, "Duplicate gem type addition rejected")
|
||||
TestHelper.assert_equal(4, tile_instance.get_active_gem_count(), "Gem count unchanged after duplicate")
|
||||
TestHelper.assert_equal(
|
||||
4, tile_instance.get_active_gem_count(), "Gem count unchanged after duplicate"
|
||||
)
|
||||
|
||||
# Test add_gem_type with invalid index
|
||||
var invalid_add = tile_instance.add_gem_type(99)
|
||||
@@ -166,7 +204,9 @@ func test_gem_type_management():
|
||||
# Test remove_gem_type
|
||||
var remove_result = tile_instance.remove_gem_type(3)
|
||||
TestHelper.assert_true(remove_result, "Valid gem type removed successfully")
|
||||
TestHelper.assert_equal(3, tile_instance.get_active_gem_count(), "Gem count decreased after removal")
|
||||
TestHelper.assert_equal(
|
||||
3, tile_instance.get_active_gem_count(), "Gem count decreased after removal"
|
||||
)
|
||||
|
||||
# Test removing non-existent gem type
|
||||
var nonexistent_remove = tile_instance.remove_gem_type(99)
|
||||
@@ -181,6 +221,7 @@ func test_gem_type_management():
|
||||
# Restore original state
|
||||
tile_instance.set_active_gem_types(original_gem_types)
|
||||
|
||||
|
||||
func test_visual_feedback_system():
|
||||
TestHelper.print_step("Visual Feedback System")
|
||||
|
||||
@@ -201,7 +242,10 @@ func test_visual_feedback_system():
|
||||
if tile_instance.sprite:
|
||||
# Test that modulate is brighter when selected
|
||||
var modulate = tile_instance.sprite.modulate
|
||||
TestHelper.assert_true(modulate.r > 1.0 or modulate.g > 1.0 or modulate.b > 1.0, "Selected tile has brighter modulate")
|
||||
TestHelper.assert_true(
|
||||
modulate.r > 1.0 or modulate.g > 1.0 or modulate.b > 1.0,
|
||||
"Selected tile has brighter modulate"
|
||||
)
|
||||
|
||||
# Test highlight visual feedback
|
||||
tile_instance.is_selected = false
|
||||
@@ -226,6 +270,7 @@ func test_visual_feedback_system():
|
||||
tile_instance.is_selected = original_selected
|
||||
tile_instance.is_highlighted = original_highlighted
|
||||
|
||||
|
||||
func test_state_management():
|
||||
TestHelper.print_step("State Management")
|
||||
|
||||
@@ -234,8 +279,12 @@ func test_state_management():
|
||||
|
||||
# Test initial state
|
||||
TestHelper.assert_true(tile_instance.tile_type >= 0, "Initial tile type is non-negative")
|
||||
TestHelper.assert_true(tile_instance.grid_position is Vector2i, "Grid position is Vector2i type")
|
||||
TestHelper.assert_true(tile_instance.original_scale is Vector2, "Original scale is Vector2 type")
|
||||
TestHelper.assert_true(
|
||||
tile_instance.grid_position is Vector2i, "Grid position is Vector2i type"
|
||||
)
|
||||
TestHelper.assert_true(
|
||||
tile_instance.original_scale is Vector2, "Original scale is Vector2 type"
|
||||
)
|
||||
|
||||
# Test tile type bounds checking
|
||||
var original_type = tile_instance.tile_type
|
||||
@@ -247,11 +296,15 @@ func test_state_management():
|
||||
TestHelper.assert_equal(max_valid_type, tile_instance.tile_type, "Valid tile type accepted")
|
||||
|
||||
# Test state consistency
|
||||
TestHelper.assert_true(tile_instance.tile_type < tile_instance.active_gem_types.size(), "Tile type within active gems range")
|
||||
TestHelper.assert_true(
|
||||
tile_instance.tile_type < tile_instance.active_gem_types.size(),
|
||||
"Tile type within active gems range"
|
||||
)
|
||||
|
||||
# Restore original type
|
||||
tile_instance.tile_type = original_type
|
||||
|
||||
|
||||
func test_input_validation():
|
||||
TestHelper.print_step("Input Validation")
|
||||
|
||||
@@ -262,16 +315,22 @@ func test_input_validation():
|
||||
var original_gems = tile_instance.active_gem_types.duplicate()
|
||||
tile_instance.set_active_gem_types([])
|
||||
# Should fall back to defaults or maintain previous state
|
||||
TestHelper.assert_true(tile_instance.get_active_gem_count() > 0, "Empty gem array handled gracefully")
|
||||
TestHelper.assert_true(
|
||||
tile_instance.get_active_gem_count() > 0, "Empty gem array handled gracefully"
|
||||
)
|
||||
|
||||
# Test null gem types array
|
||||
tile_instance.set_active_gem_types(null)
|
||||
TestHelper.assert_true(tile_instance.get_active_gem_count() > 0, "Null gem array handled gracefully")
|
||||
TestHelper.assert_true(
|
||||
tile_instance.get_active_gem_count() > 0, "Null gem array handled gracefully"
|
||||
)
|
||||
|
||||
# Test invalid gem indices in array
|
||||
tile_instance.set_active_gem_types([0, 1, 99, 2]) # 99 is invalid
|
||||
# Should use fallback or filter invalid indices
|
||||
TestHelper.assert_true(tile_instance.get_active_gem_count() > 0, "Invalid gem indices handled gracefully")
|
||||
TestHelper.assert_true(
|
||||
tile_instance.get_active_gem_count() > 0, "Invalid gem indices handled gracefully"
|
||||
)
|
||||
|
||||
# Test negative gem indices
|
||||
var negative_add = tile_instance.add_gem_type(-1)
|
||||
@@ -284,6 +343,7 @@ func test_input_validation():
|
||||
# Restore original state
|
||||
tile_instance.set_active_gem_types(original_gems)
|
||||
|
||||
|
||||
func test_scaling_and_sizing():
|
||||
TestHelper.print_step("Scaling and Sizing")
|
||||
|
||||
@@ -300,7 +360,9 @@ func test_scaling_and_sizing():
|
||||
var texture_size = tile_instance.sprite.texture.get_size()
|
||||
var scaled_size = texture_size * tile_instance.original_scale
|
||||
var max_dimension = max(scaled_size.x, scaled_size.y)
|
||||
TestHelper.assert_true(max_dimension <= tile_instance.TILE_SIZE + 1, "Scaled tile fits within TILE_SIZE")
|
||||
TestHelper.assert_true(
|
||||
max_dimension <= tile_instance.TILE_SIZE + 1, "Scaled tile fits within TILE_SIZE"
|
||||
)
|
||||
|
||||
# Test scale animation for visual feedback
|
||||
var original_scale = tile_instance.sprite.scale if tile_instance.sprite else Vector2.ONE
|
||||
@@ -312,13 +374,16 @@ func test_scaling_and_sizing():
|
||||
|
||||
if tile_instance.sprite:
|
||||
var selected_scale = tile_instance.sprite.scale
|
||||
TestHelper.assert_true(selected_scale.x >= original_scale.x, "Selected tile scale is larger or equal")
|
||||
TestHelper.assert_true(
|
||||
selected_scale.x >= original_scale.x, "Selected tile scale is larger or equal"
|
||||
)
|
||||
|
||||
# Reset to normal
|
||||
tile_instance.is_selected = false
|
||||
await process_frame
|
||||
await process_frame
|
||||
|
||||
|
||||
func test_memory_safety():
|
||||
TestHelper.print_step("Memory Safety")
|
||||
|
||||
@@ -344,12 +409,18 @@ func test_memory_safety():
|
||||
TestHelper.assert_true(is_instance_valid(tile_instance.sprite), "Sprite instance is valid")
|
||||
|
||||
# Test gem types array integrity
|
||||
TestHelper.assert_true(tile_instance.active_gem_types is Array, "Active gem types maintains Array type")
|
||||
TestHelper.assert_true(
|
||||
tile_instance.active_gem_types is Array, "Active gem types maintains Array type"
|
||||
)
|
||||
|
||||
# Test that gem indices are within bounds
|
||||
for gem_index in tile_instance.active_gem_types:
|
||||
TestHelper.assert_true(gem_index >= 0, "Gem index is non-negative")
|
||||
TestHelper.assert_true(gem_index < tile_instance.all_gem_textures.size(), "Gem index within texture array bounds")
|
||||
TestHelper.assert_true(
|
||||
gem_index < tile_instance.all_gem_textures.size(),
|
||||
"Gem index within texture array bounds"
|
||||
)
|
||||
|
||||
|
||||
func test_error_handling():
|
||||
TestHelper.print_step("Error Handling")
|
||||
@@ -390,7 +461,11 @@ func test_error_handling():
|
||||
|
||||
tile_instance.set_active_gem_types(large_gem_types)
|
||||
# Should fall back to safe defaults
|
||||
TestHelper.assert_true(tile_instance.get_active_gem_count() <= tile_instance.all_gem_textures.size(), "Large gem array handled safely")
|
||||
TestHelper.assert_true(
|
||||
tile_instance.get_active_gem_count() <= tile_instance.all_gem_textures.size(),
|
||||
"Large gem array handled safely"
|
||||
)
|
||||
|
||||
|
||||
func cleanup_tests():
|
||||
TestHelper.print_step("Cleanup")
|
||||
@@ -406,4 +481,4 @@ func cleanup_tests():
|
||||
# Wait for cleanup
|
||||
await process_frame
|
||||
|
||||
TestHelper.assert_true(true, "Test cleanup completed")
|
||||
TestHelper.assert_true(true, "Test cleanup completed")
|
||||
|
||||
@@ -11,6 +11,7 @@ var stepper_instance: Control
|
||||
var test_viewport: SubViewport
|
||||
var original_language: String
|
||||
|
||||
|
||||
func _initialize():
|
||||
# Wait for autoloads to initialize
|
||||
await process_frame
|
||||
@@ -21,6 +22,7 @@ func _initialize():
|
||||
# Exit after tests complete
|
||||
quit()
|
||||
|
||||
|
||||
func run_tests():
|
||||
TestHelper.print_test_header("ValueStepper Component")
|
||||
|
||||
@@ -47,6 +49,7 @@ func run_tests():
|
||||
|
||||
TestHelper.print_test_footer("ValueStepper Component")
|
||||
|
||||
|
||||
func setup_test_environment():
|
||||
TestHelper.print_step("Test Environment Setup")
|
||||
|
||||
@@ -69,6 +72,7 @@ func setup_test_environment():
|
||||
await process_frame
|
||||
await process_frame
|
||||
|
||||
|
||||
func test_basic_functionality():
|
||||
TestHelper.print_step("Basic Functionality")
|
||||
|
||||
@@ -77,16 +81,30 @@ func test_basic_functionality():
|
||||
return
|
||||
|
||||
# Test that ValueStepper has expected properties
|
||||
var expected_properties = ["data_source", "custom_format_function", "values", "display_names", "current_index"]
|
||||
var expected_properties = [
|
||||
"data_source", "custom_format_function", "values", "display_names", "current_index"
|
||||
]
|
||||
for prop in expected_properties:
|
||||
TestHelper.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"]
|
||||
TestHelper.assert_has_methods(stepper_instance, expected_methods, "ValueStepper component methods")
|
||||
var expected_methods = [
|
||||
"change_value",
|
||||
"setup_custom_values",
|
||||
"get_current_value",
|
||||
"set_current_value",
|
||||
"set_highlighted",
|
||||
"handle_input_action",
|
||||
"get_control_name"
|
||||
]
|
||||
TestHelper.assert_has_methods(
|
||||
stepper_instance, expected_methods, "ValueStepper component methods"
|
||||
)
|
||||
|
||||
# Test signals
|
||||
TestHelper.assert_true(stepper_instance.has_signal("value_changed"), "ValueStepper has value_changed signal")
|
||||
TestHelper.assert_true(
|
||||
stepper_instance.has_signal("value_changed"), "ValueStepper has value_changed signal"
|
||||
)
|
||||
|
||||
# Test UI components
|
||||
TestHelper.assert_not_null(stepper_instance.left_button, "Left button is available")
|
||||
@@ -98,6 +116,7 @@ func test_basic_functionality():
|
||||
TestHelper.assert_true(stepper_instance.right_button is Button, "Right button is Button type")
|
||||
TestHelper.assert_true(stepper_instance.value_display is Label, "Value display is Label type")
|
||||
|
||||
|
||||
func test_data_source_loading():
|
||||
TestHelper.print_step("Data Source Loading")
|
||||
|
||||
@@ -105,7 +124,9 @@ func test_data_source_loading():
|
||||
return
|
||||
|
||||
# Test default language data source
|
||||
TestHelper.assert_equal("language", stepper_instance.data_source, "Default data source is language")
|
||||
TestHelper.assert_equal(
|
||||
"language", stepper_instance.data_source, "Default data source is language"
|
||||
)
|
||||
|
||||
# Test that values are loaded
|
||||
TestHelper.assert_not_null(stepper_instance.values, "Values array is initialized")
|
||||
@@ -116,14 +137,24 @@ func test_data_source_loading():
|
||||
# Test that language data is loaded correctly
|
||||
if stepper_instance.data_source == "language":
|
||||
TestHelper.assert_true(stepper_instance.values.size() > 0, "Language values loaded")
|
||||
TestHelper.assert_true(stepper_instance.display_names.size() > 0, "Language display names loaded")
|
||||
TestHelper.assert_equal(stepper_instance.values.size(), stepper_instance.display_names.size(), "Values and display names arrays have same size")
|
||||
TestHelper.assert_true(
|
||||
stepper_instance.display_names.size() > 0, "Language display names loaded"
|
||||
)
|
||||
TestHelper.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:
|
||||
TestHelper.assert_equal(expected_index, stepper_instance.current_index, "Current language index set correctly")
|
||||
TestHelper.assert_equal(
|
||||
expected_index,
|
||||
stepper_instance.current_index,
|
||||
"Current language index set correctly"
|
||||
)
|
||||
|
||||
# Test resolution data source
|
||||
var resolution_stepper = stepper_scene.instantiate()
|
||||
@@ -132,7 +163,9 @@ func test_data_source_loading():
|
||||
await process_frame
|
||||
|
||||
TestHelper.assert_true(resolution_stepper.values.size() > 0, "Resolution values loaded")
|
||||
TestHelper.assert_contains(resolution_stepper.values, "1920x1080", "Resolution data contains expected value")
|
||||
TestHelper.assert_contains(
|
||||
resolution_stepper.values, "1920x1080", "Resolution data contains expected value"
|
||||
)
|
||||
|
||||
resolution_stepper.queue_free()
|
||||
|
||||
@@ -143,11 +176,14 @@ func test_data_source_loading():
|
||||
await process_frame
|
||||
|
||||
TestHelper.assert_true(difficulty_stepper.values.size() > 0, "Difficulty values loaded")
|
||||
TestHelper.assert_contains(difficulty_stepper.values, "normal", "Difficulty data contains expected value")
|
||||
TestHelper.assert_contains(
|
||||
difficulty_stepper.values, "normal", "Difficulty data contains expected value"
|
||||
)
|
||||
TestHelper.assert_equal(1, difficulty_stepper.current_index, "Difficulty defaults to normal")
|
||||
|
||||
difficulty_stepper.queue_free()
|
||||
|
||||
|
||||
func test_value_navigation():
|
||||
TestHelper.print_step("Value Navigation")
|
||||
|
||||
@@ -167,23 +203,30 @@ func test_value_navigation():
|
||||
# Test backward navigation
|
||||
stepper_instance.change_value(-1)
|
||||
var back_value = stepper_instance.get_current_value()
|
||||
TestHelper.assert_equal(initial_value, back_value, "Backward navigation returns to original value")
|
||||
TestHelper.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)
|
||||
TestHelper.assert_equal(0, stepper_instance.current_index, "Forward navigation wraps to beginning")
|
||||
TestHelper.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)
|
||||
TestHelper.assert_equal(max_index, stepper_instance.current_index, "Backward navigation wraps to end")
|
||||
TestHelper.assert_equal(
|
||||
max_index, stepper_instance.current_index, "Backward navigation wraps to end"
|
||||
)
|
||||
|
||||
# Restore original state
|
||||
stepper_instance.current_index = original_index
|
||||
stepper_instance._update_display()
|
||||
|
||||
|
||||
func test_custom_values():
|
||||
TestHelper.print_step("Custom Values")
|
||||
|
||||
@@ -202,27 +245,41 @@ func test_custom_values():
|
||||
TestHelper.assert_equal(3, stepper_instance.values.size(), "Custom values set correctly")
|
||||
TestHelper.assert_equal("apple", stepper_instance.values[0], "First custom value correct")
|
||||
TestHelper.assert_equal(0, stepper_instance.current_index, "Index reset to 0 for custom values")
|
||||
TestHelper.assert_equal("apple", stepper_instance.get_current_value(), "Current value matches first custom value")
|
||||
TestHelper.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)
|
||||
|
||||
TestHelper.assert_equal(3, stepper_instance.display_names.size(), "Custom display names set correctly")
|
||||
TestHelper.assert_equal("Red Apple", stepper_instance.display_names[0], "First display name correct")
|
||||
TestHelper.assert_equal(
|
||||
3, stepper_instance.display_names.size(), "Custom display names set correctly"
|
||||
)
|
||||
TestHelper.assert_equal(
|
||||
"Red Apple", stepper_instance.display_names[0], "First display name correct"
|
||||
)
|
||||
|
||||
# Test navigation with custom values
|
||||
stepper_instance.change_value(1)
|
||||
TestHelper.assert_equal("banana", stepper_instance.get_current_value(), "Navigation works with custom values")
|
||||
TestHelper.assert_equal(
|
||||
"banana", stepper_instance.get_current_value(), "Navigation works with custom values"
|
||||
)
|
||||
|
||||
# Test set_current_value
|
||||
stepper_instance.set_current_value("cherry")
|
||||
TestHelper.assert_equal("cherry", stepper_instance.get_current_value(), "set_current_value works correctly")
|
||||
TestHelper.assert_equal(2, stepper_instance.current_index, "Index updated correctly by set_current_value")
|
||||
TestHelper.assert_equal(
|
||||
"cherry", stepper_instance.get_current_value(), "set_current_value works correctly"
|
||||
)
|
||||
TestHelper.assert_equal(
|
||||
2, stepper_instance.current_index, "Index updated correctly by set_current_value"
|
||||
)
|
||||
|
||||
# Test invalid value
|
||||
stepper_instance.set_current_value("grape")
|
||||
TestHelper.assert_equal("cherry", stepper_instance.get_current_value(), "Invalid value doesn't change current value")
|
||||
TestHelper.assert_equal(
|
||||
"cherry", stepper_instance.get_current_value(), "Invalid value doesn't change current value"
|
||||
)
|
||||
|
||||
# Restore original state
|
||||
stepper_instance.values = original_values
|
||||
@@ -230,6 +287,7 @@ func test_custom_values():
|
||||
stepper_instance.current_index = original_index
|
||||
stepper_instance._update_display()
|
||||
|
||||
|
||||
func test_input_handling():
|
||||
TestHelper.print_step("Input Handling")
|
||||
|
||||
@@ -242,12 +300,18 @@ func test_input_handling():
|
||||
# Test left input action
|
||||
var left_handled = stepper_instance.handle_input_action("move_left")
|
||||
TestHelper.assert_true(left_handled, "Left input action handled")
|
||||
TestHelper.assert_not_equal(original_value, stepper_instance.get_current_value(), "Left action changes value")
|
||||
TestHelper.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")
|
||||
TestHelper.assert_true(right_handled, "Right input action handled")
|
||||
TestHelper.assert_equal(original_value, stepper_instance.get_current_value(), "Right action returns to original value")
|
||||
TestHelper.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")
|
||||
@@ -257,12 +321,19 @@ func test_input_handling():
|
||||
if stepper_instance.left_button:
|
||||
var before_left = stepper_instance.get_current_value()
|
||||
stepper_instance._on_left_button_pressed()
|
||||
TestHelper.assert_not_equal(before_left, stepper_instance.get_current_value(), "Left button press changes value")
|
||||
TestHelper.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._on_right_button_pressed()
|
||||
TestHelper.assert_equal(original_value, stepper_instance.get_current_value(), "Right button press returns to original")
|
||||
TestHelper.assert_equal(
|
||||
original_value,
|
||||
stepper_instance.get_current_value(),
|
||||
"Right button press returns to original"
|
||||
)
|
||||
|
||||
|
||||
func test_visual_feedback():
|
||||
TestHelper.print_step("Visual Feedback")
|
||||
@@ -277,13 +348,19 @@ func test_visual_feedback():
|
||||
# Test highlighting
|
||||
stepper_instance.set_highlighted(true)
|
||||
TestHelper.assert_true(stepper_instance.is_highlighted, "Highlighted state set correctly")
|
||||
TestHelper.assert_true(stepper_instance.scale.x > original_scale.x, "Scale increased when highlighted")
|
||||
TestHelper.assert_true(
|
||||
stepper_instance.scale.x > original_scale.x, "Scale increased when highlighted"
|
||||
)
|
||||
|
||||
# Test unhighlighting
|
||||
stepper_instance.set_highlighted(false)
|
||||
TestHelper.assert_false(stepper_instance.is_highlighted, "Highlighted state cleared correctly")
|
||||
TestHelper.assert_equal(original_scale, stepper_instance.scale, "Scale restored when unhighlighted")
|
||||
TestHelper.assert_equal(original_modulate, stepper_instance.modulate, "Modulate restored when unhighlighted")
|
||||
TestHelper.assert_equal(
|
||||
original_scale, stepper_instance.scale, "Scale restored when unhighlighted"
|
||||
)
|
||||
TestHelper.assert_equal(
|
||||
original_modulate, stepper_instance.modulate, "Modulate restored when unhighlighted"
|
||||
)
|
||||
|
||||
# Test display update
|
||||
if stepper_instance.value_display:
|
||||
@@ -291,6 +368,7 @@ func test_visual_feedback():
|
||||
TestHelper.assert_true(current_text.length() > 0, "Value display has text content")
|
||||
TestHelper.assert_not_equal("N/A", current_text, "Value display shows valid content")
|
||||
|
||||
|
||||
func test_settings_integration():
|
||||
TestHelper.print_step("Settings Integration")
|
||||
|
||||
@@ -321,6 +399,7 @@ func test_settings_integration():
|
||||
# Restore original language
|
||||
root.get_node("SettingsManager").set_setting("language", original_lang)
|
||||
|
||||
|
||||
func test_boundary_conditions():
|
||||
TestHelper.print_step("Boundary Conditions")
|
||||
|
||||
@@ -333,7 +412,9 @@ func test_boundary_conditions():
|
||||
test_viewport.add_child(empty_stepper)
|
||||
await process_frame
|
||||
|
||||
TestHelper.assert_equal("", empty_stepper.get_current_value(), "Empty values array returns empty string")
|
||||
TestHelper.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
|
||||
@@ -346,17 +427,22 @@ func test_boundary_conditions():
|
||||
# Test negative index handling
|
||||
stepper_instance.current_index = -1
|
||||
stepper_instance._update_display()
|
||||
TestHelper.assert_equal("N/A", stepper_instance.value_display.text, "Negative index shows N/A")
|
||||
TestHelper.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()
|
||||
stepper_instance._update_display()
|
||||
TestHelper.assert_equal("N/A", stepper_instance.value_display.text, "Out-of-bounds index shows N/A")
|
||||
TestHelper.assert_equal(
|
||||
"N/A", stepper_instance.value_display.text, "Out-of-bounds index shows N/A"
|
||||
)
|
||||
|
||||
# Restore valid index
|
||||
stepper_instance.current_index = 0
|
||||
stepper_instance._update_display()
|
||||
|
||||
|
||||
func test_error_handling():
|
||||
TestHelper.print_step("Error Handling")
|
||||
|
||||
@@ -376,7 +462,9 @@ func test_error_handling():
|
||||
# Test get_control_name
|
||||
var control_name = stepper_instance.get_control_name()
|
||||
TestHelper.assert_true(control_name.ends_with("_stepper"), "Control name has correct suffix")
|
||||
TestHelper.assert_true(control_name.begins_with(stepper_instance.data_source), "Control name includes data source")
|
||||
TestHelper.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"]
|
||||
@@ -385,12 +473,17 @@ func test_error_handling():
|
||||
|
||||
# Should handle gracefully - display_names should be duplicated from values
|
||||
TestHelper.assert_equal(3, stepper_instance.values.size(), "Values array size preserved")
|
||||
TestHelper.assert_equal(2, stepper_instance.display_names.size(), "Display names size preserved as provided")
|
||||
TestHelper.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
|
||||
stepper_instance._update_display()
|
||||
TestHelper.assert_equal("c", stepper_instance.value_display.text, "Falls back to value when display name missing")
|
||||
TestHelper.assert_equal(
|
||||
"c", stepper_instance.value_display.text, "Falls back to value when display name missing"
|
||||
)
|
||||
|
||||
|
||||
func cleanup_tests():
|
||||
TestHelper.print_step("Cleanup")
|
||||
@@ -409,4 +502,4 @@ func cleanup_tests():
|
||||
# Wait for cleanup
|
||||
await process_frame
|
||||
|
||||
TestHelper.assert_true(true, "Test cleanup completed")
|
||||
TestHelper.assert_true(true, "Test cleanup completed")
|
||||
|
||||
Reference in New Issue
Block a user