diff --git a/src/parser.cpp b/src/parser.cpp index 7728f4ccd6..14d3be844b 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -590,15 +590,16 @@ void Parser::ParserImpl::loadModel(const ModelPtr &model, const std::string &inp childNode = childNode->next(); } - if (!encapsulationNodes.empty()) { - loadEncapsulation(model, encapsulationNodes.at(0)); - if (encapsulationNodes.size() > 1) { - auto issue = Issue::IssueImpl::create(); - issue->mPimpl->setDescription("Model '" + model->name() + "' has more than one encapsulation element."); - issue->mPimpl->mItem->mPimpl->setEncapsulation(model); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::MODEL_MORE_THAN_ONE_ENCAPSULATION); - addIssue(issue); - } + for (const auto &encapsulationNode : encapsulationNodes) { + loadEncapsulation(model, encapsulationNode); + } + + if (mParsing20Version && encapsulationNodes.size() > 1) { + auto issue = Issue::IssueImpl::create(); + issue->mPimpl->setDescription("Model '" + model->name() + "' has more than one encapsulation element."); + issue->mPimpl->mItem->mPimpl->setEncapsulation(model); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::MODEL_MORE_THAN_ONE_ENCAPSULATION); + addIssue(issue); } NamePairList usedConnections; @@ -1109,7 +1110,7 @@ void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr issue->mPimpl->setReferenceRule(Issue::ReferenceRule::CONNECTION_EXCLUDE_SELF); addIssue(issue); } else { - if (component1Name > component2Name) { + if (!mParsing1XVersion && (component1Name > component2Name)) { std::string tmp = component1Name; component1Name = component2Name; component2Name = tmp; @@ -1240,12 +1241,6 @@ void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr mapVariablesFound = true; if (!variable1Missing && !variable2Missing) { - if (variable1Name > variable2Name) { - std::string tmp = variable1Name; - variable1Name = variable2Name; - variable2Name = tmp; - } - auto variableNamePair = std::make_pair(variable1Name, variable2Name); NamePairList::const_iterator it = std::find_if(usedMapVariables.begin(), usedMapVariables.end(), diff --git a/tests/connection/connection.cpp b/tests/connection/connection.cpp index 4789fe4b7f..abefc260c9 100644 --- a/tests/connection/connection.cpp +++ b/tests/connection/connection.cpp @@ -1435,7 +1435,7 @@ TEST(Connection, repeatedMapVariables) const std::vector expectedIssues = { "Connection in model 'connection' between 'variable1' and 'variable2' is not unique.", - "Connection in model 'connection' between 'variable3' and 'variable6' is not unique.", + "Connection in model 'connection' between 'variable6' and 'variable3' is not unique.", }; EXPECT_EQ_ISSUES(expectedIssues, p); @@ -1535,3 +1535,64 @@ TEST(Connection, addEquivalenceConnectionIdClearedAfterDisconnect) libcellml::Variable::addEquivalence(v1, v2); EXPECT_EQ("", libcellml::Variable::equivalenceConnectionId(v1, v2)); } + +TEST(Connection, twoWayConnectionFromCellML1) +{ + auto p = libcellml::Parser::create(false); + auto m = p->parseModel(fileContents("cellml1X/connections.cellml")); + + EXPECT_EQ(size_t(0), p->errorCount()); +} + +TEST(Connection, sameNamedVariablesInDifferentComponents) +{ + auto m = libcellml::Model::create("m"); + auto c1 = libcellml::Component::create("c1"); + auto c2 = libcellml::Component::create("c2"); + auto v1c1 = libcellml::Variable::create("v1"); + auto v2c1 = libcellml::Variable::create("v2"); + auto v1c2 = libcellml::Variable::create("v1"); + auto v2c2 = libcellml::Variable::create("v2"); + + m->addComponent(c1); + m->addComponent(c2); + + c1->addVariable(v1c1); + c1->addVariable(v2c1); + c2->addVariable(v1c2); + c2->addVariable(v2c2); + + v1c1->setUnits("dimensionless"); + v1c1->setInterfaceType("public"); + v2c1->setUnits("dimensionless"); + v2c1->setInterfaceType("public"); + v1c2->setUnits("dimensionless"); + v1c2->setInterfaceType("public"); + v2c2->setUnits("dimensionless"); + v2c2->setInterfaceType("public"); + + libcellml::Variable::addEquivalence(v1c1, v2c2); + libcellml::Variable::addEquivalence(v2c1, v1c2); + + auto v = libcellml::Validator::create(); + v->validateModel(m); + + EXPECT_EQ(size_t(0), v->issueCount()); + + auto printer = libcellml::Printer::create(); + + auto modelString = printer->printModel(m); + + auto p = libcellml::Parser::create(); + p->parseModel(modelString); + + EXPECT_EQ(size_t(0), p->issueCount()); +} + +TEST(Connection, mapComponentsAreOrderDependentInCellML1X) +{ + auto p = libcellml::Parser::create(false); + auto m = p->parseModel(fileContents("cellml1X/map_components.cellml")); + + EXPECT_EQ(size_t(0), p->errorCount()); +} diff --git a/tests/parser/cellml_1_1.cpp b/tests/parser/cellml_1_1.cpp index cb5a486a1f..92373fe0b0 100644 --- a/tests/parser/cellml_1_1.cpp +++ b/tests/parser/cellml_1_1.cpp @@ -141,3 +141,18 @@ TEST(ParserTransform, cellmlNsCn) EXPECT_EQ(size_t(0), validator->issueCount()); } + +TEST(ParserTransform, parseCellMl1XWithMultipleEncapsulationRelationshipGroups) +{ + std::vector expectedIssues = { + "Given model is a CellML 1.1 model, the parser will try to represent this model in CellML 2.0.", + }; + + auto parser = libcellml::Parser::create(false); + auto model = parser->parseModel(fileContents("cellml1X/multiple_encapsulations.cellml")); + + printIssues(parser); + + EXPECT_EQ_ISSUES(expectedIssues, parser); + EXPECT_EQ("Example_MassAction", model->name()); +} diff --git a/tests/parser/parser.cpp b/tests/parser/parser.cpp index 531cb3c67c..87bc95b599 100644 --- a/tests/parser/parser.cpp +++ b/tests/parser/parser.cpp @@ -956,6 +956,7 @@ TEST(Parser, invalidEncapsulations) "Encapsulation in model 'ringo' does not have a valid component attribute in a component_ref element.", "Encapsulation in model 'ringo' does not have a valid component attribute in a component_ref element.", "Encapsulation in model 'ringo' specifies an invalid parent component_ref that also does not have any children.", + "Encapsulation in model 'ringo' specifies 'bob' as a parent component_ref but it does not have any children.", "Model 'ringo' has more than one encapsulation element.", }; diff --git a/tests/resources/cellml1X/connections.cellml b/tests/resources/cellml1X/connections.cellml new file mode 100644 index 0000000000..1890e9a337 --- /dev/null +++ b/tests/resources/cellml1X/connections.cellml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/resources/cellml1X/map_components.cellml b/tests/resources/cellml1X/map_components.cellml new file mode 100644 index 0000000000..7de46b31c6 --- /dev/null +++ b/tests/resources/cellml1X/map_components.cellml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/resources/cellml1X/multiple_encapsulations.cellml b/tests/resources/cellml1X/multiple_encapsulations.cellml new file mode 100644 index 0000000000..5de46c60b7 --- /dev/null +++ b/tests/resources/cellml1X/multiple_encapsulations.cellml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +