mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-09 18:43:51 +00:00
test(extract): lock in DBC→JSON emission round-trip
4 tests covering the open_format_emitter:
- emitJsonFromDbc round-trips a hand-built 2-record DBC through
DBCFile::load (which auto-detects JSON via the '{' prefix) and
recovers identical record/field/value data.
- Missing input file → graceful failure (no JSON written).
- Bad DBC magic → graceful failure.
- emitOpenFormats walks a subdirectory and writes the side-file
in the right place (matches the extractor's recursive walk).
Brings ctest target count to 31.
This commit is contained in:
parent
d4c69a2b46
commit
6872ba2bcb
2 changed files with 135 additions and 0 deletions
|
|
@ -414,6 +414,33 @@ target_link_libraries(test_open_formats PRIVATE catch2_main)
|
||||||
add_test(NAME open_formats COMMAND test_open_formats)
|
add_test(NAME open_formats COMMAND test_open_formats)
|
||||||
register_test_target(test_open_formats)
|
register_test_target(test_open_formats)
|
||||||
|
|
||||||
|
# ── test_open_format_emitter ─────────────────────────────────
|
||||||
|
# Locks in the asset_extract → wowee open-format conversion path.
|
||||||
|
add_executable(test_open_format_emitter
|
||||||
|
test_open_format_emitter.cpp
|
||||||
|
${CMAKE_SOURCE_DIR}/tools/asset_extract/open_format_emitter.cpp
|
||||||
|
${CMAKE_SOURCE_DIR}/src/pipeline/dbc_loader.cpp
|
||||||
|
${CMAKE_SOURCE_DIR}/src/pipeline/blp_loader.cpp
|
||||||
|
${CMAKE_SOURCE_DIR}/src/pipeline/m2_loader.cpp
|
||||||
|
${CMAKE_SOURCE_DIR}/src/pipeline/wmo_loader.cpp
|
||||||
|
${CMAKE_SOURCE_DIR}/src/pipeline/adt_loader.cpp
|
||||||
|
${CMAKE_SOURCE_DIR}/src/pipeline/wowee_model.cpp
|
||||||
|
${CMAKE_SOURCE_DIR}/src/pipeline/wowee_building.cpp
|
||||||
|
${CMAKE_SOURCE_DIR}/src/pipeline/wowee_collision.cpp
|
||||||
|
${CMAKE_SOURCE_DIR}/src/core/logger.cpp
|
||||||
|
)
|
||||||
|
target_include_directories(test_open_format_emitter PRIVATE
|
||||||
|
${TEST_INCLUDE_DIRS}
|
||||||
|
${CMAKE_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
target_include_directories(test_open_format_emitter SYSTEM PRIVATE
|
||||||
|
${TEST_SYSTEM_INCLUDE_DIRS}
|
||||||
|
${CMAKE_SOURCE_DIR}/extern/nlohmann
|
||||||
|
)
|
||||||
|
target_link_libraries(test_open_format_emitter PRIVATE catch2_main)
|
||||||
|
add_test(NAME open_format_emitter COMMAND test_open_format_emitter)
|
||||||
|
register_test_target(test_open_format_emitter)
|
||||||
|
|
||||||
# ── test_camera ──────────────────────────────────────────────
|
# ── test_camera ──────────────────────────────────────────────
|
||||||
add_executable(test_camera
|
add_executable(test_camera
|
||||||
test_camera.cpp
|
test_camera.cpp
|
||||||
|
|
|
||||||
108
tests/test_open_format_emitter.cpp
Normal file
108
tests/test_open_format_emitter.cpp
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
// Tests for the asset_extract open-format emitter — verifies that the
|
||||||
|
// MPQ→loose-files pipeline produces wowee-readable side-files for the
|
||||||
|
// most common file types without touching the originals.
|
||||||
|
#include <catch_amalgamated.hpp>
|
||||||
|
#include "tools/asset_extract/open_format_emitter.hpp"
|
||||||
|
#include "pipeline/dbc_loader.hpp"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <cstring>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using namespace wowee::tools;
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
static const std::string TEST_DIR = "test_emitter_out";
|
||||||
|
|
||||||
|
static void cleanup() { fs::remove_all(TEST_DIR); }
|
||||||
|
|
||||||
|
TEST_CASE("emitJsonFromDbc produces wowee-DBC-loadable JSON", "[emitter]") {
|
||||||
|
fs::create_directories(TEST_DIR);
|
||||||
|
std::string dbcPath = TEST_DIR + "/sample.dbc";
|
||||||
|
std::string jsonPath = TEST_DIR + "/sample.json";
|
||||||
|
|
||||||
|
// Hand-build a 2-record DBC (3 fields each, no string block) so the
|
||||||
|
// round trip is small and deterministic.
|
||||||
|
{
|
||||||
|
std::ofstream f(dbcPath, std::ios::binary);
|
||||||
|
const char magic[4] = {'W','D','B','C'};
|
||||||
|
f.write(magic, 4);
|
||||||
|
uint32_t recordCount = 2, fieldCount = 3, recordSize = 12, stringBlockSize = 1;
|
||||||
|
f.write(reinterpret_cast<const char*>(&recordCount), 4);
|
||||||
|
f.write(reinterpret_cast<const char*>(&fieldCount), 4);
|
||||||
|
f.write(reinterpret_cast<const char*>(&recordSize), 4);
|
||||||
|
f.write(reinterpret_cast<const char*>(&stringBlockSize), 4);
|
||||||
|
// 2 records of 3 uint32s
|
||||||
|
uint32_t rec[6] = {1, 100, 200,
|
||||||
|
2, 300, 400};
|
||||||
|
f.write(reinterpret_cast<const char*>(rec), sizeof(rec));
|
||||||
|
char nul = 0;
|
||||||
|
f.write(&nul, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(emitJsonFromDbc(dbcPath, jsonPath));
|
||||||
|
REQUIRE(fs::exists(jsonPath));
|
||||||
|
|
||||||
|
// The JSON should round-trip back through DBCFile::loadJSON.
|
||||||
|
std::ifstream in(jsonPath, std::ios::binary | std::ios::ate);
|
||||||
|
auto sz = in.tellg();
|
||||||
|
std::vector<uint8_t> bytes(static_cast<size_t>(sz));
|
||||||
|
in.seekg(0);
|
||||||
|
in.read(reinterpret_cast<char*>(bytes.data()), sz);
|
||||||
|
|
||||||
|
wowee::pipeline::DBCFile dbc;
|
||||||
|
// Public DBCFile::load detects '{' prefix and dispatches to loadJSON.
|
||||||
|
REQUIRE(dbc.load(bytes));
|
||||||
|
REQUIRE(dbc.getRecordCount() == 2);
|
||||||
|
REQUIRE(dbc.getFieldCount() == 3);
|
||||||
|
REQUIRE(dbc.getUInt32(0, 0) == 1);
|
||||||
|
REQUIRE(dbc.getUInt32(0, 1) == 100);
|
||||||
|
REQUIRE(dbc.getUInt32(1, 2) == 400);
|
||||||
|
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("emitJsonFromDbc fails gracefully on missing input", "[emitter]") {
|
||||||
|
REQUIRE_FALSE(emitJsonFromDbc("does_not_exist.dbc", "should_not_be_written.json"));
|
||||||
|
REQUIRE_FALSE(fs::exists("should_not_be_written.json"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("emitJsonFromDbc fails gracefully on bad magic", "[emitter]") {
|
||||||
|
fs::create_directories(TEST_DIR);
|
||||||
|
std::string dbcPath = TEST_DIR + "/bad.dbc";
|
||||||
|
std::string jsonPath = TEST_DIR + "/bad.json";
|
||||||
|
{
|
||||||
|
std::ofstream f(dbcPath, std::ios::binary);
|
||||||
|
const char junk[20] = {'F','A','I','L', 0};
|
||||||
|
f.write(junk, 20);
|
||||||
|
}
|
||||||
|
REQUIRE_FALSE(emitJsonFromDbc(dbcPath, jsonPath));
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("emitOpenFormats walks a directory and writes side-files", "[emitter]") {
|
||||||
|
fs::create_directories(TEST_DIR + "/sub");
|
||||||
|
// One DBC in a subdir
|
||||||
|
{
|
||||||
|
std::ofstream f(TEST_DIR + "/sub/test.dbc", std::ios::binary);
|
||||||
|
const char magic[4] = {'W','D','B','C'};
|
||||||
|
f.write(magic, 4);
|
||||||
|
uint32_t r = 1, fc = 1, rs = 4, sb = 1;
|
||||||
|
f.write(reinterpret_cast<const char*>(&r), 4);
|
||||||
|
f.write(reinterpret_cast<const char*>(&fc), 4);
|
||||||
|
f.write(reinterpret_cast<const char*>(&rs), 4);
|
||||||
|
f.write(reinterpret_cast<const char*>(&sb), 4);
|
||||||
|
uint32_t v = 42;
|
||||||
|
f.write(reinterpret_cast<const char*>(&v), 4);
|
||||||
|
char nul = 0;
|
||||||
|
f.write(&nul, 1);
|
||||||
|
}
|
||||||
|
OpenFormatStats stats;
|
||||||
|
emitOpenFormats(TEST_DIR, /*png*/ false, /*json*/ true,
|
||||||
|
/*wom*/ false, /*wob*/ false, /*terrain*/ false, stats);
|
||||||
|
REQUIRE(stats.jsonDbcOk == 1);
|
||||||
|
REQUIRE(stats.jsonDbcFail == 0);
|
||||||
|
REQUIRE(fs::exists(TEST_DIR + "/sub/test.json"));
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue