Run clang-format (the repo's .clang-format: LLVM base, 120 cols, tabs, Allman functions) over every source file so the tree is formatter-clean. Whitespace only -- no behavior change; full x64 + x86 suites pass. Also set SortIncludes: false in .clang-format. Windows include order is load-bearing (windows.h must precede tlhelp32.h / mmreg.h / xinput.h / dinput.h; winsock2.h must precede windows.h), and the default alphabetical sort reorders tlhelp32.h ahead of windows.h -- a build break. Leaving order alone keeps the manual, correct grouping.
99 lines
3.5 KiB
C++
99 lines
3.5 KiB
C++
// Unit test for the per-game audio override store (save/load round-trip, case-insensitive
|
|
// lookup by image name, and the differing-overwrite detection that drives the warning).
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <string>
|
|
|
|
#include <windows.h>
|
|
|
|
#include <mmreg.h>
|
|
|
|
#include "audio/audio_overrides.hpp"
|
|
|
|
using namespace coop;
|
|
|
|
namespace {
|
|
int g_failures = 0;
|
|
void check(bool ok, const char* what)
|
|
{
|
|
if (!ok) {
|
|
std::printf("FAIL: %s\n", what);
|
|
++g_failures;
|
|
} else {
|
|
std::printf(" ok: %s\n", what);
|
|
}
|
|
}
|
|
|
|
std::wstring temp_path()
|
|
{
|
|
wchar_t dir[MAX_PATH] = {};
|
|
GetTempPathW(MAX_PATH, dir);
|
|
return std::wstring(dir) + L"coop_overrides_test_" + std::to_wstring(GetCurrentProcessId()) + L".ini";
|
|
}
|
|
} // namespace
|
|
|
|
int main()
|
|
{
|
|
const std::wstring path = temp_path();
|
|
DeleteFileW(path.c_str());
|
|
|
|
const AudioFormatOverride brotato{44100, 2, 32, WAVE_FORMAT_IEEE_FLOAT};
|
|
const AudioFormatOverride snb{48000, 2, 16, WAVE_FORMAT_PCM};
|
|
const AudioFormatOverride cafe_ov{96000, 2, 32, WAVE_FORMAT_IEEE_FLOAT};
|
|
// "cafe.exe" with the e replaced by U+00E9 ('e' with acute). Under the old 7-bit narrow,
|
|
// 0x00E9 & 0x7F == 0x69 == 'i', so this collapsed onto "cafi.exe" -- a silent key collision.
|
|
// Built from a code point so the source stays pure ASCII (no literal/escape encoding hazards).
|
|
const wchar_t cafe_buf[] = {L'c', L'a', L'f', static_cast<wchar_t>(0x00E9), L'.', L'e', L'x', L'e', L'\0'};
|
|
const wchar_t* kCafe = cafe_buf;
|
|
|
|
{
|
|
AudioOverrideStore store(path);
|
|
store.load(); // missing file -> empty
|
|
AudioFormatOverride got;
|
|
check(!store.find(L"brotato.exe", got), "empty store: no entry");
|
|
|
|
bool differed = true;
|
|
store.set(L"C:\\games\\Brotato.exe", brotato, &differed); // full path -> basename key
|
|
check(!differed, "first set: not a differing overwrite");
|
|
store.set(L"snb.exe", snb, &differed);
|
|
check(!differed, "new game set: not a differing overwrite");
|
|
|
|
// Same value again -> not differing.
|
|
store.set(L"brotato.exe", brotato, &differed);
|
|
check(!differed, "identical re-set: not differing");
|
|
|
|
// Different value -> differing (drives the warning).
|
|
const AudioFormatOverride brotato2{48000, 2, 32, WAVE_FORMAT_IEEE_FLOAT};
|
|
store.set(L"brotato.exe", brotato2, &differed);
|
|
check(differed, "changed value: flagged as differing overwrite");
|
|
|
|
// Non-ASCII names must keep their own entry (no high-bit collision with the ASCII look-alike).
|
|
store.set(kCafe, cafe_ov, &differed);
|
|
store.set(L"cafi.exe", snb, &differed);
|
|
AudioFormatOverride na;
|
|
check(store.find(kCafe, na) && na == cafe_ov, "non-ASCII name keeps its own override");
|
|
check(store.find(L"cafi.exe", na) && na == snb, "the ASCII look-alike keeps a separate override");
|
|
}
|
|
|
|
// Reload from disk in a fresh store: persistence + case-insensitive basename lookup.
|
|
{
|
|
AudioOverrideStore store(path);
|
|
store.load();
|
|
AudioFormatOverride got;
|
|
check(store.find(L"BROTATO.EXE", got), "reload: found case-insensitively");
|
|
check(got == AudioFormatOverride{48000, 2, 32, WAVE_FORMAT_IEEE_FLOAT}, "reload: latest value persisted");
|
|
check(store.find(L"D:\\steam\\snb.exe", got) && got == snb, "reload: found by full path basename");
|
|
check(!store.find(L"unknown.exe", got), "reload: unknown game absent");
|
|
// The non-ASCII name must survive the UTF-8 persist/reload round-trip.
|
|
check(store.find(kCafe, got) && got == cafe_ov, "reload: non-ASCII name round-trips losslessly");
|
|
}
|
|
|
|
DeleteFileW(path.c_str());
|
|
if (g_failures == 0) {
|
|
std::printf("PASS audio_overrides_test\n");
|
|
return 0;
|
|
}
|
|
std::printf("FAILED audio_overrides_test (%d)\n", g_failures);
|
|
return 1;
|
|
}
|