extends SceneTree ## Comprehensive test suite for AudioManager ## ## Tests audio resource loading, stream configuration, volume management, ## audio bus configuration, and playback control functionality. ## Validates proper audio system initialization and error handling. const TestHelper = preload("res://tests/helpers/TestHelper.gd") var audio_manager: Node var original_music_volume: float var original_sfx_volume: float func _initialize(): # Wait for autoloads to initialize await process_frame await process_frame run_tests() # Exit after tests complete quit() func run_tests(): TestHelper.print_test_header("AudioManager") # Get reference to AudioManager audio_manager = root.get_node("AudioManager") if not audio_manager: TestHelper.assert_true(false, "AudioManager autoload not found") TestHelper.print_test_footer("AudioManager") return # Store original settings for restoration var settings_manager = root.get_node("SettingsManager") original_music_volume = settings_manager.get_setting("music_volume") original_sfx_volume = settings_manager.get_setting("sfx_volume") # Run test suites test_basic_functionality() test_audio_constants() test_audio_player_initialization() test_stream_loading_and_validation() test_audio_bus_configuration() test_volume_management() test_music_playback_control() test_ui_sound_effects() test_stream_loop_configuration() test_error_handling() # Cleanup and restore original state cleanup_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") # Test that AudioManager has expected methods var expected_methods = ["update_music_volume", "play_ui_click"] TestHelper.assert_has_methods(audio_manager, expected_methods, "AudioManager methods") # 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") func test_audio_constants(): TestHelper.print_step("Audio File Constants") # Test path format validation var music_path = audio_manager.MUSIC_PATH 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") # Test file extensions var valid_audio_extensions = [".wav", ".ogg", ".mp3"] var music_has_valid_ext = false var click_has_valid_ext = false for ext in valid_audio_extensions: if music_path.ends_with(ext): music_has_valid_ext = true if click_path.ends_with(ext): click_has_valid_ext = true TestHelper.assert_true(music_has_valid_ext, "Music file has valid audio extension") TestHelper.assert_true(click_has_valid_ext, "Click sound has valid audio extension") # Test that audio files exist 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") # 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") # 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") func test_stream_loading_and_validation(): TestHelper.print_step("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") # 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") # Test stream resource loading directly var loaded_music = load(audio_manager.MUSIC_PATH) TestHelper.assert_not_null(loaded_music, "Music resource loads successfully") TestHelper.assert_true(loaded_music is AudioStream, "Loaded music is AudioStream type") var loaded_click = load(audio_manager.UI_CLICK_SOUND_PATH) 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") # Test that required audio buses exist var music_bus_index = AudioServer.get_bus_index("Music") var sfx_bus_index = AudioServer.get_bus_index("SFX") TestHelper.assert_true(music_bus_index >= 0, "Music audio bus exists") TestHelper.assert_true(sfx_bus_index >= 0, "SFX audio bus exists") # 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") if sfx_bus_index >= 0: 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") # Store original volume var settings_manager = root.get_node("SettingsManager") var original_volume = settings_manager.get_setting("music_volume") var was_playing = audio_manager.music_player.playing # 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") # 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") # 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") # 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) # 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") # Test playback state management # Note: We test the control methods exist and can be called safely var original_playing = audio_manager.music_player.playing # Test that playback methods can be called without errors if audio_manager.has_method("_start_music"): # Method exists but is private - test that the logic is sound TestHelper.assert_true(true, "Private _start_music method exists") if audio_manager.has_method("_stop_music"): # Method exists but is private - test that the logic is sound TestHelper.assert_true(true, "Private _stop_music method exists") # Test volume-based playback control var settings_manager = root.get_node("SettingsManager") var current_volume = settings_manager.get_setting("music_volume") if current_volume > 0.0: audio_manager.update_music_volume(current_volume) TestHelper.assert_true(true, "Volume-based playback start works") else: 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") # Test UI click functionality TestHelper.assert_not_null(audio_manager.ui_click_player, "UI click player exists") TestHelper.assert_not_null(audio_manager.click_stream, "Click stream is loaded") # Test that play_ui_click can be called safely var original_stream = audio_manager.ui_click_player.stream 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") # Test multiple rapid clicks (should not cause errors) for i in range(3): audio_manager.play_ui_click() TestHelper.assert_true(true, "Rapid click %d handled safely" % (i + 1)) # Test click with null stream var backup_stream = audio_manager.click_stream audio_manager.click_stream = null audio_manager.play_ui_click() # Should not crash 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") # Test that music stream has loop configuration var music_stream = audio_manager.music_player.stream if music_stream: if music_stream is AudioStreamWAV: # For WAV files, check loop mode 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") elif music_stream is AudioStreamOggVorbis: # For OGG files, check loop property var has_loop = "loop" in music_stream TestHelper.assert_true(has_loop, "OGG stream has loop property") if has_loop: TestHelper.assert_true(music_stream.loop, "OGG stream loop enabled") # 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") # Test graceful handling of missing resources # 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") # 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") # Test null stream handling in play_ui_click var original_click_stream = audio_manager.click_stream audio_manager.click_stream = null # This should not crash audio_manager.play_ui_click() TestHelper.assert_true(true, "play_ui_click handles null stream gracefully") # Restore original stream audio_manager.click_stream = original_click_stream # Test volume edge cases audio_manager.update_music_volume(0.0) TestHelper.assert_true(true, "Zero volume handled safely") audio_manager.update_music_volume(1.0) TestHelper.assert_true(true, "Maximum volume handled safely") func cleanup_tests(): TestHelper.print_step("Cleanup") # Restore original volume settings var settings_manager = root.get_node("SettingsManager") settings_manager.set_setting("music_volume", original_music_volume) settings_manager.set_setting("sfx_volume", original_sfx_volume) # Update AudioManager to original settings audio_manager.update_music_volume(original_music_volume) TestHelper.assert_true(true, "Test cleanup completed")