feat(assets): read retail assets through the vendored libra3assets library
Vendor libra3assets (C++26 modules: BIG4, RefPack, BinaryAsset, CSF, CkMp map) under third_party/ and add the ra3_assets target. ra3.fs, ra3.map and ra3.terrain become thin adapters over it: - ra3.fs delegates RefPack and the BIG4 index/payload reads (index-only, payloads read on demand). - ra3.map decodes ObjectsList and CSF via map_document/csf_table; starts come from player_starts(), replacing the off-by-one whole-buffer scan. - ra3.terrain takes the CkMp container and HeightMapData from map_document, with BlendTileData (not modelled by the library) parsed from the chunk payload. Adds an opt-in real-asset check (OPENRA3_TEST_ASSETS) plus the library's own unit suite as ra3assets_unit.
This commit is contained in:
+83
@@ -0,0 +1,83 @@
|
||||
#ifndef RA3TEST_HPP
|
||||
#define RA3TEST_HPP
|
||||
|
||||
// A tiny dependency-free test harness (registry + CHECK macros). Each unit-test
|
||||
// executable compiles test_main.cpp and links the sources under test.
|
||||
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace ra3test {
|
||||
|
||||
struct test_case {
|
||||
std::string name;
|
||||
std::function<void()> fn;
|
||||
};
|
||||
|
||||
inline auto registry() -> std::vector<test_case> & {
|
||||
static std::vector<test_case> tests;
|
||||
return tests;
|
||||
}
|
||||
|
||||
inline auto failure_count() -> int & {
|
||||
static int count = 0;
|
||||
return count;
|
||||
}
|
||||
|
||||
struct registrar {
|
||||
registrar(std::string name, std::function<void()> fn) { registry().push_back({std::move(name), std::move(fn)}); }
|
||||
};
|
||||
|
||||
inline auto report_failure(const std::string &expr, const std::string &file, int line) -> void {
|
||||
++failure_count();
|
||||
std::cerr << " FAIL " << file << ':' << line << " " << expr << '\n';
|
||||
}
|
||||
|
||||
inline auto check(bool condition, const std::string &expr, const std::string &file, int line) -> void {
|
||||
if (!condition) report_failure(expr, file, line);
|
||||
}
|
||||
|
||||
inline auto run_all() -> int {
|
||||
int passed = 0;
|
||||
for (auto &test: registry()) {
|
||||
const int before = failure_count();
|
||||
std::cout << "[ RUN ] " << test.name << '\n';
|
||||
try {
|
||||
test.fn();
|
||||
} catch (const std::exception &exc) {
|
||||
report_failure(std::string("uncaught exception: ") + exc.what(), __FILE__, __LINE__);
|
||||
}
|
||||
if (failure_count() == before) {
|
||||
++passed;
|
||||
std::cout << "[ OK ] " << test.name << '\n';
|
||||
}
|
||||
}
|
||||
std::cout << "\n" << passed << '/' << registry().size() << " tests passed, " << failure_count() << " failure(s)\n";
|
||||
return failure_count() == 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
} // namespace ra3test
|
||||
|
||||
#define TEST(name) \
|
||||
static void name(); \
|
||||
static ::ra3test::registrar ra3test_reg_##name(#name, name); \
|
||||
static void name()
|
||||
|
||||
#define CHECK(cond) ::ra3test::check((cond), #cond, __FILE__, __LINE__)
|
||||
#define CHECK_EQ(a, b) ::ra3test::check_eq((a), (b), #a, #b, __FILE__, __LINE__)
|
||||
|
||||
namespace ra3test {
|
||||
template<typename A, typename B>
|
||||
auto check_eq(const A &a, const B &b, const std::string &ea, const std::string &eb, const std::string &file, int line) -> void {
|
||||
if (!(a == b)) {
|
||||
std::ostringstream os;
|
||||
os << ea << " == " << eb;
|
||||
report_failure(os.str(), file, line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // RA3TEST_HPP
|
||||
Reference in New Issue
Block a user