test(libSceNgs2.native): run the waveform parse tests in their own executable
On Linux ngs2_atrac9 aborted without any output once TestParseFile was part of its main(). The exception that TestCorruptSuperframeAtPageEnd throws in the Ngs2 module and catches in main() has to resume through a cleanup landing pad inside main(). That resume goes through the unwinder statically linked into the test executable, which then fails with _URC_FATAL_PHASE2_ERROR and aborts silently. Whether main() gets such a pad depends on what the compiler inlines into it, so adding any function with non-trivial cleanups to that main() is enough to trigger it. Move the PCM and file parse tests into a new ngs2_parse executable and restore Ngs2Atrac9.cpp to its upstream content, so the test that catches exceptions is unchanged. The new executable has no catch and never relies on that path.
This commit is contained in:
parent
1bdc37bb86
commit
02166268ea
|
|
@ -8,7 +8,7 @@ if(MINGW)
|
|||
endif()
|
||||
|
||||
if(BUILD_TESTING)
|
||||
foreach(ngs2Test IN ITEMS Render Atrac9 Filter Custom)
|
||||
foreach(ngs2Test IN ITEMS Render Atrac9 Filter Custom Parse)
|
||||
string(TOLOWER ${ngs2Test} testName)
|
||||
add_test_executable(ngs2_${testName}_tests ${CMAKE_CURRENT_SOURCE_DIR}/tests/Ngs2${ngs2Test}.cpp)
|
||||
target_include_directories(ngs2_${testName}_tests PRIVATE ${LIBS_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/3rdparty/LibAtrac9/C/src)
|
||||
|
|
|
|||
|
|
@ -1,12 +1,9 @@
|
|||
#include "Ngs2Test.hpp"
|
||||
|
||||
#include "libatrac9.h"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <random>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
|
@ -179,71 +176,6 @@ static void TestParse() {
|
|||
Require(sceNgs2ParseWaveformData(wrongRate.data(), wrongRate.size(), &info) == SCE_NGS2_ERROR_INVALID_WAVEFORM_FORMAT);
|
||||
}
|
||||
|
||||
static std::vector<std::uint8_t> PcmFile(std::uint32_t channels, std::uint32_t sampleRate, std::uint32_t bits, std::uint32_t frames) {
|
||||
const std::uint32_t frameBytes = channels * bits / 8;
|
||||
std::vector<std::uint8_t> file;
|
||||
PutTag(file, "RIFF");
|
||||
Put32(file, 36 + frames * frameBytes);
|
||||
PutTag(file, "WAVE");
|
||||
PutTag(file, "fmt ");
|
||||
Put32(file, 16);
|
||||
Put16(file, 1);
|
||||
Put16(file, channels);
|
||||
Put32(file, sampleRate);
|
||||
Put32(file, sampleRate * frameBytes);
|
||||
Put16(file, frameBytes);
|
||||
Put16(file, bits);
|
||||
PutTag(file, "data");
|
||||
Put32(file, frames * frameBytes);
|
||||
file.resize(file.size() + frames * frameBytes, 0x11);
|
||||
return file;
|
||||
}
|
||||
|
||||
static void TestParsePcm() {
|
||||
const auto file = PcmFile(2, 44100, 16, 100);
|
||||
Ngs2WaveformInfo info{};
|
||||
Require(sceNgs2ParseWaveformData(file.data(), file.size(), &info) == SCE_NGS2_OK);
|
||||
Require(info.format.waveform_type == SCE_NGS2_WAVEFORM_TYPE_PCM_I16L && info.format.num_channels == 2 && info.format.sample_rate == 44100);
|
||||
Require(info.data_offset == 44 && info.data_size == 400 && info.num_samples == 100);
|
||||
Require(info.num_blocks == 1 && info.block[0].data_offset == 44 && info.block[0].data_size == 400 && info.block[0].num_samples == 100);
|
||||
|
||||
auto truncated = file;
|
||||
truncated.resize(44 + 202);
|
||||
Require(sceNgs2ParseWaveformData(truncated.data(), truncated.size(), &info) == SCE_NGS2_ERROR_INVALID_WAVEFORM_DATA);
|
||||
|
||||
auto partialFrame = PcmFile(2, 44100, 16, 100);
|
||||
partialFrame.resize(44 + 402, 0x11);
|
||||
const std::uint32_t partialSize = 402;
|
||||
std::memcpy(partialFrame.data() + 40, &partialSize, sizeof(partialSize));
|
||||
Require(sceNgs2ParseWaveformData(partialFrame.data(), partialFrame.size(), &info) == SCE_NGS2_ERROR_INVALID_WAVEFORM_DATA);
|
||||
|
||||
const auto eightBit = PcmFile(1, 44100, 8, 10);
|
||||
Require(sceNgs2ParseWaveformData(eightBit.data(), eightBit.size(), &info) == SCE_NGS2_ERROR_INVALID_WAVEFORM_FORMAT);
|
||||
const auto noChannels = PcmFile(0, 44100, 16, 10);
|
||||
Require(sceNgs2ParseWaveformData(noChannels.data(), noChannels.size(), &info) == SCE_NGS2_ERROR_INVALID_WAVEFORM_FORMAT);
|
||||
}
|
||||
|
||||
static void TestParseFile() {
|
||||
const auto wave = PcmFile(1, 22050, 16, 64);
|
||||
const char* const guestPath = "/aps5_ngs2_parse_file.wav";
|
||||
const auto path = ResolvePath_nid_no_patch(guestPath);
|
||||
{
|
||||
std::ofstream out(path, std::ios::binary);
|
||||
const char pad[3]{};
|
||||
out.write(pad, sizeof(pad));
|
||||
out.write(reinterpret_cast<const char*>(wave.data()), static_cast<std::streamsize>(wave.size()));
|
||||
}
|
||||
Ngs2WaveformInfo info{};
|
||||
Require(sceNgs2ParseWaveformFile(guestPath, 3, nullptr) == SCE_NGS2_ERROR_INVALID_OUT_ADDRESS);
|
||||
Require(sceNgs2ParseWaveformFile(nullptr, 0, &info) == SCE_NGS2_ERROR_INVALID_WAVEFORM_DATA);
|
||||
Require(sceNgs2ParseWaveformFile(guestPath, 3, &info) == SCE_NGS2_OK);
|
||||
Require(info.format.num_channels == 1 && info.format.sample_rate == 22050 && info.num_samples == 64);
|
||||
Require(info.data_offset == 3 + 44 && info.block[0].data_offset == 3 + 44 && info.data_size == 128);
|
||||
Require(sceNgs2ParseWaveformFile(guestPath, static_cast<std::uint32_t>(wave.size()) + 4, &info) == SCE_NGS2_ERROR_INVALID_WAVEFORM_DATA);
|
||||
Require(sceNgs2ParseWaveformFile(guestPath, 0, &info) == SCE_NGS2_ERROR_UNKNOWN_WAVEFORM_FORMAT);
|
||||
std::filesystem::remove(path);
|
||||
}
|
||||
|
||||
static void TestCalcBlock() {
|
||||
const Ngs2WaveformFormat format{SCE_NGS2_WAVEFORM_TYPE_ATRAC9, 1, 48000, Config, 0, 0};
|
||||
Ngs2WaveformBlock block{};
|
||||
|
|
@ -303,8 +235,6 @@ int main() {
|
|||
TestSkipAndBlockEnd(reference);
|
||||
TestRepeatAndState(reference);
|
||||
TestParse();
|
||||
TestParsePcm();
|
||||
TestParseFile();
|
||||
TestCalcBlock();
|
||||
TestCorruptSuperframeAtPageEnd();
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,94 @@
|
|||
#include "Ngs2Test.hpp"
|
||||
|
||||
#include "prx/libc/include/General.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
static void Put16(std::vector<std::uint8_t>& out, std::uint32_t value) {
|
||||
out.push_back(static_cast<std::uint8_t>(value));
|
||||
out.push_back(static_cast<std::uint8_t>(value >> 8));
|
||||
}
|
||||
|
||||
static void Put32(std::vector<std::uint8_t>& out, std::uint32_t value) {
|
||||
Put16(out, value & 0xffff);
|
||||
Put16(out, value >> 16);
|
||||
}
|
||||
|
||||
static void PutTag(std::vector<std::uint8_t>& out, const char* tag) {
|
||||
out.insert(out.end(), tag, tag + 4);
|
||||
}
|
||||
|
||||
static std::vector<std::uint8_t> PcmFile(std::uint32_t channels, std::uint32_t sampleRate, std::uint32_t bits, std::uint32_t frames) {
|
||||
const std::uint32_t frameBytes = channels * bits / 8;
|
||||
std::vector<std::uint8_t> file;
|
||||
PutTag(file, "RIFF");
|
||||
Put32(file, 36 + frames * frameBytes);
|
||||
PutTag(file, "WAVE");
|
||||
PutTag(file, "fmt ");
|
||||
Put32(file, 16);
|
||||
Put16(file, 1);
|
||||
Put16(file, channels);
|
||||
Put32(file, sampleRate);
|
||||
Put32(file, sampleRate * frameBytes);
|
||||
Put16(file, frameBytes);
|
||||
Put16(file, bits);
|
||||
PutTag(file, "data");
|
||||
Put32(file, frames * frameBytes);
|
||||
file.resize(file.size() + frames * frameBytes, 0x11);
|
||||
return file;
|
||||
}
|
||||
|
||||
static void TestParsePcm() {
|
||||
const auto file = PcmFile(2, 44100, 16, 100);
|
||||
Ngs2WaveformInfo info{};
|
||||
Require(sceNgs2ParseWaveformData(file.data(), file.size(), &info) == SCE_NGS2_OK);
|
||||
Require(info.format.waveform_type == SCE_NGS2_WAVEFORM_TYPE_PCM_I16L && info.format.num_channels == 2 && info.format.sample_rate == 44100);
|
||||
Require(info.data_offset == 44 && info.data_size == 400 && info.num_samples == 100);
|
||||
Require(info.num_blocks == 1 && info.block[0].data_offset == 44 && info.block[0].data_size == 400 && info.block[0].num_samples == 100);
|
||||
|
||||
auto truncated = file;
|
||||
truncated.resize(44 + 202);
|
||||
Require(sceNgs2ParseWaveformData(truncated.data(), truncated.size(), &info) == SCE_NGS2_ERROR_INVALID_WAVEFORM_DATA);
|
||||
|
||||
auto partialFrame = PcmFile(2, 44100, 16, 100);
|
||||
partialFrame.resize(44 + 402, 0x11);
|
||||
const std::uint32_t partialSize = 402;
|
||||
std::memcpy(partialFrame.data() + 40, &partialSize, sizeof(partialSize));
|
||||
Require(sceNgs2ParseWaveformData(partialFrame.data(), partialFrame.size(), &info) == SCE_NGS2_ERROR_INVALID_WAVEFORM_DATA);
|
||||
|
||||
const auto eightBit = PcmFile(1, 44100, 8, 10);
|
||||
Require(sceNgs2ParseWaveformData(eightBit.data(), eightBit.size(), &info) == SCE_NGS2_ERROR_INVALID_WAVEFORM_FORMAT);
|
||||
const auto noChannels = PcmFile(0, 44100, 16, 10);
|
||||
Require(sceNgs2ParseWaveformData(noChannels.data(), noChannels.size(), &info) == SCE_NGS2_ERROR_INVALID_WAVEFORM_FORMAT);
|
||||
}
|
||||
|
||||
static void TestParseFile() {
|
||||
const auto wave = PcmFile(1, 22050, 16, 64);
|
||||
const char* const guestPath = "/aps5_ngs2_parse_file.wav";
|
||||
const auto path = ResolvePath_nid_no_patch(guestPath);
|
||||
{
|
||||
std::ofstream out(path, std::ios::binary);
|
||||
const char pad[3]{};
|
||||
out.write(pad, sizeof(pad));
|
||||
out.write(reinterpret_cast<const char*>(wave.data()), static_cast<std::streamsize>(wave.size()));
|
||||
}
|
||||
Ngs2WaveformInfo info{};
|
||||
Require(sceNgs2ParseWaveformFile(guestPath, 3, nullptr) == SCE_NGS2_ERROR_INVALID_OUT_ADDRESS);
|
||||
Require(sceNgs2ParseWaveformFile(nullptr, 0, &info) == SCE_NGS2_ERROR_INVALID_WAVEFORM_DATA);
|
||||
Require(sceNgs2ParseWaveformFile(guestPath, 3, &info) == SCE_NGS2_OK);
|
||||
Require(info.format.num_channels == 1 && info.format.sample_rate == 22050 && info.num_samples == 64);
|
||||
Require(info.data_offset == 3 + 44 && info.block[0].data_offset == 3 + 44 && info.data_size == 128);
|
||||
Require(sceNgs2ParseWaveformFile(guestPath, static_cast<std::uint32_t>(wave.size()) + 4, &info) == SCE_NGS2_ERROR_INVALID_WAVEFORM_DATA);
|
||||
Require(sceNgs2ParseWaveformFile(guestPath, 0, &info) == SCE_NGS2_ERROR_UNKNOWN_WAVEFORM_FORMAT);
|
||||
std::filesystem::remove(path);
|
||||
}
|
||||
|
||||
int main() {
|
||||
TestParsePcm();
|
||||
TestParseFile();
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue