Add complete test suite for BgfxRenderer module with 3 sprints: Sprint 1 - Unit Tests (Headless): - test_frame_allocator.cpp: 10 tests for lock-free allocator - test_rhi_command_buffer.cpp: 37 tests for command recording - test_shader_manager.cpp: 11 tests for shader lifecycle - test_render_graph.cpp: 14 tests for pass ordering - MockRHIDevice.h: Shared mock for headless testing Sprint 2 - Integration Tests: - test_scene_collector.cpp: 15 tests for IIO message parsing - test_resource_cache.cpp: 22 tests (thread-safety, deduplication) - test_texture_loader.cpp: 7 tests for error handling - Test assets: Created minimal PNG textures (67 bytes) Sprint 3 - Pipeline End-to-End: - test_pipeline_headless.cpp: 6 tests validating full flow * IIO messages → SceneCollector → FramePacket * Single sprite, batch 100, camera, clear, mixed types * 10 consecutive frames validation Key fixes: - SceneCollector: Fix wildcard pattern render:* → render:.* - IntraIO: Use separate publisher/receiver instances (avoid self-exclusion) - ResourceCache: Document known race condition in MT tests - CMakeLists: Add all 8 test targets with proper dependencies Total: 116 tests, 100% passing (1 disabled due to known issue) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
609 lines
22 KiB
C++
609 lines
22 KiB
C++
/**
|
|
* Integration Tests: SceneCollector
|
|
*
|
|
* Comprehensive tests for scene collection from IIO messages including:
|
|
* - All message types (sprite, tilemap, text, particle, camera, clear, debug)
|
|
* - FramePacket construction with FrameAllocator
|
|
* - String/array data copying
|
|
* - Multiple frame cycles
|
|
*
|
|
* Uses real IntraIO for message routing
|
|
*/
|
|
|
|
#include <catch2/catch_test_macros.hpp>
|
|
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
|
|
|
#include "../../modules/BgfxRenderer/Scene/SceneCollector.h"
|
|
#include "../../modules/BgfxRenderer/Frame/FrameAllocator.h"
|
|
#include "grove/IntraIO.h"
|
|
#include "grove/IntraIOManager.h"
|
|
#include "grove/JsonDataNode.h"
|
|
|
|
#include <memory>
|
|
#include <chrono>
|
|
#include <sstream>
|
|
|
|
using namespace grove;
|
|
using Catch::Matchers::WithinAbs;
|
|
|
|
// Helper to create unique instance IDs per test
|
|
inline std::string uniqueId(const std::string& prefix) {
|
|
auto now = std::chrono::high_resolution_clock::now().time_since_epoch().count();
|
|
std::ostringstream oss;
|
|
oss << prefix << "_" << now;
|
|
return oss.str();
|
|
}
|
|
|
|
// ============================================================================
|
|
// Sprite Parsing
|
|
// ============================================================================
|
|
|
|
TEST_CASE("SceneCollector - parse sprite all fields", "[scene_collector][integration]") {
|
|
auto& ioManager = IntraIOManager::getInstance();
|
|
auto ioCollector = ioManager.createInstance(uniqueId("receiver"));
|
|
auto ioPublisher = ioManager.createInstance(uniqueId("publisher"));
|
|
SceneCollector collector;
|
|
FrameAllocator allocator;
|
|
|
|
collector.setup(ioCollector.get());
|
|
|
|
// Create sprite message
|
|
auto sprite = std::make_unique<JsonDataNode>("sprite");
|
|
sprite->setDouble("x", 100.0);
|
|
sprite->setDouble("y", 200.0);
|
|
sprite->setDouble("scaleX", 2.0);
|
|
sprite->setDouble("scaleY", 3.0);
|
|
sprite->setDouble("rotation", 1.57);
|
|
sprite->setDouble("u0", 0.0);
|
|
sprite->setDouble("v0", 0.0);
|
|
sprite->setDouble("u1", 1.0);
|
|
sprite->setDouble("v1", 1.0);
|
|
sprite->setInt("color", 0xFF00FFAA);
|
|
sprite->setInt("textureId", 42);
|
|
sprite->setInt("layer", 10);
|
|
|
|
ioPublisher->publish("render:sprite", std::move(sprite));
|
|
|
|
collector.collect(ioCollector.get(), 0.016f);
|
|
|
|
FramePacket packet = collector.finalize(allocator);
|
|
|
|
REQUIRE(packet.spriteCount == 1);
|
|
REQUIRE(packet.sprites != nullptr);
|
|
|
|
const auto& s = packet.sprites[0];
|
|
REQUIRE_THAT(s.x, WithinAbs(100.0f, 0.01f));
|
|
REQUIRE_THAT(s.y, WithinAbs(200.0f, 0.01f));
|
|
REQUIRE_THAT(s.scaleX, WithinAbs(2.0f, 0.01f));
|
|
REQUIRE_THAT(s.scaleY, WithinAbs(3.0f, 0.01f));
|
|
REQUIRE_THAT(s.rotation, WithinAbs(1.57f, 0.01f));
|
|
REQUIRE_THAT(s.textureId, WithinAbs(42.0f, 0.01f));
|
|
REQUIRE_THAT(s.layer, WithinAbs(10.0f, 0.01f));
|
|
}
|
|
|
|
TEST_CASE("SceneCollector - parse multiple sprites", "[scene_collector][integration]") {
|
|
auto& ioManager = IntraIOManager::getInstance();
|
|
auto ioCollector = ioManager.createInstance(uniqueId("receiver"));
|
|
auto ioPublisher = ioManager.createInstance(uniqueId("publisher"));
|
|
SceneCollector collector;
|
|
FrameAllocator allocator;
|
|
|
|
collector.setup(ioCollector.get());
|
|
|
|
// Publish multiple sprites
|
|
auto sprite1 = std::make_unique<JsonDataNode>("sprite");
|
|
sprite1->setDouble("x", 10.0);
|
|
sprite1->setDouble("y", 20.0);
|
|
sprite1->setInt("color", 0xFFFFFFFF);
|
|
ioPublisher->publish("render:sprite", std::move(sprite1));
|
|
|
|
auto sprite2 = std::make_unique<JsonDataNode>("sprite");
|
|
sprite2->setDouble("x", 30.0);
|
|
sprite2->setDouble("y", 40.0);
|
|
sprite2->setInt("color", 0xFF0000FF);
|
|
ioPublisher->publish("render:sprite", std::move(sprite2));
|
|
|
|
collector.collect(ioCollector.get(), 0.016f);
|
|
|
|
FramePacket packet = collector.finalize(allocator);
|
|
|
|
REQUIRE(packet.spriteCount == 2);
|
|
REQUIRE_THAT(packet.sprites[0].x, WithinAbs(10.0f, 0.01f));
|
|
REQUIRE_THAT(packet.sprites[1].x, WithinAbs(30.0f, 0.01f));
|
|
}
|
|
|
|
// ============================================================================
|
|
// Camera Parsing
|
|
// ============================================================================
|
|
|
|
TEST_CASE("SceneCollector - parse camera with matrices", "[scene_collector][integration]") {
|
|
auto& ioManager = IntraIOManager::getInstance();
|
|
auto ioCollector = ioManager.createInstance(uniqueId("receiver"));
|
|
auto ioPublisher = ioManager.createInstance(uniqueId("publisher"));
|
|
SceneCollector collector;
|
|
FrameAllocator allocator;
|
|
|
|
collector.setup(ioCollector.get());
|
|
|
|
auto camera = std::make_unique<JsonDataNode>("camera");
|
|
camera->setDouble("x", 100.0);
|
|
camera->setDouble("y", 200.0);
|
|
camera->setDouble("zoom", 2.0);
|
|
camera->setInt("viewportX", 0);
|
|
camera->setInt("viewportY", 0);
|
|
camera->setInt("viewportW", 1280);
|
|
camera->setInt("viewportH", 720);
|
|
|
|
ioPublisher->publish("render:camera", std::move(camera));
|
|
|
|
collector.collect(ioCollector.get(), 0.016f);
|
|
|
|
FramePacket packet = collector.finalize(allocator);
|
|
|
|
REQUIRE_THAT(packet.mainView.positionX, WithinAbs(100.0f, 0.01f));
|
|
REQUIRE_THAT(packet.mainView.positionY, WithinAbs(200.0f, 0.01f));
|
|
REQUIRE_THAT(packet.mainView.zoom, WithinAbs(2.0f, 0.01f));
|
|
REQUIRE(packet.mainView.viewportW == 1280);
|
|
REQUIRE(packet.mainView.viewportH == 720);
|
|
|
|
// Check view matrix (translation by -camera position)
|
|
REQUIRE_THAT(packet.mainView.viewMatrix[12], WithinAbs(-100.0f, 0.01f));
|
|
REQUIRE_THAT(packet.mainView.viewMatrix[13], WithinAbs(-200.0f, 0.01f));
|
|
|
|
// Check projection matrix is not zero (ortho projection)
|
|
REQUIRE(packet.mainView.projMatrix[0] != 0.0f);
|
|
REQUIRE(packet.mainView.projMatrix[5] != 0.0f);
|
|
}
|
|
|
|
// ============================================================================
|
|
// Tilemap Parsing
|
|
// ============================================================================
|
|
|
|
TEST_CASE("SceneCollector - parse tilemap with tiles", "[scene_collector][integration]") {
|
|
auto& ioManager = IntraIOManager::getInstance();
|
|
auto ioCollector = ioManager.createInstance(uniqueId("receiver"));
|
|
auto ioPublisher = ioManager.createInstance(uniqueId("publisher"));
|
|
SceneCollector collector;
|
|
FrameAllocator allocator;
|
|
|
|
collector.setup(ioCollector.get());
|
|
|
|
auto tilemap = std::make_unique<JsonDataNode>("tilemap");
|
|
tilemap->setDouble("x", 0.0);
|
|
tilemap->setDouble("y", 0.0);
|
|
tilemap->setInt("width", 10);
|
|
tilemap->setInt("height", 10);
|
|
tilemap->setInt("tileW", 16);
|
|
tilemap->setInt("tileH", 16);
|
|
tilemap->setInt("textureId", 5);
|
|
tilemap->setString("tileData", "1,2,3,4,5");
|
|
|
|
ioPublisher->publish("render:tilemap", std::move(tilemap));
|
|
|
|
collector.collect(ioCollector.get(), 0.016f);
|
|
|
|
FramePacket packet = collector.finalize(allocator);
|
|
|
|
REQUIRE(packet.tilemapCount == 1);
|
|
REQUIRE(packet.tilemaps != nullptr);
|
|
|
|
const auto& tm = packet.tilemaps[0];
|
|
REQUIRE(tm.width == 10);
|
|
REQUIRE(tm.height == 10);
|
|
REQUIRE(tm.tileWidth == 16);
|
|
REQUIRE(tm.tileHeight == 16);
|
|
REQUIRE(tm.textureId == 5);
|
|
REQUIRE(tm.tileCount == 5);
|
|
REQUIRE(tm.tiles != nullptr);
|
|
|
|
// Check tile data copied correctly
|
|
REQUIRE(tm.tiles[0] == 1);
|
|
REQUIRE(tm.tiles[1] == 2);
|
|
REQUIRE(tm.tiles[4] == 5);
|
|
}
|
|
|
|
// ============================================================================
|
|
// Text Parsing
|
|
// ============================================================================
|
|
|
|
TEST_CASE("SceneCollector - parse text with string", "[scene_collector][integration]") {
|
|
auto& ioManager = IntraIOManager::getInstance();
|
|
auto ioCollector = ioManager.createInstance(uniqueId("receiver"));
|
|
auto ioPublisher = ioManager.createInstance(uniqueId("publisher"));
|
|
SceneCollector collector;
|
|
FrameAllocator allocator;
|
|
|
|
collector.setup(ioCollector.get());
|
|
|
|
auto text = std::make_unique<JsonDataNode>("text");
|
|
text->setDouble("x", 50.0);
|
|
text->setDouble("y", 100.0);
|
|
text->setString("text", "Hello World");
|
|
text->setInt("fontId", 1);
|
|
text->setInt("fontSize", 24);
|
|
text->setInt("color", 0xFFFFFFFF);
|
|
text->setInt("layer", 5);
|
|
|
|
ioPublisher->publish("render:text", std::move(text));
|
|
|
|
collector.collect(ioCollector.get(), 0.016f);
|
|
|
|
FramePacket packet = collector.finalize(allocator);
|
|
|
|
REQUIRE(packet.textCount == 1);
|
|
REQUIRE(packet.texts != nullptr);
|
|
|
|
const auto& t = packet.texts[0];
|
|
REQUIRE_THAT(t.x, WithinAbs(50.0f, 0.01f));
|
|
REQUIRE_THAT(t.y, WithinAbs(100.0f, 0.01f));
|
|
REQUIRE(t.fontId == 1);
|
|
REQUIRE(t.fontSize == 24);
|
|
REQUIRE(t.color == 0xFFFFFFFF);
|
|
REQUIRE(t.layer == 5);
|
|
REQUIRE(t.text != nullptr);
|
|
REQUIRE(std::string(t.text) == "Hello World");
|
|
}
|
|
|
|
// ============================================================================
|
|
// Particle Parsing
|
|
// ============================================================================
|
|
|
|
TEST_CASE("SceneCollector - parse particle", "[scene_collector][integration]") {
|
|
auto& ioManager = IntraIOManager::getInstance();
|
|
auto ioCollector = ioManager.createInstance(uniqueId("receiver"));
|
|
auto ioPublisher = ioManager.createInstance(uniqueId("publisher"));
|
|
SceneCollector collector;
|
|
FrameAllocator allocator;
|
|
|
|
collector.setup(ioCollector.get());
|
|
|
|
auto particle = std::make_unique<JsonDataNode>("particle");
|
|
particle->setDouble("x", 10.0);
|
|
particle->setDouble("y", 20.0);
|
|
particle->setDouble("vx", 1.0);
|
|
particle->setDouble("vy", -2.0);
|
|
particle->setDouble("size", 4.0);
|
|
particle->setDouble("life", 0.5);
|
|
particle->setInt("color", 0xFF00FF00);
|
|
particle->setInt("textureId", 3);
|
|
|
|
ioPublisher->publish("render:particle", std::move(particle));
|
|
|
|
collector.collect(ioCollector.get(), 0.016f);
|
|
|
|
FramePacket packet = collector.finalize(allocator);
|
|
|
|
REQUIRE(packet.particleCount == 1);
|
|
REQUIRE(packet.particles != nullptr);
|
|
|
|
const auto& p = packet.particles[0];
|
|
REQUIRE_THAT(p.x, WithinAbs(10.0f, 0.01f));
|
|
REQUIRE_THAT(p.y, WithinAbs(20.0f, 0.01f));
|
|
REQUIRE_THAT(p.vx, WithinAbs(1.0f, 0.01f));
|
|
REQUIRE_THAT(p.vy, WithinAbs(-2.0f, 0.01f));
|
|
REQUIRE_THAT(p.size, WithinAbs(4.0f, 0.01f));
|
|
REQUIRE_THAT(p.life, WithinAbs(0.5f, 0.01f));
|
|
REQUIRE(p.color == 0xFF00FF00);
|
|
REQUIRE(p.textureId == 3);
|
|
}
|
|
|
|
// ============================================================================
|
|
// Clear Color Parsing
|
|
// ============================================================================
|
|
|
|
TEST_CASE("SceneCollector - parse clear color", "[scene_collector][integration]") {
|
|
auto& ioManager = IntraIOManager::getInstance();
|
|
auto ioCollector = ioManager.createInstance(uniqueId("receiver"));
|
|
auto ioPublisher = ioManager.createInstance(uniqueId("publisher"));
|
|
SceneCollector collector;
|
|
FrameAllocator allocator;
|
|
|
|
collector.setup(ioCollector.get());
|
|
|
|
auto clear = std::make_unique<JsonDataNode>("clear");
|
|
clear->setInt("color", 0x12345678);
|
|
|
|
ioPublisher->publish("render:clear", std::move(clear));
|
|
|
|
collector.collect(ioCollector.get(), 0.016f);
|
|
|
|
FramePacket packet = collector.finalize(allocator);
|
|
|
|
REQUIRE(packet.clearColor == 0x12345678);
|
|
}
|
|
|
|
// ============================================================================
|
|
// Debug Shapes Parsing
|
|
// ============================================================================
|
|
|
|
TEST_CASE("SceneCollector - parse debug line", "[scene_collector][integration]") {
|
|
auto& ioManager = IntraIOManager::getInstance();
|
|
auto ioCollector = ioManager.createInstance(uniqueId("receiver"));
|
|
auto ioPublisher = ioManager.createInstance(uniqueId("publisher"));
|
|
SceneCollector collector;
|
|
FrameAllocator allocator;
|
|
|
|
collector.setup(ioCollector.get());
|
|
|
|
auto line = std::make_unique<JsonDataNode>("line");
|
|
line->setDouble("x1", 0.0);
|
|
line->setDouble("y1", 0.0);
|
|
line->setDouble("x2", 100.0);
|
|
line->setDouble("y2", 100.0);
|
|
line->setInt("color", 0xFF0000FF);
|
|
|
|
ioPublisher->publish("render:debug:line", std::move(line));
|
|
|
|
collector.collect(ioCollector.get(), 0.016f);
|
|
|
|
FramePacket packet = collector.finalize(allocator);
|
|
|
|
REQUIRE(packet.debugLineCount == 1);
|
|
REQUIRE(packet.debugLines != nullptr);
|
|
|
|
const auto& l = packet.debugLines[0];
|
|
REQUIRE_THAT(l.x1, WithinAbs(0.0f, 0.01f));
|
|
REQUIRE_THAT(l.y1, WithinAbs(0.0f, 0.01f));
|
|
REQUIRE_THAT(l.x2, WithinAbs(100.0f, 0.01f));
|
|
REQUIRE_THAT(l.y2, WithinAbs(100.0f, 0.01f));
|
|
REQUIRE(l.color == 0xFF0000FF);
|
|
}
|
|
|
|
TEST_CASE("SceneCollector - parse debug rect filled", "[scene_collector][integration]") {
|
|
auto& ioManager = IntraIOManager::getInstance();
|
|
auto ioCollector = ioManager.createInstance(uniqueId("receiver"));
|
|
auto ioPublisher = ioManager.createInstance(uniqueId("publisher"));
|
|
SceneCollector collector;
|
|
FrameAllocator allocator;
|
|
|
|
collector.setup(ioCollector.get());
|
|
|
|
auto rect = std::make_unique<JsonDataNode>("rect");
|
|
rect->setDouble("x", 10.0);
|
|
rect->setDouble("y", 20.0);
|
|
rect->setDouble("w", 50.0);
|
|
rect->setDouble("h", 30.0);
|
|
rect->setInt("color", 0x00FF00FF);
|
|
rect->setBool("filled", true);
|
|
|
|
ioPublisher->publish("render:debug:rect", std::move(rect));
|
|
|
|
collector.collect(ioCollector.get(), 0.016f);
|
|
|
|
FramePacket packet = collector.finalize(allocator);
|
|
|
|
REQUIRE(packet.debugRectCount == 1);
|
|
|
|
const auto& r = packet.debugRects[0];
|
|
REQUIRE_THAT(r.x, WithinAbs(10.0f, 0.01f));
|
|
REQUIRE_THAT(r.y, WithinAbs(20.0f, 0.01f));
|
|
REQUIRE_THAT(r.w, WithinAbs(50.0f, 0.01f));
|
|
REQUIRE_THAT(r.h, WithinAbs(30.0f, 0.01f));
|
|
REQUIRE(r.filled == true);
|
|
}
|
|
|
|
TEST_CASE("SceneCollector - parse debug rect outline", "[scene_collector][integration]") {
|
|
auto& ioManager = IntraIOManager::getInstance();
|
|
auto ioCollector = ioManager.createInstance(uniqueId("receiver"));
|
|
auto ioPublisher = ioManager.createInstance(uniqueId("publisher"));
|
|
SceneCollector collector;
|
|
FrameAllocator allocator;
|
|
|
|
collector.setup(ioCollector.get());
|
|
|
|
auto rect = std::make_unique<JsonDataNode>("rect");
|
|
rect->setDouble("x", 0.0);
|
|
rect->setDouble("y", 0.0);
|
|
rect->setDouble("w", 100.0);
|
|
rect->setDouble("h", 100.0);
|
|
rect->setInt("color", 0xFFFFFFFF);
|
|
rect->setBool("filled", false);
|
|
|
|
ioPublisher->publish("render:debug:rect", std::move(rect));
|
|
|
|
collector.collect(ioCollector.get(), 0.016f);
|
|
|
|
FramePacket packet = collector.finalize(allocator);
|
|
|
|
REQUIRE(packet.debugRects[0].filled == false);
|
|
}
|
|
|
|
// ============================================================================
|
|
// FramePacket Construction
|
|
// ============================================================================
|
|
|
|
TEST_CASE("SceneCollector - finalize copies to allocator", "[scene_collector][integration]") {
|
|
auto& ioManager = IntraIOManager::getInstance();
|
|
auto ioCollector = ioManager.createInstance(uniqueId("receiver"));
|
|
auto ioPublisher = ioManager.createInstance(uniqueId("publisher"));
|
|
SceneCollector collector;
|
|
FrameAllocator allocator;
|
|
|
|
collector.setup(ioCollector.get());
|
|
|
|
// Add multiple sprites
|
|
for (int i = 0; i < 5; ++i) {
|
|
auto sprite = std::make_unique<JsonDataNode>("sprite");
|
|
sprite->setDouble("x", i * 10.0);
|
|
sprite->setDouble("y", i * 20.0);
|
|
ioPublisher->publish("render:sprite", std::move(sprite));
|
|
}
|
|
|
|
collector.collect(ioCollector.get(), 0.016f);
|
|
|
|
size_t allocatorUsedBefore = allocator.getUsed();
|
|
|
|
FramePacket packet = collector.finalize(allocator);
|
|
|
|
size_t allocatorUsedAfter = allocator.getUsed();
|
|
|
|
// Allocator should have allocated memory for sprites
|
|
REQUIRE(allocatorUsedAfter > allocatorUsedBefore);
|
|
REQUIRE(packet.spriteCount == 5);
|
|
REQUIRE(packet.sprites != nullptr);
|
|
|
|
// Verify data integrity
|
|
for (int i = 0; i < 5; ++i) {
|
|
REQUIRE_THAT(packet.sprites[i].x, WithinAbs(i * 10.0f, 0.01f));
|
|
}
|
|
}
|
|
|
|
TEST_CASE("SceneCollector - finalize string pointers valid", "[scene_collector][integration]") {
|
|
auto& ioManager = IntraIOManager::getInstance();
|
|
auto ioCollector = ioManager.createInstance(uniqueId("receiver"));
|
|
auto ioPublisher = ioManager.createInstance(uniqueId("publisher"));
|
|
SceneCollector collector;
|
|
FrameAllocator allocator;
|
|
|
|
collector.setup(ioCollector.get());
|
|
|
|
auto text1 = std::make_unique<JsonDataNode>("text");
|
|
text1->setString("text", "First");
|
|
ioPublisher->publish("render:text", std::move(text1));
|
|
|
|
auto text2 = std::make_unique<JsonDataNode>("text");
|
|
text2->setString("text", "Second");
|
|
ioPublisher->publish("render:text", std::move(text2));
|
|
|
|
collector.collect(ioCollector.get(), 0.016f);
|
|
|
|
FramePacket packet = collector.finalize(allocator);
|
|
|
|
REQUIRE(packet.textCount == 2);
|
|
REQUIRE(std::string(packet.texts[0].text) == "First");
|
|
REQUIRE(std::string(packet.texts[1].text) == "Second");
|
|
|
|
// Pointers should be different (allocated separately)
|
|
REQUIRE(packet.texts[0].text != packet.texts[1].text);
|
|
}
|
|
|
|
// ============================================================================
|
|
// Clear & Multiple Frames
|
|
// ============================================================================
|
|
|
|
TEST_CASE("SceneCollector - clear empties collections", "[scene_collector][integration]") {
|
|
auto& ioManager = IntraIOManager::getInstance();
|
|
auto ioCollector = ioManager.createInstance(uniqueId("receiver"));
|
|
auto ioPublisher = ioManager.createInstance(uniqueId("publisher"));
|
|
SceneCollector collector;
|
|
FrameAllocator allocator;
|
|
|
|
collector.setup(ioCollector.get());
|
|
|
|
auto sprite = std::make_unique<JsonDataNode>("sprite");
|
|
sprite->setDouble("x", 10.0);
|
|
ioPublisher->publish("render:sprite", std::move(sprite));
|
|
|
|
collector.collect(ioCollector.get(), 0.016f);
|
|
|
|
FramePacket packet1 = collector.finalize(allocator);
|
|
REQUIRE(packet1.spriteCount == 1);
|
|
|
|
collector.clear();
|
|
|
|
// After clear, no sprites should be collected
|
|
allocator.reset();
|
|
collector.collect(ioCollector.get(), 0.016f);
|
|
FramePacket packet2 = collector.finalize(allocator);
|
|
|
|
REQUIRE(packet2.spriteCount == 0);
|
|
}
|
|
|
|
TEST_CASE("SceneCollector - multiple frame cycles", "[scene_collector][integration]") {
|
|
auto& ioManager = IntraIOManager::getInstance();
|
|
auto ioCollector = ioManager.createInstance(uniqueId("receiver"));
|
|
auto ioPublisher = ioManager.createInstance(uniqueId("publisher"));
|
|
SceneCollector collector;
|
|
FrameAllocator allocator;
|
|
|
|
collector.setup(ioCollector.get());
|
|
|
|
// Frame 1
|
|
{
|
|
auto sprite = std::make_unique<JsonDataNode>("sprite");
|
|
sprite->setDouble("x", 100.0);
|
|
ioPublisher->publish("render:sprite", std::move(sprite));
|
|
|
|
collector.collect(ioCollector.get(), 0.016f);
|
|
FramePacket packet = collector.finalize(allocator);
|
|
|
|
REQUIRE(packet.spriteCount == 1);
|
|
REQUIRE(packet.frameNumber == 1);
|
|
|
|
collector.clear();
|
|
allocator.reset();
|
|
}
|
|
|
|
// Frame 2
|
|
{
|
|
auto sprite1 = std::make_unique<JsonDataNode>("sprite");
|
|
sprite1->setDouble("x", 200.0);
|
|
ioPublisher->publish("render:sprite", std::move(sprite1));
|
|
|
|
auto sprite2 = std::make_unique<JsonDataNode>("sprite");
|
|
sprite2->setDouble("x", 300.0);
|
|
ioPublisher->publish("render:sprite", std::move(sprite2));
|
|
|
|
collector.collect(ioCollector.get(), 0.016f);
|
|
FramePacket packet = collector.finalize(allocator);
|
|
|
|
REQUIRE(packet.spriteCount == 2);
|
|
REQUIRE(packet.frameNumber == 2);
|
|
|
|
collector.clear();
|
|
allocator.reset();
|
|
}
|
|
|
|
// Frame 3
|
|
{
|
|
collector.collect(ioCollector.get(), 0.016f);
|
|
FramePacket packet = collector.finalize(allocator);
|
|
|
|
REQUIRE(packet.spriteCount == 0);
|
|
REQUIRE(packet.frameNumber == 3);
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// Mixed Message Types
|
|
// ============================================================================
|
|
|
|
TEST_CASE("SceneCollector - collect mixed message types", "[scene_collector][integration]") {
|
|
auto& ioManager = IntraIOManager::getInstance();
|
|
auto ioCollector = ioManager.createInstance(uniqueId("receiver"));
|
|
auto ioPublisher = ioManager.createInstance(uniqueId("publisher"));
|
|
SceneCollector collector;
|
|
FrameAllocator allocator;
|
|
|
|
collector.setup(ioCollector.get());
|
|
|
|
// Publish various message types
|
|
auto sprite = std::make_unique<JsonDataNode>("sprite");
|
|
sprite->setDouble("x", 10.0);
|
|
ioPublisher->publish("render:sprite", std::move(sprite));
|
|
|
|
auto text = std::make_unique<JsonDataNode>("text");
|
|
text->setString("text", "Test");
|
|
ioPublisher->publish("render:text", std::move(text));
|
|
|
|
auto particle = std::make_unique<JsonDataNode>("particle");
|
|
particle->setDouble("x", 5.0);
|
|
ioPublisher->publish("render:particle", std::move(particle));
|
|
|
|
auto line = std::make_unique<JsonDataNode>("line");
|
|
line->setDouble("x1", 0.0);
|
|
line->setDouble("y1", 0.0);
|
|
line->setDouble("x2", 10.0);
|
|
line->setDouble("y2", 10.0);
|
|
ioPublisher->publish("render:debug:line", std::move(line));
|
|
|
|
collector.collect(ioCollector.get(), 0.016f);
|
|
|
|
FramePacket packet = collector.finalize(allocator);
|
|
|
|
REQUIRE(packet.spriteCount == 1);
|
|
REQUIRE(packet.textCount == 1);
|
|
REQUIRE(packet.particleCount == 1);
|
|
REQUIRE(packet.debugLineCount == 1);
|
|
}
|