Files
aee-arcade/tests/test_animated_sprite_flip.cpp
T

215 lines
6.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Smoke test del parser d'animacions amb suport de flip H/V. Stand-alone:
// només enllaça `animated_sprite_parser.cpp` (la part del motor que NO toca
// Resource::Cache ni Surface), perquè la cobertura interessa el contracte
// de càrrega del YAML, no el render real.
//
// Tests coberts:
// T1 backward compat — YAML sense cap flip declarat carrega tots els
// frames amb (flip_h=false, flip_v=false) i sense
// que l'animació prengui control del flip.
// T2 flip a nivell d'animació — `flip_h: true` amb frames `int` →
// tots els frames hereten flip_h=true.
// T3 override per-frame — frame mapping `{ index: N, flip_h: true }`
// en una animació sense flip → només aquest frame
// té el flag.
// T4 mapping no hereta — animació amb `flip_h: true` però un frame
// `{ index: N }` (mapping sense flip) → flip_h=false
// en aquest frame (el mapping declara el seu propi
// estat, sense heretar).
// T5 combinat V+H — frame `{ index, flip_h: true, flip_v: true }` →
// ambdós flags actius.
#include <cstdio>
#include <iostream>
#include <string>
#include "core/rendering/sprite/animated_sprite.hpp"
#include "external/fkyaml_node.hpp"
namespace {
int g_failures = 0;
void check(bool cond, const char* msg, const char* file, int line) {
if (!cond) {
std::cerr << " FAIL: " << msg << " (" << file << ":" << line << ")\n";
++g_failures;
}
}
#define REQUIRE(cond) check((cond), #cond, __FILE__, __LINE__)
// Paràmetres comuns per a tots els tests: spritesheet hipotètic 64×64
// amb tiles de 16×16 → grid 4×4, max_tiles=16.
auto sheetParams() -> AnimatedSprite::SheetParams {
return AnimatedSprite::SheetParams{
.frame_width = 16.0F,
.frame_height = 16.0F,
.frames_per_row = 4,
.max_tiles = 16,
};
}
auto parse(const std::string& yaml_str) {
return AnimatedSprite::parseAnimationsFromYaml(
fkyaml::node::deserialize(yaml_str), sheetParams());
}
void testBackwardCompat() {
std::cout << "[T1] backward compat: cap flip declarat\n";
const std::string YAML = R"(
animations:
walk: { frames: [0, 1, 2, 3], frame_ms: 100 }
stand: { frames: [4] }
)";
const auto ANIMS = parse(YAML);
REQUIRE(ANIMS.size() == 2);
const auto WALK_IT = ANIMS.find("walk");
REQUIRE(WALK_IT != ANIMS.end());
if (WALK_IT != ANIMS.end()) {
const auto& WALK = WALK_IT->second;
REQUIRE(WALK.frames.size() == 4);
REQUIRE(!WALK.controls_flip);
for (const auto& F : WALK.frames) {
REQUIRE(!F.flip_h);
REQUIRE(!F.flip_v);
}
}
const auto STAND_IT = ANIMS.find("stand");
REQUIRE(STAND_IT != ANIMS.end());
if (STAND_IT != ANIMS.end()) {
const auto& STAND = STAND_IT->second;
REQUIRE(STAND.frames.size() == 1);
REQUIRE(!STAND.controls_flip);
REQUIRE(!STAND.frames[0].flip_h);
REQUIRE(!STAND.frames[0].flip_v);
}
}
void testFlipAtAnimationLevel() {
std::cout << "[T2] flip a nivell d'anim hereten frames int\n";
const std::string YAML = R"(
animations:
walk_west: { frames: [8, 9, 10, 11], frame_ms: 100, flip_h: true }
)";
const auto ANIMS = parse(YAML);
const auto IT = ANIMS.find("walk_west");
REQUIRE(IT != ANIMS.end());
if (IT != ANIMS.end()) {
const auto& A = IT->second;
REQUIRE(A.frames.size() == 4);
REQUIRE(A.controls_flip);
for (const auto& F : A.frames) {
REQUIRE(F.flip_h);
REQUIRE(!F.flip_v);
}
}
}
void testOverridePerFrame() {
std::cout << "[T3] override per-frame en animació sense flip\n";
const std::string YAML = R"(
animations:
death_spin:
frames:
- 0
- 4
- 8
- { index: 8, flip_h: true }
frame_ms: 100
)";
const auto ANIMS = parse(YAML);
const auto IT = ANIMS.find("death_spin");
REQUIRE(IT != ANIMS.end());
if (IT != ANIMS.end()) {
const auto& A = IT->second;
REQUIRE(A.frames.size() == 4);
// Hi ha un mapping → l'animació pren el control del flip.
REQUIRE(A.controls_flip);
// Els tres primers (int, sense flip a l'anim) → tot a false.
REQUIRE(!A.frames[0].flip_h);
REQUIRE(!A.frames[0].flip_v);
REQUIRE(!A.frames[1].flip_h);
REQUIRE(!A.frames[1].flip_v);
REQUIRE(!A.frames[2].flip_h);
REQUIRE(!A.frames[2].flip_v);
// El quart (mapping amb flip_h: true) → només flip_h.
REQUIRE(A.frames[3].flip_h);
REQUIRE(!A.frames[3].flip_v);
}
}
void testMappingDoesNotInherit() {
std::cout << "[T4] mapping NO hereta el flip de l'animació\n";
const std::string YAML = R"(
animations:
mixed:
frames:
- 0
- { index: 4 }
frame_ms: 100
flip_h: true
)";
const auto ANIMS = parse(YAML);
const auto IT = ANIMS.find("mixed");
REQUIRE(IT != ANIMS.end());
if (IT != ANIMS.end()) {
const auto& A = IT->second;
REQUIRE(A.frames.size() == 2);
REQUIRE(A.controls_flip);
// Frame int hereta el flip_h true de l'animació.
REQUIRE(A.frames[0].flip_h);
REQUIRE(!A.frames[0].flip_v);
// Frame mapping declara els seus propis flags (cap declarat
// → false) i NO hereta del flip a nivell d'anim.
REQUIRE(!A.frames[1].flip_h);
REQUIRE(!A.frames[1].flip_v);
}
}
void testCombinedVerticalAndHorizontal() {
std::cout << "[T5] flip combinat V+H per-frame\n";
const std::string YAML = R"(
animations:
upside_down:
frames:
- { index: 5, flip_h: true, flip_v: true }
frame_ms: 100
)";
const auto ANIMS = parse(YAML);
const auto IT = ANIMS.find("upside_down");
REQUIRE(IT != ANIMS.end());
if (IT != ANIMS.end()) {
const auto& A = IT->second;
REQUIRE(A.frames.size() == 1);
REQUIRE(A.controls_flip);
REQUIRE(A.frames[0].flip_h);
REQUIRE(A.frames[0].flip_v);
}
}
} // namespace
auto main() -> int {
std::cout << "== smoke tests: animation flip parser ==\n";
testBackwardCompat();
testFlipAtAnimationLevel();
testOverridePerFrame();
testMappingDoesNotInherit();
testCombinedVerticalAndHorizontal();
if (g_failures == 0) {
std::cout << "ALL OK\n";
return 0;
}
std::cerr << g_failures << " smoke check(s) failed\n";
return 1;
}