Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrong property tags issue #970

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions iModelCore/ECDb/Tests/NonPublished/ECSqlStatementTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1535,6 +1535,96 @@ TEST_F(ECSqlStatementTestFixture, IsNull)
}

//---------------------------------------------------------------------------------------
//@bsimethod
//---------------------------------------------------------------------------------------
TEST_F(ECSqlStatementTestFixture, UseOfWrongPropertyTags_ForAllVersions)
{
ASSERT_EQ(DbResult::BE_SQLITE_OK, SetupECDb("UseOfWrongPropertyTags.ecdb"));

unsigned int ecXmlMajorVersion;
unsigned int ecXmlMinorVersion;
EXPECT_EQ(ECObjectsStatus::Success, ECSchema::ParseECVersion(ecXmlMajorVersion, ecXmlMinorVersion, ECVersion::Latest));

//Below schema uses ECProperty tag for Struct property which is wrong. It should use ECStructProperty tag.
Utf8CP xmlSchema = R"xml(<ECSchema schemaName="TestSchema" alias="ts" version="1.0.0" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.%d.%d">
<ECStructClass typeName="PrimStruct">
<ECProperty propertyName="p2d" typeName="Point2d" />
<ECProperty propertyName="p3d" typeName="Point3d" />
</ECStructClass>
<ECEntityClass typeName="UseOfWrongPropertyTags">
<ECProperty propertyName="Struct" typeName="PrimStruct" />
<ECStructArrayProperty propertyName="Struct_Array" typeName="PrimStruct" />
</ECEntityClass>
</ECSchema>)xml";

//Below schema uses ECProperty tag for Struct property which is wrong. It should use ECStructProperty tag.
//Declaring separate xmlSchema for version 2.0 since, previous versions had different xml schema format.
Utf8CP xmlSchemaFor_V2_0 = R"xml(<ECSchema schemaName="TestSchema" version="1.0" nameSpacePrefix="test" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.2.0">
<ECClass typeName="PrimStruct" isStruct = "true">
<ECProperty propertyName="i" typeName="int" />
<ECArrayProperty propertyName="I" typeName="int" />
</ECClass>
<ECClass typeName="UseOfWrongPropertyTags">
<ECProperty propertyName="Struct" typeName="PrimStruct" />
</ECClass>
</ECSchema>)xml";

//Below schema uses ECProperty tag for Struct property which is wrong. It should use ECStructProperty tag.
//Declaring separate xmlSchema for version 3.0 since, previous versions had different xml schema format.
Utf8CP xmlSchemaFor_V3_0 = R"xml(<ECSchema schemaName="TestSchema" version="1.0" nameSpacePrefix="test" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.0">
<ECStructClass typeName="PrimStruct">
<ECProperty propertyName="p2d" typeName="Point2d" />
<ECArrayProperty propertyName="p3d" typeName="Point3d" />
</ECStructClass>
<ECEntityClass typeName="UseOfWrongPropertyTags">
<ECProperty propertyName="Struct" typeName="PrimStruct" />
<ECStructArrayProperty propertyName="Struct_Array" typeName="PrimStruct" />
</ECEntityClass>
</ECSchema>)xml";

for (const auto& [testCaseNumber, majorVersion, minorVersion, xmlSchemaVar, deserializationStatus, importStatus] : std::vector<std::tuple<unsigned int, unsigned int, unsigned int, Utf8CP, bool, bool>>
{
{ 1, 2U, 0U, xmlSchemaFor_V2_0, true , true }, // Older versions on encountering wrong property tags default to a safe type in this case, "string"
{ 2, 3U, 0U, xmlSchemaFor_V3_0, true , true }, // Older versions on encountering wrong property tags default to a safe type in this case, "string"
{ 3, 3U, 1U, xmlSchema, true , true }, // Older versions on encountering wrong property tags default to a safe type in this case, "string"
{ 4, ecXmlMajorVersion, ecXmlMinorVersion, xmlSchema, false , false }, // Current version should always log an error on encountering wrong property tags with no deserialization and import
{ 5, ecXmlMajorVersion, ecXmlMinorVersion + 1U, xmlSchema, true , false }, // Future versions should deserialize successfully, default to a safe type but, import should fail
})
{
ECSchemaPtr schema;
const auto context = ECSchemaReadContext::CreateContext();

// Schema should always be deserialized successfully irrespective of the ECXml version
ASSERT_EQ(deserializationStatus, SchemaReadStatus::Success == ECSchema::ReadFromXmlString(schema, Utf8PrintfString(xmlSchemaVar, majorVersion, minorVersion).c_str(), *context)) << "Test case number " << testCaseNumber << " failed at deserializing.";
ASSERT_EQ(deserializationStatus, schema.IsValid()) << "Test case number: " << testCaseNumber << " failed due to invalid schemas.";

// Checking if the wrong property tags are defaulted to string type
if (deserializationStatus)
{
// Fetching the class pointer
auto classP = schema->GetClassCP("UseOfWrongPropertyTags");
ASSERT_TRUE(classP) << "Test case failed." << testCaseNumber << "failed to fetch class pointer.";
// Fetching the property pointer
auto propP = classP->GetPropertyByIndex(0);
ASSERT_TRUE(propP) << "Test case failed." << testCaseNumber << "failed to fetch property pointer.";
// Fetching property as primitive property
auto primProp = propP->GetAsPrimitiveProperty();
ASSERT_TRUE(primProp) << "Test case failed." << testCaseNumber << "failed to fetch the primitive property";
// Checking for equality of primivite property type to string
auto propType = primProp->GetType();
EXPECT_EQ(PRIMITIVETYPE_String, propType) << "Test case failed." << testCaseNumber << "did not default to string type.";
}


// Schema import should fail when ECXml version of the schema is greater than the current version that the ECDb supports
EXPECT_EQ(importStatus, m_ecdb.Schemas().ImportSchemas(context->GetCache().GetSchemas()) == SchemaImportResult::OK) << "Test case number " << testCaseNumber << " failed.";
if (importStatus)
EXPECT_NE(nullptr, m_ecdb.Schemas().GetSchema("TestSchema")) << "Test case number " << testCaseNumber << " failed.";
m_ecdb.AbandonChanges();

}
}
//---------------------------------------------------------------------------------------
// @bsimethod
//+---------------+---------------+---------------+---------------+---------------+------
TEST_F(ECSqlStatementTestFixture, pragma_ecdb_version)
Expand Down
7 changes: 7 additions & 0 deletions iModelCore/ecobjects/src/ECProperty.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ SchemaReadStatus ReadTypeNameWithPruning(pugi::xml_node node, ECPropertyP prop,
// must come after prune check to make sure we don't default to string properties that should be pruned
if (setTypeStatus == ECObjectsStatus::ParseError && ignoreParseErrors)
{
// Unknown type encounter in the schema for the current version returning ERROR status
if (prop->GetClass().GetSchema().GetOriginalECXmlVersionAsString() == ECSchema::GetECVersionString(ECVersion::Latest))
{
LOG.errorv("Invalid ECSchemaXML: The Property '%s.%s' has a type name '%s' that can not be resolved to a known type.",
prop->GetClass().GetFullName(), prop->GetName().c_str(), typeName.c_str());
return SchemaReadStatus::InvalidECSchemaXml;
}
LOG.warningv ("Defaulting the type of ECProperty '%s' to '%s' in reaction to non-fatal parse error.", prop->GetName().c_str(), prop->GetTypeName().c_str());
return SchemaReadStatus::Success;
}
Expand Down
48 changes: 48 additions & 0 deletions iModelCore/ecobjects/test/NonPublished/SchemaComparerTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1121,6 +1121,54 @@ TEST_F(SchemaCompareTest, CompareECClassIdentical)
//----------------------------------------------------------------------------------------
// @bsimethod
//---------------+---------------+---------------+---------------+---------------+--------
TEST_F(SchemaComparerXmlTests, CompareSchemasWithWrongPropertyTags)
{
//Test created for 3.1 version of schema specifically
//to observe defaulting behavior for and when the property tags are wrong
bvector<Utf8CP> firstSchemasXml {
R"schema(<?xml version='1.0' encoding='utf-8' ?>
<ECSchema schemaName="TestSchema" alias="ts" version="1.0.0" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.1">
<ECStructClass typeName="PrimStruct">
<ECProperty propertyName="p2d" typeName="Point2d" />
<ECProperty propertyName="p3d" typeName="Point3d" />
</ECStructClass>
<ECEntityClass typeName="UseOfWrongPropertyTags">
<ECProperty propertyName="Struct" typeName="PrimStruct" />
<ECStructArrayProperty propertyName="Struct_Array" typeName="PrimStruct" />
</ECEntityClass>
</ECSchema>)schema"
};

LoadSchemasIntoContext(m_firstContext, firstSchemasXml);

bvector<Utf8CP> secondSchemasXml {
R"schema(<?xml version='1.0' encoding='utf-8' ?>
<ECSchema schemaName="TestSchema" alias="ts" version="1.0.0" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.1">
<ECStructClass typeName="PrimStruct">
<ECProperty propertyName="p2d" typeName="Point2d" />
<ECProperty propertyName="p3d" typeName="Point3d" />
</ECStructClass>
<ECEntityClass typeName="UseOfWrongPropertyTags">
<ECStructProperty propertyName="Struct" typeName="PrimStruct" />
<ECStructArrayProperty propertyName="Struct_Array" typeName="PrimStruct" />
</ECEntityClass>
</ECSchema>)schema"
};

LoadSchemasIntoContext(m_secondContext, secondSchemasXml);

SchemaComparer comparer;
SchemaDiff changes;
comparer.Compare(changes, m_firstContext->GetCache().GetSchemas(), m_secondContext->GetCache().GetSchemas());

ASSERT_EQ(1, changes.Changes().Count());

// We default to string when the property tag is wrong therefore, property change should be observed.
ASSERT_TRUE(changes.Changes()[0].Classes()[0].Properties()[0].IsChanged());
}
//----------------------------------------------------------------------------------------
// @bsimethod
//---------------+---------------+---------------+---------------+---------------+--------
TEST_F(SchemaCompareTest, CompareECSchemaClassPropertyDescriptionAgainstNull)
{
CreateFirstSchema();
Expand Down