#include "test/mossrose-test.h" #include PMutex * mock_p_mutex_new_(); pboolean mock_p_mutex_trylock_(); pboolean mock_p_mutex_lock_(); pboolean mock_p_mutex_unlock_(); #define p_mutex_new mock_p_mutex_new_ #define p_mutex_trylock mock_p_mutex_trylock_ #define p_mutex_lock mock_p_mutex_lock_ #define p_mutex_unlock mock_p_mutex_unlock_ #include "channel.c" #undef p_mutex_new /* ~~~~~~~~ mocks ~~~~~~~~ */ lily_mock_t *mock_p_mutex_new = NULL; PMutex * mock_p_mutex_new_() { mock_p_mutex_new->n_calls += 1; return NULL; } lily_mock_t *mock_p_mutex_trylock = NULL; pboolean mock_p_mutex_trylock_(PMutex *m) { mock_p_mutex_trylock->n_calls += 1; pboolean result; lily_get_value(mock_p_mutex_trylock, pboolean, &result); return result; } lily_mock_t *mock_p_mutex_lock = NULL; pboolean mock_p_mutex_lock_(PMutex *m) { mock_p_mutex_lock->n_calls += 1; return TRUE; } lily_mock_t *mock_p_mutex_unlock = NULL; pboolean mock_p_mutex_unlock_(PMutex *m) { mock_p_mutex_unlock->n_calls += 1; return TRUE; } /* ~~~~~~~~ tests ~~~~~~~~ */ void test_channel_init() { lily_mock_use(&mock_p_mutex_new); struct channel_t chan; channel_init(&chan); lily_assert_int_equal(mock_p_mutex_new->n_calls, 1); lily_assert_int_equal(chan.shared.active, false); lily_assert_int_equal(chan.shared.paused, false); lily_assert_int_equal(chan.shared.volume, 255); lily_assert_int_equal(chan.shared.pan_left, -128); lily_assert_int_equal(chan.shared.pan_right, 128); lily_assert_null(chan.sound.left); lily_assert_null(chan.sound.right); lily_assert_int_equal(chan.pos, 0); } void test_channel_reset_last_loop() { struct channel_t chan; chan.shared.active = true; chan.shared.loops = 1; channel_reset(&chan); lily_assert_int_equal(chan.shared.active, false); } void test_channel_reset_penultimate_loop() { struct channel_t chan; chan.shared.active = true; chan.shared.loops = 2; chan.pos = 98; channel_reset(&chan); lily_assert_int_equal(chan.shared.active, true); lily_assert_int_equal(chan.shared.loops, 1); lily_assert_int_equal(chan.pos, 0); } void test_channel_reset_infinite_loop() { struct channel_t chan; chan.shared.active = true; chan.shared.loops = 0; chan.pos = 17; channel_reset(&chan); lily_assert_int_equal(chan.shared.active, true); lily_assert_int_equal(chan.shared.loops, 0); lily_assert_int_equal(chan.pos, 0); } void test_channel_pause() { struct channel_t chan; chan.shared.paused = false; channel_pause(&chan); lily_assert_int_equal(chan.shared.paused, true); } void test_channel_resume() { struct channel_t chan; chan.shared.paused = true; channel_resume(&chan); lily_assert_int_equal(chan.shared.paused, false); } void test_channel_set_volume() { struct channel_t chan; chan.shared.volume = 255; channel_set_volume(&chan, 0.0f); lily_assert_int_equal(chan.shared.volume, 0); channel_set_volume(&chan, 0.5f); lily_assert_int_equal(chan.shared.volume, 127); channel_set_volume(&chan, 1.0f); lily_assert_int_equal(chan.shared.volume, 255); /* oob */ channel_set_volume(&chan, -1.0f); lily_assert_int_equal(chan.shared.volume, 0); channel_set_volume(&chan, 2.0f); lily_assert_int_equal(chan.shared.volume, 255); } void test_channel_set_pan() { struct channel_t chan; chan.shared.pan_left = 255; chan.shared.pan_right = 255; channel_set_pan(&chan, -1.0f, 1.0f); lily_assert_int_equal(chan.shared.pan_left, -128); lily_assert_int_equal(chan.shared.pan_right, 128); channel_set_pan(&chan, -0.5f, 0.5f); lily_assert_int_equal(chan.shared.pan_left, -64); lily_assert_int_equal(chan.shared.pan_right, 64); channel_set_pan(&chan, 0.0f, 0.0f); lily_assert_int_equal(chan.shared.pan_left, 0); lily_assert_int_equal(chan.shared.pan_right, 0); channel_set_pan(&chan, 0.5f, -0.5f); lily_assert_int_equal(chan.shared.pan_left, 64); lily_assert_int_equal(chan.shared.pan_right, -64); channel_set_pan(&chan, 1.0f, -1.0f); lily_assert_int_equal(chan.shared.pan_left, 128); lily_assert_int_equal(chan.shared.pan_right, -128); /* oob */ channel_set_pan(&chan, -10.0f, 2.0f); lily_assert_int_equal(chan.shared.pan_left, -128); lily_assert_int_equal(chan.shared.pan_right, 128); channel_set_pan(&chan, 2.0f, -10.0f); lily_assert_int_equal(chan.shared.pan_left, 128); lily_assert_int_equal(chan.shared.pan_right, -128); } void test_channel_sound_load() { lily_mock_use(&mock_p_mutex_lock); lily_mock_use(&mock_p_mutex_unlock); float audio_left[] = { 0.2, 0.5, 1.0 }; float audio_right[] = { 1.0, 0.5, 0.2 }; struct mossrose_sound_t sound; sound.left = audio_left; sound.right = audio_right; sound.mono = false; sound.len = 3; struct channel_t chan; chan.shared.active = false; chan.sound.left = NULL; chan.sound.right = NULL; chan.pos = 5; int result = channel_sound_load(&chan, &sound, false, 1); lily_assert_int_equal(mock_p_mutex_lock->n_calls, 1); lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 1); lily_assert_int_equal(result, 0); lily_assert_int_equal(chan.shared.active, true); lily_assert_int_equal(chan.shared.paused, false); lily_assert_int_equal(chan.shared.volume, 255); lily_assert_int_equal(chan.shared.pan_left, -128); lily_assert_int_equal(chan.shared.pan_right, 128); lily_assert_memory_equal(chan.sound.left, audio_left, sizeof(audio_left)); lily_assert_memory_equal(chan.sound.right, audio_right, sizeof(audio_right)); lily_assert_int_equal(chan.sound.mono, false); lily_assert_int_equal(chan.pos, 0); } void test_channel_sound_load_mono() { lily_mock_use(&mock_p_mutex_lock); lily_mock_use(&mock_p_mutex_unlock); float audio[] = { 0.2, 0.5, 1.0 }; struct mossrose_sound_t sound; sound.left = audio; sound.right = NULL; sound.mono = true; sound.len = 3; struct channel_t chan; chan.shared.active = false; chan.sound.left = NULL; chan.sound.right = NULL; int result = channel_sound_load(&chan, &sound, false, 1); lily_assert_int_equal(mock_p_mutex_lock->n_calls, 1); lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 1); lily_assert_int_equal(result, 0); lily_assert_int_equal(chan.shared.active, true); lily_assert_int_equal(chan.shared.paused, false); lily_assert_int_equal(chan.shared.volume, 255); lily_assert_int_equal(chan.shared.pan_left, 0); lily_assert_int_equal(chan.shared.pan_right, 0); lily_assert_memory_equal(chan.sound.left, audio, sizeof(audio)); lily_assert_null(chan.sound.right); lily_assert_int_equal(chan.sound.mono, true); lily_assert_int_equal(chan.pos, 0); } void test_channel_sound_load_preserve() { lily_mock_use(&mock_p_mutex_lock); lily_mock_use(&mock_p_mutex_unlock); float audio_left[] = { 0.2, 0.5, 1.0 }; float audio_right[] = { 1.0, 0.5, 0.2 }; struct mossrose_sound_t sound; sound.left = audio_left; sound.right = audio_right; sound.mono = false; sound.len = 3; struct channel_t chan; chan.shared.active = false; chan.sound.left = NULL; chan.sound.right = NULL; chan.shared.volume = 127; chan.shared.pan_left = 0; chan.shared.pan_right = 64; int result = channel_sound_load(&chan, &sound, true, 1); lily_assert_int_equal(mock_p_mutex_lock->n_calls, 1); lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 1); lily_assert_int_equal(result, 0); lily_assert_int_equal(chan.shared.active, true); lily_assert_int_equal(chan.shared.paused, false); lily_assert_int_equal(chan.shared.volume, 127); lily_assert_int_equal(chan.shared.pan_left, 0); lily_assert_int_equal(chan.shared.pan_right, 64); lily_assert_memory_equal(chan.sound.left, audio_left, sizeof(audio_left)); lily_assert_memory_equal(chan.sound.right, audio_right, sizeof(audio_right)); lily_assert_int_equal(chan.sound.mono, false); lily_assert_int_equal(chan.pos, 0); } void test_channel_sound_fail() { lily_mock_use(&mock_p_mutex_lock); lily_mock_use(&mock_p_mutex_unlock); float audio_left[] = { 0.2, 0.5, 1.0 }; float audio_right[] = { 1.0, 0.5, 0.2 }; struct mossrose_sound_t sound; sound.left = audio_left; sound.right = audio_right; sound.mono = false; sound.len = 3; struct channel_t chan; chan.shared.active = true; chan.shared.paused = true; chan.shared.volume = 2; chan.shared.pan_left = 4; chan.shared.pan_right = 4; chan.sound.left = NULL; chan.sound.right = NULL; chan.sound.mono = true; chan.pos = 6; int result = channel_sound_load(&chan, &sound, false, 1); lily_assert_int_equal(mock_p_mutex_lock->n_calls, 0); lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 0); lily_assert_int_equal(result, 1); lily_assert_int_equal(chan.shared.active, true); lily_assert_int_equal(chan.shared.paused, true); lily_assert_int_equal(chan.shared.volume, 2); lily_assert_int_equal(chan.shared.pan_left, 4); lily_assert_int_equal(chan.shared.pan_right, 4); lily_assert_null(chan.sound.left); lily_assert_null(chan.sound.right); lily_assert_int_equal(chan.sound.mono, true); lily_assert_int_equal(chan.pos, 6); } /* get_next_sample tests */ void test_channel_get_next_sample_inactive() { lily_mock_use(&mock_p_mutex_trylock); lily_mock_use(&mock_p_mutex_unlock); struct channel_t chan; chan.shared.active = false; chan.pos = 0; float l = 22; float r = 22; channel_update_shared(&chan); channel_get_next_sample(&l, &r, &chan); lily_assert_int_equal(mock_p_mutex_trylock->n_calls, 0); lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 0); lily_assert_int_equal(chan.pos, 0); lily_assert_float_equal(l, 0.0f, 0.1f); lily_assert_float_equal(r, 0.0f, 0.1f); } void test_channel_get_next_sample_paused() { lily_mock_use(&mock_p_mutex_trylock); lily_mock_use(&mock_p_mutex_unlock); struct channel_t chan; chan.shared.active = true; chan.shared.paused = true; chan.pos = 0; float l = 22; float r = 22; channel_update_shared(&chan); channel_get_next_sample(&l, &r, &chan); lily_assert_int_equal(mock_p_mutex_trylock->n_calls, 0); lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 0); lily_assert_int_equal(chan.pos, 0); lily_assert_float_equal(l, 0.0f, 0.1f); lily_assert_float_equal(r, 0.0f, 0.1f); } void test_channel_get_next_sample_nolock() { lily_mock_use(&mock_p_mutex_trylock); lily_mock_use(&mock_p_mutex_unlock); struct channel_t chan; chan.shared.active = true; chan.shared.paused = false; chan.pos = 0; float l = 22; float r = 22; lily_store_value(mock_p_mutex_trylock, pboolean, FALSE); channel_update_shared(&chan); channel_get_next_sample(&l, &r, &chan); lily_assert_int_equal(mock_p_mutex_trylock->n_calls, 1); lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 0); lily_assert_int_equal(chan.pos, 0); lily_assert_float_equal(l, 0.0f, 0.1f); lily_assert_float_equal(r, 0.0f, 0.1f); } void test_channel_get_next_sample_normal() { lily_mock_use(&mock_p_mutex_trylock); lily_mock_use(&mock_p_mutex_unlock); struct channel_t chan; chan.shared.active = true; chan.shared.paused = false; chan.shared.loops = 1; chan.shared.volume = 255; chan.shared.pan_left = -128; chan.shared.pan_right = 128; float audio_left[] = { 0.0, 0.5, 1.0 }; float audio_right[] = { 1.0, 0.5, 0.0 }; chan.sound.left = audio_left; chan.sound.right = audio_right; chan.sound.mono = false; chan.sound.len = 3; chan.pos = 0; float l, r; lily_store_value(mock_p_mutex_trylock, pboolean, TRUE); channel_update_shared(&chan); channel_get_next_sample(&l, &r, &chan); lily_assert_int_equal(mock_p_mutex_trylock->n_calls, 1); lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 1); lily_assert_int_equal(chan.pos, 1); lily_assert_float_equal(l, 0.0f, 0.1f); lily_assert_float_equal(r, 1.0f, 0.1f); lily_store_value(mock_p_mutex_trylock, pboolean, TRUE); channel_update_shared(&chan); channel_get_next_sample(&l, &r, &chan); lily_assert_int_equal(mock_p_mutex_trylock->n_calls, 2); lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 2); lily_assert_int_equal(chan.pos, 2); lily_assert_float_equal(l, 0.5f, 0.1f); lily_assert_float_equal(r, 0.5f, 0.1f); lily_store_value(mock_p_mutex_trylock, pboolean, TRUE); channel_update_shared(&chan); channel_get_next_sample(&l, &r, &chan); lily_assert_int_equal(mock_p_mutex_trylock->n_calls, 3); lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 3); lily_assert_int_equal(chan.shared.active, false); lily_assert_float_equal(l, 1.0f, 0.1f); lily_assert_float_equal(r, 0.0f, 0.1f); } void test_channel_get_next_sample_volume_0() { lily_mock_use(&mock_p_mutex_trylock); lily_mock_use(&mock_p_mutex_unlock); struct channel_t chan; chan.shared.active = true; chan.shared.paused = false; chan.shared.loops = 1; chan.shared.volume = 0; chan.shared.pan_left = -128; chan.shared.pan_right = 128; float audio_left[] = { 0.0, 0.5, 1.0 }; float audio_right[] = { 1.0, 0.5, 0.0 }; chan.sound.left = audio_left; chan.sound.right = audio_right; chan.sound.mono = false; chan.sound.len = 3; chan.pos = 0; float l, r; lily_store_value(mock_p_mutex_trylock, pboolean, TRUE); channel_update_shared(&chan); channel_get_next_sample(&l, &r, &chan); lily_assert_int_equal(mock_p_mutex_trylock->n_calls, 1); lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 1); lily_assert_int_equal(chan.pos, 1); lily_assert_float_equal(l, 0.0f, 0.1f); lily_assert_float_equal(r, 0.0f, 0.1f); lily_store_value(mock_p_mutex_trylock, pboolean, TRUE); channel_update_shared(&chan); channel_get_next_sample(&l, &r, &chan); lily_assert_int_equal(mock_p_mutex_trylock->n_calls, 2); lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 2); lily_assert_int_equal(chan.pos, 2); lily_assert_float_equal(l, 0.0f, 0.1f); lily_assert_float_equal(r, 0.0f, 0.1f); lily_store_value(mock_p_mutex_trylock, pboolean, TRUE); channel_update_shared(&chan); channel_get_next_sample(&l, &r, &chan); lily_assert_int_equal(mock_p_mutex_trylock->n_calls, 3); lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 3); lily_assert_int_equal(chan.shared.active, false); lily_assert_float_equal(l, 0.0f, 0.1f); lily_assert_float_equal(r, 0.0f, 0.1f); } void test_channel_get_next_sample_mono() { lily_mock_use(&mock_p_mutex_trylock); lily_mock_use(&mock_p_mutex_unlock); struct channel_t chan; chan.shared.active = true; chan.shared.paused = false; chan.shared.loops = 1; chan.shared.volume = 255; chan.shared.pan_left = 0; chan.shared.pan_right = 128; float audio[] = { 0.0, 0.5, 1.0 }; chan.sound.left = audio; chan.sound.right = NULL; chan.sound.mono = true; chan.sound.len = 3; chan.pos = 0; float l, r; const float gain = 0.7071; /* constant-power panning center gain */ lily_store_value(mock_p_mutex_trylock, pboolean, TRUE); channel_update_shared(&chan); channel_get_next_sample(&l, &r, &chan); lily_assert_int_equal(mock_p_mutex_trylock->n_calls, 1); lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 1); lily_assert_int_equal(chan.pos, 1); lily_assert_float_equal(l, gain * 0.0f, 0.1f); lily_assert_float_equal(r, gain * 0.0f, 0.1f); lily_store_value(mock_p_mutex_trylock, pboolean, TRUE); channel_update_shared(&chan); channel_get_next_sample(&l, &r, &chan); lily_assert_int_equal(mock_p_mutex_trylock->n_calls, 2); lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 2); lily_assert_int_equal(chan.pos, 2); lily_assert_float_equal(l, gain * 0.5f, 0.1f); lily_assert_float_equal(r, gain * 0.5f, 0.1f); lily_store_value(mock_p_mutex_trylock, pboolean, TRUE); channel_update_shared(&chan); channel_get_next_sample(&l, &r, &chan); lily_assert_int_equal(mock_p_mutex_trylock->n_calls, 3); lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 3); lily_assert_int_equal(chan.shared.active, false); lily_assert_float_equal(l, gain * 1.0f, 0.1f); lily_assert_float_equal(r, gain * 1.0f, 0.1f); } void test_channel_get_next_sample_mono_panned() { lily_mock_use(&mock_p_mutex_trylock); lily_mock_use(&mock_p_mutex_unlock); struct channel_t chan; chan.shared.active = true; chan.shared.paused = false; chan.shared.loops = 1; chan.shared.volume = 255; chan.shared.pan_left = -128; chan.shared.pan_right = 128; float audio[] = { 0.0, 0.5, 1.0 }; chan.sound.left = audio; chan.sound.right = NULL; chan.sound.mono = true; chan.sound.len = 3; chan.pos = 0; float l, r; lily_store_value(mock_p_mutex_trylock, pboolean, TRUE); channel_update_shared(&chan); channel_get_next_sample(&l, &r, &chan); lily_assert_int_equal(mock_p_mutex_trylock->n_calls, 1); lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 1); lily_assert_int_equal(chan.pos, 1); lily_assert_float_equal(l, 0.0f, 0.1f); lily_assert_float_equal(r, 0.0f, 0.1f); lily_store_value(mock_p_mutex_trylock, pboolean, TRUE); channel_update_shared(&chan); channel_get_next_sample(&l, &r, &chan); lily_assert_int_equal(mock_p_mutex_trylock->n_calls, 2); lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 2); lily_assert_int_equal(chan.pos, 2); lily_assert_float_equal(l, 0.5f, 0.1f); lily_assert_float_equal(r, 0.0f, 0.1f); lily_store_value(mock_p_mutex_trylock, pboolean, TRUE); channel_update_shared(&chan); channel_get_next_sample(&l, &r, &chan); lily_assert_int_equal(mock_p_mutex_trylock->n_calls, 3); lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 3); lily_assert_int_equal(chan.shared.active, false); lily_assert_float_equal(l, 1.0f, 0.1f); lily_assert_float_equal(r, 0.0f, 0.1f); } void test_channel_get_next_sample_panned() { lily_mock_use(&mock_p_mutex_trylock); lily_mock_use(&mock_p_mutex_unlock); struct channel_t chan; chan.shared.active = true; chan.shared.paused = false; chan.shared.loops = 1; chan.shared.volume = 255; chan.shared.pan_left = 128; chan.shared.pan_right = 0; float audio_left[] = { 0.2, 0.5, 1.0 }; float audio_right[] = { 1.0, 0.5, 0.2 }; chan.sound.left = audio_left; chan.sound.right = audio_right; chan.sound.mono = false; chan.sound.len = 3; chan.pos = 0; float l, r; const float gain = 0.7071; /* constant-power panning center gain */ lily_store_value(mock_p_mutex_trylock, pboolean, TRUE); channel_update_shared(&chan); channel_get_next_sample(&l, &r, &chan); lily_assert_int_equal(mock_p_mutex_trylock->n_calls, 1); lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 1); lily_assert_int_equal(chan.pos, 1); lily_assert_float_equal(l, gain * 1.0f, 0.1f); lily_assert_float_equal(r, gain * 1.0f + 0.2f, 0.1f); lily_store_value(mock_p_mutex_trylock, pboolean, TRUE); channel_update_shared(&chan); channel_get_next_sample(&l, &r, &chan); lily_assert_int_equal(mock_p_mutex_trylock->n_calls, 2); lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 2); lily_assert_int_equal(chan.pos, 2); lily_assert_float_equal(l, gain * 0.5f, 0.1f); lily_assert_float_equal(r, gain * 0.5f + 0.5f, 0.1f); lily_store_value(mock_p_mutex_trylock, pboolean, TRUE); channel_update_shared(&chan); channel_get_next_sample(&l, &r, &chan); lily_assert_int_equal(mock_p_mutex_trylock->n_calls, 3); lily_assert_int_equal(mock_p_mutex_unlock->n_calls, 3); lily_assert_int_equal(chan.shared.active, false); lily_assert_float_equal(l, gain * 0.2f, 0.1f); lily_assert_float_equal(r, gain * 0.2f + 1.0f, 0.1f); } void suite_channel() { lily_run_test(test_channel_init); lily_run_test(test_channel_pause); lily_run_test(test_channel_resume); lily_run_test(test_channel_set_volume); lily_run_test(test_channel_set_pan); lily_run_test(test_channel_reset_last_loop); lily_run_test(test_channel_reset_penultimate_loop); lily_run_test(test_channel_reset_infinite_loop); lily_run_test(test_channel_sound_load); lily_run_test(test_channel_sound_load_mono); lily_run_test(test_channel_sound_load_preserve); lily_run_test(test_channel_sound_fail); lily_run_test(test_channel_get_next_sample_inactive); lily_run_test(test_channel_get_next_sample_paused); lily_run_test(test_channel_get_next_sample_normal); lily_run_test(test_channel_get_next_sample_nolock); lily_run_test(test_channel_get_next_sample_volume_0); lily_run_test(test_channel_get_next_sample_mono); lily_run_test(test_channel_get_next_sample_mono_panned); lily_run_test(test_channel_get_next_sample_panned); lily_mock_destroy(mock_p_mutex_new); lily_mock_destroy(mock_p_mutex_trylock); lily_mock_destroy(mock_p_mutex_unlock); }