450 lines
13 KiB
GDScript
450 lines
13 KiB
GDScript
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 TestHelperClass = 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():
|
|
TestHelperClass.print_test_header("AudioManager")
|
|
|
|
# Get reference to AudioManager
|
|
audio_manager = root.get_node("AudioManager")
|
|
if not audio_manager:
|
|
TestHelperClass.assert_true(false, "AudioManager autoload not found")
|
|
TestHelperClass.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()
|
|
|
|
TestHelperClass.print_test_footer("AudioManager")
|
|
|
|
|
|
func test_basic_functionality():
|
|
TestHelperClass.print_step("Basic Functionality")
|
|
|
|
# Test that AudioManager has expected properties
|
|
TestHelperClass.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"]
|
|
TestHelperClass.assert_has_methods(
|
|
audio_manager, expected_methods, "AudioManager methods"
|
|
)
|
|
|
|
# Test that AudioManager has expected constants
|
|
TestHelperClass.assert_true(
|
|
"MUSIC_PATH" in audio_manager, "MUSIC_PATH constant exists"
|
|
)
|
|
TestHelperClass.assert_true(
|
|
"UI_CLICK_SOUND_PATH" in audio_manager,
|
|
"UI_CLICK_SOUND_PATH constant exists"
|
|
)
|
|
|
|
|
|
func test_audio_constants():
|
|
TestHelperClass.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
|
|
|
|
TestHelperClass.assert_true(
|
|
music_path.begins_with("res://"), "Music path uses res:// protocol"
|
|
)
|
|
TestHelperClass.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
|
|
|
|
TestHelperClass.assert_true(
|
|
music_has_valid_ext, "Music file has valid audio extension"
|
|
)
|
|
TestHelperClass.assert_true(
|
|
click_has_valid_ext, "Click sound has valid audio extension"
|
|
)
|
|
|
|
# Test that audio files exist
|
|
TestHelperClass.assert_true(
|
|
ResourceLoader.exists(music_path), "Music file exists at path"
|
|
)
|
|
TestHelperClass.assert_true(
|
|
ResourceLoader.exists(click_path), "Click sound file exists at path"
|
|
)
|
|
|
|
|
|
func test_audio_player_initialization():
|
|
TestHelperClass.print_step("Audio Player Initialization")
|
|
|
|
# Test music player initialization
|
|
TestHelperClass.assert_not_null(
|
|
audio_manager.music_player, "Music player is initialized"
|
|
)
|
|
TestHelperClass.assert_true(
|
|
audio_manager.music_player is AudioStreamPlayer,
|
|
"Music player is AudioStreamPlayer type"
|
|
)
|
|
TestHelperClass.assert_true(
|
|
audio_manager.music_player.get_parent() == audio_manager,
|
|
"Music player is child of AudioManager"
|
|
)
|
|
|
|
# Test UI click player initialization
|
|
TestHelperClass.assert_not_null(
|
|
audio_manager.ui_click_player, "UI click player is initialized"
|
|
)
|
|
TestHelperClass.assert_true(
|
|
audio_manager.ui_click_player is AudioStreamPlayer,
|
|
"UI click player is AudioStreamPlayer type"
|
|
)
|
|
TestHelperClass.assert_true(
|
|
audio_manager.ui_click_player.get_parent() == audio_manager,
|
|
"UI click player is child of AudioManager"
|
|
)
|
|
|
|
# Test audio bus assignment
|
|
TestHelperClass.assert_equal(
|
|
"Music",
|
|
audio_manager.music_player.bus,
|
|
"Music player assigned to Music bus"
|
|
)
|
|
TestHelperClass.assert_equal(
|
|
"SFX",
|
|
audio_manager.ui_click_player.bus,
|
|
"UI click player assigned to SFX bus"
|
|
)
|
|
|
|
|
|
func test_stream_loading_and_validation():
|
|
TestHelperClass.print_step("Stream Loading and Validation")
|
|
|
|
# Test music stream loading
|
|
TestHelperClass.assert_not_null(
|
|
audio_manager.music_player.stream, "Music stream is loaded"
|
|
)
|
|
if audio_manager.music_player.stream:
|
|
TestHelperClass.assert_true(
|
|
audio_manager.music_player.stream is AudioStream,
|
|
"Music stream is AudioStream type"
|
|
)
|
|
|
|
# Test click stream loading
|
|
TestHelperClass.assert_not_null(
|
|
audio_manager.click_stream, "Click stream is loaded"
|
|
)
|
|
if audio_manager.click_stream:
|
|
TestHelperClass.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)
|
|
TestHelperClass.assert_not_null(
|
|
loaded_music, "Music resource loads successfully"
|
|
)
|
|
TestHelperClass.assert_true(
|
|
loaded_music is AudioStream, "Loaded music is AudioStream type"
|
|
)
|
|
|
|
var loaded_click = load(audio_manager.UI_CLICK_SOUND_PATH)
|
|
TestHelperClass.assert_not_null(
|
|
loaded_click, "Click resource loads successfully"
|
|
)
|
|
TestHelperClass.assert_true(
|
|
loaded_click is AudioStream, "Loaded click sound is AudioStream type"
|
|
)
|
|
|
|
|
|
func test_audio_bus_configuration():
|
|
TestHelperClass.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")
|
|
|
|
TestHelperClass.assert_true(music_bus_index >= 0, "Music audio bus exists")
|
|
TestHelperClass.assert_true(sfx_bus_index >= 0, "SFX audio bus exists")
|
|
|
|
# Test player bus assignments match actual AudioServer buses
|
|
if music_bus_index >= 0:
|
|
TestHelperClass.assert_equal(
|
|
"Music",
|
|
audio_manager.music_player.bus,
|
|
"Music player correctly assigned to Music bus"
|
|
)
|
|
|
|
if sfx_bus_index >= 0:
|
|
TestHelperClass.assert_equal(
|
|
"SFX",
|
|
audio_manager.ui_click_player.bus,
|
|
"UI click player correctly assigned to SFX bus"
|
|
)
|
|
|
|
|
|
func test_volume_management():
|
|
TestHelperClass.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)
|
|
TestHelperClass.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)
|
|
TestHelperClass.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)
|
|
TestHelperClass.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)
|
|
TestHelperClass.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():
|
|
TestHelperClass.print_step("Music Playback Control")
|
|
|
|
# Test that music player exists and has a stream
|
|
TestHelperClass.assert_not_null(
|
|
audio_manager.music_player, "Music player exists for playback testing"
|
|
)
|
|
TestHelperClass.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
|
|
TestHelperClass.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
|
|
TestHelperClass.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)
|
|
TestHelperClass.assert_true(true, "Volume-based playback start works")
|
|
else:
|
|
audio_manager.update_music_volume(0.0)
|
|
TestHelperClass.assert_true(true, "Volume-based playback stop works")
|
|
|
|
|
|
func test_ui_sound_effects():
|
|
TestHelperClass.print_step("UI Sound Effects")
|
|
|
|
# Test UI click functionality
|
|
TestHelperClass.assert_not_null(
|
|
audio_manager.ui_click_player, "UI click player exists"
|
|
)
|
|
TestHelperClass.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
|
|
TestHelperClass.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()
|
|
TestHelperClass.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
|
|
TestHelperClass.assert_true(true, "Null click stream handled safely")
|
|
audio_manager.click_stream = backup_stream
|
|
|
|
|
|
func test_stream_loop_configuration():
|
|
TestHelperClass.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
|
|
TestHelperClass.assert_true(
|
|
has_loop_mode, "WAV stream has loop_mode property"
|
|
)
|
|
if has_loop_mode:
|
|
TestHelperClass.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
|
|
TestHelperClass.assert_true(
|
|
has_loop, "OGG stream has loop property"
|
|
)
|
|
if has_loop:
|
|
TestHelperClass.assert_true(
|
|
music_stream.loop, "OGG stream loop enabled"
|
|
)
|
|
|
|
# Test loop configuration for different stream types
|
|
TestHelperClass.assert_true(
|
|
true, "Stream loop configuration tested based on type"
|
|
)
|
|
|
|
|
|
func test_error_handling():
|
|
TestHelperClass.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
|
|
TestHelperClass.assert_not_null(
|
|
audio_manager,
|
|
"AudioManager initializes despite potential resource issues"
|
|
)
|
|
|
|
# Test that players are still created even if streams fail to load
|
|
TestHelperClass.assert_not_null(
|
|
audio_manager.music_player,
|
|
"Music player created regardless of stream loading"
|
|
)
|
|
TestHelperClass.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()
|
|
TestHelperClass.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)
|
|
TestHelperClass.assert_true(true, "Zero volume handled safely")
|
|
|
|
audio_manager.update_music_volume(1.0)
|
|
TestHelperClass.assert_true(true, "Maximum volume handled safely")
|
|
|
|
|
|
func cleanup_tests():
|
|
TestHelperClass.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)
|
|
|
|
TestHelperClass.assert_true(true, "Test cleanup completed")
|