#include #include #include #include #include #include using namespace XCEngine::Resources; namespace { void WriteTextFile(const std::filesystem::path& path, const std::string& contents) { std::filesystem::create_directories(path.parent_path()); std::ofstream output(path, std::ios::binary | std::ios::trunc); ASSERT_TRUE(output.is_open()); output << contents; ASSERT_TRUE(static_cast(output)); } void ExpectSchemaCompileFailure( const char* testFolderName, const char* markup, const char* expectedMessageFragment) { namespace fs = std::filesystem; const fs::path root = fs::temp_directory_path() / testFolderName; const fs::path schemaPath = root / "invalid.xcschema"; fs::remove_all(root); WriteTextFile(schemaPath, markup); UISchemaLoader loader; UIDocumentCompileResult compileResult = {}; EXPECT_FALSE(loader.CompileDocument(schemaPath.string().c_str(), compileResult)); EXPECT_FALSE(compileResult.succeeded); EXPECT_FALSE(compileResult.errorMessage.Empty()); ASSERT_FALSE(compileResult.document.diagnostics.Empty()); const std::string errorMessage = compileResult.errorMessage.CStr(); EXPECT_NE(errorMessage.find(expectedMessageFragment), std::string::npos); fs::remove_all(root); } TEST(UISchemaDocument, CompileAndArtifactLoadPopulateSchemaDefinition) { namespace fs = std::filesystem; const fs::path root = fs::temp_directory_path() / "xc_ui_schema_compile_test"; const fs::path schemaPath = root / "markup.xcschema"; const fs::path artifactPath = root / "markup.xcschemaasset"; fs::remove_all(root); WriteTextFile( schemaPath, "\n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" "\n"); UISchemaLoader loader; UIDocumentCompileResult compileResult = {}; ASSERT_TRUE(loader.CompileDocument(schemaPath.string().c_str(), compileResult)); ASSERT_TRUE(compileResult.succeeded); ASSERT_TRUE(compileResult.document.valid); ASSERT_TRUE(compileResult.document.schemaDefinition.valid); EXPECT_EQ(compileResult.document.schemaDefinition.name, "EditorMarkup"); const UISchemaElementDefinition* viewElement = compileResult.document.schemaDefinition.FindElement("View"); ASSERT_NE(viewElement, nullptr); EXPECT_TRUE(viewElement->allowUnknownChildren); const UISchemaAttributeDefinition* themeAttribute = viewElement->FindAttribute("theme"); ASSERT_NE(themeAttribute, nullptr); EXPECT_EQ(themeAttribute->valueType, UISchemaValueType::Document); EXPECT_TRUE(themeAttribute->restrictDocumentKind); EXPECT_EQ(themeAttribute->documentKind, UIDocumentKind::Theme); const UISchemaAttributeDefinition* modeAttribute = viewElement->FindAttribute("mode"); ASSERT_NE(modeAttribute, nullptr); EXPECT_EQ(modeAttribute->valueType, UISchemaValueType::Enum); ASSERT_EQ(modeAttribute->allowedValues.Size(), 2u); EXPECT_EQ(modeAttribute->allowedValues[0], "compact"); EXPECT_EQ(modeAttribute->allowedValues[1], "cozy"); LoadResult loadResult = loader.Load(schemaPath.string().c_str()); ASSERT_TRUE(loadResult); ASSERT_NE(loadResult.resource, nullptr); auto* schemaResource = static_cast(loadResult.resource); ASSERT_NE(schemaResource, nullptr); ASSERT_TRUE(schemaResource->GetSchemaDefinition().valid); ASSERT_NE(schemaResource->GetSchemaDefinition().FindElement("View"), nullptr); delete schemaResource; XCEngine::Containers::String artifactWriteError; ASSERT_TRUE( WriteUIDocumentArtifact(artifactPath.string().c_str(), compileResult, &artifactWriteError)) << artifactWriteError.CStr(); XCEngine::Containers::Array artifactPayload; ASSERT_TRUE(ReadArtifactContainerMainEntryPayload( artifactPath.string().c_str(), ResourceType::UISchema, artifactPayload)); EXPECT_FALSE(artifactPayload.Empty()); UIDocumentCompileResult artifactResult = {}; ASSERT_TRUE(LoadUIDocumentArtifact( artifactPath.string().c_str(), UIDocumentKind::Schema, artifactResult)); ASSERT_TRUE(artifactResult.succeeded); ASSERT_TRUE(artifactResult.document.valid); ASSERT_TRUE(artifactResult.document.schemaDefinition.valid); const UISchemaElementDefinition* artifactViewElement = artifactResult.document.schemaDefinition.FindElement("View"); ASSERT_NE(artifactViewElement, nullptr); ASSERT_NE(artifactViewElement->FindChild("Column"), nullptr); fs::remove_all(root); } TEST(UISchemaDocument, CompileRejectsInvalidSchemaFlags) { namespace fs = std::filesystem; const fs::path root = fs::temp_directory_path() / "xc_ui_schema_invalid_flag_test"; const fs::path schemaPath = root / "broken.xcschema"; fs::remove_all(root); WriteTextFile( schemaPath, "\n" " \n" "\n"); UISchemaLoader loader; UIDocumentCompileResult compileResult = {}; EXPECT_FALSE(loader.CompileDocument(schemaPath.string().c_str(), compileResult)); EXPECT_FALSE(compileResult.succeeded); EXPECT_FALSE(compileResult.errorMessage.Empty()); ASSERT_FALSE(compileResult.document.diagnostics.Empty()); const std::string errorMessage = compileResult.errorMessage.CStr(); EXPECT_NE(errorMessage.find("allowUnknownChildren"), std::string::npos); fs::remove_all(root); } TEST(UISchemaDocument, CompileRejectsDuplicateAttributeDefinitions) { namespace fs = std::filesystem; const fs::path root = fs::temp_directory_path() / "xc_ui_schema_duplicate_attribute_test"; const fs::path schemaPath = root / "duplicate.xcschema"; fs::remove_all(root); WriteTextFile( schemaPath, "\n" " \n" " \n" " \n" " \n" "\n"); UISchemaLoader loader; UIDocumentCompileResult compileResult = {}; EXPECT_FALSE(loader.CompileDocument(schemaPath.string().c_str(), compileResult)); EXPECT_FALSE(compileResult.succeeded); EXPECT_FALSE(compileResult.errorMessage.Empty()); ASSERT_FALSE(compileResult.document.diagnostics.Empty()); const std::string errorMessage = compileResult.errorMessage.CStr(); EXPECT_NE(errorMessage.find("Duplicate schema attribute definition"), std::string::npos); fs::remove_all(root); } TEST(UISchemaDocument, CompileRejectsAllowedValuesOnNonEnumAttribute) { ExpectSchemaCompileFailure( "xc_ui_schema_allowed_values_non_enum_test", "\n" " \n" " \n" " \n" "\n", "allowedValues"); } TEST(UISchemaDocument, CompileRejectsDocumentKindOnNonDocumentAttribute) { ExpectSchemaCompileFailure( "xc_ui_schema_document_kind_non_document_test", "\n" " \n" " \n" " \n" "\n", "documentKind"); } TEST(UISchemaDocument, CompileRejectsRestrictDocumentKindOnNonDocumentAttribute) { ExpectSchemaCompileFailure( "xc_ui_schema_restrict_non_document_test", "\n" " \n" " \n" " \n" "\n", "restrictDocumentKind"); } TEST(UISchemaDocument, CompileRejectsRestrictDocumentKindWithoutExplicitDocumentKind) { ExpectSchemaCompileFailure( "xc_ui_schema_restrict_without_kind_test", "\n" " \n" " \n" " \n" "\n", "must declare 'documentKind'"); } } // namespace