Files
Renderive/web_server/tests/Web_Bridge_Tests.cpp
2026-08-17 15:24:28 +08:00

140 lines
6.3 KiB
C++

#include "../app/Gallery_Plot_Session.h"
#include "../app/Gallery_Protocol.h"
#include "../app/Web_Event_Adapter.h"
#include "../app/Web_Plot_Session.h"
#include "../app/common/Pixel_Frame.h"
#include <gtest/gtest.h>
#include <nlohmann/json.hpp>
#include <cstdint>
#include <string>
#include <variant>
namespace renderive::web {
namespace {
std::uint32_t read_u32_le(const std::string& value, std::size_t offset) {
return static_cast<std::uint8_t>(value[offset]) |
(static_cast<std::uint32_t>(static_cast<std::uint8_t>(value[offset + 1])) << 8U) |
(static_cast<std::uint32_t>(static_cast<std::uint8_t>(value[offset + 2])) << 16U) |
(static_cast<std::uint32_t>(static_cast<std::uint8_t>(value[offset + 3])) << 24U);
}
TEST(RenderiveWebBridge, DecodesTransportAndPointerEvents) {
const auto resize = Web_Event_Adapter::decode(
R"({"category":"event","type":"resize","width":640,"height":360})");
ASSERT_TRUE(resize);
ASSERT_TRUE(std::holds_alternative<Viewport_Resize>(*resize));
EXPECT_EQ(std::get<Viewport_Resize>(*resize).size.width, 640);
EXPECT_EQ(std::get<Viewport_Resize>(*resize).size.height, 360);
const auto pointer = Web_Event_Adapter::decode(
R"({"category":"event","type":"pointer_move","x":12.5,"y":7.25})");
ASSERT_TRUE(pointer);
ASSERT_TRUE(std::holds_alternative<Pointer_Event>(*pointer));
EXPECT_DOUBLE_EQ(std::get<Pointer_Event>(*pointer).position.x, 12.5);
EXPECT_FALSE(Web_Event_Adapter::decode(R"({"type":"frame"})"));
}
TEST(RenderiveWebBridge, EncodesRvp2PixelFrames) {
const std::string frame = make_rgba8_pixel_frame(4, 3, 9);
ASSERT_EQ(frame.size(), pixel_frame_header_size + 4U * 3U * 4U);
EXPECT_EQ(frame.substr(0, 4), "RVP2");
EXPECT_EQ(read_u32_le(frame, 4), 4U);
EXPECT_EQ(read_u32_le(frame, 8), 3U);
EXPECT_EQ(read_u32_le(frame, 12), 16U);
}
TEST(RenderiveWebBridge, CurrentTwoDimensionalSceneRendersAfterResize) {
Web_Plot_Session session;
EXPECT_FALSE(session.handle(Viewport_Resize{{320, 200}}));
const auto response = session.handle(Frame_Request{});
ASSERT_TRUE(response);
ASSERT_EQ(response->type, Web_Response_Type::Pixels);
ASSERT_GE(response->payload.size(), pixel_frame_header_size);
EXPECT_EQ(response->payload.substr(0, 4), "RVP2");
EXPECT_EQ(read_u32_le(response->payload, 4), 320U);
EXPECT_EQ(read_u32_le(response->payload, 8), 200U);
}
TEST(RenderiveWebGallery, CatalogUsesOneDefaultPageAndThreeDynamicStrategies) {
const auto catalog = nlohmann::json::parse(Gallery_Protocol::catalog_json());
ASSERT_EQ(catalog.at("type"), "catalog");
EXPECT_EQ(catalog.at("cases").size(), 23U);
EXPECT_EQ(catalog.at("frame_modes").size(), 3U);
EXPECT_EQ(catalog.at("coverage").at("page_count"), 1U);
EXPECT_EQ(catalog.at("coverage").at("canvas_count"), 23U);
const auto request = Gallery_Protocol::open_request(
R"({"category":"event","type":"gallery_open","case":"spectrum","frame_mode":"low_latency"})");
ASSERT_TRUE(request);
EXPECT_EQ(request->case_id, "spectrum");
EXPECT_EQ(request->frame_mode, Gallery_Frame_Mode::Low_Latency);
EXPECT_FALSE(Gallery_Protocol::open_request(
R"({"category":"event","type":"gallery_open","case":"unknown","frame_mode":"low_latency"})"));
}
TEST(RenderiveWebGallery, TwoDimensionalGalleryPublishesStateAndPixels) {
Gallery_Plot_Session session;
const std::string open =
R"({"category":"event","type":"gallery_open","case":"spectrum","frame_mode":"low_latency"})";
const auto opened = session.handle(Gallery_Request{Gallery_Request_Kind::Open, open});
ASSERT_TRUE(opened);
ASSERT_EQ(opened->type, Web_Response_Type::Json);
const auto state = nlohmann::json::parse(opened->payload);
EXPECT_EQ(state.at("type"), "case_state");
EXPECT_EQ(state.at("case"), "spectrum");
const auto& controls = state.at("controls");
EXPECT_FALSE(controls.at("render_plan").at("nodes").empty());
EXPECT_TRUE(controls.at("performance_capture").at("controller").is_object());
EXPECT_TRUE(controls.at("performance_capture").at("sessions").is_array());
EXPECT_TRUE(controls.at("performance_capture").at("plans").is_array());
const auto& observer = state.at("telemetry").at("kernel_observer");
EXPECT_EQ(observer.at("state").at("viewport").at("width"), 560);
EXPECT_EQ(observer.at("renderable_count"), 4U);
const auto switched = session.handle(Gallery_Request{
Gallery_Request_Kind::Action,
R"({"category":"event","type":"gallery_action","action":"frame_strategy_manual"})"});
ASSERT_TRUE(switched);
const auto switched_state = nlohmann::json::parse(switched->payload);
EXPECT_EQ(switched_state.at("frame_mode"), "manual");
EXPECT_EQ(switched_state.at("telemetry").at("kernel_observer").at("mode"),
"manual");
const std::string render =
R"({"category":"event","type":"gallery_action","action":"mode_render"})";
const auto rendered = session.handle(
Gallery_Request{Gallery_Request_Kind::Action, render});
ASSERT_TRUE(rendered);
EXPECT_EQ(nlohmann::json::parse(rendered->payload).at("type"), "case_state");
const std::string capture =
R"({"category":"event","type":"gallery_action","action":"capture_next_frame"})";
const auto captured = session.handle(
Gallery_Request{Gallery_Request_Kind::Action, capture});
ASSERT_TRUE(captured);
const auto capture_state = nlohmann::json::parse(captured->payload);
const auto& sessions = capture_state.at("controls")
.at("performance_capture").at("sessions");
ASSERT_EQ(sessions.size(), 1U);
EXPECT_EQ(sessions.front().at("captured_count"), 1U);
const auto pixels = session.handle(Frame_Request{});
ASSERT_TRUE(pixels);
ASSERT_EQ(pixels->type, Web_Response_Type::Pixels);
EXPECT_EQ(pixels->payload.substr(0, 4), "RVP2");
const auto first_pixel = pixels->payload.substr(pixel_frame_header_size, 4);
bool contains_drawn_pixel = false;
for (std::size_t offset = pixel_frame_header_size;
offset + 4 <= pixels->payload.size(); offset += 4) {
if (pixels->payload.compare(offset, 4, first_pixel) != 0) {
contains_drawn_pixel = true;
break;
}
}
EXPECT_TRUE(contains_drawn_pixel);
}
} // namespace
} // namespace renderive::web