diff --git a/tests/parser/parser.cpp b/tests/parser/parser.cpp index 531cb3c67c..319182a84a 100644 --- a/tests/parser/parser.cpp +++ b/tests/parser/parser.cpp @@ -682,6 +682,66 @@ TEST(Parser, modelWithInvalidUnits) EXPECT_EQ(e, a); } +TEST(Parser, unitAttributesWithLeadingPlusSign) +{ + // CellML 2.0 section 1.3.3.2: a real number string may begin with a '+' sign. + const std::string in = + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + + libcellml::ParserPtr parser = libcellml::Parser::create(); + libcellml::ModelPtr model = parser->parseModel(in); + + EXPECT_EQ(size_t(0), parser->issueCount()); + + EXPECT_EQ(2.0, model->units("millivolt_squared")->unitAttributeExponent(0)); + EXPECT_EQ(1.5, model->units("scaled_volt")->unitAttributeMultiplier(0)); + EXPECT_EQ(10.0, model->units("scaled_e_notation_volt")->unitAttributeExponent(0)); + EXPECT_EQ(2.5e-3, model->units("scaled_e_notation_volt")->unitAttributeMultiplier(0)); +} + +TEST(Parser, unitAttributesWithDegenerateRealNumbers) +{ + const std::string in = + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + + const std::vector expectedIssues = { + "Unit referencing 'volt' in units 'degenerate_exponents' has an exponent with the value '-.' that is not a representation of a CellML real valued number.", + "Unit referencing 'ampere' in units 'degenerate_exponents' has an exponent with the value '-' that is not a representation of a CellML real valued number.", + "Unit referencing 'second' in units 'degenerate_exponents' has an exponent with the value '.' that is not a representation of a CellML real valued number.", + "Unit referencing 'volt' in units 'degenerate_multipliers' has a multiplier with the value '-.' that is not a representation of a CellML real valued number.", + "Unit referencing 'ampere' in units 'degenerate_multipliers' has a multiplier with the value '-' that is not a representation of a CellML real valued number.", + "Unit referencing 'second' in units 'degenerate_multipliers' has a multiplier with the value '.' that is not a representation of a CellML real valued number.", + }; + + libcellml::ParserPtr parser = libcellml::Parser::create(); + parser->parseModel(in); + + EXPECT_EQ_ISSUES(expectedIssues, parser); +} + TEST(Parser, emptyEncapsulation) { const std::string in = diff --git a/tests/validator/validator.cpp b/tests/validator/validator.cpp index b3527f98db..149d37efcc 100644 --- a/tests/validator/validator.cpp +++ b/tests/validator/validator.cpp @@ -294,6 +294,73 @@ TEST(Validator, invalidVariableInitialValuesAndInterfaces) EXPECT_EQ_ISSUES(expectedIssues, validator); } +TEST(Validator, variableInitialValuesWithLeadingPlusSign) +{ + // CellML 2.0 section 1.3.3.2: a real number string may begin with a '+' sign. + libcellml::ValidatorPtr validator = libcellml::Validator::create(); + libcellml::ModelPtr model = libcellml::Model::create(); + libcellml::ComponentPtr c1 = libcellml::Component::create(); + libcellml::VariablePtr v1 = libcellml::Variable::create(); + libcellml::VariablePtr v2 = libcellml::Variable::create(); + libcellml::VariablePtr v3 = libcellml::Variable::create(); + model->addComponent(c1); + c1->addVariable(v1); + c1->addVariable(v2); + c1->addVariable(v3); + + model->setName("model"); + c1->setName("component"); + v1->setName("v1"); + v1->setUnits("dimensionless"); + v1->setInitialValue("+2"); + v2->setName("v2"); + v2->setUnits("dimensionless"); + v2->setInitialValue("+1.5"); + v3->setName("v3"); + v3->setUnits("dimensionless"); + v3->setInitialValue("+1.5e+3"); + + validator->validateModel(model); + + EXPECT_EQ(size_t(0), validator->issueCount()); +} + +TEST(Validator, variableInitialValuesWithDegenerateRealNumbers) +{ + const std::vector expectedIssues = { + "Variable 'v1' in component 'component' has an invalid initial value '-.'. Initial values must be a real number string or a variable reference.", + "Variable 'v2' in component 'component' has an invalid initial value '-'. Initial values must be a real number string or a variable reference.", + "Variable 'v3' in component 'component' has an invalid initial value '.'. Initial values must be a real number string or a variable reference.", + }; + + libcellml::ValidatorPtr validator = libcellml::Validator::create(); + libcellml::ModelPtr model = libcellml::Model::create(); + libcellml::ComponentPtr c1 = libcellml::Component::create(); + libcellml::VariablePtr v1 = libcellml::Variable::create(); + libcellml::VariablePtr v2 = libcellml::Variable::create(); + libcellml::VariablePtr v3 = libcellml::Variable::create(); + model->addComponent(c1); + c1->addVariable(v1); + c1->addVariable(v2); + c1->addVariable(v3); + + model->setName("model"); + c1->setName("component"); + v1->setName("v1"); + v1->setUnits("dimensionless"); + v1->setInitialValue("-."); + v2->setName("v2"); + v2->setUnits("dimensionless"); + v2->setInitialValue("-"); + v3->setName("v3"); + v3->setUnits("dimensionless"); + v3->setInitialValue("."); + + validator->validateModel(model); + + EXPECT_EQ_ISSUES(expectedIssues, validator); +} + libcellml::ModelPtr createImportUnitsModel() { libcellml::ModelPtr m = libcellml::Model::create(); @@ -963,6 +1030,342 @@ TEST(Validator, invalidMathMLCiAndCnElementsWithCellMLUnits) EXPECT_EQ_ISSUES(expectedIssues, v); } +libcellml::ModelPtr createModelWithMath(const std::string &math) +{ + libcellml::ModelPtr m = libcellml::Model::create(); + libcellml::ComponentPtr c = libcellml::Component::create(); + libcellml::VariablePtr v1 = libcellml::Variable::create(); + libcellml::VariablePtr v2 = libcellml::Variable::create(); + libcellml::VariablePtr v3 = libcellml::Variable::create(); + + m->setName("modelName"); + c->setName("componentName"); + v1->setName("A"); + v2->setName("B"); + v3->setName("t"); + v1->setUnits("dimensionless"); + v2->setUnits("dimensionless"); + v3->setUnits("dimensionless"); + + c->addVariable(v1); + c->addVariable(v2); + c->addVariable(v3); + c->setMath(math); + m->addComponent(c); + + return m; +} + +TEST(Validator, mathCnElementsWithLeadingPlusSign) +{ + // CellML 2.0 section 1.3.3.2: a real number string may begin with a '+' sign. + const std::string math = + "\n" + " \n" + " \n" + " A\n" + " \n" + " \n" + " +2\n" + " +1.5\n" + " +1.5+3\n" + " \n" + " \n" + "\n"; + + libcellml::ValidatorPtr v = libcellml::Validator::create(); + libcellml::ModelPtr m = createModelWithMath(math); + + v->validateModel(m); + + EXPECT_EQ(size_t(0), v->issueCount()); +} + +TEST(Validator, mathCnElementsWithDegenerateRealNumbers) +{ + const std::string math = + "\n" + " \n" + " \n" + " A\n" + " \n" + " \n" + " -.\n" + " -\n" + " .\n" + " -.3\n" + " -3\n" + " .3\n" + " \n" + " \n" + "\n"; + const std::vector expectedIssues = { + "Math has a 'cn' element of 'real' type with no valid text node (representing a basic number) as a child.", + "Math has a 'cn' element of 'real' type with no valid text node (representing a basic number) as a child.", + "Math has a 'cn' element of 'real' type with no valid text node (representing a basic number) as a child.", + "Math has a 'cn' element of 'e-notation' type with no valid text node (representing a basic number), no 'sep' element, and/or no valid text node (representing an integer) as children.", + "Math has a 'cn' element of 'e-notation' type with no valid text node (representing a basic number), no 'sep' element, and/or no valid text node (representing an integer) as children.", + "Math has a 'cn' element of 'e-notation' type with no valid text node (representing a basic number), no 'sep' element, and/or no valid text node (representing an integer) as children.", + }; + + libcellml::ValidatorPtr v = libcellml::Validator::create(); + libcellml::ModelPtr m = createModelWithMath(math); + + v->validateModel(m); + + EXPECT_EQ_ISSUES(expectedIssues, v); +} + +TEST(Validator, mathEmptyCnElements) +{ + const std::string math = + "\n" + " \n" + " \n" + " A\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + const std::vector expectedIssues = { + "Math has a 'cn' element of 'real' type with no valid text node (representing a basic number) as a child.", + "Math has a 'cn' element of 'real' type with no valid text node (representing a basic number) as a child.", + }; + + libcellml::ValidatorPtr v = libcellml::Validator::create(); + libcellml::ModelPtr m = createModelWithMath(math); + + v->validateModel(m); + + EXPECT_EQ_ISSUES(expectedIssues, v); +} + +TEST(Validator, mathDegreeElementsWithLeadingPlusSign) +{ + // CellML 2.0 section 1.3.3.2: a real number string may begin with a '+' sign. + const std::string math = + "\n" + " \n" + " \n" + " A\n" + " \n" + " \n" + " \n" + " +3\n" + " \n" + " B\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " t\n" + " \n" + " +2\n" + " \n" + " \n" + " B\n" + " \n" + " 1\n" + " \n" + "\n"; + + libcellml::ValidatorPtr v = libcellml::Validator::create(); + libcellml::ModelPtr m = createModelWithMath(math); + + v->validateModel(m); + + EXPECT_EQ(size_t(0), v->issueCount()); +} + +TEST(Validator, mathDegreeElementsWithDegenerateRealNumbers) +{ + const std::string math = + "\n" + " \n" + " \n" + " A\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " -.\n" + " \n" + " B\n" + " \n" + " \n" + " \n" + " \n" + " -\n" + " \n" + " B\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " t\n" + " \n" + " .\n" + " \n" + " \n" + " B\n" + " \n" + " 1\n" + " \n" + "\n"; + const std::vector expectedIssues = { + "Math has a 'cn' element of 'real' type with no valid text node (representing a basic number) as a child.", + "Math has a 'cn' element of 'real' type with no valid text node (representing a basic number) as a child.", + "Math has a 'cn' element of 'real' type with no valid text node (representing a basic number) as a child.", + }; + + libcellml::ValidatorPtr v = libcellml::Validator::create(); + libcellml::ModelPtr m = createModelWithMath(math); + + v->validateModel(m); + + EXPECT_EQ_ISSUES(expectedIssues, v); +} + +TEST(Validator, mathDegreeElementsWithEmptyCnElements) +{ + const std::string math = + "\n" + " \n" + " \n" + " A\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " B\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " t\n" + " \n" + " \n" + " \n" + " \n" + " B\n" + " \n" + " 1\n" + " \n" + "\n"; + const std::vector expectedIssues = { + "Math has a 'cn' element of 'real' type with no valid text node (representing a basic number) as a child.", + "Math has a 'cn' element of 'real' type with no valid text node (representing a basic number) as a child.", + }; + + libcellml::ValidatorPtr v = libcellml::Validator::create(); + libcellml::ModelPtr m = createModelWithMath(math); + + v->validateModel(m); + + EXPECT_EQ_ISSUES(expectedIssues, v); +} + +TEST(Validator, mathLogbaseElementsWithDegenerateRealNumbers) +{ + const std::string math = + "\n" + " \n" + " \n" + " A\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " -.\n" + " \n" + " B\n" + " \n" + " \n" + " \n" + " \n" + " -\n" + " \n" + " B\n" + " \n" + " \n" + " \n" + " \n" + " .\n" + " \n" + " B\n" + " \n" + " \n" + " \n" + "\n"; + const std::vector expectedIssues = { + "Math has a 'cn' element of 'real' type with no valid text node (representing a basic number) as a child.", + "Math has a 'cn' element of 'real' type with no valid text node (representing a basic number) as a child.", + "Math has a 'cn' element of 'real' type with no valid text node (representing a basic number) as a child.", + }; + + libcellml::ValidatorPtr v = libcellml::Validator::create(); + libcellml::ModelPtr m = createModelWithMath(math); + + v->validateModel(m); + + EXPECT_EQ_ISSUES(expectedIssues, v); +} + +TEST(Validator, mathLogbaseElementsWithEmptyCnElements) +{ + const std::string math = + "\n" + " \n" + " \n" + " A\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " B\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " B\n" + " \n" + " \n" + " \n" + "\n"; + const std::vector expectedIssues = { + "Math has a 'cn' element of 'real' type with no valid text node (representing a basic number) as a child.", + "Math has a 'cn' element of 'real' type with no valid text node (representing a basic number) as a child.", + }; + + libcellml::ValidatorPtr v = libcellml::Validator::create(); + libcellml::ModelPtr m = createModelWithMath(math); + + v->validateModel(m); + + EXPECT_EQ_ISSUES(expectedIssues, v); +} + TEST(Validator, validMathMLCiAndCnElementsWithCellMLUnits) { const std::string math =