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";
+
+ 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";
+ 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";
+ 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";
+
+ 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";
+ 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";
+ 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";
+ 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";
+ 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 =