From 9722fb3724a6789c1b9258ade7eb89da59e27597 Mon Sep 17 00:00:00 2001 From: Chris Thrasher Date: Sat, 15 Apr 2023 20:50:24 -0600 Subject: [PATCH] Add tests for Audio module types --- .github/workflows/ci.yml | 26 ++-- test/Audio/Music.test.cpp | 209 ++++++++++++++++++++++++++++++- test/Audio/Sound.test.cpp | 89 +++++++++++-- test/Audio/SoundBuffer.test.cpp | 149 +++++++++++++++++++++- test/Audio/SoundSource.test.cpp | 136 +++++++++++++++++++- test/Audio/SoundStream.test.cpp | 44 ++++++- test/CMakeLists.txt | 7 ++ test/TestUtilities/AudioUtil.cpp | 12 ++ test/TestUtilities/AudioUtil.hpp | 5 + 9 files changed, 640 insertions(+), 37 deletions(-) create mode 100644 test/TestUtilities/AudioUtil.cpp create mode 100644 test/TestUtilities/AudioUtil.hpp diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3a1e31a75..714826e73 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,13 +36,13 @@ jobs: - { name: Windows VS2022 Unity, os: windows-2022, flags: -DSFML_USE_MESA3D=TRUE -DCMAKE_UNITY_BUILD=ON -GNinja } - { name: Windows LLVM/Clang, os: windows-2022, flags: -DSFML_USE_MESA3D=TRUE -DCMAKE_CXX_COMPILER=clang++ -GNinja } - { name: Windows MinGW, os: windows-2022, flags: -DSFML_USE_MESA3D=TRUE -DCMAKE_CXX_COMPILER=g++ -GNinja } - - { name: Linux GCC, os: ubuntu-22.04, flags: -GNinja } - - { name: Linux Clang, os: ubuntu-22.04, flags: -DCMAKE_CXX_COMPILER=clang++ -GNinja , gcovr_options: '--gcov-executable="llvm-cov-$CLANG_VERSION gcov"' } - - { name: Linux GCC DRM, os: ubuntu-22.04, flags: -DSFML_USE_DRM=ON -DSFML_RUN_DISPLAY_TESTS=OFF -GNinja } - - { name: Linux GCC OpenGL ES, os: ubuntu-22.04, flags: -DSFML_OPENGL_ES=ON -DSFML_RUN_DISPLAY_TESTS=OFF -GNinja } + - { name: Linux GCC, os: ubuntu-22.04, flags: -DSFML_RUN_AUDIO_DEVICE_TESTS=OFF -GNinja } + - { name: Linux Clang, os: ubuntu-22.04, flags: -DCMAKE_CXX_COMPILER=clang++ -DSFML_RUN_AUDIO_DEVICE_TESTS=OFF -GNinja , gcovr_options: '--gcov-executable="llvm-cov-$CLANG_VERSION gcov"' } + - { name: Linux GCC DRM, os: ubuntu-22.04, flags: -DSFML_USE_DRM=ON -DSFML_RUN_DISPLAY_TESTS=OFF -DSFML_RUN_AUDIO_DEVICE_TESTS=OFF -GNinja } + - { name: Linux GCC OpenGL ES, os: ubuntu-22.04, flags: -DSFML_OPENGL_ES=ON -DSFML_RUN_DISPLAY_TESTS=OFF -DSFML_RUN_AUDIO_DEVICE_TESTS=OFF -GNinja } - { name: macOS x64, os: macos-12, flags: -GNinja } - { name: macOS x64 Xcode, os: macos-12, flags: -GXcode } - - { name: macOS arm64, os: macos-14, flags: -GNinja } + - { name: macOS arm64, os: macos-14, flags: -GNinja -DSFML_RUN_AUDIO_DEVICE_TESTS=OFF } - { name: iOS, os: macos-12, flags: -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_ARCHITECTURES=arm64 } - { name: iOS Xcode, os: macos-12, flags: -DCMAKE_SYSTEM_NAME=iOS -GXcode -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=NO } config: @@ -56,9 +56,9 @@ jobs: - platform: { name: Windows VS2022 x64, os: windows-2022 } config: { name: Static with PCH (MSVC), flags: -DSFML_USE_MESA3D=TRUE -GNinja -DBUILD_SHARED_LIBS=FALSE -DSFML_ENABLE_PCH=1 } - platform: { name: Linux GCC, os: ubuntu-22.04 } - config: { name: Static with PCH (GCC), flags: -GNinja -DCMAKE_CXX_COMPILER=g++ -DBUILD_SHARED_LIBS=FALSE -DSFML_ENABLE_PCH=1 } + config: { name: Static with PCH (GCC), flags: -GNinja -DCMAKE_CXX_COMPILER=g++ -DBUILD_SHARED_LIBS=FALSE -DSFML_ENABLE_PCH=1 -DSFML_RUN_AUDIO_DEVICE_TESTS=OFF } - platform: { name: Linux Clang, os: ubuntu-22.04 } - config: { name: Static with PCH (Clang), flags: -GNinja -DCMAKE_CXX_COMPILER=clang++ -DBUILD_SHARED_LIBS=FALSE -DSFML_ENABLE_PCH=1 } + config: { name: Static with PCH (Clang), flags: -GNinja -DCMAKE_CXX_COMPILER=clang++ -DBUILD_SHARED_LIBS=FALSE -DSFML_ENABLE_PCH=1 -DSFML_RUN_AUDIO_DEVICE_TESTS=OFF } - platform: { name: Windows MinGW, os: windows-2022 } config: { name: Static Standard Libraries, flags: -GNinja -DSFML_USE_MESA3D=TRUE -DCMAKE_CXX_COMPILER=g++ -DSFML_USE_STATIC_STD_LIBS=TRUE } - platform: { name: Windows MinGW, os: windows-2022 } @@ -70,7 +70,7 @@ jobs: - platform: { name: Android, os: ubuntu-latest } config: name: x86 (API 21) - flags: -GNinja -DCMAKE_ANDROID_ARCH_ABI=x86 -DCMAKE_SYSTEM_NAME=Android -DCMAKE_SYSTEM_VERSION=21 -DCMAKE_ANDROID_NDK=$ANDROID_NDK_ROOT -DBUILD_SHARED_LIBS=TRUE -DCMAKE_ANDROID_STL_TYPE=c++_shared -DSFML_RUN_DISPLAY_TESTS=OFF + flags: -GNinja -DCMAKE_ANDROID_ARCH_ABI=x86 -DCMAKE_SYSTEM_NAME=Android -DCMAKE_SYSTEM_VERSION=21 -DCMAKE_ANDROID_NDK=$ANDROID_NDK_ROOT -DBUILD_SHARED_LIBS=TRUE -DCMAKE_ANDROID_STL_TYPE=c++_shared -DSFML_RUN_DISPLAY_TESTS=OFF -DSFML_RUN_AUDIO_DEVICE_TESTS=OFF arch: x86 api: 21 libcxx: i686-linux-android/libc++_shared.so @@ -80,7 +80,7 @@ jobs: - platform: { name: Android, os: ubuntu-latest } config: name: x86_64 (API 24) - flags: -GNinja -DCMAKE_ANDROID_ARCH_ABI=x86_64 -DCMAKE_SYSTEM_NAME=Android -DCMAKE_SYSTEM_VERSION=24 -DCMAKE_ANDROID_NDK=$ANDROID_NDK_ROOT -DBUILD_SHARED_LIBS=TRUE -DCMAKE_ANDROID_STL_TYPE=c++_shared -DSFML_RUN_DISPLAY_TESTS=OFF + flags: -GNinja -DCMAKE_ANDROID_ARCH_ABI=x86_64 -DCMAKE_SYSTEM_NAME=Android -DCMAKE_SYSTEM_VERSION=24 -DCMAKE_ANDROID_NDK=$ANDROID_NDK_ROOT -DBUILD_SHARED_LIBS=TRUE -DCMAKE_ANDROID_STL_TYPE=c++_shared -DSFML_RUN_DISPLAY_TESTS=OFF -DSFML_RUN_AUDIO_DEVICE_TESTS=OFF arch: x86_64 api: 24 libcxx: x86_64-linux-android/libc++_shared.so @@ -98,7 +98,7 @@ jobs: - platform: { name: Android, os: ubuntu-latest } config: name: arm64-v8a (API 33) - flags: -GNinja -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a -DCMAKE_SYSTEM_NAME=Android -DCMAKE_SYSTEM_VERSION=33 -DCMAKE_ANDROID_NDK=$ANDROID_NDK_ROOT -DBUILD_SHARED_LIBS=TRUE -DCMAKE_ANDROID_STL_TYPE=c++_shared -DSFML_RUN_DISPLAY_TESTS=OFF + flags: -GNinja -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a -DCMAKE_SYSTEM_NAME=Android -DCMAKE_SYSTEM_VERSION=33 -DCMAKE_ANDROID_NDK=$ANDROID_NDK_ROOT -DBUILD_SHARED_LIBS=TRUE -DCMAKE_ANDROID_STL_TYPE=c++_shared -DSFML_RUN_DISPLAY_TESTS=OFF -DSFML_RUN_AUDIO_DEVICE_TESTS=OFF arch: arm64-v8a api: 33 libcxx: aarch64-linux-android/libc++_shared.so @@ -386,9 +386,9 @@ jobs: fail-fast: false matrix: platform: - - { name: Linux, os: ubuntu-22.04 } - - { name: Linux DRM, os: ubuntu-22.04, flags: -DSFML_RUN_DISPLAY_TESTS=OFF -DSFML_USE_DRM=ON } - - { name: Linux GCC OpenGL ES, os: ubuntu-22.04, flags: -DSFML_RUN_DISPLAY_TESTS=OFF -DSFML_OPENGL_ES=ON } + - { name: Linux, os: ubuntu-22.04, flags: -DSFML_RUN_AUDIO_DEVICE_TESTS=OFF } + - { name: Linux DRM, os: ubuntu-22.04, flags: -DSFML_RUN_AUDIO_DEVICE_TESTS=OFF -DSFML_RUN_DISPLAY_TESTS=OFF -DSFML_USE_DRM=ON } + - { name: Linux GCC OpenGL ES, os: ubuntu-22.04, flags: -DSFML_RUN_AUDIO_DEVICE_TESTS=OFF -DSFML_RUN_DISPLAY_TESTS=OFF -DSFML_OPENGL_ES=ON } steps: - name: Checkout Code diff --git a/test/Audio/Music.test.cpp b/test/Audio/Music.test.cpp index 150771a1f..cf29595f0 100644 --- a/test/Audio/Music.test.cpp +++ b/test/Audio/Music.test.cpp @@ -1,8 +1,209 @@ #include +// Other 1st party headers +#include + +#include + +#include +#include +#include +#include +#include #include -static_assert(!std::is_copy_constructible_v); -static_assert(!std::is_copy_assignable_v); -static_assert(!std::is_nothrow_move_constructible_v); -static_assert(!std::is_nothrow_move_assignable_v); +TEST_CASE("[Audio] sf::Music", runAudioDeviceTests()) +{ + SECTION("Type traits") + { + STATIC_CHECK(!std::is_copy_constructible_v); + STATIC_CHECK(!std::is_copy_assignable_v); + STATIC_CHECK(!std::is_nothrow_move_constructible_v); + STATIC_CHECK(!std::is_nothrow_move_assignable_v); + STATIC_CHECK(std::has_virtual_destructor_v); + } + + SECTION("Span") + { + const sf::Music::Span span; + CHECK(span.offset == 0); + CHECK(span.length == 0); + + const sf::Music::TimeSpan timeSpan; + CHECK(timeSpan.offset == sf::Time::Zero); + CHECK(timeSpan.length == sf::Time::Zero); + } + + SECTION("Construction") + { + const sf::Music music; + CHECK(music.getDuration() == sf::Time::Zero); + const auto [offset, length] = music.getLoopPoints(); + CHECK(offset == sf::Time::Zero); + CHECK(length == sf::Time::Zero); + CHECK(music.getChannelCount() == 0); + CHECK(music.getSampleRate() == 0); + CHECK(music.getStatus() == sf::SoundSource::Status::Stopped); + CHECK(music.getPlayingOffset() == sf::Time::Zero); + CHECK(!music.getLoop()); + } + + SECTION("openFromFile()") + { + sf::Music music; + + SECTION("Invalid file") + { + REQUIRE(!music.openFromFile("does/not/exist.wav")); + CHECK(music.getDuration() == sf::Time::Zero); + const auto [offset, length] = music.getLoopPoints(); + CHECK(offset == sf::Time::Zero); + CHECK(length == sf::Time::Zero); + CHECK(music.getChannelCount() == 0); + CHECK(music.getSampleRate() == 0); + CHECK(music.getStatus() == sf::SoundSource::Status::Stopped); + CHECK(music.getPlayingOffset() == sf::Time::Zero); + CHECK(!music.getLoop()); + } + + SECTION("Valid file") + { + REQUIRE(music.openFromFile("Audio/ding.mp3")); + CHECK(music.getDuration() == sf::microseconds(1990884)); + const auto [offset, length] = music.getLoopPoints(); + CHECK(offset == sf::Time::Zero); + CHECK(length == sf::microseconds(1990884)); + CHECK(music.getChannelCount() == 1); + CHECK(music.getSampleRate() == 44100); + CHECK(music.getStatus() == sf::SoundSource::Status::Stopped); + CHECK(music.getPlayingOffset() == sf::Time::Zero); + CHECK(!music.getLoop()); + } + } + + SECTION("openFromMemory()") + { + std::vector memory; + sf::Music music; + + SECTION("Invalid buffer") + { + REQUIRE(!music.openFromMemory(memory.data(), memory.size())); + CHECK(music.getDuration() == sf::Time::Zero); + const auto [offset, length] = music.getLoopPoints(); + CHECK(offset == sf::Time::Zero); + CHECK(length == sf::Time::Zero); + CHECK(music.getChannelCount() == 0); + CHECK(music.getSampleRate() == 0); + CHECK(music.getStatus() == sf::SoundSource::Status::Stopped); + CHECK(music.getPlayingOffset() == sf::Time::Zero); + CHECK(!music.getLoop()); + } + + SECTION("Valid buffer") + { + memory = loadIntoMemory("Audio/ding.flac"); + REQUIRE(music.openFromMemory(memory.data(), memory.size())); + CHECK(music.getDuration() == sf::microseconds(1990884)); + const auto [offset, length] = music.getLoopPoints(); + CHECK(offset == sf::Time::Zero); + CHECK(length == sf::microseconds(1990884)); + CHECK(music.getChannelCount() == 1); + CHECK(music.getSampleRate() == 44100); + CHECK(music.getStatus() == sf::SoundSource::Status::Stopped); + CHECK(music.getPlayingOffset() == sf::Time::Zero); + CHECK(!music.getLoop()); + } + } + + SECTION("openFromStream()") + { + sf::FileInputStream stream; + sf::Music music; + + SECTION("Invalid stream") + { + CHECK(!music.openFromStream(stream)); + CHECK(music.getDuration() == sf::Time::Zero); + const auto [offset, length] = music.getLoopPoints(); + CHECK(offset == sf::Time::Zero); + CHECK(length == sf::Time::Zero); + CHECK(music.getChannelCount() == 0); + CHECK(music.getSampleRate() == 0); + CHECK(music.getStatus() == sf::SoundSource::Status::Stopped); + CHECK(music.getPlayingOffset() == sf::Time::Zero); + CHECK(!music.getLoop()); + } + + SECTION("Valid stream") + { + REQUIRE(stream.open("Audio/doodle_pop.ogg")); + REQUIRE(music.openFromStream(stream)); + CHECK(music.getDuration() == sf::microseconds(24002176)); + const auto [offset, length] = music.getLoopPoints(); + CHECK(offset == sf::Time::Zero); + CHECK(length == sf::microseconds(24002176)); + CHECK(music.getChannelCount() == 2); + CHECK(music.getSampleRate() == 44100); + CHECK(music.getStatus() == sf::SoundSource::Status::Stopped); + CHECK(music.getPlayingOffset() == sf::Time::Zero); + CHECK(!music.getLoop()); + } + } + + SECTION("play/pause/stop") + { + sf::Music music; + REQUIRE(music.openFromFile("Audio/ding.mp3")); + + // Wait for background thread to start + music.play(); + while (music.getStatus() == sf::SoundSource::Status::Stopped) + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + CHECK(music.getStatus() == sf::SoundSource::Status::Playing); + + // Wait for background thread to pause + music.pause(); + while (music.getStatus() == sf::SoundSource::Status::Playing) + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + CHECK(music.getStatus() == sf::SoundSource::Status::Paused); + + // Wait for background thread to stop + music.stop(); + while (music.getStatus() == sf::SoundSource::Status::Paused) + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + CHECK(music.getStatus() == sf::SoundSource::Status::Stopped); + } + + SECTION("setLoopPoints()") + { + sf::Music music; + + SECTION("No file") + { + music.setLoopPoints({sf::Time::Zero, sf::Time::Zero}); + const auto [offset, length] = music.getLoopPoints(); + CHECK(offset == sf::Time::Zero); + CHECK(length == sf::Time::Zero); + CHECK(music.getChannelCount() == 0); + CHECK(music.getSampleRate() == 0); + CHECK(music.getStatus() == sf::SoundSource::Status::Stopped); + CHECK(music.getPlayingOffset() == sf::Time::Zero); + CHECK(!music.getLoop()); + } + + SECTION("Loaded file") + { + REQUIRE(music.openFromFile("Audio/killdeer.wav")); + music.setLoopPoints({sf::seconds(1), sf::seconds(2)}); + const auto [offset, length] = music.getLoopPoints(); + CHECK(offset == sf::seconds(1)); + CHECK(length == sf::seconds(2)); + CHECK(music.getChannelCount() == 1); + CHECK(music.getSampleRate() == 22050); + CHECK(music.getStatus() == sf::SoundSource::Status::Stopped); + CHECK(music.getPlayingOffset() == sf::Time::Zero); + CHECK(!music.getLoop()); + } + } +} diff --git a/test/Audio/Sound.test.cpp b/test/Audio/Sound.test.cpp index f0944d743..e97006522 100644 --- a/test/Audio/Sound.test.cpp +++ b/test/Audio/Sound.test.cpp @@ -1,11 +1,86 @@ #include +// Other 1st party headers +#include + +#include + +#include + +#include +#include #include -static_assert(!std::is_constructible_v); -static_assert(std::is_copy_constructible_v); -static_assert(std::is_copy_assignable_v); -static_assert(std::is_move_constructible_v); -static_assert(!std::is_nothrow_move_constructible_v); -static_assert(std::is_move_assignable_v); -static_assert(!std::is_nothrow_move_assignable_v); +TEST_CASE("[Audio] sf::Sound", runAudioDeviceTests()) +{ + SECTION("Type traits") + { + STATIC_CHECK(!std::is_constructible_v); + STATIC_CHECK(std::is_copy_constructible_v); + STATIC_CHECK(std::is_copy_assignable_v); + STATIC_CHECK(std::is_move_constructible_v); + STATIC_CHECK(!std::is_nothrow_move_constructible_v); + STATIC_CHECK(std::is_move_assignable_v); + STATIC_CHECK(!std::is_nothrow_move_assignable_v); + STATIC_CHECK(std::has_virtual_destructor_v); + } + + sf::SoundBuffer soundBuffer; + REQUIRE(soundBuffer.loadFromFile("Audio/ding.flac")); + + SECTION("Construction") + { + const sf::Sound sound(soundBuffer); + CHECK(&sound.getBuffer() == &soundBuffer); + CHECK(!sound.getLoop()); + CHECK(sound.getPlayingOffset() == sf::Time::Zero); + CHECK(sound.getStatus() == sf::SoundSource::Status::Stopped); + } + + SECTION("Copy semantics") + { + const sf::Sound sound(soundBuffer); + + SECTION("Construction") + { + const sf::Sound soundCopy(sound); // NOLINT(performance-unnecessary-copy-initialization) + CHECK(&soundCopy.getBuffer() == &soundBuffer); + CHECK(!soundCopy.getLoop()); + CHECK(soundCopy.getPlayingOffset() == sf::Time::Zero); + CHECK(soundCopy.getStatus() == sf::SoundSource::Status::Stopped); + } + + SECTION("Assignment") + { + const sf::SoundBuffer emptySoundBuffer; + sf::Sound soundCopy(emptySoundBuffer); + soundCopy = sound; + CHECK(&soundCopy.getBuffer() == &soundBuffer); + CHECK(!soundCopy.getLoop()); + CHECK(soundCopy.getPlayingOffset() == sf::Time::Zero); + CHECK(soundCopy.getStatus() == sf::SoundSource::Status::Stopped); + } + } + + SECTION("Set/get buffer") + { + const sf::SoundBuffer otherSoundBuffer; + sf::Sound sound(soundBuffer); + sound.setBuffer(otherSoundBuffer); + CHECK(&sound.getBuffer() == &otherSoundBuffer); + } + + SECTION("Set/get loop") + { + sf::Sound sound(soundBuffer); + sound.setLoop(true); + CHECK(sound.getLoop()); + } + + SECTION("Set/get playing offset") + { + sf::Sound sound(soundBuffer); + sound.setPlayingOffset(sf::seconds(10)); + CHECK(sound.getPlayingOffset() == sf::seconds(10)); + } +} diff --git a/test/Audio/SoundBuffer.test.cpp b/test/Audio/SoundBuffer.test.cpp index c62ea06db..a907f2470 100644 --- a/test/Audio/SoundBuffer.test.cpp +++ b/test/Audio/SoundBuffer.test.cpp @@ -1,10 +1,147 @@ #include +// Other 1st party headers +#include + +#include + +#include +#include +#include #include -static_assert(std::is_copy_constructible_v); -static_assert(std::is_copy_assignable_v); -static_assert(std::is_move_constructible_v); -static_assert(!std::is_nothrow_move_constructible_v); -static_assert(std::is_move_assignable_v); -static_assert(!std::is_nothrow_move_assignable_v); +TEST_CASE("[Audio] sf::SoundBuffer", runAudioDeviceTests()) +{ + SECTION("Type traits") + { + STATIC_CHECK(std::is_copy_constructible_v); + STATIC_CHECK(std::is_copy_assignable_v); + STATIC_CHECK(std::is_move_constructible_v); + STATIC_CHECK(!std::is_nothrow_move_constructible_v); + STATIC_CHECK(std::is_move_assignable_v); + STATIC_CHECK(!std::is_nothrow_move_assignable_v); + } + + SECTION("Construction") + { + const sf::SoundBuffer soundBuffer; + CHECK(soundBuffer.getSamples() == nullptr); + CHECK(soundBuffer.getSampleCount() == 0); + CHECK(soundBuffer.getSampleRate() == 44100); + CHECK(soundBuffer.getChannelCount() == 1); + CHECK(soundBuffer.getDuration() == sf::Time::Zero); + } + + SECTION("Copy semantics") + { + sf::SoundBuffer soundBuffer; + REQUIRE(soundBuffer.loadFromFile("Audio/ding.flac")); + + SECTION("Construction") + { + const sf::SoundBuffer soundBufferCopy(soundBuffer); // NOLINT(performance-unnecessary-copy-initialization) + CHECK(soundBufferCopy.getSamples() != nullptr); + CHECK(soundBufferCopy.getSampleCount() == 87798); + CHECK(soundBufferCopy.getSampleRate() == 44100); + CHECK(soundBufferCopy.getChannelCount() == 1); + CHECK(soundBufferCopy.getDuration() == sf::microseconds(1990884)); + } + + SECTION("Assignment") + { + sf::SoundBuffer soundBufferCopy; + soundBufferCopy = soundBuffer; + CHECK(soundBufferCopy.getSamples() != nullptr); + CHECK(soundBufferCopy.getSampleCount() == 87798); + CHECK(soundBufferCopy.getSampleRate() == 44100); + CHECK(soundBufferCopy.getChannelCount() == 1); + CHECK(soundBufferCopy.getDuration() == sf::microseconds(1990884)); + } + } + + SECTION("loadFromFile()") + { + sf::SoundBuffer soundBuffer; + + SECTION("Invalid filename") + { + CHECK(!soundBuffer.loadFromFile("does/not/exist.wav")); + } + + SECTION("Valid file") + { + REQUIRE(soundBuffer.loadFromFile("Audio/ding.flac")); + CHECK(soundBuffer.getSamples() != nullptr); + CHECK(soundBuffer.getSampleCount() == 87798); + CHECK(soundBuffer.getSampleRate() == 44100); + CHECK(soundBuffer.getChannelCount() == 1); + CHECK(soundBuffer.getDuration() == sf::microseconds(1990884)); + } + } + + SECTION("loadFromMemory()") + { + sf::SoundBuffer soundBuffer; + + SECTION("Invalid memory") + { + CHECK(!soundBuffer.loadFromMemory(nullptr, 0)); + constexpr std::array memory{}; + CHECK(!soundBuffer.loadFromMemory(memory.data(), memory.size())); + } + + SECTION("Valid memory") + { + const auto memory = loadIntoMemory("Audio/ding.flac"); + REQUIRE(soundBuffer.loadFromMemory(memory.data(), memory.size())); + CHECK(soundBuffer.getSamples() != nullptr); + CHECK(soundBuffer.getSampleCount() == 87798); + CHECK(soundBuffer.getSampleRate() == 44100); + CHECK(soundBuffer.getChannelCount() == 1); + CHECK(soundBuffer.getDuration() == sf::microseconds(1990884)); + } + } + + SECTION("loadFromStream()") + { + sf::FileInputStream stream; + sf::SoundBuffer soundBuffer; + + SECTION("Invalid stream") + { + CHECK(!soundBuffer.loadFromStream(stream)); + } + + SECTION("Valid stream") + { + REQUIRE(stream.open("Audio/ding.flac")); + REQUIRE(soundBuffer.loadFromStream(stream)); + CHECK(soundBuffer.getSamples() != nullptr); + CHECK(soundBuffer.getSampleCount() == 87798); + CHECK(soundBuffer.getSampleRate() == 44100); + CHECK(soundBuffer.getChannelCount() == 1); + CHECK(soundBuffer.getDuration() == sf::microseconds(1990884)); + } + } + + SECTION("saveToFile()") + { + const auto filename = std::filesystem::temp_directory_path() / "ding.flac"; + + { + sf::SoundBuffer soundBuffer; + REQUIRE(soundBuffer.loadFromFile("Audio/ding.flac")); + REQUIRE(soundBuffer.saveToFile(filename)); + } + + sf::SoundBuffer soundBuffer; + REQUIRE(soundBuffer.loadFromFile(filename)); + CHECK(soundBuffer.getSamples() != nullptr); + CHECK(soundBuffer.getSampleCount() == 87798); + CHECK(soundBuffer.getSampleRate() == 44100); + CHECK(soundBuffer.getChannelCount() == 1); + CHECK(soundBuffer.getDuration() == sf::microseconds(1990884)); + + CHECK(std::filesystem::remove(filename)); + } +} diff --git a/test/Audio/SoundSource.test.cpp b/test/Audio/SoundSource.test.cpp index 4804e6781..8fafb31dc 100644 --- a/test/Audio/SoundSource.test.cpp +++ b/test/Audio/SoundSource.test.cpp @@ -1,10 +1,134 @@ #include +#include + +#include +#include #include -static_assert(!std::is_constructible_v); -static_assert(!std::is_copy_constructible_v); -static_assert(std::is_copy_assignable_v); -static_assert(!std::is_move_constructible_v); -static_assert(std::is_move_assignable_v); -static_assert(!std::is_nothrow_move_assignable_v); +namespace +{ +class SoundSource : public sf::SoundSource +{ + void play() override + { + } + + void pause() override + { + } + + void stop() override + { + } + + void* getSound() const override + { + return {}; + } + +public: + Status getStatus() const override + { + return {}; + } +}; +} // namespace + +TEST_CASE("[Audio] sf::SoundSource", runAudioDeviceTests()) +{ + SECTION("Type traits") + { + STATIC_CHECK(!std::is_constructible_v); + STATIC_CHECK(!std::is_copy_constructible_v); + STATIC_CHECK(std::is_copy_assignable_v); + STATIC_CHECK(!std::is_move_constructible_v); + STATIC_CHECK(std::is_move_assignable_v); + STATIC_CHECK(!std::is_nothrow_move_assignable_v); + STATIC_CHECK(std::has_virtual_destructor_v); + } + + SECTION("Construction") + { + const SoundSource soundSource; + CHECK(soundSource.getPitch() == 0); + CHECK(soundSource.getVolume() == 0); + CHECK(soundSource.getPosition() == sf::Vector3f()); + CHECK(!soundSource.isRelativeToListener()); + CHECK(soundSource.getMinDistance() == 0); + CHECK(soundSource.getAttenuation() == 0); + CHECK(soundSource.getStatus() == sf::SoundSource::Status::Stopped); + } + + SECTION("Copy semantics") + { + const SoundSource soundSource; + + SECTION("Construction") + { + const SoundSource soundSourceCopy(soundSource); // NOLINT(performance-unnecessary-copy-initialization) + CHECK(soundSourceCopy.getPitch() == 0); + CHECK(soundSourceCopy.getVolume() == 0); + CHECK(soundSourceCopy.getPosition() == sf::Vector3f()); + CHECK(!soundSourceCopy.isRelativeToListener()); + CHECK(soundSourceCopy.getMinDistance() == 0); + CHECK(soundSourceCopy.getAttenuation() == 0); + CHECK(soundSourceCopy.getStatus() == sf::SoundSource::Status::Stopped); + } + + SECTION("Assignment") + { + SoundSource soundSourceCopy; + soundSourceCopy = soundSource; + CHECK(soundSourceCopy.getPitch() == 0); + CHECK(soundSourceCopy.getVolume() == 0); + CHECK(soundSourceCopy.getPosition() == sf::Vector3f()); + CHECK(!soundSourceCopy.isRelativeToListener()); + CHECK(soundSourceCopy.getMinDistance() == 0); + CHECK(soundSourceCopy.getAttenuation() == 0); + CHECK(soundSourceCopy.getStatus() == sf::SoundSource::Status::Stopped); + } + } + + SECTION("Set/get pitch") + { + SoundSource soundSource; + soundSource.setPitch(42); + CHECK(soundSource.getPitch() == 0); + } + + SECTION("Set/get volume") + { + SoundSource soundSource; + soundSource.setVolume(0.5f); + CHECK(soundSource.getVolume() == 0); + } + + SECTION("Set/get position") + { + SoundSource soundSource; + soundSource.setPosition({1, 2, 3}); + CHECK(soundSource.getPosition() == sf::Vector3f()); + } + + SECTION("Set/get relative to listener") + { + SoundSource soundSource; + soundSource.setRelativeToListener(true); + CHECK(!soundSource.isRelativeToListener()); + } + + SECTION("Set/get min distance") + { + SoundSource soundSource; + soundSource.setMinDistance(12.34f); + CHECK(soundSource.getMinDistance() == 0); + } + + SECTION("Set/get attenuation") + { + SoundSource soundSource; + soundSource.setAttenuation(10); + CHECK(soundSource.getAttenuation() == 0); + } +} diff --git a/test/Audio/SoundStream.test.cpp b/test/Audio/SoundStream.test.cpp index aca5e5525..bc89d72f6 100644 --- a/test/Audio/SoundStream.test.cpp +++ b/test/Audio/SoundStream.test.cpp @@ -2,9 +2,26 @@ #include +#include +#include #include -TEST_CASE("[Audio] sf::SoundStream") +namespace +{ +class SoundStream : public sf::SoundStream +{ + [[nodiscard]] bool onGetData(Chunk& /* data */) override + { + return true; + } + + void onSeek(sf::Time /* timeOffset */) override + { + } +}; +} // namespace + +TEST_CASE("[Audio] sf::SoundStream", runAudioDeviceTests()) { SECTION("Type traits") { @@ -13,6 +30,7 @@ TEST_CASE("[Audio] sf::SoundStream") STATIC_CHECK(!std::is_copy_assignable_v); STATIC_CHECK(!std::is_nothrow_move_constructible_v); STATIC_CHECK(!std::is_nothrow_move_assignable_v); + STATIC_CHECK(std::has_virtual_destructor_v); } SECTION("Chunk") @@ -21,4 +39,28 @@ TEST_CASE("[Audio] sf::SoundStream") CHECK(chunk.samples == nullptr); CHECK(chunk.sampleCount == 0); } + + SECTION("Construction") + { + const SoundStream soundStream; + CHECK(soundStream.getChannelCount() == 0); + CHECK(soundStream.getSampleRate() == 0); + CHECK(soundStream.getStatus() == sf::SoundSource::Status::Stopped); + CHECK(soundStream.getPlayingOffset() == sf::Time::Zero); + CHECK(!soundStream.getLoop()); + } + + SECTION("Set/get playing offset") + { + SoundStream soundStream; + soundStream.setPlayingOffset(sf::milliseconds(100)); + CHECK(soundStream.getPlayingOffset() == sf::milliseconds(0)); + } + + SECTION("Set/get loop") + { + SoundStream soundStream; + soundStream.setLoop(true); + CHECK(soundStream.getLoop()); + } } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 36111b233..563d6d6c2 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -28,6 +28,8 @@ add_library(sfml-test-main STATIC TestUtilities/WindowUtil.cpp TestUtilities/GraphicsUtil.hpp TestUtilities/GraphicsUtil.cpp + TestUtilities/AudioUtil.hpp + TestUtilities/AudioUtil.cpp ) target_include_directories(sfml-test-main PUBLIC TestUtilities) target_link_libraries(sfml-test-main PUBLIC SFML::System Catch2::Catch2WithMain) @@ -43,6 +45,11 @@ if(SFML_RUN_DISPLAY_TESTS) target_compile_definitions(sfml-test-main PRIVATE SFML_RUN_DISPLAY_TESTS) endif() +sfml_set_option(SFML_RUN_AUDIO_DEVICE_TESTS ON BOOL "TRUE to run tests that require an audio device, FALSE to ignore it") +if(SFML_RUN_AUDIO_DEVICE_TESTS) + target_compile_definitions(sfml-test-main PRIVATE SFML_RUN_AUDIO_DEVICE_TESTS) +endif() + set(SYSTEM_SRC System/Angle.test.cpp System/Clock.test.cpp diff --git a/test/TestUtilities/AudioUtil.cpp b/test/TestUtilities/AudioUtil.cpp new file mode 100644 index 000000000..30b4f50ca --- /dev/null +++ b/test/TestUtilities/AudioUtil.cpp @@ -0,0 +1,12 @@ +#include + +std::string runAudioDeviceTests() +{ +#ifdef SFML_RUN_AUDIO_DEVICE_TESTS + return ""; +#else + // https://github.com/catchorg/Catch2/blob/devel/docs/test-cases-and-sections.md#special-tags + // This tag tells Catch2 to not run a given TEST_CASE + return "[.audio_device]"; +#endif +} diff --git a/test/TestUtilities/AudioUtil.hpp b/test/TestUtilities/AudioUtil.hpp new file mode 100644 index 000000000..c4d759c39 --- /dev/null +++ b/test/TestUtilities/AudioUtil.hpp @@ -0,0 +1,5 @@ +#pragma once + +#include + +[[nodiscard]] std::string runAudioDeviceTests();