// Smoke test per a TilemapWriter::saveDataBlock. Stand-alone: no obre // finestra, no necessita SDL. Comprova que: // // T1 round-trip pur — escriure el mateix `data:` no canvia el fitxer. // T2 modificació — canviar un tile només toca el bloc `data:` i la // resta del fitxer queda byte a byte idèntica. // T3 format — el bloc generat respecta ` - [v0, v1, ...]` amb // alineació a dreta (màx. amplada) i `]\n` final. // T4 error path — fitxer sense `data:` a columna 0 → retorna false // i no escriu. // // Execució: `./build/test_tilemap_writer` o via `ctest`. #include #include #include #include #include #include #include #include #include "game/map/tilemap_writer.hpp" namespace { // El fixture usa max_width=3 (valor 230) perquè coincideixi amb el format // que el writer emet per a la mateixa graella: així T1 pot comparar byte // a byte el fitxer original amb el reescrit amb la mateixa data. constexpr const char* FIXTURE = "# Capçalera amb comentaris\n" "tileset: data/tilesets/tomb.gif\n" "tile_size: 16\n" "origin: [-8, 0]\n" "\n" "# Bloc geometry preservat\n" "geometry:\n" " grid_cols: 4\n" " grid_rows: 5\n" "\n" "data:\n" " - [ 1, 2, 3]\n" " - [ 4,230, 6]\n" " - [ 7, 8, 9]\n" "\n" "# Epíleg amb comentari\n" "entities:\n" " - type: torch\n" " position: [4, 2]\n"; auto readFile(const std::string& path) -> std::string { std::ifstream in(path, std::ios::binary); std::ostringstream ss; ss << in.rdbuf(); return ss.str(); } void writeFile(const std::string& path, const std::string& content) { std::ofstream out(path, std::ios::binary | std::ios::trunc); out.write(content.data(), static_cast(content.size())); } auto tmpPath(const char* name) -> std::string { auto p = std::filesystem::temp_directory_path() / name; return p.string(); } // Extrau el substring entre "data:\n" i la pròxima línia buida o EOF. // Útil per aïllar el bloc `data:` i comparar preàmbul/epíleg a banda. auto splitAroundData(const std::string& content) -> std::tuple { const auto DATA_LINE = content.find("\ndata:\n"); assert(DATA_LINE != std::string::npos); const auto DATA_START = DATA_LINE + std::string("\ndata:\n").size(); auto block_end = DATA_START; while (block_end < content.size()) { const char C = content[block_end]; if (C != ' ' && C != '\t') { break; } const auto NL = content.find('\n', block_end); block_end = (NL == std::string::npos) ? content.size() : NL + 1; } return { content.substr(0, DATA_START), content.substr(DATA_START, block_end - DATA_START), content.substr(block_end), }; } void T1_roundTrip() { const auto PATH = tmpPath("aee_test_tw_t1.yaml"); writeFile(PATH, FIXTURE); const std::vector> data = { {1, 2, 3}, {4, 230, 6}, {7, 8, 9} }; const bool OK = TilemapWriter::saveDataBlock(PATH, data); assert(OK); const auto AFTER = readFile(PATH); assert(AFTER == FIXTURE); std::filesystem::remove(PATH); std::printf("T1 round-trip: OK\n"); } void T2_modificacio() { const auto PATH = tmpPath("aee_test_tw_t2.yaml"); writeFile(PATH, FIXTURE); // Dades distintes al fixture però mantenint max_width=3 (pel 231). const std::vector> data = { {10, 20, 30}, {40, 231, 60}, {70, 80, 90} }; const bool OK = TilemapWriter::saveDataBlock(PATH, data); assert(OK); const auto AFTER = readFile(PATH); const auto [PRE_BEFORE, DATA_BEFORE, POST_BEFORE] = splitAroundData(FIXTURE); const auto [PRE_AFTER, DATA_AFTER, POST_AFTER] = splitAroundData(AFTER); // Preàmbul i epíleg byte a byte idèntics. assert(PRE_BEFORE == PRE_AFTER); assert(POST_BEFORE == POST_AFTER); // El bloc data ha canviat. assert(DATA_BEFORE != DATA_AFTER); // Valor nou present. assert(AFTER.find("231") != std::string::npos); std::filesystem::remove(PATH); std::printf("T2 modificació: OK\n"); } void T3_format() { const auto PATH = tmpPath("aee_test_tw_t3.yaml"); writeFile(PATH, FIXTURE); // max_width=3 → valors a 3 chars, separats per ','. const std::vector> data = { {1, 2, 3}, {230, 1, 1}, {1, 1, 1} }; const bool OK = TilemapWriter::saveDataBlock(PATH, data); assert(OK); const auto AFTER = readFile(PATH); // Primera fila: " - [ 1, 2, 3]\n" assert(AFTER.find(" - [ 1, 2, 3]\n") != std::string::npos); // Fila amb valor de 3 chars: " - [230, 1, 1]\n" assert(AFTER.find(" - [230, 1, 1]\n") != std::string::npos); std::filesystem::remove(PATH); std::printf("T3 format: OK\n"); } void T4_errorPath() { const auto PATH = tmpPath("aee_test_tw_t4.yaml"); // Fitxer sense "data:" a columna 0. writeFile(PATH, "tileset: x\ntile_size: 16\n# sense data\n"); const auto BEFORE = readFile(PATH); const std::vector> data = {{1, 2, 3}}; const bool OK = TilemapWriter::saveDataBlock(PATH, data); assert(!OK); const auto AFTER = readFile(PATH); assert(AFTER == BEFORE); // fitxer intacte std::filesystem::remove(PATH); std::printf("T4 error path: OK\n"); } } // namespace auto main() -> int { T1_roundTrip(); T2_modificacio(); T3_format(); T4_errorPath(); std::printf("tilemap_writer: tots els tests OK\n"); return 0; }