#include #include "XCUIBackend/XCUIRHICommandSupport.h" #include namespace { using XCEngine::Editor::XCUIBackend::AccumulateXCUIRHICommandSupport; using XCEngine::Editor::XCUIBackend::AnalyzeXCUIRHICommandSupport; using XCEngine::Editor::XCUIBackend::BuildXCUIRHICommandSupportDiagnostic; using XCEngine::Editor::XCUIBackend::ClassifyXCUIRHICommandSupport; using XCEngine::Editor::XCUIBackend::SummarizeXCUIRHICommandSupport; using XCEngine::Editor::XCUIBackend::XCUIRHICommandCategory; using XCEngine::Editor::XCUIBackend::XCUIRHICommandDiagnosticOptions; using XCEngine::Editor::XCUIBackend::XCUIRHICommandSupportReason; using XCEngine::Editor::XCUIBackend::XCUIRHICommandSupportStats; using XCEngine::UI::UIColor; using XCEngine::UI::UIDrawCommand; using XCEngine::UI::UIDrawCommandType; using XCEngine::UI::UIDrawData; using XCEngine::UI::UIDrawList; using XCEngine::UI::UIPoint; using XCEngine::UI::UIRect; using XCEngine::UI::UITextureHandle; using XCEngine::UI::UITextureHandleKind; UITextureHandle MakeShaderResourceTexture() { UITextureHandle texture = {}; texture.nativeHandle = 42u; texture.width = 64u; texture.height = 64u; texture.kind = UITextureHandleKind::ShaderResourceView; return texture; } UIDrawCommand MakeUnknownCommand() { UIDrawCommand command = {}; command.type = static_cast(255); return command; } } // namespace TEST(XCUIRHICommandSupportTest, ClassifySupportedCommandTypes) { UIDrawList drawList("Supported"); drawList.AddFilledRect(UIRect(0.0f, 0.0f, 12.0f, 10.0f), UIColor(1.0f, 0.0f, 0.0f, 1.0f)); drawList.AddRectOutline( UIRect(1.0f, 2.0f, 8.0f, 5.0f), UIColor(0.0f, 1.0f, 0.0f, 1.0f), 2.0f, 1.0f); drawList.AddText(UIPoint(4.0f, 5.0f), "label", UIColor(1.0f, 1.0f, 1.0f, 1.0f), 14.0f); drawList.AddImage( UIRect(2.0f, 3.0f, 18.0f, 14.0f), MakeShaderResourceTexture(), UIColor(1.0f, 1.0f, 1.0f, 1.0f)); drawList.PushClipRect(UIRect(0.0f, 0.0f, 24.0f, 20.0f)); drawList.PopClipRect(); const auto& commands = drawList.GetCommands(); EXPECT_EQ( ClassifyXCUIRHICommandSupport(commands[0]).category, XCUIRHICommandCategory::FilledRect); EXPECT_EQ( ClassifyXCUIRHICommandSupport(commands[1]).category, XCUIRHICommandCategory::RectOutline); EXPECT_EQ( ClassifyXCUIRHICommandSupport(commands[2]).category, XCUIRHICommandCategory::Text); EXPECT_EQ( ClassifyXCUIRHICommandSupport(commands[3]).category, XCUIRHICommandCategory::Image); EXPECT_EQ( ClassifyXCUIRHICommandSupport(commands[4]).category, XCUIRHICommandCategory::PushClipRect); EXPECT_EQ( ClassifyXCUIRHICommandSupport(commands[5]).category, XCUIRHICommandCategory::PopClipRect); for (const UIDrawCommand& command : commands) { EXPECT_TRUE(ClassifyXCUIRHICommandSupport(command).IsSupported()); } } TEST(XCUIRHICommandSupportTest, InvalidImageCommandIsClassifiedAsUnsupportedTexture) { UIDrawCommand command = {}; command.type = UIDrawCommandType::Image; command.rect = UIRect(0.0f, 0.0f, 12.0f, 12.0f); command.texture.nativeHandle = 7u; command.texture.width = 32u; command.texture.height = 32u; command.texture.kind = UITextureHandleKind::ImGuiDescriptor; const auto classification = ClassifyXCUIRHICommandSupport(command); EXPECT_EQ(classification.category, XCUIRHICommandCategory::Image); EXPECT_EQ( classification.supportReason, XCUIRHICommandSupportReason::UnsupportedImageTexture); EXPECT_FALSE(classification.IsSupported()); } TEST(XCUIRHICommandSupportTest, UnknownCommandTypeIsClassifiedSeparately) { const auto classification = ClassifyXCUIRHICommandSupport(MakeUnknownCommand()); EXPECT_EQ(classification.category, XCUIRHICommandCategory::Unknown); EXPECT_EQ( classification.supportReason, XCUIRHICommandSupportReason::UnsupportedUnknownCommand); EXPECT_FALSE(classification.IsSupported()); } TEST(XCUIRHICommandSupportTest, AnalyzeDrawDataAggregatesSupportedAndUnsupportedCounts) { UIDrawData drawData = {}; UIDrawList& firstDrawList = drawData.EmplaceDrawList("First"); firstDrawList.AddFilledRect( UIRect(0.0f, 0.0f, 8.0f, 8.0f), UIColor(1.0f, 0.0f, 0.0f, 1.0f)); firstDrawList.AddImage( UIRect(2.0f, 2.0f, 12.0f, 10.0f), MakeShaderResourceTexture(), UIColor(1.0f, 1.0f, 1.0f, 1.0f)); UIDrawList& secondDrawList = drawData.EmplaceDrawList("Second"); secondDrawList.PushClipRect(UIRect(0.0f, 0.0f, 100.0f, 60.0f)); secondDrawList.AddText( UIPoint(5.0f, 6.0f), "status", UIColor(1.0f, 1.0f, 1.0f, 1.0f), 12.0f); UITextureHandle invalidTexture = {}; invalidTexture.nativeHandle = 9u; invalidTexture.width = 32u; invalidTexture.height = 32u; invalidTexture.kind = UITextureHandleKind::ImGuiDescriptor; secondDrawList.AddImage( UIRect(1.0f, 1.0f, 6.0f, 6.0f), invalidTexture, UIColor(1.0f, 1.0f, 1.0f, 1.0f)); const auto stats = AnalyzeXCUIRHICommandSupport(drawData); EXPECT_EQ(stats.drawListCount, 2u); EXPECT_EQ(stats.commandCount, 5u); EXPECT_EQ(stats.filledRectCommandCount, 1u); EXPECT_EQ(stats.textCommandCount, 1u); EXPECT_EQ(stats.imageCommandCount, 2u); EXPECT_EQ(stats.clipPushCommandCount, 1u); EXPECT_EQ(stats.clipPopCommandCount, 0u); EXPECT_EQ(stats.supportedCommandCount, 4u); EXPECT_EQ(stats.unsupportedCommandCount, 1u); EXPECT_EQ(stats.unsupportedImageCommandCount, 1u); EXPECT_EQ(stats.unsupportedUnknownCommandCount, 0u); EXPECT_FALSE(stats.SupportsAllCommands()); } TEST(XCUIRHICommandSupportTest, DiagnosticIncludesUnsupportedReasonsAndCanBeCustomized) { XCUIRHICommandSupportStats stats = {}; AccumulateXCUIRHICommandSupport(MakeUnknownCommand(), stats); UIDrawCommand invalidImage = {}; invalidImage.type = UIDrawCommandType::Image; invalidImage.texture.nativeHandle = 11u; invalidImage.texture.width = 16u; invalidImage.texture.height = 16u; invalidImage.texture.kind = UITextureHandleKind::ImGuiDescriptor; AccumulateXCUIRHICommandSupport(invalidImage, stats); const std::string defaultDiagnostic = BuildXCUIRHICommandSupportDiagnostic(stats); EXPECT_NE(defaultDiagnostic.find("2 command(s) will be skipped by native overlay: "), std::string::npos); EXPECT_NE(defaultDiagnostic.find("1 image command(s) missing valid ShaderResourceView textures"), std::string::npos); EXPECT_NE(defaultDiagnostic.find("1 unknown command type(s)"), std::string::npos); XCUIRHICommandDiagnosticOptions options = {}; options.noCommandsMessage = "No overlay commands."; options.allSupportedMessage = "Everything supported."; options.unsupportedPrefix = "command(s) rejected:"; const std::string customDiagnostic = BuildXCUIRHICommandSupportDiagnostic(stats, options); EXPECT_NE(customDiagnostic.find("2 command(s) rejected:"), std::string::npos); } TEST(XCUIRHICommandSupportTest, SummaryReturnsNoCommandAndAllSupportedMessages) { const auto emptySummary = SummarizeXCUIRHICommandSupport(UIDrawData()); EXPECT_EQ(emptySummary.stats.commandCount, 0u); EXPECT_EQ(emptySummary.diagnostic, "Overlay runtime produced no commands."); UIDrawData drawData = {}; UIDrawList& drawList = drawData.EmplaceDrawList("Supported"); drawList.AddFilledRect( UIRect(0.0f, 0.0f, 4.0f, 4.0f), UIColor(0.2f, 0.4f, 0.8f, 1.0f)); const auto supportedSummary = SummarizeXCUIRHICommandSupport(drawData); EXPECT_EQ(supportedSummary.stats.supportedCommandCount, 1u); EXPECT_TRUE(supportedSummary.stats.SupportsAllCommands()); EXPECT_EQ(supportedSummary.diagnostic, "All commands preflight for native overlay."); }