From c2102c29cba9078b6f46e000e330f0f6e5799cd6 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Mon, 8 Apr 2024 16:31:09 +0100 Subject: [PATCH 01/50] Remove unused includes from validator.h. --- src/api/libcellml/validator.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/api/libcellml/validator.h b/src/api/libcellml/validator.h index 934dcd9f6..0c5d64bbf 100644 --- a/src/api/libcellml/validator.h +++ b/src/api/libcellml/validator.h @@ -16,9 +16,6 @@ limitations under the License. #pragma once -#include -#include - #include "libcellml/logger.h" #include "libcellml/types.h" From 3e9aa02b7bcb5ce252b67781bece17d62d61f6f5 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Tue, 9 Apr 2024 14:12:36 +0100 Subject: [PATCH 02/50] Update ReferenceRule enumerations to validator coverage document. --- src/api/libcellml/issue.h | 113 +++++++++++++++++++++----------------- 1 file changed, 63 insertions(+), 50 deletions(-) diff --git a/src/api/libcellml/issue.h b/src/api/libcellml/issue.h index 98eac31a4..eb10f2f52 100644 --- a/src/api/libcellml/issue.h +++ b/src/api/libcellml/issue.h @@ -70,87 +70,100 @@ class LIBCELLML_EXPORT Issue // Specification errors. XML, + XML_UNEXPECTED_ELEMENT, + XML_UNEXPECTED_CHARACTER, + XML_UNEXPECTED_NAMESPACE, + XML_UNEXPECTED_NAMESPACE_PREFIX, XML_ID_ATTRIBUTE, - DATA_REPR_IDENTIFIER_UNICODE, - DATA_REPR_IDENTIFIER_LATIN_ALPHANUM, - DATA_REPR_IDENTIFIER_AT_LEAST_ONE_ALPHANUM, - DATA_REPR_IDENTIFIER_BEGIN_EURO_NUM, - DATA_REPR_IDENTIFIER_IDENTICAL, - DATA_REPR_INT_BASE10, - DATA_REPR_INT_SIGN, - DATA_REPR_INT_DIGIT, - DATA_REPR_BASIC_REAL_BASE10, - DATA_REPR_BASIC_REAL_SIGN, - DATA_REPR_BASIC_REAL_DECIMAL, - DATA_REPR_BASIC_REAL_DIGIT, - DATA_REPR_REAL_BASE10, - DATA_REPR_REAL_SIGNIFICAND, - DATA_REPR_REAL_EXPONENT, MODEL_ELEMENT, MODEL_NAME, + MODEL_NAME_VALUE, MODEL_CHILD, MODEL_MORE_THAN_ONE_ENCAPSULATION, - IMPORT_ATTRIBUTE, + IMPORT_ELEMENT, IMPORT_HREF, + IMPORT_HREF_INVALID_LOCATOR, IMPORT_CHILD, - IMPORT_EQUIVALENT, + IMPORT_EQUIVALENT_INFOSET, + IMPORT_UNITS_ELEMENT, IMPORT_UNITS_NAME, + IMPORT_UNITS_NAME_VALUE, IMPORT_UNITS_NAME_UNIQUE, - IMPORT_UNITS_REF, + IMPORT_UNITS_UNITS_REF, + IMPORT_UNITS_UNITS_REF_VALUE, + IMPORT_UNITS_UNITS_REF_VALUE_TARGET, IMPORT_COMPONENT_NAME, IMPORT_COMPONENT_NAME_UNIQUE, IMPORT_COMPONENT_COMPONENT_REF, - UNITS_ATTRIBUTE, + UNITS_ELEMENT, UNITS_NAME, + UNITS_NAME_VALUE, UNITS_NAME_UNIQUE, UNITS_STANDARD, UNITS_CHILD, - UNIT_ATTRIBUTE, - UNIT_UNITS_REF, - UNIT_CIRCULAR_REF, - UNIT_OPTIONAL_ATTRIBUTE, - UNIT_PREFIX, - UNIT_MULTIPLIER, - UNIT_EXPONENT, - COMPONENT_ATTRIBUTE, + UNIT_ELEMENT, + UNIT_UNITS, + UNIT_UNITS_REFERENCE, + UNIT_UNITS_CIRCULAR_REFERENCE, + UNIT_ATTRIBUTE_OPTIONAL, + UNIT_ATTRIBUTE_PREFIX_VALUE, + UNIT_ATTRIBUTE_MULTIPLIER_VALUE, + UNIT_ATTRIBUTE_EXPONENT_VALUE, + COMPONENT_ELEMENT, COMPONENT_NAME, + COMPONENT_NAME_VALUE, COMPONENT_NAME_UNIQUE, COMPONENT_CHILD, - VARIABLE_ATTRIBUTE, - VARIABLE_CHILD, - VARIABLE_NAME, + VARIABLE_ELEMENT, + VARIABLE_REQUIRED_ATTRIBUTE, + VARIABLE_NAME_VALUE, VARIABLE_NAME_UNIQUE, - VARIABLE_UNITS, - VARIABLE_INTERFACE, - VARIABLE_INITIAL_VALUE, - RESET_ATTRIBUTE, - RESET_VARIABLE_REF, - RESET_TEST_VARIABLE_REF, - RESET_ORDER, + VARIABLE_UNITS_VALUE, + VARIABLE_ATTRIBUTE, + VARIABLE_INTERFACE_VALUE, + VARIABLE_INITIAL_VALUE_VALUE, + RESET_ELEMENT, + RESET_REQUIRED_ATTRIBUTE, + RESET_VARIABLE_REFERENCE, + RESET_TEST_VARIABLE_REFERENCE, + RESET_ORDER_VALUE, + RESET_ORDER_UNIQUE, RESET_CHILD, - RESET_TEST_VALUE, - RESET_RESET_VALUE, + RESET_RESET_VALUE_CHILD, + RESET_TEST_VALUE_CHILD, + TEST_VALUE_ELEMENT, + TEST_VALUE_CHILD, + RESET_VALUE_ELEMENT, + RESET_VALUE_CHILD, + MATH_ELEMENT, MATH_MATHML, MATH_CHILD, - MATH_CI_VARIABLE_REF, - MATH_CN_UNITS, + MATH_CI_VARIABLE_REFERENCE, + MATH_CN_UNITS_ATTRIBUTE, + MATH_CN_UNITS_ATTRIBUTE_REFERENCE, MATH_CN_BASE10, MATH_CN_FORMAT, - ENCAPSULATION_ATTRIBUTE, + ENCAPSULATION_ELEMENT, ENCAPSULATION_CHILD, - COMPONENT_REF_COMPONENT, + COMPONENT_REF_ELEMENT, + COMPONENT_REF_COMPONENT_ATTRIBUTE, + COMPONENT_REF_COMPONENT_ATTRIBUTE_REFERENCE, + COMPONENT_REF_COMPONENT_ATTRIBUTE_UNIQUE, COMPONENT_REF_CHILD, - CONNECTION_ATTRIBUTE, - CONNECTION_COMPONENT1, - CONNECTION_COMPONENT2, + CONNECTION_ELEMENT, + CONNECTION_COMPONENT1_ATTRIBUTE, + CONNECTION_COMPONENT1_ATTRIBUTE_REFERENCE, + CONNECTION_COMPONENT2_ATTRIBUTE, + CONNECTION_COMPONENT2_ATTRIBUTE_REFERENCE, CONNECTION_EXCLUDE_SELF, CONNECTION_UNIQUE, CONNECTION_CHILD, - MAP_VARIABLES_ATTRIBUTE, - MAP_VARIABLES_VARIABLE1, - MAP_VARIABLES_VARIABLE2, + MAP_VARIABLES_ELEMENT, + MAP_VARIABLES_VARIABLE1_ATTRIBUTE, + MAP_VARIABLES_VARIABLE1_ATTRIBUTE_REFERENCE, + MAP_VARIABLES_VARIABLE2_ATTRIBUTE, + MAP_VARIABLES_VARIABLE2_ATTRIBUTE_REFERENCE, MAP_VARIABLES_UNIQUE, - MAP_VARIABLES_AVAILABLE_INTERFACE, // Issues not present in the normative specification: MAP_VARIABLES_IDENTICAL_UNIT_REDUCTION, From 877bb8efaee43f34ffcd469b6546f3de9d07f495 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Tue, 9 Apr 2024 14:24:17 +0100 Subject: [PATCH 03/50] Remove INVLID from IMPORT_HREF_INVALID_LOCATOR. --- src/api/libcellml/issue.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/libcellml/issue.h b/src/api/libcellml/issue.h index eb10f2f52..1d079af4c 100644 --- a/src/api/libcellml/issue.h +++ b/src/api/libcellml/issue.h @@ -82,7 +82,7 @@ class LIBCELLML_EXPORT Issue MODEL_MORE_THAN_ONE_ENCAPSULATION, IMPORT_ELEMENT, IMPORT_HREF, - IMPORT_HREF_INVALID_LOCATOR, + IMPORT_HREF_LOCATOR, IMPORT_CHILD, IMPORT_EQUIVALENT_INFOSET, IMPORT_UNITS_ELEMENT, From dd26313527ba983ee01a3b2ff6a0f710ec730512 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Tue, 9 Apr 2024 14:28:45 +0100 Subject: [PATCH 04/50] Add in missing reference rule enumerations. --- src/api/libcellml/issue.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/api/libcellml/issue.h b/src/api/libcellml/issue.h index 1d079af4c..bd843ab48 100644 --- a/src/api/libcellml/issue.h +++ b/src/api/libcellml/issue.h @@ -89,12 +89,14 @@ class LIBCELLML_EXPORT Issue IMPORT_UNITS_NAME, IMPORT_UNITS_NAME_VALUE, IMPORT_UNITS_NAME_UNIQUE, - IMPORT_UNITS_UNITS_REF, - IMPORT_UNITS_UNITS_REF_VALUE, - IMPORT_UNITS_UNITS_REF_VALUE_TARGET, + IMPORT_UNITS_UNITS_REFERENCE, + IMPORT_UNITS_UNITS_REFERENCE_VALUE, + IMPORT_UNITS_UNITS_REFERENCE_VALUE_TARGET, IMPORT_COMPONENT_NAME, IMPORT_COMPONENT_NAME_UNIQUE, - IMPORT_COMPONENT_COMPONENT_REF, + IMPORT_COMPONENT_COMPONENT_REFERENCE, + IMPORT_COMPONENT_COMPONENT_REFERENCE_VALUE, + IMPORT_COMPONENT_COMPONENT_REFERENCE_TARGET, UNITS_ELEMENT, UNITS_NAME, UNITS_NAME_VALUE, From 8bbbb4de8f408125a7b5b1b0acfe34430903e543 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Tue, 9 Apr 2024 14:31:30 +0100 Subject: [PATCH 05/50] Add missing reference rule enumeration IMPORT_COMPONENT_ELEMENT. --- src/api/libcellml/issue.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/api/libcellml/issue.h b/src/api/libcellml/issue.h index bd843ab48..cc8ce5f1a 100644 --- a/src/api/libcellml/issue.h +++ b/src/api/libcellml/issue.h @@ -92,7 +92,9 @@ class LIBCELLML_EXPORT Issue IMPORT_UNITS_UNITS_REFERENCE, IMPORT_UNITS_UNITS_REFERENCE_VALUE, IMPORT_UNITS_UNITS_REFERENCE_VALUE_TARGET, + IMPORT_COMPONENT_ELEMENT, IMPORT_COMPONENT_NAME, + IMPORT_COMPONENT_NAME_VALUE, IMPORT_COMPONENT_NAME_UNIQUE, IMPORT_COMPONENT_COMPONENT_REFERENCE, IMPORT_COMPONENT_COMPONENT_REFERENCE_VALUE, From 2f7508f88ca74efce81390cc6b7811af787f0bf1 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Tue, 9 Apr 2024 14:42:13 +0100 Subject: [PATCH 06/50] Change around variable required and optional reference rule enumerations. --- src/api/libcellml/issue.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/libcellml/issue.h b/src/api/libcellml/issue.h index cc8ce5f1a..46e1660b6 100644 --- a/src/api/libcellml/issue.h +++ b/src/api/libcellml/issue.h @@ -119,11 +119,11 @@ class LIBCELLML_EXPORT Issue COMPONENT_NAME_UNIQUE, COMPONENT_CHILD, VARIABLE_ELEMENT, - VARIABLE_REQUIRED_ATTRIBUTE, + VARIABLE_ATTRIBUTE_REQUIRED, VARIABLE_NAME_VALUE, VARIABLE_NAME_UNIQUE, VARIABLE_UNITS_VALUE, - VARIABLE_ATTRIBUTE, + VARIABLE_ATTRIBUTE_OPTIONAL, VARIABLE_INTERFACE_VALUE, VARIABLE_INITIAL_VALUE_VALUE, RESET_ELEMENT, From 64656d5d63e72b151e914efcb2f2839777cecb6d Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Tue, 9 Apr 2024 14:45:53 +0100 Subject: [PATCH 07/50] Rename reference rule RESET_REQUIRED_ATTRIBUTE to RESET_ATTRIBUTE_REQUIRED. --- src/api/libcellml/issue.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/libcellml/issue.h b/src/api/libcellml/issue.h index 46e1660b6..c8d4e3713 100644 --- a/src/api/libcellml/issue.h +++ b/src/api/libcellml/issue.h @@ -127,7 +127,7 @@ class LIBCELLML_EXPORT Issue VARIABLE_INTERFACE_VALUE, VARIABLE_INITIAL_VALUE_VALUE, RESET_ELEMENT, - RESET_REQUIRED_ATTRIBUTE, + RESET_ATTRIBUTE_REQUIRED, RESET_VARIABLE_REFERENCE, RESET_TEST_VARIABLE_REFERENCE, RESET_ORDER_VALUE, From e36c2a7b563d8f54cc72bfb8b004bd5e2e53160d Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Tue, 9 Apr 2024 15:04:22 +0100 Subject: [PATCH 08/50] Remove MAP_VARIABLES_IDENTICAL_UNIT_REDUCTION from reference rule enumerations. --- src/api/libcellml/issue.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/api/libcellml/issue.h b/src/api/libcellml/issue.h index c8d4e3713..a1b1cc25e 100644 --- a/src/api/libcellml/issue.h +++ b/src/api/libcellml/issue.h @@ -170,7 +170,6 @@ class LIBCELLML_EXPORT Issue MAP_VARIABLES_UNIQUE, // Issues not present in the normative specification: - MAP_VARIABLES_IDENTICAL_UNIT_REDUCTION, INVALID_ARGUMENT, // Importer class issues: From 83643e2759938438d68f7a190daf3fab5a65746e Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Tue, 9 Apr 2024 15:04:51 +0100 Subject: [PATCH 09/50] Update ruleToInformation map. --- src/issue.cpp | 140 ++++++++++++++++++++++++++++---------------------- 1 file changed, 78 insertions(+), 62 deletions(-) diff --git a/src/issue.cpp b/src/issue.cpp index 45c4259b2..25620f2d3 100644 --- a/src/issue.cpp +++ b/src/issue.cpp @@ -80,91 +80,107 @@ static const std::map> ruleToInfo {Issue::ReferenceRule::UNDEFINED, {"", "", "", ""}}, // Validation errors related to the CellML Specification: - {Issue::ReferenceRule::XML, {"XML", "1.2.1", baseSpecificationUrl, "specA02"}}, - {Issue::ReferenceRule::XML_ID_ATTRIBUTE, {"XML", "1.2.5", baseSpecificationUrl, "specA02"}}, - {Issue::ReferenceRule::DATA_REPR_IDENTIFIER_UNICODE, {"DATA_REPR_IDENTIFIER_UNICODE", "1.3.1.1", baseSpecificationUrl, "specA03"}}, - {Issue::ReferenceRule::DATA_REPR_IDENTIFIER_LATIN_ALPHANUM, {"DATA_REPR_IDENTIFIER_LATIN_ALPHANUM", "1.3.1.1", baseSpecificationUrl, "specA03"}}, - {Issue::ReferenceRule::DATA_REPR_IDENTIFIER_AT_LEAST_ONE_ALPHANUM, {"DATA_REPR_IDENTIFIER_AT_LEAST_ONE_ALPHANUM", "1.3.1.1", baseSpecificationUrl, "specA03"}}, - {Issue::ReferenceRule::DATA_REPR_IDENTIFIER_BEGIN_EURO_NUM, {"DATA_REPR_IDENTIFIER_BEGIN_EURO_NUM", "1.3.1.1", baseSpecificationUrl, "specA03"}}, - {Issue::ReferenceRule::DATA_REPR_IDENTIFIER_IDENTICAL, {"DATA_REPR_IDENTIFIER_IDENTICAL", "1.3.1.2", baseSpecificationUrl, "specA03"}}, - {Issue::ReferenceRule::DATA_REPR_INT_BASE10, {"DATA_REPR_INT_BASE10", "1.3.2.1", baseSpecificationUrl, "specA03"}}, - {Issue::ReferenceRule::DATA_REPR_INT_SIGN, {"DATA_REPR_INT_SIGN", "1.3.2.2", baseSpecificationUrl, "specA03"}}, - {Issue::ReferenceRule::DATA_REPR_INT_DIGIT, {"DATA_REPR_INT_DIGIT", "1.3.2.3", baseSpecificationUrl, "specA03"}}, - {Issue::ReferenceRule::DATA_REPR_BASIC_REAL_BASE10, {"DATA_REPR_BASIC_REAL_BASE10", "1.3.3.1", baseSpecificationUrl, "specA03"}}, - {Issue::ReferenceRule::DATA_REPR_BASIC_REAL_SIGN, {"DATA_REPR_BASIC_REAL_SIGN", "1.3.3.2", baseSpecificationUrl, "specA03"}}, - {Issue::ReferenceRule::DATA_REPR_BASIC_REAL_DECIMAL, {"DATA_REPR_BASIC_REAL_DECIMAL", "1.3.3.3", baseSpecificationUrl, "specA03"}}, - {Issue::ReferenceRule::DATA_REPR_BASIC_REAL_DIGIT, {"DATA_REPR_BASIC_REAL_DIGIT", "1.3.3.4", baseSpecificationUrl, "specA03"}}, - {Issue::ReferenceRule::DATA_REPR_REAL_BASE10, {"DATA_REPR_REAL_BASE10", "1.3.4.1", baseSpecificationUrl, "specA03"}}, - {Issue::ReferenceRule::DATA_REPR_REAL_SIGNIFICAND, {"DATA_REPR_REAL_SIGNIFICAND", "1.3.4.3", baseSpecificationUrl, "specA03"}}, - {Issue::ReferenceRule::DATA_REPR_REAL_EXPONENT, {"DATA_REPR_REAL_EXPONENT", "1.3.4.4", baseSpecificationUrl, "specA03"}}, + {Issue::ReferenceRule::XML, {"XML", "1.2.1.1", baseSpecificationUrl, "specA02"}}, + {Issue::ReferenceRule::XML_UNEXPECTED_ELEMENT, {"XML_UNEXPECTED_ELEMENT", "1.2.2.2", baseSpecificationUrl, "specA02"}}, + {Issue::ReferenceRule::XML_UNEXPECTED_CHARACTER, {"XML_UNEXPECTED_CHARACTER", "1.2.3.2", baseSpecificationUrl, "specA02"}}, + {Issue::ReferenceRule::XML_UNEXPECTED_NAMESPACE, {"XML_UNEXPECTED_NAMESPACE", "1.2.4.1", baseSpecificationUrl, "specA02"}}, + {Issue::ReferenceRule::XML_UNEXPECTED_NAMESPACE_PREFIX, {"XML_UNEXPECTED_NAMESPACE_PREFIX", "1.2.4.2", baseSpecificationUrl, "specA02"}}, + {Issue::ReferenceRule::XML_ID_ATTRIBUTE, {"XML_ID_ATTRIBUTE", "1.2.5.1.1", baseSpecificationUrl, "specA02"}}, {Issue::ReferenceRule::MODEL_ELEMENT, {"MODEL_ELEMENT", "2.1", baseSpecificationUrl, "specB01"}}, {Issue::ReferenceRule::MODEL_NAME, {"MODEL_NAME", "2.1.1", baseSpecificationUrl, "specB01"}}, + {Issue::ReferenceRule::MODEL_NAME_VALUE, {"MODEL_NAME_VALUE", "2.1.1.1", baseSpecificationUrl, "specB01"}}, {Issue::ReferenceRule::MODEL_CHILD, {"MODEL_CHILD", "2.1.2", baseSpecificationUrl, "specB01"}}, {Issue::ReferenceRule::MODEL_MORE_THAN_ONE_ENCAPSULATION, {"MODEL_MORE_THAN_ONE_ENCAPSULATION", "2.1.3", baseSpecificationUrl, "specB01"}}, - {Issue::ReferenceRule::IMPORT_ATTRIBUTE, {"IMPORT_ATTRIBUTE", "2.2", baseSpecificationUrl, "specB02"}}, + {Issue::ReferenceRule::IMPORT_ELEMENT, {"IMPORT_ELEMENT", "2.2", baseSpecificationUrl, "specB02"}}, {Issue::ReferenceRule::IMPORT_HREF, {"IMPORT_HREF", "2.2.1", baseSpecificationUrl, "specB02"}}, + {Issue::ReferenceRule::IMPORT_HREF_LOCATOR, {"IMPORT_HREF_LOCATOR", "2.2.1.1", baseSpecificationUrl, "specB02"}}, {Issue::ReferenceRule::IMPORT_CHILD, {"IMPORT_CHILD", "2.2.2", baseSpecificationUrl, "specB02"}}, - {Issue::ReferenceRule::IMPORT_EQUIVALENT, {"IMPORT_EQUIVALENT", "2.2.3", baseSpecificationUrl, "specB02"}}, + {Issue::ReferenceRule::IMPORT_EQUIVALENT_INFOSET, {"IMPORT_EQUIVALENT_INFOSET", "2.2.3", baseSpecificationUrl, "specB02"}}, + {Issue::ReferenceRule::IMPORT_UNITS_ELEMENT, {"IMPORT_UNITS_ELEMENT", "2.3", baseSpecificationUrl, "specB03"}}, {Issue::ReferenceRule::IMPORT_UNITS_NAME, {"IMPORT_UNITS_NAME", "2.3.1", baseSpecificationUrl, "specB03"}}, - {Issue::ReferenceRule::IMPORT_UNITS_NAME_UNIQUE, {"IMPORT_UNITS_NAME_UNIQUE", "2.3.1", baseSpecificationUrl, "specB03"}}, - {Issue::ReferenceRule::IMPORT_UNITS_REF, {"IMPORT_UNITS_REF", "2.3.2", baseSpecificationUrl, "specB03"}}, + {Issue::ReferenceRule::IMPORT_UNITS_NAME_VALUE, {"IMPORT_UNITS_NAME_VALUE", "2.3.1.1", baseSpecificationUrl, "specB03"}}, + {Issue::ReferenceRule::IMPORT_UNITS_NAME_UNIQUE, {"IMPORT_UNITS_NAME_UNIQUE", "2.3.1.2", baseSpecificationUrl, "specB03"}}, + {Issue::ReferenceRule::IMPORT_UNITS_UNITS_REFERENCE, {"IMPORT_UNITS_UNITS_REFERENCE", "2.3.2", baseSpecificationUrl, "specB03"}}, + {Issue::ReferenceRule::IMPORT_UNITS_UNITS_REFERENCE_VALUE, {"IMPORT_UNITS_UNITS_REFERENCE_VALUE", "2.3.2.1", baseSpecificationUrl, "specB03"}}, + {Issue::ReferenceRule::IMPORT_UNITS_UNITS_REFERENCE_VALUE_TARGET, {"IMPORT_UNITS_UNITS_REFERENCE_VALUE_TARGET", "2.3.2.2", baseSpecificationUrl, "specB03"}}, + {Issue::ReferenceRule::IMPORT_COMPONENT_ELEMENT, {"IMPORT_COMPONENT_ELEMENT", "2.4", baseSpecificationUrl, "specB04"}}, {Issue::ReferenceRule::IMPORT_COMPONENT_NAME, {"IMPORT_COMPONENT_NAME", "2.4.1", baseSpecificationUrl, "specB04"}}, - {Issue::ReferenceRule::IMPORT_COMPONENT_NAME_UNIQUE, {"IMPORT_COMPONENT_NAME_UNIQUE", "2.4.1", baseSpecificationUrl, "specB04"}}, - {Issue::ReferenceRule::IMPORT_COMPONENT_COMPONENT_REF, {"IMPORT_COMPONENT_COMPONENT_REF", "2.4.2", baseSpecificationUrl, "specB04"}}, - {Issue::ReferenceRule::UNITS_ATTRIBUTE, {"UNITS_ATTRIBUTE", "2.5", baseSpecificationUrl, "specB05"}}, + {Issue::ReferenceRule::IMPORT_COMPONENT_NAME_VALUE, {"IMPORT_COMPONENT_NAME_VALUE", "2.4.1.1", baseSpecificationUrl, "specB04"}}, + {Issue::ReferenceRule::IMPORT_COMPONENT_NAME_UNIQUE, {"IMPORT_COMPONENT_NAME_UNIQUE", "2.4.1.2", baseSpecificationUrl, "specB04"}}, + {Issue::ReferenceRule::IMPORT_COMPONENT_COMPONENT_REFERENCE, {"IMPORT_COMPONENT_COMPONENT_REFERENCE", "2.4.2", baseSpecificationUrl, "specB04"}}, + {Issue::ReferenceRule::IMPORT_COMPONENT_COMPONENT_REFERENCE_VALUE, {"IMPORT_COMPONENT_COMPONENT_REFERENCE_VALUE", "2.4.2.1", baseSpecificationUrl, "specB04"}}, + {Issue::ReferenceRule::IMPORT_COMPONENT_COMPONENT_REFERENCE_TARGET, {"IMPORT_COMPONENT_COMPONENT_REFERENCE_TARGET", "2.4.2.2", baseSpecificationUrl, "specB04"}}, + {Issue::ReferenceRule::UNITS_ELEMENT, {"UNITS_ELEMENT", "2.5", baseSpecificationUrl, "specB05"}}, {Issue::ReferenceRule::UNITS_NAME, {"UNITS_NAME", "2.5.1", baseSpecificationUrl, "specB05"}}, - {Issue::ReferenceRule::UNITS_NAME_UNIQUE, {"UNITS_NAME_UNIQUE", "2.5.1", baseSpecificationUrl, "specB05"}}, + {Issue::ReferenceRule::UNITS_NAME_VALUE, {"UNITS_NAME_VALUE", "2.5.1.1", baseSpecificationUrl, "specB05"}}, + {Issue::ReferenceRule::UNITS_NAME_UNIQUE, {"UNITS_NAME_UNIQUE", "2.5.1.2", baseSpecificationUrl, "specB05"}}, {Issue::ReferenceRule::UNITS_STANDARD, {"UNITS_STANDARD", "2.5.2", baseSpecificationUrl, "specB05"}}, {Issue::ReferenceRule::UNITS_CHILD, {"UNITS_CHILD", "2.5.3", baseSpecificationUrl, "specB05"}}, - {Issue::ReferenceRule::UNIT_ATTRIBUTE, {"UNIT_ATTRIBUTE", "2.6", baseSpecificationUrl, "specB06"}}, - {Issue::ReferenceRule::UNIT_UNITS_REF, {"UNIT_UNITS_REF", "2.6.1", baseSpecificationUrl, "specB06"}}, - {Issue::ReferenceRule::UNIT_CIRCULAR_REF, {"UNIT_CIRCULAR_REF", "2.6.1.2", baseSpecificationUrl, "specB06"}}, - {Issue::ReferenceRule::UNIT_OPTIONAL_ATTRIBUTE, {"UNIT_OPTIONAL_ATTRIBUTE", "2.6.2", baseSpecificationUrl, "specB06"}}, - {Issue::ReferenceRule::UNIT_PREFIX, {"UNIT_PREFIX", "2.6.2.1", baseSpecificationUrl, "specB06"}}, - {Issue::ReferenceRule::UNIT_MULTIPLIER, {"UNIT_MULTIPLIER", "2.6.2.2", baseSpecificationUrl, "specB06"}}, - {Issue::ReferenceRule::UNIT_EXPONENT, {"UNIT_EXPONENT", "2.6.2.3", baseSpecificationUrl, "specB06"}}, - {Issue::ReferenceRule::COMPONENT_ATTRIBUTE, {"COMPONENT_ATTRIBUTE", "2.7", baseSpecificationUrl, "specB07"}}, + {Issue::ReferenceRule::UNIT_ELEMENT, {"UNIT_ELEMENT", "2.6", baseSpecificationUrl, "specB06"}}, + {Issue::ReferenceRule::UNIT_UNITS, {"UNIT_UNITS", "2.6.1", baseSpecificationUrl, "specB06"}}, + {Issue::ReferenceRule::UNIT_UNITS_REFERENCE, {"UNIT_UNITS_REFERENCE", "2.6.1.1", baseSpecificationUrl, "specB06"}}, + {Issue::ReferenceRule::UNIT_UNITS_CIRCULAR_REFERENCE, {"UNIT_UNITS_CIRCULAR_REFERENCE", "2.6.1.2", baseSpecificationUrl, "specB06"}}, + {Issue::ReferenceRule::UNIT_ATTRIBUTE_OPTIONAL, {"UNIT_ATTRIBUTE_OPTIONAL", "2.6.2", baseSpecificationUrl, "specB06"}}, + {Issue::ReferenceRule::UNIT_ATTRIBUTE_PREFIX_VALUE, {"UNIT_ATTRIBUTE_PREFIX_VALUE", "2.6.2.1.1", baseSpecificationUrl, "specB06"}}, + {Issue::ReferenceRule::UNIT_ATTRIBUTE_MULTIPLIER_VALUE, {"UNIT_ATTRIBUTE_MULTIPLIER_VALUE", "2.6.2.2.1", baseSpecificationUrl, "specB06"}}, + {Issue::ReferenceRule::UNIT_ATTRIBUTE_EXPONENT_VALUE, {"UNIT_ATTRIBUTE_EXPONENT_VALUE", "2.6.2.3.1", baseSpecificationUrl, "specB06"}}, + {Issue::ReferenceRule::COMPONENT_ELEMENT, {"COMPONENT_ELEMENT", "2.7", baseSpecificationUrl, "specB07"}}, {Issue::ReferenceRule::COMPONENT_NAME, {"COMPONENT_NAME", "2.7.1", baseSpecificationUrl, "specB07"}}, - {Issue::ReferenceRule::COMPONENT_NAME_UNIQUE, {"COMPONENT_NAME_UNIQUE", "2.7.1", baseSpecificationUrl, "specB07"}}, + {Issue::ReferenceRule::COMPONENT_NAME_VALUE, {"COMPONENT_NAME_VALUE", "2.7.1.1", baseSpecificationUrl, "specB07"}}, + {Issue::ReferenceRule::COMPONENT_NAME_UNIQUE, {"COMPONENT_NAME_UNIQUE", "2.7.1.2", baseSpecificationUrl, "specB07"}}, {Issue::ReferenceRule::COMPONENT_CHILD, {"COMPONENT_CHILD", "2.7.2", baseSpecificationUrl, "specB07"}}, - {Issue::ReferenceRule::VARIABLE_ATTRIBUTE, {"VARIABLE_ATTRIBUTE", "2.8", baseSpecificationUrl, "specB08"}}, - {Issue::ReferenceRule::VARIABLE_CHILD, {"VARIABLE_CHILD", "2.8", baseSpecificationUrl, "specB08"}}, - {Issue::ReferenceRule::VARIABLE_NAME, {"VARIABLE_NAME", "2.8.1.1", baseSpecificationUrl, "specB08"}}, - {Issue::ReferenceRule::VARIABLE_NAME_UNIQUE, {"VARIABLE_NAME_UNIQUE", "2.8.1.1", baseSpecificationUrl, "specB08"}}, - {Issue::ReferenceRule::VARIABLE_UNITS, {"VARIABLE_UNITS", "2.8.1.2", baseSpecificationUrl, "specB08"}}, - {Issue::ReferenceRule::VARIABLE_INTERFACE, {"VARIABLE_INTERFACE", "2.8.2.1", baseSpecificationUrl, "specB08"}}, - {Issue::ReferenceRule::VARIABLE_INITIAL_VALUE, {"VARIABLE_INITIAL_VALUE", "2.8.2.2", baseSpecificationUrl, "specB08"}}, - {Issue::ReferenceRule::RESET_ATTRIBUTE, {"RESET_ATTRIBUTE", "2.9", baseSpecificationUrl, "specB09"}}, - {Issue::ReferenceRule::RESET_VARIABLE_REF, {"RESET_VARIABLE_REF", "2.9.1.1", baseSpecificationUrl, "specB09"}}, - {Issue::ReferenceRule::RESET_TEST_VARIABLE_REF, {"RESET_TEST_VARIABLE_REF", "2.9.1.2", baseSpecificationUrl, "specB09"}}, - {Issue::ReferenceRule::RESET_ORDER, {"RESET_ORDER", "2.9.1.3", baseSpecificationUrl, "specB09"}}, + {Issue::ReferenceRule::VARIABLE_ELEMENT, {"VARIABLE_ELEMENT", "2.8", baseSpecificationUrl, "specB08"}}, + {Issue::ReferenceRule::VARIABLE_ATTRIBUTE_REQUIRED, {"VARIABLE_ATTRIBUTE_REQUIRED", "2.8.1", baseSpecificationUrl, "specB08"}}, + {Issue::ReferenceRule::VARIABLE_NAME_VALUE, {"VARIABLE_NAME_VALUE", "2.8.1.1.1", baseSpecificationUrl, "specB08"}}, + {Issue::ReferenceRule::VARIABLE_NAME_UNIQUE, {"VARIABLE_NAME_UNIQUE", "2.8.1.1.2", baseSpecificationUrl, "specB08"}}, + {Issue::ReferenceRule::VARIABLE_UNITS_VALUE, {"VARIABLE_UNITS_VALUE", "2.8.1.2.1", baseSpecificationUrl, "specB08"}}, + {Issue::ReferenceRule::VARIABLE_ATTRIBUTE_OPTIONAL, {"VARIABLE_ATTRIBUTE_OPTIONAL", "2.8.2", baseSpecificationUrl, "specB08"}}, + {Issue::ReferenceRule::VARIABLE_INTERFACE_VALUE, {"VARIABLE_INTERFACE_VALUE", "2.8.2.1.1", baseSpecificationUrl, "specB08"}}, + {Issue::ReferenceRule::VARIABLE_INITIAL_VALUE_VALUE, {"VARIABLE_INITIAL_VALUE_VALUE", "2.8.2.2.1", baseSpecificationUrl, "specB08"}}, + {Issue::ReferenceRule::RESET_ELEMENT, {"RESET_ELEMENT", "2.9", baseSpecificationUrl, "specB09"}}, + {Issue::ReferenceRule::RESET_ATTRIBUTE_REQUIRED, {"RESET_ATTRIBUTE_REQUIRED", "2.9.1", baseSpecificationUrl, "specB09"}}, + {Issue::ReferenceRule::RESET_VARIABLE_REFERENCE, {"RESET_VARIABLE_REFERENCE", "2.9.1.1.1", baseSpecificationUrl, "specB09"}}, + {Issue::ReferenceRule::RESET_TEST_VARIABLE_REFERENCE, {"RESET_TEST_VARIABLE_REFERENCE", "2.9.1.2.1", baseSpecificationUrl, "specB09"}}, + {Issue::ReferenceRule::RESET_ORDER_VALUE, {"RESET_ORDER_VALUE", "2.9.1.3.1", baseSpecificationUrl, "specB09"}}, + {Issue::ReferenceRule::RESET_ORDER_UNIQUE, {"RESET_ORDER_UNIQUE", "2.9.1.3.2", baseSpecificationUrl, "specB09"}}, {Issue::ReferenceRule::RESET_CHILD, {"RESET_CHILD", "2.9.2", baseSpecificationUrl, "specB09"}}, - {Issue::ReferenceRule::RESET_TEST_VALUE, {"RESET_TEST_VALUE", "2.10", baseSpecificationUrl, "specB10"}}, - {Issue::ReferenceRule::RESET_RESET_VALUE, {"RESET_RESET_VALUE", "2.11", baseSpecificationUrl, "specB11"}}, + {Issue::ReferenceRule::RESET_RESET_VALUE_CHILD, {"RESET_RESET_VALUE_CHILD", "2.9.2.1", baseSpecificationUrl, "specB09"}}, + {Issue::ReferenceRule::RESET_TEST_VALUE_CHILD, {"RESET_TEST_VALUE_CHILD", "2.9.2.2", baseSpecificationUrl, "specB09"}}, + {Issue::ReferenceRule::TEST_VALUE_ELEMENT, {"TEST_VALUE_ELEMENT", "2.10", baseSpecificationUrl, "specB10"}}, + {Issue::ReferenceRule::TEST_VALUE_CHILD, {"TEST_VALUE_CHILD", "2.10.1", baseSpecificationUrl, "specB10"}}, + {Issue::ReferenceRule::RESET_VALUE_ELEMENT, {"RESET_VALUE_ELEMENT", "2.11", baseSpecificationUrl, "specB11"}}, + {Issue::ReferenceRule::RESET_VALUE_CHILD, {"RESET_VALUE_CHILD", "2.11.1", baseSpecificationUrl, "specB11"}}, + {Issue::ReferenceRule::MATH_ELEMENT, {"MATH_ELEMENT", "2.12", baseSpecificationUrl, "specB12"}}, {Issue::ReferenceRule::MATH_MATHML, {"MATH_MATHML", "2.12.1", baseSpecificationUrl, "specB12"}}, {Issue::ReferenceRule::MATH_CHILD, {"MATH_CHILD", "2.12.2", baseSpecificationUrl, "specB12"}}, - {Issue::ReferenceRule::MATH_CI_VARIABLE_REF, {"MATH_CI_VARIABLE_REF", "2.12.3", baseSpecificationUrl, "specB12"}}, - {Issue::ReferenceRule::MATH_CN_UNITS, {"MATH_CN_UNITS", "2.12.4", baseSpecificationUrl, "specB13"}}, - {Issue::ReferenceRule::MATH_CN_BASE10, {"MATH_CN_BASE10", "2.12.5", baseSpecificationUrl, "specB13"}}, - {Issue::ReferenceRule::MATH_CN_FORMAT, {"MATH_CN_FORMAT", "2.12.5", baseSpecificationUrl, "specB13"}}, - {Issue::ReferenceRule::ENCAPSULATION_ATTRIBUTE, {"ENCAPSULATION_ATTRIBUTE", "2.13", baseSpecificationUrl, "specB13"}}, + {Issue::ReferenceRule::MATH_CI_VARIABLE_REFERENCE, {"MATH_CI_VARIABLE_REFERENCE", "2.12.3", baseSpecificationUrl, "specB12"}}, + {Issue::ReferenceRule::MATH_CN_UNITS_ATTRIBUTE, {"MATH_CN_UNITS_ATTRIBUTE", "2.12.4", baseSpecificationUrl, "specB12"}}, + {Issue::ReferenceRule::MATH_CN_UNITS_ATTRIBUTE_REFERENCE, {"MATH_CN_UNITS_ATTRIBUTE_REFERENCE", "2.12.4.1", baseSpecificationUrl, "specB12"}}, + {Issue::ReferenceRule::MATH_CN_BASE10, {"MATH_CN_BASE10", "2.12.5", baseSpecificationUrl, "specB12"}}, + {Issue::ReferenceRule::MATH_CN_FORMAT, {"MATH_CN_FORMAT", "2.12.5.1", baseSpecificationUrl, "specB12"}}, + {Issue::ReferenceRule::ENCAPSULATION_ELEMENT, {"ENCAPSULATION_ELEMENT", "2.13", baseSpecificationUrl, "specB13"}}, {Issue::ReferenceRule::ENCAPSULATION_CHILD, {"ENCAPSULATION_CHILD", "2.13.1", baseSpecificationUrl, "specB13"}}, - {Issue::ReferenceRule::COMPONENT_REF_COMPONENT, {"COMPONENT_REF_COMPONENT", "2.14.1", baseSpecificationUrl, "specB14"}}, + {Issue::ReferenceRule::COMPONENT_REF_ELEMENT, {"COMPONENT_REF_ELEMENT", "2.14", baseSpecificationUrl, "specB14"}}, + {Issue::ReferenceRule::COMPONENT_REF_COMPONENT_ATTRIBUTE, {"COMPONENT_REF_COMPONENT_ATTRIBUTE", "2.14.1", baseSpecificationUrl, "specB14"}}, + {Issue::ReferenceRule::COMPONENT_REF_COMPONENT_ATTRIBUTE_REFERENCE, {"COMPONENT_REF_COMPONENT_ATTRIBUTE_REFERENCE", "2.14.1.1", baseSpecificationUrl, "specB14"}}, + {Issue::ReferenceRule::COMPONENT_REF_COMPONENT_ATTRIBUTE_UNIQUE, {"COMPONENT_REF_COMPONENT_ATTRIBUTE_UNIQUE", "2.14.1.2", baseSpecificationUrl, "specB14"}}, {Issue::ReferenceRule::COMPONENT_REF_CHILD, {"COMPONENT_REF_CHILD", "2.14.2", baseSpecificationUrl, "specB14"}}, - {Issue::ReferenceRule::CONNECTION_ATTRIBUTE, {"CONNECTION_ATTRIBUTE", "2.15", baseSpecificationUrl, "specB14"}}, - {Issue::ReferenceRule::CONNECTION_COMPONENT1, {"CONNECTION_COMPONENT1", "2.15.1", baseSpecificationUrl, "specB15"}}, - {Issue::ReferenceRule::CONNECTION_COMPONENT2, {"CONNECTION_COMPONENT2", "2.15.2", baseSpecificationUrl, "specB15"}}, + {Issue::ReferenceRule::CONNECTION_ELEMENT, {"CONNECTION_ELEMENT", "2.15", baseSpecificationUrl, "specB14"}}, + {Issue::ReferenceRule::CONNECTION_COMPONENT1_ATTRIBUTE, {"CONNECTION_COMPONENT1_ATTRIBUTE", "2.15.1", baseSpecificationUrl, "specB15"}}, + {Issue::ReferenceRule::CONNECTION_COMPONENT1_ATTRIBUTE_REFERENCE, {"CONNECTION_COMPONENT1_ATTRIBUTE_REFERENCE", "2.15.1.1", baseSpecificationUrl, "specB15"}}, + {Issue::ReferenceRule::CONNECTION_COMPONENT2_ATTRIBUTE, {"CONNECTION_COMPONENT2_ATTRIBUTE", "2.15.2", baseSpecificationUrl, "specB15"}}, + {Issue::ReferenceRule::CONNECTION_COMPONENT2_ATTRIBUTE_REFERENCE, {"CONNECTION_COMPONENT2_ATTRIBUTE_REFERENCE", "2.15.2.1", baseSpecificationUrl, "specB15"}}, {Issue::ReferenceRule::CONNECTION_EXCLUDE_SELF, {"CONNECTION_EXCLUDE_SELF", "2.15.3", baseSpecificationUrl, "specB15"}}, {Issue::ReferenceRule::CONNECTION_UNIQUE, {"CONNECTION_UNIQUE", "2.15.4", baseSpecificationUrl, "specB15"}}, {Issue::ReferenceRule::CONNECTION_CHILD, {"CONNECTION_CHILD", "2.15.5", baseSpecificationUrl, "specB15"}}, - {Issue::ReferenceRule::MAP_VARIABLES_ATTRIBUTE, {"MAP_VARIABLES_ATTRIBUTE", "2.16", baseSpecificationUrl, "specB16"}}, - {Issue::ReferenceRule::MAP_VARIABLES_VARIABLE1, {"MAP_VARIABLES_VARIABLE1", "2.16.1", baseSpecificationUrl, "specB16"}}, - {Issue::ReferenceRule::MAP_VARIABLES_VARIABLE2, {"MAP_VARIABLES_VARIABLE2", "2.16.2", baseSpecificationUrl, "specB16"}}, + {Issue::ReferenceRule::MAP_VARIABLES_ELEMENT, {"MAP_VARIABLES_ELEMENT", "2.16", baseSpecificationUrl, "specB16"}}, + {Issue::ReferenceRule::MAP_VARIABLES_VARIABLE1_ATTRIBUTE, {"MAP_VARIABLES_VARIABLE1_ATTRIBUTE", "2.16.1", baseSpecificationUrl, "specB16"}}, + {Issue::ReferenceRule::MAP_VARIABLES_VARIABLE1_ATTRIBUTE_REFERENCE, {"MAP_VARIABLES_VARIABLE1_ATTRIBUTE_REFERENCE", "2.16.1.1", baseSpecificationUrl, "specB16"}}, + {Issue::ReferenceRule::MAP_VARIABLES_VARIABLE2_ATTRIBUTE, {"MAP_VARIABLES_VARIABLE2", "2.16.2", baseSpecificationUrl, "specB16"}}, + {Issue::ReferenceRule::MAP_VARIABLES_VARIABLE2_ATTRIBUTE_REFERENCE, {"MAP_VARIABLES_VARIABLE2_ATTRIBUTE_REFERENCE", "2.16.2.1", baseSpecificationUrl, "specB16"}}, {Issue::ReferenceRule::MAP_VARIABLES_UNIQUE, {"MAP_VARIABLES_UNIQUE", "2.16.3", baseSpecificationUrl, "specB16"}}, - {Issue::ReferenceRule::MAP_VARIABLES_AVAILABLE_INTERFACE, {"MAP_VARIABLES_AVAILABLE_INTERFACE", "3.10.8", baseSpecificationUrl, "specC10"}}, - {Issue::ReferenceRule::MAP_VARIABLES_IDENTICAL_UNIT_REDUCTION, {"MAP_VARIABLES_IDENTICAL_UNIT_REDUCTION", "3.10.9", baseSpecificationUrl, "specC10"}}, - // Importer and Validator + // Not in normative specification: {Issue::ReferenceRule::INVALID_ARGUMENT, {"INVALID_ARGUMENT", "", docsUrl, ""}}, // Importer class issues: From 8b66e1796e964684a4eaa9320db2658d3c38053c Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Tue, 9 Apr 2024 16:32:21 +0100 Subject: [PATCH 10/50] Reinstate three specification errors that are used to test for invalid identifiers. --- src/api/libcellml/issue.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/api/libcellml/issue.h b/src/api/libcellml/issue.h index a1b1cc25e..445839728 100644 --- a/src/api/libcellml/issue.h +++ b/src/api/libcellml/issue.h @@ -68,7 +68,7 @@ class LIBCELLML_EXPORT Issue { UNDEFINED, - // Specification errors. + // Specification errors: XML, XML_UNEXPECTED_ELEMENT, XML_UNEXPECTED_CHARACTER, @@ -169,6 +169,11 @@ class LIBCELLML_EXPORT Issue MAP_VARIABLES_VARIABLE2_ATTRIBUTE_REFERENCE, MAP_VARIABLES_UNIQUE, + // Secondary specification errors: + DATA_REPR_IDENTIFIER_AT_LEAST_ONE_ALPHANUM, + DATA_REPR_IDENTIFIER_BEGIN_EURO_NUM, + DATA_REPR_IDENTIFIER_LATIN_ALPHANUM, + // Issues not present in the normative specification: INVALID_ARGUMENT, From 532e15d2f41c8efdb9f9bda4bbf014fc1da31298 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Tue, 9 Apr 2024 16:32:53 +0100 Subject: [PATCH 11/50] Update Python reference rule enumeration to correctly reflect the current reference rule enumeration. --- src/bindings/python/__init__.py | 152 +++++++++++++++++++++----------- 1 file changed, 100 insertions(+), 52 deletions(-) diff --git a/src/bindings/python/__init__.py b/src/bindings/python/__init__.py index 4ae2736eb..5f28af5f4 100644 --- a/src/bindings/python/__init__.py +++ b/src/bindings/python/__init__.py @@ -197,87 +197,135 @@ class Object: ]) convert(Issue, 'ReferenceRule', [ 'UNDEFINED', - 'XML', - 'DATA_REPR_IDENTIFIER_UNICODE', - 'DATA_REPR_IDENTIFIER_LATIN_ALPHANUM', - 'DATA_REPR_IDENTIFIER_AT_LEAST_ONE_ALPHANUM', - 'DATA_REPR_IDENTIFIER_BEGIN_EURO_NUM', - 'DATA_REPR_IDENTIFIER_IDENTICAL', - 'DATA_REPR_INT_BASE10', - 'DATA_REPR_INT_SIGN', - 'DATA_REPR_INT_DIGIT', - 'DATA_REPR_BASIC_REAL_BASE10', - 'DATA_REPR_BASIC_REAL_SIGN', - 'DATA_REPR_BASIC_REAL_DECIMAL', - 'DATA_REPR_BASIC_REAL_DIGIT', - 'DATA_REPR_REAL_BASE10', - 'DATA_REPR_REAL_SIGNIFICAND', - 'DATA_REPR_REAL_EXPONENT', + 'XML_UNEXPECTED_ELEMENT', + 'XML_UNEXPECTED_CHARACTER', + 'XML_UNEXPECTED_NAMESPACE', + 'XML_UNEXPECTED_NAMESPACE_PREFIX', + 'XML_ID_ATTRIBUTE', 'MODEL_ELEMENT', 'MODEL_NAME', + 'MODEL_NAME_VALUE', 'MODEL_CHILD', 'MODEL_MORE_THAN_ONE_ENCAPSULATION', - 'IMPORT_ATTRIBUTE', + 'IMPORT_ELEMENT', 'IMPORT_HREF', + 'IMPORT_HREF_LOCATOR', 'IMPORT_CHILD', - 'IMPORT_EQUIVALENT', + 'IMPORT_EQUIVALENT_INFOSET', + 'IMPORT_UNITS_ELEMENT', 'IMPORT_UNITS_NAME', + 'IMPORT_UNITS_NAME_VALUE', 'IMPORT_UNITS_NAME_UNIQUE', - 'IMPORT_UNITS_REF', + 'IMPORT_UNITS_UNITS_REFERENCE', + 'IMPORT_UNITS_UNITS_REFERENCE_VALUE', + 'IMPORT_UNITS_UNITS_REFERENCE_VALUE_TARGET', + 'IMPORT_COMPONENT_ELEMENT', 'IMPORT_COMPONENT_NAME', + 'IMPORT_COMPONENT_NAME_VALUE', 'IMPORT_COMPONENT_NAME_UNIQUE', - 'IMPORT_COMPONENT_COMPONENT_REF', - 'UNITS_ATTRIBUTE', + 'IMPORT_COMPONENT_COMPONENT_REFERENCE', + 'IMPORT_COMPONENT_COMPONENT_REFERENCE_VALUE', + 'IMPORT_COMPONENT_COMPONENT_REFERENCE_TARGET', + 'UNITS_ELEMENT', 'UNITS_NAME', + 'UNITS_NAME_VALUE', 'UNITS_NAME_UNIQUE', 'UNITS_STANDARD', 'UNITS_CHILD', - 'UNIT_ATTRIBUTE', - 'UNIT_UNITS_REF', - 'UNIT_CIRCULAR_REF', - 'UNIT_OPTIONAL_ATTRIBUTE', - 'UNIT_PREFIX', - 'UNIT_MULTIPLIER', - 'UNIT_EXPONENT', - 'COMPONENT_ATTRIBUTE', + 'UNIT_ELEMENT', + 'UNIT_UNITS', + 'UNIT_UNITS_REFERENCE', + 'UNIT_UNITS_CIRCULAR_REFERENCE', + 'UNIT_ATTRIBUTE_OPTIONAL', + 'UNIT_ATTRIBUTE_PREFIX_VALUE', + 'UNIT_ATTRIBUTE_MULTIPLIER_VALUE', + 'UNIT_ATTRIBUTE_EXPONENT_VALUE', + 'COMPONENT_ELEMENT', 'COMPONENT_NAME', + 'COMPONENT_NAME_VALUE', 'COMPONENT_NAME_UNIQUE', 'COMPONENT_CHILD', - 'VARIABLE_ATTRIBUTE', - 'VARIABLE_CHILD', - 'VARIABLE_NAME', + 'VARIABLE_ELEMENT', + 'VARIABLE_ATTRIBUTE_REQUIRED', + 'VARIABLE_NAME_VALUE', 'VARIABLE_NAME_UNIQUE', - 'VARIABLE_UNITS', - 'VARIABLE_INTERFACE', - 'VARIABLE_INITIAL_VALUE', - 'RESET_ATTRIBUTE', - 'RESET_VARIABLE_REF', - 'RESET_TEST_VARIABLE_REF', - 'RESET_ORDER', + 'VARIABLE_UNITS_VALUE', + 'VARIABLE_ATTRIBUTE_OPTIONAL', + 'VARIABLE_INTERFACE_VALUE', + 'VARIABLE_INITIAL_VALUE_VALUE', + 'RESET_ELEMENT', + 'RESET_ATTRIBUTE_REQUIRED', + 'RESET_VARIABLE_REFERENCE', + 'RESET_TEST_VARIABLE_REFERENCE', + 'RESET_ORDER_VALUE', + 'RESET_ORDER_UNIQUE', 'RESET_CHILD', - 'RESET_TEST_VALUE', - 'RESET_RESET_VALUE', + 'RESET_RESET_VALUE_CHILD', + 'RESET_TEST_VALUE_CHILD', + 'TEST_VALUE_ELEMENT', + 'TEST_VALUE_CHILD', + 'RESET_VALUE_ELEMENT', + 'RESET_VALUE_CHILD', + 'MATH_ELEMENT', 'MATH_MATHML', 'MATH_CHILD', - 'MATH_CI_VARIABLE_REF', - 'MATH_CN_UNITS', + 'MATH_CI_VARIABLE_REFERENCE', + 'MATH_CN_UNITS_ATTRIBUTE', + 'MATH_CN_UNITS_ATTRIBUTE_REFERENCE', 'MATH_CN_BASE10', 'MATH_CN_FORMAT', + 'ENCAPSULATION_ELEMENT', 'ENCAPSULATION_CHILD', - 'ENCAPSULATION_ATTRIBUTE', - 'COMPONENT_REF_COMPONENT', + 'COMPONENT_REF_ELEMENT', + 'COMPONENT_REF_COMPONENT_ATTRIBUTE', + 'COMPONENT_REF_COMPONENT_ATTRIBUTE_REFERENCE', + 'COMPONENT_REF_COMPONENT_ATTRIBUTE_UNIQUE', 'COMPONENT_REF_CHILD', - 'CONNECTION_ATTRIBUTE', - 'CONNECTION_COMPONENT1', - 'CONNECTION_COMPONENT2', + 'CONNECTION_ELEMENT', + 'CONNECTION_COMPONENT1_ATTRIBUTE', + 'CONNECTION_COMPONENT1_ATTRIBUTE_REFERENCE', + 'CONNECTION_COMPONENT2_ATTRIBUTE', + 'CONNECTION_COMPONENT2_ATTRIBUTE_REFERENCE', 'CONNECTION_EXCLUDE_SELF', 'CONNECTION_UNIQUE', 'CONNECTION_CHILD', - 'MAP_VARIABLES_ATTRIBUTE', - 'MAP_VARIABLES_VARIABLE1', - 'MAP_VARIABLES_VARIABLE2', + 'MAP_VARIABLES_ELEMENT', + 'MAP_VARIABLES_VARIABLE1_ATTRIBUTE', + 'MAP_VARIABLES_VARIABLE1_ATTRIBUTE_REFERENCE', + 'MAP_VARIABLES_VARIABLE2_ATTRIBUTE', + 'MAP_VARIABLES_VARIABLE2_ATTRIBUTE_REFERENCE', 'MAP_VARIABLES_UNIQUE', - 'MAP_VARIABLES_IDENTICAL_UNIT_REDUCTION', + 'DATA_REPR_IDENTIFIER_AT_LEAST_ONE_ALPHANUM', + 'DATA_REPR_IDENTIFIER_BEGIN_EURO_NUM', + 'DATA_REPR_IDENTIFIER_LATIN_ALPHANUM', + 'INVALID_ARGUMENT', + 'IMPORTER_ERROR_IMPORTING_UNITS', + 'IMPORTER_MISSING_FILE', + 'IMPORTER_MISSING_COMPONENT', + 'IMPORTER_MISSING_UNITS', + 'IMPORTER_NULL_MODEL', + 'IMPORTER_UNDEFINED_MODEL', + 'IMPORTER_UNRESOLVED_IMPORTS', + 'ANALYSER_EQUATION_NOT_EQUALITY_STATEMENT', + 'ANALYSER_UNITS', + 'ANALYSER_UNLINKED_UNITS', + 'ANALYSER_VARIABLE_INITIALISED_MORE_THAN_ONCE', + 'ANALYSER_VARIABLE_NON_CONSTANT_INITIALISATION', + 'ANALYSER_VOI_INITIALISED', + 'ANALYSER_VOI_SEVERAL', + 'ANALYSER_ODE_NOT_FIRST_ORDER', + 'ANALYSER_VARIABLE_UNUSED', + 'ANALYSER_STATE_NOT_INITIALISED', + 'ANALYSER_STATE_RATE_AS_ALGEBRAIC', + 'ANALYSER_VARIABLE_COMPUTED_MORE_THAN_ONCE', + 'ANALYSER_EXTERNAL_VARIABLE_DIFFERENT_MODEL', + 'ANALYSER_EXTERNAL_VARIABLE_VOI', + 'ANALYSER_EXTERNAL_VARIABLE_USE_PRIMARY_VARIABLE', + 'ANNOTATOR_ID_NOT_FOUND', + 'ANNOTATOR_ID_NOT_UNIQUE', + 'ANNOTATOR_NO_MODEL', + 'ANNOTATOR_INCONSISTENT_TYPE', + 'ANNOTATOR_NULL_MODEL', 'UNSPECIFIED' ]) convert(Units, 'Prefix', [ From dddac541376bdbcff5f107b409914c265885f02f Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Tue, 9 Apr 2024 17:35:24 +0100 Subject: [PATCH 12/50] Update tests to use the latest ReferenceRule settings. --- tests/analyser/analyser.cpp | 8 +- tests/bindings/python/test_issue.py | 198 +++++++++++++++++----------- tests/parser/parser.cpp | 34 ++--- tests/validator/validator.cpp | 4 +- 4 files changed, 146 insertions(+), 98 deletions(-) diff --git a/tests/analyser/analyser.cpp b/tests/analyser/analyser.cpp index b2a0f2c7b..c7e1678b9 100644 --- a/tests/analyser/analyser.cpp +++ b/tests/analyser/analyser.cpp @@ -205,8 +205,8 @@ TEST(Analyser, undefinedVariables) EXPECT_EQ_ISSUES_CELLMLELEMENTTYPES_LEVELS_REFERENCERULES_URLS(expectedIssues, expectedCellmlElementTypes(expectedIssues.size(), libcellml::CellmlElementType::MATH), expectedLevels(expectedIssues.size(), libcellml::Issue::Level::ERROR), - expectedReferenceRules(expectedIssues.size(), libcellml::Issue::ReferenceRule::MATH_CI_VARIABLE_REF), - expectedUrls(expectedIssues.size(), "https://cellml-specification.readthedocs.io/en/latest/reference/formal_and_informative/specB12.html?issue=MATH_CI_VARIABLE_REF"), + expectedReferenceRules(expectedIssues.size(), libcellml::Issue::ReferenceRule::MATH_CI_VARIABLE_REFERENCE), + expectedUrls(expectedIssues.size(), "https://cellml-specification.readthedocs.io/en/latest/reference/formal_and_informative/specB12.html?issue=MATH_CI_VARIABLE_REFERENCE"), analyser); EXPECT_EQ(libcellml::AnalyserModel::Type::INVALID, analyser->model()->type()); @@ -280,8 +280,8 @@ TEST(Analyser, nonExistingInitialisingVariable) EXPECT_EQ_ISSUES_CELLMLELEMENTTYPES_LEVELS_REFERENCERULES_URLS(expectedIssues, expectedCellmlElementTypes(expectedIssues.size(), libcellml::CellmlElementType::VARIABLE), expectedLevels(expectedIssues.size(), libcellml::Issue::Level::ERROR), - expectedReferenceRules(expectedIssues.size(), libcellml::Issue::ReferenceRule::VARIABLE_INITIAL_VALUE), - expectedUrls(expectedIssues.size(), "https://cellml-specification.readthedocs.io/en/latest/reference/formal_and_informative/specB08.html?issue=VARIABLE_INITIAL_VALUE"), + expectedReferenceRules(expectedIssues.size(), libcellml::Issue::ReferenceRule::VARIABLE_INITIAL_VALUE_VALUE), + expectedUrls(expectedIssues.size(), "https://cellml-specification.readthedocs.io/en/latest/reference/formal_and_informative/specB08.html?issue=VARIABLE_INITIAL_VALUE_VALUE"), analyser); EXPECT_EQ(libcellml::AnalyserModel::Type::INVALID, analyser->model()->type()); diff --git a/tests/bindings/python/test_issue.py b/tests/bindings/python/test_issue.py index 17d767afc..6eca2474b 100644 --- a/tests/bindings/python/test_issue.py +++ b/tests/bindings/python/test_issue.py @@ -25,89 +25,137 @@ def test_item_type_enum(self): def test_reference_rule_enum(self): from libcellml import Issue - self.assertIsInstance(Issue.ReferenceRule.UNDEFINED, int) - self.assertIsInstance(Issue.ReferenceRule.XML, int) - self.assertIsInstance(Issue.ReferenceRule.DATA_REPR_IDENTIFIER_UNICODE, int) - self.assertIsInstance(Issue.ReferenceRule.DATA_REPR_IDENTIFIER_LATIN_ALPHANUM, int) + self.assertIsInstance(Issue.ReferenceRule.ANALYSER_EQUATION_NOT_EQUALITY_STATEMENT, int) + self.assertIsInstance(Issue.ReferenceRule.ANALYSER_EXTERNAL_VARIABLE_DIFFERENT_MODEL, int) + self.assertIsInstance(Issue.ReferenceRule.ANALYSER_EXTERNAL_VARIABLE_USE_PRIMARY_VARIABLE, int) + self.assertIsInstance(Issue.ReferenceRule.ANALYSER_EXTERNAL_VARIABLE_VOI, int) + self.assertIsInstance(Issue.ReferenceRule.ANALYSER_ODE_NOT_FIRST_ORDER, int) + self.assertIsInstance(Issue.ReferenceRule.ANALYSER_STATE_NOT_INITIALISED, int) + self.assertIsInstance(Issue.ReferenceRule.ANALYSER_STATE_RATE_AS_ALGEBRAIC, int) + self.assertIsInstance(Issue.ReferenceRule.ANALYSER_UNITS, int) + self.assertIsInstance(Issue.ReferenceRule.ANALYSER_UNLINKED_UNITS, int) + self.assertIsInstance(Issue.ReferenceRule.ANALYSER_VARIABLE_COMPUTED_MORE_THAN_ONCE, int) + self.assertIsInstance(Issue.ReferenceRule.ANALYSER_VARIABLE_INITIALISED_MORE_THAN_ONCE, int) + self.assertIsInstance(Issue.ReferenceRule.ANALYSER_VARIABLE_NON_CONSTANT_INITIALISATION, int) + self.assertIsInstance(Issue.ReferenceRule.ANALYSER_VARIABLE_UNUSED, int) + self.assertIsInstance(Issue.ReferenceRule.ANALYSER_VOI_INITIALISED, int) + self.assertIsInstance(Issue.ReferenceRule.ANALYSER_VOI_SEVERAL, int) + self.assertIsInstance(Issue.ReferenceRule.ANNOTATOR_ID_NOT_FOUND, int) + self.assertIsInstance(Issue.ReferenceRule.ANNOTATOR_ID_NOT_UNIQUE, int) + self.assertIsInstance(Issue.ReferenceRule.ANNOTATOR_INCONSISTENT_TYPE, int) + self.assertIsInstance(Issue.ReferenceRule.ANNOTATOR_NO_MODEL, int) + self.assertIsInstance(Issue.ReferenceRule.ANNOTATOR_NULL_MODEL, int) + self.assertIsInstance(Issue.ReferenceRule.COMPONENT_CHILD, int) + self.assertIsInstance(Issue.ReferenceRule.COMPONENT_ELEMENT, int) + self.assertIsInstance(Issue.ReferenceRule.COMPONENT_NAME, int) + self.assertIsInstance(Issue.ReferenceRule.COMPONENT_NAME_UNIQUE, int) + self.assertIsInstance(Issue.ReferenceRule.COMPONENT_NAME_VALUE, int) + self.assertIsInstance(Issue.ReferenceRule.COMPONENT_REF_CHILD, int) + self.assertIsInstance(Issue.ReferenceRule.COMPONENT_REF_COMPONENT_ATTRIBUTE, int) + self.assertIsInstance(Issue.ReferenceRule.COMPONENT_REF_COMPONENT_ATTRIBUTE_REFERENCE, int) + self.assertIsInstance(Issue.ReferenceRule.COMPONENT_REF_COMPONENT_ATTRIBUTE_UNIQUE, int) + self.assertIsInstance(Issue.ReferenceRule.COMPONENT_REF_ELEMENT, int) + self.assertIsInstance(Issue.ReferenceRule.CONNECTION_CHILD, int) + self.assertIsInstance(Issue.ReferenceRule.CONNECTION_COMPONENT1_ATTRIBUTE, int) + self.assertIsInstance(Issue.ReferenceRule.CONNECTION_COMPONENT1_ATTRIBUTE_REFERENCE, int) + self.assertIsInstance(Issue.ReferenceRule.CONNECTION_COMPONENT2_ATTRIBUTE, int) + self.assertIsInstance(Issue.ReferenceRule.CONNECTION_COMPONENT2_ATTRIBUTE_REFERENCE, int) + self.assertIsInstance(Issue.ReferenceRule.CONNECTION_ELEMENT, int) + self.assertIsInstance(Issue.ReferenceRule.CONNECTION_EXCLUDE_SELF, int) + self.assertIsInstance(Issue.ReferenceRule.CONNECTION_UNIQUE, int) self.assertIsInstance(Issue.ReferenceRule.DATA_REPR_IDENTIFIER_AT_LEAST_ONE_ALPHANUM, int) self.assertIsInstance(Issue.ReferenceRule.DATA_REPR_IDENTIFIER_BEGIN_EURO_NUM, int) - self.assertIsInstance(Issue.ReferenceRule.DATA_REPR_IDENTIFIER_IDENTICAL, int) - self.assertIsInstance(Issue.ReferenceRule.DATA_REPR_INT_BASE10, int) - self.assertIsInstance(Issue.ReferenceRule.DATA_REPR_INT_SIGN, int) - self.assertIsInstance(Issue.ReferenceRule.DATA_REPR_INT_DIGIT, int) - self.assertIsInstance(Issue.ReferenceRule.DATA_REPR_BASIC_REAL_BASE10, int) - self.assertIsInstance(Issue.ReferenceRule.DATA_REPR_BASIC_REAL_SIGN, int) - self.assertIsInstance(Issue.ReferenceRule.DATA_REPR_BASIC_REAL_DECIMAL, int) - self.assertIsInstance(Issue.ReferenceRule.DATA_REPR_BASIC_REAL_DIGIT, int) - self.assertIsInstance(Issue.ReferenceRule.DATA_REPR_REAL_BASE10, int) - self.assertIsInstance(Issue.ReferenceRule.DATA_REPR_REAL_SIGNIFICAND, int) - self.assertIsInstance(Issue.ReferenceRule.DATA_REPR_REAL_EXPONENT, int) - self.assertIsInstance(Issue.ReferenceRule.MODEL_ELEMENT, int) - self.assertIsInstance(Issue.ReferenceRule.MODEL_NAME, int) - self.assertIsInstance(Issue.ReferenceRule.MODEL_CHILD, int) - self.assertIsInstance(Issue.ReferenceRule.MODEL_MORE_THAN_ONE_ENCAPSULATION, int) - self.assertIsInstance(Issue.ReferenceRule.IMPORT_ATTRIBUTE, int) - self.assertIsInstance(Issue.ReferenceRule.IMPORT_HREF, int) + self.assertIsInstance(Issue.ReferenceRule.DATA_REPR_IDENTIFIER_LATIN_ALPHANUM, int) + self.assertIsInstance(Issue.ReferenceRule.ENCAPSULATION_CHILD, int) + self.assertIsInstance(Issue.ReferenceRule.ENCAPSULATION_ELEMENT, int) + self.assertIsInstance(Issue.ReferenceRule.IMPORTER_ERROR_IMPORTING_UNITS, int) + self.assertIsInstance(Issue.ReferenceRule.IMPORTER_MISSING_COMPONENT, int) + self.assertIsInstance(Issue.ReferenceRule.IMPORTER_MISSING_FILE, int) + self.assertIsInstance(Issue.ReferenceRule.IMPORTER_MISSING_UNITS, int) + self.assertIsInstance(Issue.ReferenceRule.IMPORTER_NULL_MODEL, int) + self.assertIsInstance(Issue.ReferenceRule.IMPORTER_UNDEFINED_MODEL, int) + self.assertIsInstance(Issue.ReferenceRule.IMPORTER_UNRESOLVED_IMPORTS, int) self.assertIsInstance(Issue.ReferenceRule.IMPORT_CHILD, int) - self.assertIsInstance(Issue.ReferenceRule.IMPORT_EQUIVALENT, int) - self.assertIsInstance(Issue.ReferenceRule.IMPORT_UNITS_NAME, int) - self.assertIsInstance(Issue.ReferenceRule.IMPORT_UNITS_NAME_UNIQUE, int) - self.assertIsInstance(Issue.ReferenceRule.IMPORT_UNITS_REF, int) + self.assertIsInstance(Issue.ReferenceRule.IMPORT_COMPONENT_COMPONENT_REFERENCE, int) + self.assertIsInstance(Issue.ReferenceRule.IMPORT_COMPONENT_COMPONENT_REFERENCE_TARGET, int) + self.assertIsInstance(Issue.ReferenceRule.IMPORT_COMPONENT_COMPONENT_REFERENCE_VALUE, int) + self.assertIsInstance(Issue.ReferenceRule.IMPORT_COMPONENT_ELEMENT, int) self.assertIsInstance(Issue.ReferenceRule.IMPORT_COMPONENT_NAME, int) self.assertIsInstance(Issue.ReferenceRule.IMPORT_COMPONENT_NAME_UNIQUE, int) - self.assertIsInstance(Issue.ReferenceRule.IMPORT_COMPONENT_COMPONENT_REF, int) - self.assertIsInstance(Issue.ReferenceRule.UNITS_ATTRIBUTE, int) - self.assertIsInstance(Issue.ReferenceRule.UNITS_NAME, int) - self.assertIsInstance(Issue.ReferenceRule.UNITS_NAME_UNIQUE, int) - self.assertIsInstance(Issue.ReferenceRule.UNITS_STANDARD, int) - self.assertIsInstance(Issue.ReferenceRule.UNITS_CHILD, int) - self.assertIsInstance(Issue.ReferenceRule.UNIT_ATTRIBUTE, int) - self.assertIsInstance(Issue.ReferenceRule.UNIT_UNITS_REF, int) - self.assertIsInstance(Issue.ReferenceRule.UNIT_CIRCULAR_REF, int) - self.assertIsInstance(Issue.ReferenceRule.UNIT_OPTIONAL_ATTRIBUTE, int) - self.assertIsInstance(Issue.ReferenceRule.UNIT_PREFIX, int) - self.assertIsInstance(Issue.ReferenceRule.UNIT_MULTIPLIER, int) - self.assertIsInstance(Issue.ReferenceRule.UNIT_EXPONENT, int) - self.assertIsInstance(Issue.ReferenceRule.COMPONENT_ATTRIBUTE, int) - self.assertIsInstance(Issue.ReferenceRule.COMPONENT_NAME, int) - self.assertIsInstance(Issue.ReferenceRule.COMPONENT_NAME_UNIQUE, int) - self.assertIsInstance(Issue.ReferenceRule.COMPONENT_CHILD, int) - self.assertIsInstance(Issue.ReferenceRule.VARIABLE_ATTRIBUTE, int) - self.assertIsInstance(Issue.ReferenceRule.VARIABLE_CHILD, int) - self.assertIsInstance(Issue.ReferenceRule.VARIABLE_NAME, int) - self.assertIsInstance(Issue.ReferenceRule.VARIABLE_NAME_UNIQUE, int) - self.assertIsInstance(Issue.ReferenceRule.VARIABLE_UNITS, int) - self.assertIsInstance(Issue.ReferenceRule.VARIABLE_INTERFACE, int) - self.assertIsInstance(Issue.ReferenceRule.VARIABLE_INITIAL_VALUE, int) - self.assertIsInstance(Issue.ReferenceRule.RESET_ATTRIBUTE, int) - self.assertIsInstance(Issue.ReferenceRule.RESET_VARIABLE_REF, int) - self.assertIsInstance(Issue.ReferenceRule.RESET_TEST_VARIABLE_REF, int) - self.assertIsInstance(Issue.ReferenceRule.RESET_ORDER, int) - self.assertIsInstance(Issue.ReferenceRule.RESET_CHILD, int) - self.assertIsInstance(Issue.ReferenceRule.RESET_TEST_VALUE, int) - self.assertIsInstance(Issue.ReferenceRule.RESET_RESET_VALUE, int) - self.assertIsInstance(Issue.ReferenceRule.MATH_MATHML, int) + self.assertIsInstance(Issue.ReferenceRule.IMPORT_COMPONENT_NAME_VALUE, int) + self.assertIsInstance(Issue.ReferenceRule.IMPORT_ELEMENT, int) + self.assertIsInstance(Issue.ReferenceRule.IMPORT_EQUIVALENT_INFOSET, int) + self.assertIsInstance(Issue.ReferenceRule.IMPORT_HREF, int) + self.assertIsInstance(Issue.ReferenceRule.IMPORT_HREF_LOCATOR, int) + self.assertIsInstance(Issue.ReferenceRule.IMPORT_UNITS_ELEMENT, int) + self.assertIsInstance(Issue.ReferenceRule.IMPORT_UNITS_NAME, int) + self.assertIsInstance(Issue.ReferenceRule.IMPORT_UNITS_NAME_UNIQUE, int) + self.assertIsInstance(Issue.ReferenceRule.IMPORT_UNITS_NAME_VALUE, int) + self.assertIsInstance(Issue.ReferenceRule.IMPORT_UNITS_UNITS_REFERENCE, int) + self.assertIsInstance(Issue.ReferenceRule.IMPORT_UNITS_UNITS_REFERENCE_VALUE, int) + self.assertIsInstance(Issue.ReferenceRule.IMPORT_UNITS_UNITS_REFERENCE_VALUE_TARGET, int) + self.assertIsInstance(Issue.ReferenceRule.INVALID_ARGUMENT, int) + self.assertIsInstance(Issue.ReferenceRule.MAP_VARIABLES_ELEMENT, int) + self.assertIsInstance(Issue.ReferenceRule.MAP_VARIABLES_UNIQUE, int) + self.assertIsInstance(Issue.ReferenceRule.MAP_VARIABLES_VARIABLE1_ATTRIBUTE, int) + self.assertIsInstance(Issue.ReferenceRule.MAP_VARIABLES_VARIABLE1_ATTRIBUTE_REFERENCE, int) + self.assertIsInstance(Issue.ReferenceRule.MAP_VARIABLES_VARIABLE2_ATTRIBUTE, int) + self.assertIsInstance(Issue.ReferenceRule.MAP_VARIABLES_VARIABLE2_ATTRIBUTE_REFERENCE, int) self.assertIsInstance(Issue.ReferenceRule.MATH_CHILD, int) - self.assertIsInstance(Issue.ReferenceRule.MATH_CI_VARIABLE_REF, int) - self.assertIsInstance(Issue.ReferenceRule.MATH_CN_UNITS, int) + self.assertIsInstance(Issue.ReferenceRule.MATH_CI_VARIABLE_REFERENCE, int) self.assertIsInstance(Issue.ReferenceRule.MATH_CN_BASE10, int) self.assertIsInstance(Issue.ReferenceRule.MATH_CN_FORMAT, int) - self.assertIsInstance(Issue.ReferenceRule.ENCAPSULATION_ATTRIBUTE, int) - self.assertIsInstance(Issue.ReferenceRule.ENCAPSULATION_CHILD, int) - self.assertIsInstance(Issue.ReferenceRule.COMPONENT_REF_COMPONENT, int) - self.assertIsInstance(Issue.ReferenceRule.COMPONENT_REF_CHILD, int) - self.assertIsInstance(Issue.ReferenceRule.CONNECTION_ATTRIBUTE, int) - self.assertIsInstance(Issue.ReferenceRule.CONNECTION_COMPONENT1, int) - self.assertIsInstance(Issue.ReferenceRule.CONNECTION_COMPONENT2, int) - self.assertIsInstance(Issue.ReferenceRule.CONNECTION_EXCLUDE_SELF, int) - self.assertIsInstance(Issue.ReferenceRule.CONNECTION_UNIQUE, int) - self.assertIsInstance(Issue.ReferenceRule.CONNECTION_CHILD, int) - self.assertIsInstance(Issue.ReferenceRule.MAP_VARIABLES_ATTRIBUTE, int) - self.assertIsInstance(Issue.ReferenceRule.MAP_VARIABLES_VARIABLE1, int) - self.assertIsInstance(Issue.ReferenceRule.MAP_VARIABLES_VARIABLE2, int) - self.assertIsInstance(Issue.ReferenceRule.MAP_VARIABLES_UNIQUE, int) - self.assertIsInstance(Issue.ReferenceRule.MAP_VARIABLES_IDENTICAL_UNIT_REDUCTION, int) + self.assertIsInstance(Issue.ReferenceRule.MATH_CN_UNITS_ATTRIBUTE, int) + self.assertIsInstance(Issue.ReferenceRule.MATH_CN_UNITS_ATTRIBUTE_REFERENCE, int) + self.assertIsInstance(Issue.ReferenceRule.MATH_ELEMENT, int) + self.assertIsInstance(Issue.ReferenceRule.MATH_MATHML, int) + self.assertIsInstance(Issue.ReferenceRule.MODEL_CHILD, int) + self.assertIsInstance(Issue.ReferenceRule.MODEL_ELEMENT, int) + self.assertIsInstance(Issue.ReferenceRule.MODEL_MORE_THAN_ONE_ENCAPSULATION, int) + self.assertIsInstance(Issue.ReferenceRule.MODEL_NAME, int) + self.assertIsInstance(Issue.ReferenceRule.MODEL_NAME_VALUE, int) + self.assertIsInstance(Issue.ReferenceRule.RESET_ATTRIBUTE_REQUIRED, int) + self.assertIsInstance(Issue.ReferenceRule.RESET_CHILD, int) + self.assertIsInstance(Issue.ReferenceRule.RESET_ELEMENT, int) + self.assertIsInstance(Issue.ReferenceRule.RESET_ORDER_UNIQUE, int) + self.assertIsInstance(Issue.ReferenceRule.RESET_ORDER_VALUE, int) + self.assertIsInstance(Issue.ReferenceRule.RESET_RESET_VALUE_CHILD, int) + self.assertIsInstance(Issue.ReferenceRule.RESET_TEST_VALUE_CHILD, int) + self.assertIsInstance(Issue.ReferenceRule.RESET_TEST_VARIABLE_REFERENCE, int) + self.assertIsInstance(Issue.ReferenceRule.RESET_VALUE_CHILD, int) + self.assertIsInstance(Issue.ReferenceRule.RESET_VALUE_ELEMENT, int) + self.assertIsInstance(Issue.ReferenceRule.RESET_VARIABLE_REFERENCE, int) + self.assertIsInstance(Issue.ReferenceRule.TEST_VALUE_CHILD, int) + self.assertIsInstance(Issue.ReferenceRule.TEST_VALUE_ELEMENT, int) + self.assertIsInstance(Issue.ReferenceRule.UNDEFINED, int) + self.assertIsInstance(Issue.ReferenceRule.UNITS_CHILD, int) + self.assertIsInstance(Issue.ReferenceRule.UNITS_ELEMENT, int) + self.assertIsInstance(Issue.ReferenceRule.UNITS_NAME, int) + self.assertIsInstance(Issue.ReferenceRule.UNITS_NAME_UNIQUE, int) + self.assertIsInstance(Issue.ReferenceRule.UNITS_NAME_VALUE, int) + self.assertIsInstance(Issue.ReferenceRule.UNITS_STANDARD, int) + self.assertIsInstance(Issue.ReferenceRule.UNIT_ATTRIBUTE_EXPONENT_VALUE, int) + self.assertIsInstance(Issue.ReferenceRule.UNIT_ATTRIBUTE_MULTIPLIER_VALUE, int) + self.assertIsInstance(Issue.ReferenceRule.UNIT_ATTRIBUTE_OPTIONAL, int) + self.assertIsInstance(Issue.ReferenceRule.UNIT_ATTRIBUTE_PREFIX_VALUE, int) + self.assertIsInstance(Issue.ReferenceRule.UNIT_ELEMENT, int) + self.assertIsInstance(Issue.ReferenceRule.UNIT_UNITS, int) + self.assertIsInstance(Issue.ReferenceRule.UNIT_UNITS_CIRCULAR_REFERENCE, int) + self.assertIsInstance(Issue.ReferenceRule.UNIT_UNITS_REFERENCE, int) self.assertIsInstance(Issue.ReferenceRule.UNSPECIFIED, int) + self.assertIsInstance(Issue.ReferenceRule.VARIABLE_ATTRIBUTE_OPTIONAL, int) + self.assertIsInstance(Issue.ReferenceRule.VARIABLE_ATTRIBUTE_REQUIRED, int) + self.assertIsInstance(Issue.ReferenceRule.VARIABLE_ELEMENT, int) + self.assertIsInstance(Issue.ReferenceRule.VARIABLE_INITIAL_VALUE_VALUE, int) + self.assertIsInstance(Issue.ReferenceRule.VARIABLE_INTERFACE_VALUE, int) + self.assertIsInstance(Issue.ReferenceRule.VARIABLE_NAME_UNIQUE, int) + self.assertIsInstance(Issue.ReferenceRule.VARIABLE_NAME_VALUE, int) + self.assertIsInstance(Issue.ReferenceRule.VARIABLE_UNITS_VALUE, int) + self.assertIsInstance(Issue.ReferenceRule.XML_ID_ATTRIBUTE, int) + self.assertIsInstance(Issue.ReferenceRule.XML_UNEXPECTED_CHARACTER, int) + self.assertIsInstance(Issue.ReferenceRule.XML_UNEXPECTED_ELEMENT, int) + self.assertIsInstance(Issue.ReferenceRule.XML_UNEXPECTED_NAMESPACE, int) + self.assertIsInstance(Issue.ReferenceRule.XML_UNEXPECTED_NAMESPACE_PREFIX, int) def test_coverage(self): from libcellml import Issue @@ -125,7 +173,7 @@ def test_coverage(self): self.assertEqual(Issue.Level.ERROR, i.level()) self.assertNotEqual(None, i.item()) - self.assertEqual("1.2.1", i.referenceHeading()) + self.assertEqual("1.2.1.1", i.referenceHeading()) self.assertEqual(1, i.referenceRule()) self.assertEqual( "https://cellml-specification.readthedocs.io/en/latest/reference/formal_and_informative/specA02.html?issue=XML", diff --git a/tests/parser/parser.cpp b/tests/parser/parser.cpp index 218dd4552..5a962282d 100644 --- a/tests/parser/parser.cpp +++ b/tests/parser/parser.cpp @@ -994,8 +994,8 @@ TEST(Parser, emptyConnections) " \n" "\n"; const std::vector expectedIssues = { - "Connection in model 'model_name' does not have a valid component_1 in a connection element.", - "Connection in model 'model_name' does not have a valid component_2 in a connection element.", + "Connection in model 'model_name' does not specify a component_1 in a connection element.", + "Connection in model 'model_name' does not specify a component_2 in a connection element.", "Connection in model 'model_name' does not contain any 'map_variables' elements and will be disregarded.", }; @@ -1012,8 +1012,8 @@ TEST(Parser, emptyConnectionWithId) " \n" "\n"; const std::vector expectedIssues = { - "Connection in model 'model_name' does not have a valid component_1 in a connection element.", - "Connection in model 'model_name' does not have a valid component_2 in a connection element.", + "Connection in model 'model_name' does not specify a component_1 in a connection element.", + "Connection in model 'model_name' does not specify a component_2 in a connection element.", "Connection in model 'model_name' has an identifier of 'myId' but does not contain any 'map_variables' elements. The connection will be disregarded and the associated identifier will be lost.", }; @@ -1035,7 +1035,7 @@ TEST(Parser, connectionErrorNoComponent2) " \n" "\n"; const std::vector expectedIssues = { - "Connection in model 'modelA' does not have a valid component_2 in a connection element.", + "Connection in model 'modelA' does not specify a component_2 in a connection element.", "Connection in model 'modelA' specifies 'component1' as component_1 but it does not exist in the model.", "Connection in model 'modelA' specifies 'variable1' as variable_1 but the corresponding component_1 is invalid.", "Connection in model 'modelA' specifies 'variable2' as variable_2 but the corresponding component_2 is invalid.", @@ -1082,7 +1082,7 @@ TEST(Parser, connectionErrorNoComponent1) "\n" "\n"; const std::vector expectedIssues = { - "Connection in model 'modelName' does not have a valid component_1 in a connection element.", + "Connection in model 'modelName' does not specify a component_1 in a connection element.", "Connection in model 'modelName' specifies 'variable1' as variable_1 but the corresponding component_1 is invalid.", "Variable 'variable2' is specified as variable_2 in a connection but it does not exist in component_2 component 'componentA' of model 'modelName'.", }; @@ -1108,8 +1108,8 @@ TEST(Parser, connectionErrorNoMapComponents) "\n"; const std::vector expectedIssues = { "Connection in model 'modelName' has an invalid connection attribute 'name'.", - "Connection in model 'modelName' does not have a valid component_1 in a connection element.", - "Connection in model 'modelName' does not have a valid component_2 in a connection element.", + "Connection in model 'modelName' does not specify a component_1 in a connection element.", + "Connection in model 'modelName' does not specify a component_2 in a connection element.", "Connection in model 'modelName' has an invalid child element 'map_units' of element 'map_variables'.", "Connection in model 'modelName' has an invalid map_variables attribute 'variable_3'.", "Connection in model 'modelName' specifies 'variable1' as variable_1 but the corresponding component_1 is invalid.", @@ -1255,7 +1255,7 @@ TEST(Parser, component2InConnectionMissing) "\n"; const std::vector expectedIssues = { - "Connection in model '' does not have a valid component_2 in a connection element.", + "Connection in model '' does not specify a component_2 in a connection element.", "Connection in model '' specifies 'variable_angus' as variable_2 but the corresponding component_2 is invalid.", }; @@ -1286,7 +1286,7 @@ TEST(Parser, connectionVariable2Missing) "\n"; const std::vector expectedIssues = { - "Connection in model '' does not have a valid variable_2 in a map_variables element.", + "Connection in model '' does not specify a variable_2 in a map_variables element.", }; // Parse @@ -1311,7 +1311,7 @@ TEST(Parser, connectionVariable1Missing) " \n" "\n"; const std::vector expectedIssues = { - "Connection in model '' does not have a valid variable_1 in a map_variables element.", + "Connection in model '' does not specify a variable_1 in a map_variables element.", "Model does not contain the units 'scrat' required by variable 'variable_bob' in component 'component_bob'.", "Model does not contain the units 'gone' required by variable 'variable_dave' in component 'component_dave'.", }; @@ -1427,8 +1427,8 @@ TEST(Parser, invalidModelWithDifferentItemTypesOfIssues) "Encapsulation in model 'starwars' has an invalid attribute 'yoda'.", "Encapsulation in model 'starwars' does not contain any child elements.", "Connection in model 'starwars' has an invalid connection attribute 'wookie'.", - "Connection in model 'starwars' does not have a valid component_1 in a connection element.", - "Connection in model 'starwars' does not have a valid component_2 in a connection element.", + "Connection in model 'starwars' does not specify a component_1 in a connection element.", + "Connection in model 'starwars' does not specify a component_2 in a connection element.", "Connection in model 'starwars' does not contain any 'map_variables' elements and will be disregarded.", }; @@ -1543,12 +1543,12 @@ TEST(Parser, invalidModelWithTextInAllElements) "Encapsulation in model 'starwars' has an invalid non-whitespace child text element '\n awakens\n '.", "Encapsulation in model 'starwars' has an invalid non-whitespace child text element '\n force\n '.", "Encapsulation in model 'starwars' specifies 'ship' as a parent component_ref but it does not have any children.", - "Connection in model 'starwars' does not have a valid component_1 in a connection element.", - "Connection in model 'starwars' does not have a valid component_2 in a connection element.", + "Connection in model 'starwars' does not specify a component_1 in a connection element.", + "Connection in model 'starwars' does not specify a component_2 in a connection element.", "Connection in model 'starwars' has an invalid non-whitespace child text element '\n finn\n '.", "Connection in model 'starwars' has an invalid non-whitespace child text element '\n trooper\n '.", - "Connection in model 'starwars' does not have a valid variable_1 in a map_variables element.", - "Connection in model 'starwars' does not have a valid variable_2 in a map_variables element.", + "Connection in model 'starwars' does not specify a variable_1 in a map_variables element.", + "Connection in model 'starwars' does not specify a variable_2 in a map_variables element.", "Connection in model 'starwars' specifies '' as variable_1 but the corresponding component_1 is invalid.", "Connection in model 'starwars' specifies '' as variable_2 but the corresponding component_2 is invalid.", }; diff --git a/tests/validator/validator.cpp b/tests/validator/validator.cpp index 0bc8ee0f4..0492e87ff 100644 --- a/tests/validator/validator.cpp +++ b/tests/validator/validator.cpp @@ -116,10 +116,10 @@ TEST(Validator, invalidElementIdAttribute) "Model 'valid_name' does not have a valid 'id' attribute, '993-++$@'.", }; const std::vector expectedSpecificationHeadings = { - "1.2.5", + "1.2.5.1.1", }; const std::vector expectedUrls = { - "https://cellml-specification.readthedocs.io/en/latest/reference/formal_and_informative/specA02.html?issue=XML", + "https://cellml-specification.readthedocs.io/en/latest/reference/formal_and_informative/specA02.html?issue=XML_ID_ATTRIBUTE", }; libcellml::ModelPtr model = libcellml::Model::create("valid_name"); From 3dc9aa1275118a34e65863da4f1acfcdb511508b Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Tue, 9 Apr 2024 17:35:58 +0100 Subject: [PATCH 13/50] Implement changes due to modifications to the reference rule enumeration. --- src/importer.cpp | 2 +- src/issue.cpp | 5 ++ src/parser.cpp | 131 ++++++++++++++++++++++++++++++---------------- src/validator.cpp | 72 ++++++++++++------------- 4 files changed, 129 insertions(+), 81 deletions(-) diff --git a/src/importer.cpp b/src/importer.cpp index 4b233c9d7..7e74657fa 100644 --- a/src/importer.cpp +++ b/src/importer.cpp @@ -396,7 +396,7 @@ bool Importer::ImporterImpl::checkForImportCycles(const ImportSourcePtr &importS auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription(description); issue->mPimpl->mItem->mPimpl->setImportSource(importSource); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_EQUIVALENT); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_EQUIVALENT_INFOSET); addIssue(issue); return true; } diff --git a/src/issue.cpp b/src/issue.cpp index 25620f2d3..656a2bcb7 100644 --- a/src/issue.cpp +++ b/src/issue.cpp @@ -180,6 +180,11 @@ static const std::map> ruleToInfo {Issue::ReferenceRule::MAP_VARIABLES_VARIABLE2_ATTRIBUTE_REFERENCE, {"MAP_VARIABLES_VARIABLE2_ATTRIBUTE_REFERENCE", "2.16.2.1", baseSpecificationUrl, "specB16"}}, {Issue::ReferenceRule::MAP_VARIABLES_UNIQUE, {"MAP_VARIABLES_UNIQUE", "2.16.3", baseSpecificationUrl, "specB16"}}, + // Secondary specification rules: + {Issue::ReferenceRule::DATA_REPR_IDENTIFIER_AT_LEAST_ONE_ALPHANUM, {"DATA_REPR_IDENTIFIER_AT_LEAST_ONE_ALPHANUM", "1.3.1.1", baseSpecificationUrl, "specA03"}}, + {Issue::ReferenceRule::DATA_REPR_IDENTIFIER_BEGIN_EURO_NUM, {"DATA_REPR_IDENTIFIER_BEGIN_EURO_NUM", "1.3.1.1", baseSpecificationUrl, "specA03"}}, + {Issue::ReferenceRule::DATA_REPR_IDENTIFIER_LATIN_ALPHANUM, {"DATA_REPR_IDENTIFIER_LATIN_ALPHANUM", "1.3.1.1", baseSpecificationUrl, "specA03"}}, + // Not in normative specification: {Issue::ReferenceRule::INVALID_ARGUMENT, {"INVALID_ARGUMENT", "", docsUrl, ""}}, diff --git a/src/parser.cpp b/src/parser.cpp index 679a62278..ce7bf103e 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -489,7 +489,7 @@ void Parser::ParserImpl::loadModel(const ModelPtr &model, const std::string &inp auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Encapsulation in model '" + model->name() + "' has an invalid attribute '" + childAttribute->name() + "'."); issue->mPimpl->mItem->mPimpl->setEncapsulation(model); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::ENCAPSULATION_ATTRIBUTE); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::ENCAPSULATION_ELEMENT); addIssue(issue); } childAttribute = childAttribute->next(); @@ -566,7 +566,7 @@ void Parser::ParserImpl::loadModel(const ModelPtr &model, const std::string &inp auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription(entry.second); issue->mPimpl->setLevel(Issue::Level::WARNING); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::VARIABLE_UNITS); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::VARIABLE_ELEMENT); issue->mPimpl->mItem->mPimpl->setVariable(entry.first); addIssue(issue); } @@ -587,7 +587,7 @@ void Parser::ParserImpl::loadComponent(const ComponentPtr &component, const XmlN issue->mPimpl->setLevel(Issue::Level::MESSAGE); } else { issue->mPimpl->setDescription("Component '" + node->attribute("name") + "' has an invalid attribute '" + attribute->name() + "'."); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::COMPONENT_ATTRIBUTE); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::COMPONENT_ELEMENT); } issue->mPimpl->mItem->mPimpl->setComponent(component); addIssue(issue); @@ -694,7 +694,7 @@ void Parser::ParserImpl::loadUnits(const UnitsPtr &units, const XmlNodePtr &node issue->mPimpl->setLevel(Issue::Level::MESSAGE); } else { issue->mPimpl->setDescription("Units '" + units->name() + "' has an invalid attribute '" + attribute->name() + "'."); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNITS_ATTRIBUTE); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNITS_ELEMENT); } issue->mPimpl->mItem->mPimpl->setUnits(units); addIssue(issue); @@ -777,7 +777,7 @@ void Parser::ParserImpl::loadUnit(const UnitsPtr &units, const XmlNodePtr &node) auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Unit referencing '" + node->attribute("units") + "' in units '" + units->name() + "' has an exponent with the value '" + attribute->value() + "' that is a representation of a CellML real valued number, but out of range of the 'double' type."); issue->mPimpl->mItem->mPimpl->setUnits(units); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNIT_EXPONENT); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNIT_ATTRIBUTE_EXPONENT_VALUE); addIssue(issue); } } else { @@ -785,7 +785,7 @@ void Parser::ParserImpl::loadUnit(const UnitsPtr &units, const XmlNodePtr &node) auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Unit referencing '" + node->attribute("units") + "' in units '" + units->name() + "' has an exponent with the value '" + attribute->value() + "' that is not a representation of a CellML real valued number."); issue->mPimpl->mItem->mPimpl->setUnits(units); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNIT_EXPONENT); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNIT_ATTRIBUTE_EXPONENT_VALUE); addIssue(issue); } } else if (attribute->isType("multiplier")) { @@ -795,7 +795,7 @@ void Parser::ParserImpl::loadUnit(const UnitsPtr &units, const XmlNodePtr &node) auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Unit referencing '" + node->attribute("units") + "' in units '" + units->name() + "' has a multiplier with the value '" + attribute->value() + "' that is a representation of a CellML real valued number, but out of range of the 'double' type."); issue->mPimpl->mItem->mPimpl->setUnits(units); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNIT_MULTIPLIER); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNIT_ATTRIBUTE_MULTIPLIER_VALUE); addIssue(issue); } } else { @@ -803,7 +803,7 @@ void Parser::ParserImpl::loadUnit(const UnitsPtr &units, const XmlNodePtr &node) auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Unit referencing '" + node->attribute("units") + "' in units '" + units->name() + "' has a multiplier with the value '" + attribute->value() + "' that is not a representation of a CellML real valued number."); issue->mPimpl->mItem->mPimpl->setUnits(units); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNIT_MULTIPLIER); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNIT_ATTRIBUTE_MULTIPLIER_VALUE); addIssue(issue); } } else if (isIdAttribute(attribute, mParsing1XVersion)) { @@ -812,7 +812,7 @@ void Parser::ParserImpl::loadUnit(const UnitsPtr &units, const XmlNodePtr &node) auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Unit referencing '" + node->attribute("units") + "' in units '" + units->name() + "' has an invalid attribute '" + attribute->name() + "'."); issue->mPimpl->mItem->mPimpl->setUnits(units); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNIT_OPTIONAL_ATTRIBUTE); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNIT_ATTRIBUTE_OPTIONAL); addIssue(issue); } attribute = attribute->next(); @@ -833,7 +833,7 @@ void Parser::ParserImpl::loadVariable(const VariablePtr &variable, const XmlNode auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Variable '" + node->attribute("name") + "' has an invalid non-whitespace child text element '" + textNode + "'."); issue->mPimpl->mItem->mPimpl->setVariable(variable); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::VARIABLE_CHILD); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::VARIABLE_ELEMENT); addIssue(issue); } } else if (childNode->isComment()) { @@ -845,7 +845,7 @@ void Parser::ParserImpl::loadVariable(const VariablePtr &variable, const XmlNode issue->mPimpl->setLevel(Issue::Level::MESSAGE); } else { issue->mPimpl->setDescription("Variable '" + node->attribute("name") + "' has an invalid child element '" + childNode->name() + "'."); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::VARIABLE_CHILD); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::VARIABLE_ELEMENT); } issue->mPimpl->mItem->mPimpl->setVariable(variable); addIssue(issue); @@ -887,7 +887,7 @@ void Parser::ParserImpl::loadVariable(const VariablePtr &variable, const XmlNode issue->mPimpl->setLevel(Issue::Level::MESSAGE); } else { issue->mPimpl->setDescription("Variable '" + node->attribute("name") + "' has an invalid attribute '" + attribute->name() + "'."); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::VARIABLE_ATTRIBUTE); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::VARIABLE_ATTRIBUTE_OPTIONAL); } issue->mPimpl->mItem->mPimpl->setVariable(variable); addIssue(issue); @@ -939,12 +939,16 @@ void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr componentNode = node; } + bool component1Attribute = false; + bool component2Attribute = false; XmlAttributePtr attribute = componentNode->firstAttribute(); while (attribute != nullptr) { if (attribute->isType("component_1")) { component1Name = attribute->value(); + component1Attribute = true; } else if (attribute->isType("component_2")) { component2Name = attribute->value(); + component2Attribute = true; } else if (isIdAttribute(attribute, mParsing1XVersion)) { connectionId = attribute->value(); } else { @@ -954,7 +958,7 @@ void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr issue->mPimpl->setLevel(Issue::Level::MESSAGE); } else { issue->mPimpl->setDescription("Connection in model '" + model->name() + "' has an invalid connection attribute '" + attribute->name() + "'."); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::CONNECTION_ATTRIBUTE); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::CONNECTION_ELEMENT); } issue->mPimpl->mItem->mPimpl->setModel(model); addIssue(issue); @@ -962,23 +966,39 @@ void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr attribute = attribute->next(); } - // Check that we found both components. - if (component1Name.empty()) { + // Check that both components were specified and found. + if (!component1Attribute) { + auto issue = Issue::IssueImpl::create(); + issue->mPimpl->setDescription("Connection in model '" + model->name() + "' does not specify a component_1 in a connection element."); + issue->mPimpl->mItem->mPimpl->setModel(model); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::CONNECTION_COMPONENT1_ATTRIBUTE); + addIssue(issue); + component1Missing = true; + } else if (component1Name.empty()) { auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Connection in model '" + model->name() + "' does not have a valid component_1 in a connection element."); issue->mPimpl->mItem->mPimpl->setModel(model); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::CONNECTION_COMPONENT1); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::CONNECTION_COMPONENT1_ATTRIBUTE_REFERENCE); addIssue(issue); component1Missing = true; } - if (component2Name.empty()) { + + if (!component2Attribute) { + auto issue = Issue::IssueImpl::create(); + issue->mPimpl->setDescription("Connection in model '" + model->name() + "' does not specify a component_2 in a connection element."); + issue->mPimpl->mItem->mPimpl->setModel(model); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::CONNECTION_COMPONENT2_ATTRIBUTE); + addIssue(issue); + component2Missing = true; + } else if (component2Name.empty()) { auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Connection in model '" + model->name() + "' does not have a valid component_2 in a connection element."); issue->mPimpl->mItem->mPimpl->setModel(model); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::CONNECTION_COMPONENT2); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::CONNECTION_COMPONENT2_ATTRIBUTE_REFERENCE); addIssue(issue); component2Missing = true; } + componentNamePair = std::make_pair(component1Name, component2Name); XmlNodePtr childNode = node->firstChild(); @@ -1030,38 +1050,57 @@ void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr if (parseNode(childNode, "map_variables")) { std::string variable1Name; std::string variable2Name; + bool variable1Attribute = false; + bool variable2Attribute = false; XmlAttributePtr childAttribute = childNode->firstAttribute(); mappingId.clear(); while (childAttribute) { if (childAttribute->isType("variable_1")) { variable1Name = childAttribute->value(); + variable1Attribute = true; } else if (childAttribute->isType("variable_2")) { variable2Name = childAttribute->value(); + variable2Attribute = true; } else if (isIdAttribute(childAttribute, mParsing1XVersion)) { mappingId = childAttribute->value(); } else { auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Connection in model '" + model->name() + "' has an invalid map_variables attribute '" + childAttribute->name() + "'."); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::MAP_VARIABLES_ATTRIBUTE); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::MAP_VARIABLES_ELEMENT); issue->mPimpl->mItem->mPimpl->setModel(model); addIssue(issue); } childAttribute = childAttribute->next(); } - // Check that we found both variables. - if (variable1Name.empty()) { + + // Check that both variables were specified and found. + if (!variable1Attribute) { + auto issue = Issue::IssueImpl::create(); + issue->mPimpl->setDescription("Connection in model '" + model->name() + "' does not specify a variable_1 in a map_variables element."); + issue->mPimpl->mItem->mPimpl->setModel(model); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::MAP_VARIABLES_VARIABLE1_ATTRIBUTE); + addIssue(issue); + variable1Missing = true; + } else if (variable1Name.empty()) { auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Connection in model '" + model->name() + "' does not have a valid variable_1 in a map_variables element."); issue->mPimpl->mItem->mPimpl->setModel(model); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::MAP_VARIABLES_VARIABLE1); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::MAP_VARIABLES_VARIABLE1_ATTRIBUTE_REFERENCE); addIssue(issue); variable1Missing = true; } - if (variable2Name.empty()) { + if (!variable2Attribute) { + auto issue = Issue::IssueImpl::create(); + issue->mPimpl->setDescription("Connection in model '" + model->name() + "' does not specify a variable_2 in a map_variables element."); + issue->mPimpl->mItem->mPimpl->setModel(model); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::MAP_VARIABLES_VARIABLE2_ATTRIBUTE); + addIssue(issue); + variable2Missing = true; + } else if (variable2Name.empty()) { auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Connection in model '" + model->name() + "' does not have a valid variable_2 in a map_variables element."); issue->mPimpl->mItem->mPimpl->setModel(model); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::MAP_VARIABLES_VARIABLE2); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::MAP_VARIABLES_VARIABLE2_ATTRIBUTE_REFERENCE); addIssue(issue); variable2Missing = true; } @@ -1109,7 +1148,7 @@ void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Connection in model '" + model->name() + "' specifies '" + componentNamePair.first + "' as component_1 but it does not exist in the model."); issue->mPimpl->mItem->mPimpl->setModel(model); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::CONNECTION_COMPONENT1); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::CONNECTION_COMPONENT1_ATTRIBUTE_REFERENCE); addIssue(issue); } } @@ -1120,7 +1159,7 @@ void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Connection in model '" + model->name() + "' specifies '" + componentNamePair.second + "' as component_2 but it does not exist in the model."); issue->mPimpl->mItem->mPimpl->setModel(model); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::CONNECTION_COMPONENT2); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::CONNECTION_COMPONENT2_ATTRIBUTE_REFERENCE); addIssue(issue); } } @@ -1143,7 +1182,7 @@ void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Variable '" + iterInfo[0] + "' is specified as variable_1 in a connection but it does not exist in component_1 component '" + component1->name() + "' of model '" + model->name() + "'."); issue->mPimpl->mItem->mPimpl->setConnection(variable1, variable2); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::CONNECTION_COMPONENT1); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::MAP_VARIABLES_VARIABLE1_ATTRIBUTE_REFERENCE); addIssue(issue); } } @@ -1151,7 +1190,7 @@ void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Connection in model '" + model->name() + "' specifies '" + iterInfo[0] + "' as variable_1 but the corresponding component_1 is invalid."); issue->mPimpl->mItem->mPimpl->setConnection(variable1, variable2); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::CONNECTION_COMPONENT1); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::CONNECTION_COMPONENT1_ATTRIBUTE); addIssue(issue); } if (component2) { @@ -1167,7 +1206,7 @@ void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Variable '" + iterInfo[1] + "' is specified as variable_2 in a connection but it does not exist in component_2 component '" + component2->name() + "' of model '" + model->name() + "'."); issue->mPimpl->mItem->mPimpl->setConnection(variable1, variable2); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::CONNECTION_COMPONENT2); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::MAP_VARIABLES_VARIABLE2_ATTRIBUTE_REFERENCE); addIssue(issue); } } @@ -1175,7 +1214,7 @@ void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Connection in model '" + model->name() + "' specifies '" + iterInfo[1] + "' as variable_2 but the corresponding component_2 is invalid."); issue->mPimpl->mItem->mPimpl->setConnection(variable1, variable2); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::CONNECTION_COMPONENT2); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::CONNECTION_COMPONENT2_ATTRIBUTE); addIssue(issue); } // Set the variable equivalence relationship for this variable pair. @@ -1209,7 +1248,7 @@ ComponentPtr Parser::ParserImpl::loadComponentRef(const ModelPtr &model, const X auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Encapsulation in model '" + model->name() + "' specifies '" + parentComponentName + "' as a component in a component_ref but it does not exist in the model."); issue->mPimpl->mItem->mPimpl->setEncapsulation(model); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::COMPONENT_REF_COMPONENT); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::COMPONENT_REF_COMPONENT_ATTRIBUTE_REFERENCE); addIssue(issue); } } else if (isIdAttribute(attribute, mParsing1XVersion)) { @@ -1218,7 +1257,7 @@ ComponentPtr Parser::ParserImpl::loadComponentRef(const ModelPtr &model, const X auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Encapsulation in model '" + model->name() + "' has an invalid component_ref attribute '" + attribute->name() + "'."); issue->mPimpl->mItem->mPimpl->setEncapsulation(model); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::COMPONENT_REF_COMPONENT); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::COMPONENT_REF_COMPONENT_ATTRIBUTE); addIssue(issue); } attribute = attribute->next(); @@ -1227,7 +1266,7 @@ ComponentPtr Parser::ParserImpl::loadComponentRef(const ModelPtr &model, const X auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Encapsulation in model '" + model->name() + "' does not have a valid component attribute in a component_ref element."); issue->mPimpl->mItem->mPimpl->setEncapsulation(model); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::COMPONENT_REF_COMPONENT); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::COMPONENT_REF_COMPONENT_ATTRIBUTE); addIssue(issue); } else if (parentComponent) { parentComponent->setEncapsulationId(encapsulationId); @@ -1352,7 +1391,7 @@ void Parser::ParserImpl::loadImport(ImportSourcePtr &importSource, const ModelPt auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Import from '" + node->attribute("href") + "' has an invalid attribute '" + attribute->name() + "'."); issue->mPimpl->mItem->mPimpl->setImportSource(importSource); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_ATTRIBUTE); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_HREF); addIssue(issue); } attribute = attribute->next(); @@ -1467,7 +1506,7 @@ void Parser::ParserImpl::loadResetChild(const std::string &childType, const Rese auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Reset in component '" + component->name() + "' referencing variable '" + variableName + "' and test_variable '" + testVariableName + "' has an unexpected attribute in the " + childType + " block of '" + childAttribute->name() + "'."); issue->mPimpl->mItem->mPimpl->setReset(reset); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_TEST_VALUE); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_ELEMENT); addIssue(issue); } childAttribute = childAttribute->next(); @@ -1491,7 +1530,7 @@ void Parser::ParserImpl::loadResetChild(const std::string &childType, const Rese auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("The " + childType + " in the reset in component '" + component->name() + "' referencing variable '" + variableName + "' and test_variable '" + testVariableName + "' should have a MathML block as a child."); issue->mPimpl->mItem->mPimpl->setReset(reset); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_TEST_VALUE); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_CHILD); addIssue(issue); } } @@ -1526,7 +1565,7 @@ void Parser::ParserImpl::checkResetChildMultiplicity(size_t count, const std::st issue->mPimpl->setDescription("Reset in component '" + component->name() + "' referencing variable '" + variableName + "' and test_variable '" + testVariableName + "' has " + convertToString(count) + " " + childType + " blocks."); issue->mPimpl->mItem->mPimpl->setReset(reset); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_TEST_VALUE); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_CHILD); addIssue(issue); } if (count == 0) { @@ -1534,7 +1573,11 @@ void Parser::ParserImpl::checkResetChildMultiplicity(size_t count, const std::st issue->mPimpl->setDescription("Reset in component '" + component->name() + "' referencing variable '" + variableName + "' and test_variable '" + testVariableName + "' does not have a " + childType + " block defined."); issue->mPimpl->mItem->mPimpl->setReset(reset); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_TEST_VALUE); + if (childType == "reset_value") { + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_RESET_VALUE_CHILD); + } else { + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_TEST_VALUE_CHILD); + } addIssue(issue); } } @@ -1555,7 +1598,7 @@ void Parser::ParserImpl::loadReset(const ResetPtr &reset, const ComponentPtr &co auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Reset referencing variable '" + variableReference + "' is not a valid reference for a variable in component '" + component->name() + "'."); issue->mPimpl->mItem->mPimpl->setReset(reset); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_VARIABLE_REF); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_VARIABLE_REFERENCE); addIssue(issue); } else { reset->setVariable(referencedVariable); @@ -1567,7 +1610,7 @@ void Parser::ParserImpl::loadReset(const ResetPtr &reset, const ComponentPtr &co auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Reset referencing test_variable '" + testVariableReference + "' is not a valid reference for a variable in component '" + component->name() + "'."); issue->mPimpl->mItem->mPimpl->setReset(reset); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_TEST_VARIABLE_REF); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_TEST_VARIABLE_REFERENCE); addIssue(issue); } else { reset->setTestVariable(testVariable); @@ -1585,7 +1628,7 @@ void Parser::ParserImpl::loadReset(const ResetPtr &reset, const ComponentPtr &co auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Reset in component '" + component->name() + "' referencing variable '" + variableName + "' has an out of range integer order value '" + attribute->value() + "'."); issue->mPimpl->mItem->mPimpl->setReset(reset); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_ORDER); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_ORDER_VALUE); addIssue(issue); } } else { // This value won't be saved for validation later, so it does need to be reported now. @@ -1596,7 +1639,7 @@ void Parser::ParserImpl::loadReset(const ResetPtr &reset, const ComponentPtr &co auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Reset in component '" + component->name() + "' referencing variable '" + variableName + "' has a non-integer order value '" + attribute->value() + "'."); issue->mPimpl->mItem->mPimpl->setReset(reset); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_ORDER); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_ORDER_VALUE); addIssue(issue); } } else if (attribute->isType("id")) { @@ -1605,7 +1648,7 @@ void Parser::ParserImpl::loadReset(const ResetPtr &reset, const ComponentPtr &co auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Reset in component '" + component->name() + "' has an invalid attribute '" + attribute->name() + "'."); issue->mPimpl->mItem->mPimpl->setReset(reset); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_ATTRIBUTE); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_ATTRIBUTE_REQUIRED); addIssue(issue); } attribute = attribute->next(); @@ -1617,7 +1660,7 @@ void Parser::ParserImpl::loadReset(const ResetPtr &reset, const ComponentPtr &co auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Reset in component '" + component->name() + "' does not have its order set."); issue->mPimpl->mItem->mPimpl->setReset(reset); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_ORDER); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_ORDER_VALUE); addIssue(issue); } diff --git a/src/validator.cpp b/src/validator.cpp index 47c9dd65c..e9e3324a6 100644 --- a/src/validator.cpp +++ b/src/validator.cpp @@ -927,7 +927,7 @@ void Validator::ValidatorImpl::validateComponent(const ComponentPtr &component, auto issue = makeIssueIllegalIdentifier(componentRef); issue->mPimpl->setDescription(descriptionPrefix + "'" + componentName + "' does not have a valid component_ref attribute. " + issue->description()); issue->mPimpl->mItem->mPimpl->setComponent(component); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_COMPONENT_COMPONENT_REF); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_COMPONENT_COMPONENT_REFERENCE); addIssue(issue); } @@ -943,7 +943,7 @@ void Validator::ValidatorImpl::validateComponent(const ComponentPtr &component, auto description = formDescriptionOfCyclicDependency(history, "resolve"); IssuePtr issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription(description); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_COMPONENT_COMPONENT_REF); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_COMPONENT_COMPONENT_REFERENCE); issue->mPimpl->mItem->mPimpl->setImportSource(component->importSource()); addIssue(issue); } else { @@ -957,7 +957,7 @@ void Validator::ValidatorImpl::validateComponent(const ComponentPtr &component, auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription(descriptionPrefix + "'" + componentName + "' refers to component '" + componentRef + "' which does not appear in '" + component->importSource()->url() + "'."); issue->mPimpl->mItem->mPimpl->setComponent(component); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_COMPONENT_COMPONENT_REF); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_COMPONENT_COMPONENT_REFERENCE_TARGET); addIssue(issue); } } @@ -1052,7 +1052,7 @@ void Validator::ValidatorImpl::validateUnits(const UnitsPtr &units, History &his auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Cyclic units exist: " + des + "."); issue->mPimpl->mItem->mPimpl->setUnits(units); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNIT_CIRCULAR_REF); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNIT_UNITS_CIRCULAR_REFERENCE); addIssue(issue); } history.pop_back(); @@ -1095,7 +1095,7 @@ void Validator::ValidatorImpl::validateUnits(const UnitsPtr &units, History &his auto issue = makeIssueIllegalIdentifier(unitsRef); issue->mPimpl->setDescription("Imported units '" + unitsName + "' does not have a valid units_ref attribute. " + issue->description()); issue->mPimpl->mItem->mPimpl->setUnits(units); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_UNITS_REF); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_UNITS_UNITS_REFERENCE); addIssue(issue); } @@ -1112,7 +1112,7 @@ void Validator::ValidatorImpl::validateUnits(const UnitsPtr &units, History &his auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription(description); issue->mPimpl->mItem->mPimpl->setModel(model); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_UNITS_REF); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_UNITS_UNITS_REFERENCE); addIssue(issue); } } @@ -1132,7 +1132,7 @@ void Validator::ValidatorImpl::validateUnits(const UnitsPtr &units, History &his IssuePtr issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription(description); issue->mPimpl->mItem->mPimpl->setUnits(units); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_UNITS_REF); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_UNITS_UNITS_REFERENCE); addIssue(issue); } else { modelsVisited.push_back(importSourceModel); @@ -1144,7 +1144,7 @@ void Validator::ValidatorImpl::validateUnits(const UnitsPtr &units, History &his auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Imported units '" + units->name() + "' refers to units '" + unitsRef + "' which does not appear in '" + importSource->url() + "'."); issue->mPimpl->mItem->mPimpl->setUnits(units); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_UNITS_REF); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_UNITS_UNITS_REFERENCE); addIssue(issue); } } @@ -1224,14 +1224,14 @@ void Validator::ValidatorImpl::validateUnitsUnitsItem(size_t index, const UnitsP auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Units reference '" + reference + "' in units '" + units->name() + "' is not a valid reference to a local units or a standard unit type."); issue->mPimpl->mItem->mPimpl->setUnitsItem(UnitsItem::create(units, index)); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNIT_UNITS_REF); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNIT_UNITS_REFERENCE); addIssue(issue); } } else { auto issue = makeIssueIllegalIdentifier(reference); issue->mPimpl->setDescription("Unit in units '" + units->name() + "' does not have a valid units reference. The reference given is '" + reference + "'. " + issue->description()); issue->mPimpl->mItem->mPimpl->setUnitsItem(UnitsItem::create(units, index)); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNIT_UNITS_REF); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNIT_UNITS_REFERENCE); addIssue(issue); } // Check for a valid identifier. @@ -1248,7 +1248,7 @@ void Validator::ValidatorImpl::validateUnitsUnitsItem(size_t index, const UnitsP auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Prefix '" + prefix + "' of a unit referencing '" + reference + "' in units '" + units->name() + "' is not a valid integer or an SI prefix."); issue->mPimpl->mItem->mPimpl->setUnitsItem(UnitsItem::create(units, index)); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNIT_PREFIX); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNIT_ATTRIBUTE_PREFIX_VALUE); addIssue(issue); } else { try { @@ -1258,7 +1258,7 @@ void Validator::ValidatorImpl::validateUnitsUnitsItem(size_t index, const UnitsP auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Prefix '" + prefix + "' of a unit referencing '" + reference + "' in units '" + units->name() + "' is out of the integer range."); issue->mPimpl->mItem->mPimpl->setUnitsItem(UnitsItem::create(units, index)); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNIT_PREFIX); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNIT_ATTRIBUTE_PREFIX_VALUE); addIssue(issue); } } @@ -1275,7 +1275,7 @@ void Validator::ValidatorImpl::validateVariable(const VariablePtr &variable, con auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Component '" + component->name() + "' contains multiple variables with the name '" + variableName + "'. Valid variable names must be unique to their component."); issue->mPimpl->mItem->mPimpl->setComponent(component); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::VARIABLE_NAME); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::VARIABLE_NAME_UNIQUE); addIssue(issue); } } @@ -1285,7 +1285,7 @@ void Validator::ValidatorImpl::validateVariable(const VariablePtr &variable, con auto issue = makeIssueIllegalIdentifier(variableName); issue->mPimpl->setDescription("Variable '" + variableName + "' in component '" + component->name() + "' does not have a valid name attribute. " + issue->description()); issue->mPimpl->mItem->mPimpl->setVariable(variable); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::VARIABLE_NAME); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::VARIABLE_ATTRIBUTE_REQUIRED); addIssue(issue); } // Check for a valid identifier. @@ -1301,7 +1301,7 @@ void Validator::ValidatorImpl::validateVariable(const VariablePtr &variable, con auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Variable '" + variableName + "' in component '" + component->name() + "' does not have any units specified."); issue->mPimpl->mItem->mPimpl->setVariable(variable); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::VARIABLE_UNITS); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::VARIABLE_UNITS_VALUE); addIssue(issue); } else { std::string unitsName = variable->units()->name(); @@ -1309,7 +1309,7 @@ void Validator::ValidatorImpl::validateVariable(const VariablePtr &variable, con auto issue = makeIssueIllegalIdentifier(unitsName); issue->mPimpl->setDescription("Variable '" + variableName + "' in component '" + component->name() + "' does not have a valid units attribute. The attribute given is '" + unitsName + "'. " + issue->description()); issue->mPimpl->mItem->mPimpl->setVariable(variable); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::VARIABLE_UNITS); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::VARIABLE_UNITS_VALUE); addIssue(issue); } else if (!isStandardUnitName(unitsName)) { ModelPtr model = owningModel(component); @@ -1317,7 +1317,7 @@ void Validator::ValidatorImpl::validateVariable(const VariablePtr &variable, con auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Variable '" + variableName + "' in component '" + component->name() + "' has a units reference '" + unitsName + "' which is neither standard nor defined in the parent model."); issue->mPimpl->mItem->mPimpl->setVariable(variable); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::VARIABLE_UNITS); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::VARIABLE_UNITS_VALUE); addIssue(issue); } } @@ -1329,7 +1329,7 @@ void Validator::ValidatorImpl::validateVariable(const VariablePtr &variable, con auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Variable '" + variableName + "' in component '" + component->name() + "' has an invalid interface attribute value '" + interfaceType + "'."); issue->mPimpl->mItem->mPimpl->setVariable(variable); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::VARIABLE_INTERFACE); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::VARIABLE_INTERFACE_VALUE); addIssue(issue); } } @@ -1343,7 +1343,7 @@ void Validator::ValidatorImpl::validateVariable(const VariablePtr &variable, con auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Variable '" + variableName + "' in component '" + component->name() + "' has an invalid initial value '" + initialValue + "'. Initial values must be a real number string or a variable reference."); issue->mPimpl->mItem->mPimpl->setVariable(variable); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::VARIABLE_INITIAL_VALUE); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::VARIABLE_INITIAL_VALUE_VALUE); addIssue(issue); } } @@ -1440,49 +1440,49 @@ void Validator::ValidatorImpl::validateReset(const ResetPtr &reset, const Compon auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription(description + "does not have an order set."); issue->mPimpl->mItem->mPimpl->setComponent(component); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_ORDER); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_ORDER_VALUE); addIssue(issue); } if (noVariable) { auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription(description + "does not reference a variable."); issue->mPimpl->mItem->mPimpl->setReset(reset); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_VARIABLE_REF); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_VARIABLE_REFERENCE); addIssue(issue); } if (noTestVariable) { auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription(description + "does not reference a test_variable."); issue->mPimpl->mItem->mPimpl->setReset(reset); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_TEST_VARIABLE_REF); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_TEST_VARIABLE_REFERENCE); addIssue(issue); } if (noTestValue) { auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription(description + "does not have a test_value specified."); issue->mPimpl->mItem->mPimpl->setReset(reset); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_TEST_VALUE); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::TEST_VALUE_ELEMENT); addIssue(issue); } if (noResetValue) { auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription(description + "does not have a reset_value specified."); issue->mPimpl->mItem->mPimpl->setReset(reset); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_RESET_VALUE); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_VALUE_ELEMENT); addIssue(issue); } if (varOutsideComponent) { auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription(description + "refers to a variable '" + reset->variable()->name() + "' in a different component '" + varParentName + "'."); issue->mPimpl->mItem->mPimpl->setReset(reset); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_VARIABLE_REF); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_VARIABLE_REFERENCE); addIssue(issue); } if (testVarOutsideComponent) { auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription(description + "refers to a test_variable '" + reset->testVariable()->name() + "' in a different component '" + testVarParentName + "'."); issue->mPimpl->mItem->mPimpl->setReset(reset); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_TEST_VARIABLE_REF); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_TEST_VARIABLE_REFERENCE); addIssue(issue); } } @@ -1578,7 +1578,7 @@ bool Validator::ValidatorImpl::validateCnUnits(const ComponentPtr &component, co IssuePtr issue = makeIssueIllegalIdentifier(unitsName); issue->mPimpl->setDescription("Math cn element with the value '" + textNode + "' does not have a valid cellml:units attribute. " + issue->description()); issue->mPimpl->mItem->mPimpl->setMath(component); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::MATH_CN_UNITS); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::MATH_CN_UNITS_ATTRIBUTE); addIssue(issue); return false; @@ -1634,7 +1634,7 @@ void Validator::ValidatorImpl::validateAndCleanCnNode(const XmlNodePtr &node, co auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Math has a " + node->name() + " element with a cellml:units attribute '" + unitsName + "' that is not a valid reference to units in the model '" + model->name() + "' or a standard unit."); issue->mPimpl->mItem->mPimpl->setMath(component); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::MATH_CN_UNITS); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::MATH_CN_UNITS_ATTRIBUTE_REFERENCE); addIssue(issue); } } @@ -1660,7 +1660,7 @@ void Validator::ValidatorImpl::validateAndCleanCiNode(const XmlNodePtr &node, co auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("MathML ci element has the child text '" + textInNode + "' which does not correspond with any variable names present in component '" + component->name() + "'."); issue->mPimpl->mItem->mPimpl->setMath(component); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::MATH_CI_VARIABLE_REF); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::MATH_CI_VARIABLE_REFERENCE); addIssue(issue); } } @@ -2115,7 +2115,7 @@ void Validator::ValidatorImpl::validateMathMLElementsChildrenAndSiblings(const X if (!ok) { addMathmlIssue("Math has a 'ci' element with no identifier as a child.", - Issue::ReferenceRule::MATH_CI_VARIABLE_REF, + Issue::ReferenceRule::MATH_CI_VARIABLE_REFERENCE, component); } } else if (node->isMathmlElement("cn")) { @@ -2293,7 +2293,7 @@ void Validator::ValidatorImpl::validateVariableInterface(const VariablePtr &vari IssuePtr err = Issue::IssueImpl::create(); err->mPimpl->setDescription("The equivalence between '" + variable->name() + "' in component '" + componentName + "' and '" + equivalentVariable->name() + "' in component '" + equivalentComponentName + "' is invalid. Component '" + componentName + "' and '" + equivalentComponentName + "' are neither siblings nor in a parent/child relationship."); err->mPimpl->mItem->mPimpl->setMapVariables(variable, equivalentVariable); - err->mPimpl->setReferenceRule(Issue::ReferenceRule::MAP_VARIABLES_AVAILABLE_INTERFACE); + err->mPimpl->setReferenceRule(Issue::ReferenceRule::MAP_VARIABLES_ELEMENT); addIssue(err); } } @@ -2308,7 +2308,7 @@ void Validator::ValidatorImpl::validateVariableInterface(const VariablePtr &vari err->mPimpl->setDescription("Variable '" + variable->name() + "' in component '" + componentName + "' has an interface type set to '" + interfaceTypeString + "' which is not the correct interface type for this variable. The interface type required is '" + interfaceTypeToString.find(interfaceType)->second + "'."); } err->mPimpl->mItem->mPimpl->setVariable(variable); - err->mPimpl->setReferenceRule(Issue::ReferenceRule::MAP_VARIABLES_AVAILABLE_INTERFACE); + err->mPimpl->setReferenceRule(Issue::ReferenceRule::MAP_VARIABLES_ELEMENT); addIssue(err); } } @@ -2350,7 +2350,7 @@ void Validator::ValidatorImpl::validateEquivalenceUnits(const ModelPtr &model, c IssuePtr err = Issue::IssueImpl::create(); err->mPimpl->setDescription("Variable '" + variable->name() + "' in component '" + parentComponent->name() + "' has units of '" + variable->units()->name() + "' and an equivalent variable '" + equivalentVariable->name() + "' in component '" + equivalentComponent->name() + "' with non-matching units of '" + equivalentVariable->units()->name() + "'. The mismatch is: " + hints); err->mPimpl->mItem->mPimpl->setMapVariables(variable, equivalentVariable); - err->mPimpl->setReferenceRule(Issue::ReferenceRule::MAP_VARIABLES_IDENTICAL_UNIT_REDUCTION); + err->mPimpl->setReferenceRule(Issue::ReferenceRule::MAP_VARIABLES_ELEMENT); addIssue(err); } } @@ -2366,7 +2366,7 @@ void Validator::ValidatorImpl::validateEquivalenceStructure(const VariablePtr &v IssuePtr err = Issue::IssueImpl::create(); err->mPimpl->setDescription("Variable '" + equivalentVariable->name() + "' is an equivalent variable to '" + variable->name() + "' but '" + equivalentVariable->name() + "' has no parent component."); err->mPimpl->mItem->mPimpl->setMapVariables(variable, equivalentVariable); - err->mPimpl->setReferenceRule(Issue::ReferenceRule::MAP_VARIABLES_VARIABLE1); + err->mPimpl->setReferenceRule(Issue::ReferenceRule::MAP_VARIABLES_VARIABLE1_ATTRIBUTE); addIssue(err); } } @@ -2404,7 +2404,7 @@ IssuePtr Validator::ValidatorImpl::makeIssueIllegalIdentifier(const std::string { auto issue = Issue::IssueImpl::create(); auto referenceRule = validateCellmlIdentifier(name); - issue->mPimpl->setReferenceRule(referenceRule); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML_ID_ATTRIBUTE); if (referenceRule == Issue::ReferenceRule::DATA_REPR_IDENTIFIER_AT_LEAST_ONE_ALPHANUM) { // One or more alphabetic characters. @@ -2555,7 +2555,7 @@ void Validator::ValidatorImpl::checkUniqueIds(const ModelPtr &model) } } auto issue = Issue::IssueImpl::create(); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::DATA_REPR_IDENTIFIER_IDENTICAL); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML_ID_ATTRIBUTE); issue->mPimpl->setDescription(desc); issue->mPimpl->mItem->mPimpl->setModel(model); addIssue(issue); From 42b3bc64a4bbeb710ba4d25dbd26173bd8a08abf Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Tue, 9 Apr 2024 17:45:05 +0100 Subject: [PATCH 14/50] Modify invalidModelWithTextInAllElements test to cover empty componet and variable references in connections. --- tests/parser/parser.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/parser/parser.cpp b/tests/parser/parser.cpp index 5a962282d..912f2efd5 100644 --- a/tests/parser/parser.cpp +++ b/tests/parser/parser.cpp @@ -1514,9 +1514,9 @@ TEST(Parser, invalidModelWithTextInAllElements) " \n" " \n" " \n" - " \n" + " \n" " finn\n" - " \n" + " \n" " trooper\n" " \n" " \n" @@ -1543,12 +1543,12 @@ TEST(Parser, invalidModelWithTextInAllElements) "Encapsulation in model 'starwars' has an invalid non-whitespace child text element '\n awakens\n '.", "Encapsulation in model 'starwars' has an invalid non-whitespace child text element '\n force\n '.", "Encapsulation in model 'starwars' specifies 'ship' as a parent component_ref but it does not have any children.", - "Connection in model 'starwars' does not specify a component_1 in a connection element.", - "Connection in model 'starwars' does not specify a component_2 in a connection element.", + "Connection in model 'starwars' does not have a valid component_1 in a connection element.", + "Connection in model 'starwars' does not have a valid component_2 in a connection element.", "Connection in model 'starwars' has an invalid non-whitespace child text element '\n finn\n '.", "Connection in model 'starwars' has an invalid non-whitespace child text element '\n trooper\n '.", - "Connection in model 'starwars' does not specify a variable_1 in a map_variables element.", - "Connection in model 'starwars' does not specify a variable_2 in a map_variables element.", + "Connection in model 'starwars' does not have a valid variable_1 in a map_variables element.", + "Connection in model 'starwars' does not have a valid variable_2 in a map_variables element.", "Connection in model 'starwars' specifies '' as variable_1 but the corresponding component_1 is invalid.", "Connection in model 'starwars' specifies '' as variable_2 but the corresponding component_2 is invalid.", }; From e1d73c05613dfab4275914463176d947a1222d09 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Tue, 9 Apr 2024 18:16:51 +0100 Subject: [PATCH 15/50] Update reference rule for javascript bindings. --- src/bindings/javascript/issue.cpp | 211 +++++++++++++++++------------- 1 file changed, 122 insertions(+), 89 deletions(-) diff --git a/src/bindings/javascript/issue.cpp b/src/bindings/javascript/issue.cpp index fba9ddbdc..48b55d823 100644 --- a/src/bindings/javascript/issue.cpp +++ b/src/bindings/javascript/issue.cpp @@ -30,104 +30,137 @@ EMSCRIPTEN_BINDINGS(libcellml_issue) { ; enum_("Issue.ReferenceRule") - .value("UNDEFINED", libcellml::Issue::ReferenceRule::UNDEFINED) - .value("XML", libcellml::Issue::ReferenceRule::XML) - .value("DATA_REPR_IDENTIFIER_UNICODE", libcellml::Issue::ReferenceRule::DATA_REPR_IDENTIFIER_UNICODE) - .value("DATA_REPR_IDENTIFIER_LATIN_ALPHANUM", libcellml::Issue::ReferenceRule::DATA_REPR_IDENTIFIER_LATIN_ALPHANUM) + .value("ANALYSER_EQUATION_NOT_EQUALITY_STATEMENT", libcellml::Issue::ReferenceRule::ANALYSER_EQUATION_NOT_EQUALITY_STATEMENT) + .value("ANALYSER_EXTERNAL_VARIABLE_DIFFERENT_MODEL", libcellml::Issue::ReferenceRule::ANALYSER_EXTERNAL_VARIABLE_DIFFERENT_MODEL) + .value("ANALYSER_EXTERNAL_VARIABLE_USE_PRIMARY_VARIABLE", libcellml::Issue::ReferenceRule::ANALYSER_EXTERNAL_VARIABLE_USE_PRIMARY_VARIABLE) + .value("ANALYSER_EXTERNAL_VARIABLE_VOI", libcellml::Issue::ReferenceRule::ANALYSER_EXTERNAL_VARIABLE_VOI) + .value("ANALYSER_ODE_NOT_FIRST_ORDER", libcellml::Issue::ReferenceRule::ANALYSER_ODE_NOT_FIRST_ORDER) + .value("ANALYSER_STATE_NOT_INITIALISED", libcellml::Issue::ReferenceRule::ANALYSER_STATE_NOT_INITIALISED) + .value("ANALYSER_STATE_RATE_AS_ALGEBRAIC", libcellml::Issue::ReferenceRule::ANALYSER_STATE_RATE_AS_ALGEBRAIC) + .value("ANALYSER_UNITS", libcellml::Issue::ReferenceRule::ANALYSER_UNITS) + .value("ANALYSER_UNLINKED_UNITS", libcellml::Issue::ReferenceRule::ANALYSER_UNLINKED_UNITS) + .value("ANALYSER_VARIABLE_COMPUTED_MORE_THAN_ONCE", libcellml::Issue::ReferenceRule::ANALYSER_VARIABLE_COMPUTED_MORE_THAN_ONCE) + .value("ANALYSER_VARIABLE_INITIALISED_MORE_THAN_ONCE", libcellml::Issue::ReferenceRule::ANALYSER_VARIABLE_INITIALISED_MORE_THAN_ONCE) + .value("ANALYSER_VARIABLE_NON_CONSTANT_INITIALISATION", libcellml::Issue::ReferenceRule::ANALYSER_VARIABLE_NON_CONSTANT_INITIALISATION) + .value("ANALYSER_VARIABLE_UNUSED", libcellml::Issue::ReferenceRule::ANALYSER_VARIABLE_UNUSED) + .value("ANALYSER_VOI_INITIALISED", libcellml::Issue::ReferenceRule::ANALYSER_VOI_INITIALISED) + .value("ANALYSER_VOI_SEVERAL", libcellml::Issue::ReferenceRule::ANALYSER_VOI_SEVERAL) + .value("ANNOTATOR_ID_NOT_FOUND", libcellml::Issue::ReferenceRule::ANNOTATOR_ID_NOT_FOUND) + .value("ANNOTATOR_ID_NOT_UNIQUE", libcellml::Issue::ReferenceRule::ANNOTATOR_ID_NOT_UNIQUE) + .value("ANNOTATOR_INCONSISTENT_TYPE", libcellml::Issue::ReferenceRule::ANNOTATOR_INCONSISTENT_TYPE) + .value("ANNOTATOR_NO_MODEL", libcellml::Issue::ReferenceRule::ANNOTATOR_NO_MODEL) + .value("ANNOTATOR_NULL_MODEL", libcellml::Issue::ReferenceRule::ANNOTATOR_NULL_MODEL) + .value("COMPONENT_CHILD", libcellml::Issue::ReferenceRule::COMPONENT_CHILD) + .value("COMPONENT_ELEMENT", libcellml::Issue::ReferenceRule::COMPONENT_ELEMENT) + .value("COMPONENT_NAME", libcellml::Issue::ReferenceRule::COMPONENT_NAME) + .value("COMPONENT_NAME_UNIQUE", libcellml::Issue::ReferenceRule::COMPONENT_NAME_UNIQUE) + .value("COMPONENT_NAME_VALUE", libcellml::Issue::ReferenceRule::COMPONENT_NAME_VALUE) + .value("COMPONENT_REF_CHILD", libcellml::Issue::ReferenceRule::COMPONENT_REF_CHILD) + .value("COMPONENT_REF_COMPONENT_ATTRIBUTE", libcellml::Issue::ReferenceRule::COMPONENT_REF_COMPONENT_ATTRIBUTE) + .value("COMPONENT_REF_COMPONENT_ATTRIBUTE_REFERENCE", libcellml::Issue::ReferenceRule::COMPONENT_REF_COMPONENT_ATTRIBUTE_REFERENCE) + .value("COMPONENT_REF_COMPONENT_ATTRIBUTE_UNIQUE", libcellml::Issue::ReferenceRule::COMPONENT_REF_COMPONENT_ATTRIBUTE_UNIQUE) + .value("COMPONENT_REF_ELEMENT", libcellml::Issue::ReferenceRule::COMPONENT_REF_ELEMENT) + .value("CONNECTION_CHILD", libcellml::Issue::ReferenceRule::CONNECTION_CHILD) + .value("CONNECTION_COMPONENT1_ATTRIBUTE", libcellml::Issue::ReferenceRule::CONNECTION_COMPONENT1_ATTRIBUTE) + .value("CONNECTION_COMPONENT1_ATTRIBUTE_REFERENCE", libcellml::Issue::ReferenceRule::CONNECTION_COMPONENT1_ATTRIBUTE_REFERENCE) + .value("CONNECTION_COMPONENT2_ATTRIBUTE", libcellml::Issue::ReferenceRule::CONNECTION_COMPONENT2_ATTRIBUTE) + .value("CONNECTION_COMPONENT2_ATTRIBUTE_REFERENCE", libcellml::Issue::ReferenceRule::CONNECTION_COMPONENT2_ATTRIBUTE_REFERENCE) + .value("CONNECTION_ELEMENT", libcellml::Issue::ReferenceRule::CONNECTION_ELEMENT) + .value("CONNECTION_EXCLUDE_SELF", libcellml::Issue::ReferenceRule::CONNECTION_EXCLUDE_SELF) + .value("CONNECTION_UNIQUE", libcellml::Issue::ReferenceRule::CONNECTION_UNIQUE) .value("DATA_REPR_IDENTIFIER_AT_LEAST_ONE_ALPHANUM", libcellml::Issue::ReferenceRule::DATA_REPR_IDENTIFIER_AT_LEAST_ONE_ALPHANUM) .value("DATA_REPR_IDENTIFIER_BEGIN_EURO_NUM", libcellml::Issue::ReferenceRule::DATA_REPR_IDENTIFIER_BEGIN_EURO_NUM) - .value("DATA_REPR_IDENTIFIER_IDENTICAL", libcellml::Issue::ReferenceRule::DATA_REPR_IDENTIFIER_IDENTICAL) - .value("DATA_REPR_INT_BASE10", libcellml::Issue::ReferenceRule::DATA_REPR_INT_BASE10) - .value("DATA_REPR_INT_SIGN", libcellml::Issue::ReferenceRule::DATA_REPR_INT_SIGN) - .value("DATA_REPR_INT_DIGIT", libcellml::Issue::ReferenceRule::DATA_REPR_INT_DIGIT) - .value("DATA_REPR_BASIC_REAL_BASE10", libcellml::Issue::ReferenceRule::DATA_REPR_BASIC_REAL_BASE10) - .value("DATA_REPR_BASIC_REAL_SIGN", libcellml::Issue::ReferenceRule::DATA_REPR_BASIC_REAL_SIGN) - .value("DATA_REPR_BASIC_REAL_DECIMAL", libcellml::Issue::ReferenceRule::DATA_REPR_BASIC_REAL_DECIMAL) - .value("DATA_REPR_BASIC_REAL_DIGIT", libcellml::Issue::ReferenceRule::DATA_REPR_BASIC_REAL_DIGIT) - .value("DATA_REPR_REAL_BASE10", libcellml::Issue::ReferenceRule::DATA_REPR_REAL_BASE10) - .value("DATA_REPR_REAL_SIGNIFICAND", libcellml::Issue::ReferenceRule::DATA_REPR_REAL_SIGNIFICAND) - .value("DATA_REPR_REAL_EXPONENT", libcellml::Issue::ReferenceRule::DATA_REPR_REAL_EXPONENT) - .value("MODEL_ELEMENT", libcellml::Issue::ReferenceRule::MODEL_ELEMENT) - .value("MODEL_NAME", libcellml::Issue::ReferenceRule::MODEL_NAME) - .value("MODEL_CHILD", libcellml::Issue::ReferenceRule::MODEL_CHILD) - .value("MODEL_MORE_THAN_ONE_ENCAPSULATION", libcellml::Issue::ReferenceRule::MODEL_MORE_THAN_ONE_ENCAPSULATION) - .value("IMPORT_ATTRIBUTE", libcellml::Issue::ReferenceRule::IMPORT_ATTRIBUTE) - .value("IMPORT_HREF", libcellml::Issue::ReferenceRule::IMPORT_HREF) + .value("DATA_REPR_IDENTIFIER_LATIN_ALPHANUM", libcellml::Issue::ReferenceRule::DATA_REPR_IDENTIFIER_LATIN_ALPHANUM) + .value("ENCAPSULATION_CHILD", libcellml::Issue::ReferenceRule::ENCAPSULATION_CHILD) + .value("ENCAPSULATION_ELEMENT", libcellml::Issue::ReferenceRule::ENCAPSULATION_ELEMENT) + .value("IMPORTER_ERROR_IMPORTING_UNITS", libcellml::Issue::ReferenceRule::IMPORTER_ERROR_IMPORTING_UNITS) + .value("IMPORTER_MISSING_COMPONENT", libcellml::Issue::ReferenceRule::IMPORTER_MISSING_COMPONENT) + .value("IMPORTER_MISSING_FILE", libcellml::Issue::ReferenceRule::IMPORTER_MISSING_FILE) + .value("IMPORTER_MISSING_UNITS", libcellml::Issue::ReferenceRule::IMPORTER_MISSING_UNITS) + .value("IMPORTER_NULL_MODEL", libcellml::Issue::ReferenceRule::IMPORTER_NULL_MODEL) + .value("IMPORTER_UNDEFINED_MODEL", libcellml::Issue::ReferenceRule::IMPORTER_UNDEFINED_MODEL) + .value("IMPORTER_UNRESOLVED_IMPORTS", libcellml::Issue::ReferenceRule::IMPORTER_UNRESOLVED_IMPORTS) .value("IMPORT_CHILD", libcellml::Issue::ReferenceRule::IMPORT_CHILD) - .value("IMPORT_EQUIVALENT", libcellml::Issue::ReferenceRule::IMPORT_EQUIVALENT) - .value("IMPORT_UNITS_NAME", libcellml::Issue::ReferenceRule::IMPORT_UNITS_NAME) - .value("IMPORT_UNITS_NAME_UNIQUE", libcellml::Issue::ReferenceRule::IMPORT_UNITS_NAME_UNIQUE) - .value("IMPORT_UNITS_REF", libcellml::Issue::ReferenceRule::IMPORT_UNITS_REF) + .value("IMPORT_COMPONENT_COMPONENT_REFERENCE", libcellml::Issue::ReferenceRule::IMPORT_COMPONENT_COMPONENT_REFERENCE) + .value("IMPORT_COMPONENT_COMPONENT_REFERENCE_TARGET", libcellml::Issue::ReferenceRule::IMPORT_COMPONENT_COMPONENT_REFERENCE_TARGET) + .value("IMPORT_COMPONENT_COMPONENT_REFERENCE_VALUE", libcellml::Issue::ReferenceRule::IMPORT_COMPONENT_COMPONENT_REFERENCE_VALUE) + .value("IMPORT_COMPONENT_ELEMENT", libcellml::Issue::ReferenceRule::IMPORT_COMPONENT_ELEMENT) .value("IMPORT_COMPONENT_NAME", libcellml::Issue::ReferenceRule::IMPORT_COMPONENT_NAME) .value("IMPORT_COMPONENT_NAME_UNIQUE", libcellml::Issue::ReferenceRule::IMPORT_COMPONENT_NAME_UNIQUE) - .value("IMPORT_COMPONENT_COMPONENT_REF", libcellml::Issue::ReferenceRule::IMPORT_COMPONENT_COMPONENT_REF) - .value("UNITS_ATTRIBUTE", libcellml::Issue::ReferenceRule::UNITS_ATTRIBUTE) - .value("UNITS_NAME", libcellml::Issue::ReferenceRule::UNITS_NAME) - .value("UNITS_NAME_UNIQUE", libcellml::Issue::ReferenceRule::UNITS_NAME_UNIQUE) - .value("UNITS_STANDARD", libcellml::Issue::ReferenceRule::UNITS_STANDARD) - .value("UNITS_CHILD", libcellml::Issue::ReferenceRule::UNITS_CHILD) - .value("UNIT_ATTRIBUTE", libcellml::Issue::ReferenceRule::UNIT_ATTRIBUTE) - .value("UNIT_UNITS_REF", libcellml::Issue::ReferenceRule::UNIT_UNITS_REF) - .value("UNIT_CIRCULAR_REF", libcellml::Issue::ReferenceRule::UNIT_CIRCULAR_REF) - .value("UNIT_OPTIONAL_ATTRIBUTE", libcellml::Issue::ReferenceRule::UNIT_OPTIONAL_ATTRIBUTE) - .value("UNIT_PREFIX", libcellml::Issue::ReferenceRule::UNIT_PREFIX) - .value("UNIT_MULTIPLIER", libcellml::Issue::ReferenceRule::UNIT_MULTIPLIER) - .value("UNIT_EXPONENT", libcellml::Issue::ReferenceRule::UNIT_EXPONENT) - .value("COMPONENT_ATTRIBUTE", libcellml::Issue::ReferenceRule::COMPONENT_ATTRIBUTE) - .value("COMPONENT_NAME", libcellml::Issue::ReferenceRule::COMPONENT_NAME) - .value("COMPONENT_NAME_UNIQUE", libcellml::Issue::ReferenceRule::COMPONENT_NAME_UNIQUE) - .value("COMPONENT_CHILD", libcellml::Issue::ReferenceRule::COMPONENT_CHILD) - .value("VARIABLE_NAME", libcellml::Issue::ReferenceRule::VARIABLE_NAME) - .value("VARIABLE_NAME_UNIQUE", libcellml::Issue::ReferenceRule::VARIABLE_NAME_UNIQUE) - .value("VARIABLE_UNITS", libcellml::Issue::ReferenceRule::VARIABLE_UNITS) - .value("VARIABLE_INTERFACE", libcellml::Issue::ReferenceRule::VARIABLE_INTERFACE) - .value("VARIABLE_INITIAL_VALUE", libcellml::Issue::ReferenceRule::VARIABLE_INITIAL_VALUE) - .value("RESET_ATTRIBUTE", libcellml::Issue::ReferenceRule::RESET_ATTRIBUTE) - .value("RESET_VARIABLE_REF", libcellml::Issue::ReferenceRule::RESET_VARIABLE_REF) - .value("RESET_TEST_VARIABLE_REF", libcellml::Issue::ReferenceRule::RESET_TEST_VARIABLE_REF) - .value("RESET_ORDER", libcellml::Issue::ReferenceRule::RESET_ORDER) - .value("RESET_CHILD", libcellml::Issue::ReferenceRule::RESET_CHILD) - .value("RESET_TEST_VALUE", libcellml::Issue::ReferenceRule::RESET_TEST_VALUE) - .value("RESET_RESET_VALUE", libcellml::Issue::ReferenceRule::RESET_RESET_VALUE) - .value("MATH_MATHML", libcellml::Issue::ReferenceRule::MATH_MATHML) + .value("IMPORT_COMPONENT_NAME_VALUE", libcellml::Issue::ReferenceRule::IMPORT_COMPONENT_NAME_VALUE) + .value("IMPORT_ELEMENT", libcellml::Issue::ReferenceRule::IMPORT_ELEMENT) + .value("IMPORT_EQUIVALENT_INFOSET", libcellml::Issue::ReferenceRule::IMPORT_EQUIVALENT_INFOSET) + .value("IMPORT_HREF", libcellml::Issue::ReferenceRule::IMPORT_HREF) + .value("IMPORT_HREF_LOCATOR", libcellml::Issue::ReferenceRule::IMPORT_HREF_LOCATOR) + .value("IMPORT_UNITS_ELEMENT", libcellml::Issue::ReferenceRule::IMPORT_UNITS_ELEMENT) + .value("IMPORT_UNITS_NAME", libcellml::Issue::ReferenceRule::IMPORT_UNITS_NAME) + .value("IMPORT_UNITS_NAME_UNIQUE", libcellml::Issue::ReferenceRule::IMPORT_UNITS_NAME_UNIQUE) + .value("IMPORT_UNITS_NAME_VALUE", libcellml::Issue::ReferenceRule::IMPORT_UNITS_NAME_VALUE) + .value("IMPORT_UNITS_UNITS_REFERENCE", libcellml::Issue::ReferenceRule::IMPORT_UNITS_UNITS_REFERENCE) + .value("IMPORT_UNITS_UNITS_REFERENCE_VALUE", libcellml::Issue::ReferenceRule::IMPORT_UNITS_UNITS_REFERENCE_VALUE) + .value("IMPORT_UNITS_UNITS_REFERENCE_VALUE_TARGET", libcellml::Issue::ReferenceRule::IMPORT_UNITS_UNITS_REFERENCE_VALUE_TARGET) + .value("INVALID_ARGUMENT", libcellml::Issue::ReferenceRule::INVALID_ARGUMENT) + .value("MAP_VARIABLES_ELEMENT", libcellml::Issue::ReferenceRule::MAP_VARIABLES_ELEMENT) + .value("MAP_VARIABLES_UNIQUE", libcellml::Issue::ReferenceRule::MAP_VARIABLES_UNIQUE) + .value("MAP_VARIABLES_VARIABLE1_ATTRIBUTE", libcellml::Issue::ReferenceRule::MAP_VARIABLES_VARIABLE1_ATTRIBUTE) + .value("MAP_VARIABLES_VARIABLE1_ATTRIBUTE_REFERENCE", libcellml::Issue::ReferenceRule::MAP_VARIABLES_VARIABLE1_ATTRIBUTE_REFERENCE) + .value("MAP_VARIABLES_VARIABLE2_ATTRIBUTE", libcellml::Issue::ReferenceRule::MAP_VARIABLES_VARIABLE2_ATTRIBUTE) + .value("MAP_VARIABLES_VARIABLE2_ATTRIBUTE_REFERENCE", libcellml::Issue::ReferenceRule::MAP_VARIABLES_VARIABLE2_ATTRIBUTE_REFERENCE) .value("MATH_CHILD", libcellml::Issue::ReferenceRule::MATH_CHILD) - .value("MATH_CI_VARIABLE_REF", libcellml::Issue::ReferenceRule::MATH_CI_VARIABLE_REF) - .value("MATH_CN_UNITS", libcellml::Issue::ReferenceRule::MATH_CN_UNITS) + .value("MATH_CI_VARIABLE_REFERENCE", libcellml::Issue::ReferenceRule::MATH_CI_VARIABLE_REFERENCE) .value("MATH_CN_BASE10", libcellml::Issue::ReferenceRule::MATH_CN_BASE10) .value("MATH_CN_FORMAT", libcellml::Issue::ReferenceRule::MATH_CN_FORMAT) - .value("ENCAPSULATION_ATTRIBUTE", libcellml::Issue::ReferenceRule::ENCAPSULATION_ATTRIBUTE) - .value("ENCAPSULATION_CHILD", libcellml::Issue::ReferenceRule::ENCAPSULATION_CHILD) - .value("COMPONENT_REF_COMPONENT", libcellml::Issue::ReferenceRule::COMPONENT_REF_COMPONENT) - .value("COMPONENT_REF_CHILD", libcellml::Issue::ReferenceRule::COMPONENT_REF_CHILD) - .value("CONNECTION_ATTRIBUTE", libcellml::Issue::ReferenceRule::CONNECTION_ATTRIBUTE) - .value("CONNECTION_COMPONENT1", libcellml::Issue::ReferenceRule::CONNECTION_COMPONENT1) - .value("CONNECTION_COMPONENT2", libcellml::Issue::ReferenceRule::CONNECTION_COMPONENT2) - .value("CONNECTION_EXCLUDE_SELF", libcellml::Issue::ReferenceRule::CONNECTION_EXCLUDE_SELF) - .value("CONNECTION_UNIQUE", libcellml::Issue::ReferenceRule::CONNECTION_UNIQUE) - .value("CONNECTION_CHILD", libcellml::Issue::ReferenceRule::CONNECTION_CHILD) - .value("MAP_VARIABLES_ATTRIBUTE", libcellml::Issue::ReferenceRule::MAP_VARIABLES_ATTRIBUTE) - .value("MAP_VARIABLES_VARIABLE1", libcellml::Issue::ReferenceRule::MAP_VARIABLES_VARIABLE1) - .value("MAP_VARIABLES_VARIABLE2", libcellml::Issue::ReferenceRule::MAP_VARIABLES_VARIABLE2) - .value("MAP_VARIABLES_UNIQUE", libcellml::Issue::ReferenceRule::MAP_VARIABLES_UNIQUE) - .value("MAP_VARIABLES_AVAILABLE_INTERFACE", libcellml::Issue::ReferenceRule::MAP_VARIABLES_AVAILABLE_INTERFACE) - .value("MAP_VARIABLES_IDENTICAL_UNIT_REDUCTION", libcellml::Issue::ReferenceRule::MAP_VARIABLES_IDENTICAL_UNIT_REDUCTION) - .value("INVALID_ARGUMENT", libcellml::Issue::ReferenceRule::INVALID_ARGUMENT) - .value("IMPORTER_NULL_MODEL", libcellml::Issue::ReferenceRule::IMPORTER_NULL_MODEL) - .value("IMPORTER_MISSING_COMPONENT", libcellml::Issue::ReferenceRule::IMPORTER_MISSING_COMPONENT) - .value("IMPORTER_MISSING_UNITS", libcellml::Issue::ReferenceRule::IMPORTER_MISSING_UNITS) - .value("ANALYSER_VARIABLE_INITIALISED_MORE_THAN_ONCE", libcellml::Issue::ReferenceRule::ANALYSER_VARIABLE_INITIALISED_MORE_THAN_ONCE) - .value("ANALYSER_VARIABLE_NON_CONSTANT_INITIALISATION", libcellml::Issue::ReferenceRule::ANALYSER_VARIABLE_NON_CONSTANT_INITIALISATION) - .value("ANALYSER_VOI_INITIALISED", libcellml::Issue::ReferenceRule::ANALYSER_VOI_INITIALISED) - .value("ANALYSER_VOI_SEVERAL", libcellml::Issue::ReferenceRule::ANALYSER_VOI_SEVERAL) - .value("ANALYSER_ODE_NOT_FIRST_ORDER", libcellml::Issue::ReferenceRule::ANALYSER_ODE_NOT_FIRST_ORDER) - .value("ANALYSER_VARIABLE_UNUSED", libcellml::Issue::ReferenceRule::ANALYSER_VARIABLE_UNUSED) - .value("ANALYSER_STATE_NOT_INITIALISED", libcellml::Issue::ReferenceRule::ANALYSER_STATE_NOT_INITIALISED) - .value("ANALYSER_STATE_RATE_AS_ALGEBRAIC", libcellml::Issue::ReferenceRule::ANALYSER_STATE_RATE_AS_ALGEBRAIC) - .value("ANALYSER_VARIABLE_COMPUTED_MORE_THAN_ONCE", libcellml::Issue::ReferenceRule::ANALYSER_VARIABLE_COMPUTED_MORE_THAN_ONCE) - .value("ANALYSER_EXTERNAL_VARIABLE_DIFFERENT_MODEL", libcellml::Issue::ReferenceRule::ANALYSER_EXTERNAL_VARIABLE_DIFFERENT_MODEL) - .value("ANALYSER_EXTERNAL_VARIABLE_VOI", libcellml::Issue::ReferenceRule::ANALYSER_EXTERNAL_VARIABLE_VOI) - .value("ANALYSER_EXTERNAL_VARIABLE_USE_PRIMARY_VARIABLE", libcellml::Issue::ReferenceRule::ANALYSER_EXTERNAL_VARIABLE_USE_PRIMARY_VARIABLE) + .value("MATH_CN_UNITS_ATTRIBUTE", libcellml::Issue::ReferenceRule::MATH_CN_UNITS_ATTRIBUTE) + .value("MATH_CN_UNITS_ATTRIBUTE_REFERENCE", libcellml::Issue::ReferenceRule::MATH_CN_UNITS_ATTRIBUTE_REFERENCE) + .value("MATH_ELEMENT", libcellml::Issue::ReferenceRule::MATH_ELEMENT) + .value("MATH_MATHML", libcellml::Issue::ReferenceRule::MATH_MATHML) + .value("MODEL_CHILD", libcellml::Issue::ReferenceRule::MODEL_CHILD) + .value("MODEL_ELEMENT", libcellml::Issue::ReferenceRule::MODEL_ELEMENT) + .value("MODEL_MORE_THAN_ONE_ENCAPSULATION", libcellml::Issue::ReferenceRule::MODEL_MORE_THAN_ONE_ENCAPSULATION) + .value("MODEL_NAME", libcellml::Issue::ReferenceRule::MODEL_NAME) + .value("MODEL_NAME_VALUE", libcellml::Issue::ReferenceRule::MODEL_NAME_VALUE) + .value("RESET_ATTRIBUTE_REQUIRED", libcellml::Issue::ReferenceRule::RESET_ATTRIBUTE_REQUIRED) + .value("RESET_CHILD", libcellml::Issue::ReferenceRule::RESET_CHILD) + .value("RESET_ELEMENT", libcellml::Issue::ReferenceRule::RESET_ELEMENT) + .value("RESET_ORDER_UNIQUE", libcellml::Issue::ReferenceRule::RESET_ORDER_UNIQUE) + .value("RESET_ORDER_VALUE", libcellml::Issue::ReferenceRule::RESET_ORDER_VALUE) + .value("RESET_RESET_VALUE_CHILD", libcellml::Issue::ReferenceRule::RESET_RESET_VALUE_CHILD) + .value("RESET_TEST_VALUE_CHILD", libcellml::Issue::ReferenceRule::RESET_TEST_VALUE_CHILD) + .value("RESET_TEST_VARIABLE_REFERENCE", libcellml::Issue::ReferenceRule::RESET_TEST_VARIABLE_REFERENCE) + .value("RESET_VALUE_CHILD", libcellml::Issue::ReferenceRule::RESET_VALUE_CHILD) + .value("RESET_VALUE_ELEMENT", libcellml::Issue::ReferenceRule::RESET_VALUE_ELEMENT) + .value("RESET_VARIABLE_REFERENCE", libcellml::Issue::ReferenceRule::RESET_VARIABLE_REFERENCE) + .value("TEST_VALUE_CHILD", libcellml::Issue::ReferenceRule::TEST_VALUE_CHILD) + .value("TEST_VALUE_ELEMENT", libcellml::Issue::ReferenceRule::TEST_VALUE_ELEMENT) + .value("UNDEFINED", libcellml::Issue::ReferenceRule::UNDEFINED) + .value("UNITS_CHILD", libcellml::Issue::ReferenceRule::UNITS_CHILD) + .value("UNITS_ELEMENT", libcellml::Issue::ReferenceRule::UNITS_ELEMENT) + .value("UNITS_NAME", libcellml::Issue::ReferenceRule::UNITS_NAME) + .value("UNITS_NAME_UNIQUE", libcellml::Issue::ReferenceRule::UNITS_NAME_UNIQUE) + .value("UNITS_NAME_VALUE", libcellml::Issue::ReferenceRule::UNITS_NAME_VALUE) + .value("UNITS_STANDARD", libcellml::Issue::ReferenceRule::UNITS_STANDARD) + .value("UNIT_ATTRIBUTE_EXPONENT_VALUE", libcellml::Issue::ReferenceRule::UNIT_ATTRIBUTE_EXPONENT_VALUE) + .value("UNIT_ATTRIBUTE_MULTIPLIER_VALUE", libcellml::Issue::ReferenceRule::UNIT_ATTRIBUTE_MULTIPLIER_VALUE) + .value("UNIT_ATTRIBUTE_OPTIONAL", libcellml::Issue::ReferenceRule::UNIT_ATTRIBUTE_OPTIONAL) + .value("UNIT_ATTRIBUTE_PREFIX_VALUE", libcellml::Issue::ReferenceRule::UNIT_ATTRIBUTE_PREFIX_VALUE) + .value("UNIT_ELEMENT", libcellml::Issue::ReferenceRule::UNIT_ELEMENT) + .value("UNIT_UNITS", libcellml::Issue::ReferenceRule::UNIT_UNITS) + .value("UNIT_UNITS_CIRCULAR_REFERENCE", libcellml::Issue::ReferenceRule::UNIT_UNITS_CIRCULAR_REFERENCE) + .value("UNIT_UNITS_REFERENCE", libcellml::Issue::ReferenceRule::UNIT_UNITS_REFERENCE) .value("UNSPECIFIED", libcellml::Issue::ReferenceRule::UNSPECIFIED) + .value("VARIABLE_ATTRIBUTE_OPTIONAL", libcellml::Issue::ReferenceRule::VARIABLE_ATTRIBUTE_OPTIONAL) + .value("VARIABLE_ATTRIBUTE_REQUIRED", libcellml::Issue::ReferenceRule::VARIABLE_ATTRIBUTE_REQUIRED) + .value("VARIABLE_ELEMENT", libcellml::Issue::ReferenceRule::VARIABLE_ELEMENT) + .value("VARIABLE_INITIAL_VALUE_VALUE", libcellml::Issue::ReferenceRule::VARIABLE_INITIAL_VALUE_VALUE) + .value("VARIABLE_INTERFACE_VALUE", libcellml::Issue::ReferenceRule::VARIABLE_INTERFACE_VALUE) + .value("VARIABLE_NAME_UNIQUE", libcellml::Issue::ReferenceRule::VARIABLE_NAME_UNIQUE) + .value("VARIABLE_NAME_VALUE", libcellml::Issue::ReferenceRule::VARIABLE_NAME_VALUE) + .value("VARIABLE_UNITS_VALUE", libcellml::Issue::ReferenceRule::VARIABLE_UNITS_VALUE) + .value("XML_ID_ATTRIBUTE", libcellml::Issue::ReferenceRule::XML_ID_ATTRIBUTE) + .value("XML_UNEXPECTED_CHARACTER", libcellml::Issue::ReferenceRule::XML_UNEXPECTED_CHARACTER) + .value("XML_UNEXPECTED_ELEMENT", libcellml::Issue::ReferenceRule::XML_UNEXPECTED_ELEMENT) + .value("XML_UNEXPECTED_NAMESPACE", libcellml::Issue::ReferenceRule::XML_UNEXPECTED_NAMESPACE) + .value("XML_UNEXPECTED_NAMESPACE_PREFIX", libcellml::Issue::ReferenceRule::XML_UNEXPECTED_NAMESPACE_PREFIX) ; class_("Issue") From 109105c5947269f178fb7cbf275810f4dc6872a0 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Wed, 10 Apr 2024 10:43:45 +0100 Subject: [PATCH 16/50] Cover all 2.1 validation issues. --- src/parser.cpp | 12 +++++- src/validator.cpp | 2 +- tests/component/encapsulation.cpp | 2 +- tests/connection/connection.cpp | 6 +-- tests/coverage/coverage.cpp | 2 +- tests/parser/parser.cpp | 39 ++++++++++--------- tests/resources/import_units_model.cellml | 2 +- ...t_with_imported_units_missing_model.cellml | 2 +- ...orting_component_with_missing_units.cellml | 2 +- tests/validator/validator.cpp | 8 ++-- tests/variable/variable.cpp | 2 +- 11 files changed, 45 insertions(+), 34 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index ce7bf103e..f2739a859 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -438,10 +438,12 @@ void Parser::ParserImpl::loadModel(const ModelPtr &model, const std::string &inp addIssue(issue); } // Get model attributes. + bool nameAttributePresent = false; XmlAttributePtr attribute = node->firstAttribute(); while (attribute != nullptr) { if (attribute->isType("name")) { model->setName(attribute->value()); + nameAttributePresent = true; } else if (isIdAttribute(attribute, mParsing1XVersion)) { model->setId(attribute->value()); } else { @@ -451,7 +453,7 @@ void Parser::ParserImpl::loadModel(const ModelPtr &model, const std::string &inp issue->mPimpl->setLevel(Issue::Level::MESSAGE); } else { issue->mPimpl->setDescription("Model '" + node->attribute("name") + "' has an invalid attribute '" + attribute->name() + "'."); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::MODEL_NAME); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::MODEL_ELEMENT); } issue->mPimpl->mItem->mPimpl->setModel(model); addIssue(issue); @@ -459,6 +461,14 @@ void Parser::ParserImpl::loadModel(const ModelPtr &model, const std::string &inp attribute = attribute->next(); } + if (!mParsing1XVersion && !nameAttributePresent) { + auto issue = Issue::IssueImpl::create(); + issue->mPimpl->setDescription("Model does not have a name attribute."); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::MODEL_NAME); + issue->mPimpl->mItem->mPimpl->setModel(model); + addIssue(issue); + } + // Get model children (CellML entities). XmlNodePtr childNode = node->firstChild(); std::vector connectionNodes; diff --git a/src/validator.cpp b/src/validator.cpp index e9e3324a6..5b6b5b2c7 100644 --- a/src/validator.cpp +++ b/src/validator.cpp @@ -724,7 +724,7 @@ void Validator::validateModel(const ModelPtr &model) if (!isCellmlIdentifier(model->name())) { auto issue = pFunc()->makeIssueIllegalIdentifier(model->name()); issue->mPimpl->mItem->mPimpl->setModel(model); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::MODEL_NAME); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::MODEL_NAME_VALUE); issue->mPimpl->setDescription("Model '" + model->name() + "' does not have a valid name attribute. " + issue->description()); pFunc()->addIssue(issue); } diff --git a/tests/component/encapsulation.cpp b/tests/component/encapsulation.cpp index c1339868c..25640cdce 100644 --- a/tests/component/encapsulation.cpp +++ b/tests/component/encapsulation.cpp @@ -312,7 +312,7 @@ TEST(Encapsulation, parseAlternateFormHierarchy) { const std::string in = "\n" - "\n" + "\n" " \n" " \n" " \n" diff --git a/tests/connection/connection.cpp b/tests/connection/connection.cpp index 653c4052b..c478fb53c 100644 --- a/tests/connection/connection.cpp +++ b/tests/connection/connection.cpp @@ -236,7 +236,7 @@ TEST(Connection, parseValidAlternateFormConnection) { const std::string in = "\n" - "\n" + "\n" " \n" " \n" " \n" @@ -1264,7 +1264,7 @@ TEST(Connection, importedComponentConnectionAndParse) // Parse libcellml::ParserPtr parser = libcellml::Parser::create(); libcellml::ModelPtr model = parser->parseModel(e); - EXPECT_EQ(size_t(0), parser->issueCount()); + EXPECT_EQ(size_t(1), parser->issueCount()); a = printer->printModel(model); EXPECT_EQ(e, a); @@ -1274,7 +1274,7 @@ TEST(Connection, componentConnectionAndParseMissingVariable) { const std::string s = "\n" - "\n" + "\n" " \n" " \n" " \n" diff --git a/tests/coverage/coverage.cpp b/tests/coverage/coverage.cpp index 811dd9ead..628beab4e 100644 --- a/tests/coverage/coverage.cpp +++ b/tests/coverage/coverage.cpp @@ -48,7 +48,7 @@ TEST(Coverage, importWithNonHrefXlink) { const std::string e = "\n" - "\n" + "\n" " \n" " \n" " \n" diff --git a/tests/parser/parser.cpp b/tests/parser/parser.cpp index 912f2efd5..888332c20 100644 --- a/tests/parser/parser.cpp +++ b/tests/parser/parser.cpp @@ -184,6 +184,7 @@ TEST(Parser, invalidModelAttribute) "\n"; const std::vector expectedIssues = { "Model '' has an invalid attribute 'game'.", + "Model does not have a name attribute.", }; libcellml::ParserPtr p = libcellml::Parser::create(); @@ -219,7 +220,7 @@ TEST(Parser, modelWithInvalidElement) }; const std::string in2 = "\n" - "\n" + "\n" " \n" "\n"; const std::vector expectedIssues2 = { @@ -920,7 +921,7 @@ TEST(Parser, invalidVariableAttributesAndGetVariableIssue) { const std::string in = "\n" - "\n" + "\n" " \n" " \n" " \n" @@ -1125,7 +1126,7 @@ TEST(Parser, connectionErrorNoMapVariables) { const std::string in = "\n" - "\n" + "\n" " \n" " \n" " \n" @@ -1145,9 +1146,9 @@ TEST(Parser, connectionErrorNoMapVariables) TEST(Parser, importedComponent2Connection) { - const std::string e = + const std::string in = "\n" - "\n" + "\n" " \n" " \n" " \n" @@ -1161,7 +1162,7 @@ TEST(Parser, importedComponent2Connection) // Parse libcellml::ParserPtr parser = libcellml::Parser::create(); - parser->parseModel(e); + parser->parseModel(in); EXPECT_EQ(size_t(0), parser->issueCount()); } @@ -1186,7 +1187,7 @@ TEST(Parser, validConnectionMapVariablesFirst) { const std::string e = "\n" - "\n" + "\n" " \n" " \n" " \n" @@ -1205,9 +1206,9 @@ TEST(Parser, validConnectionMapVariablesFirst) TEST(Parser, component2ConnectionVariableMissing) { - const std::string e = + const std::string in = "\n" - "\n" + "\n" " \n" " \n" " \n" @@ -1224,7 +1225,7 @@ TEST(Parser, component2ConnectionVariableMissing) // Parse libcellml::ParserPtr p = libcellml::Parser::create(); - p->parseModel(e); + p->parseModel(in); EXPECT_EQ_ISSUES(expectedIssues, p); } @@ -1232,7 +1233,7 @@ TEST(Parser, component2InConnectionMissing) { const std::string in = "\n" - "\n" + "\n" " \n" " \n" " \n" @@ -1273,7 +1274,7 @@ TEST(Parser, connectionVariable2Missing) { const std::string e = "\n" - "\n" + "\n" " \n" " \n" " \n" @@ -1299,7 +1300,7 @@ TEST(Parser, connectionVariable1Missing) { const std::string e = "\n" - "\n" + "\n" " \n" " \n" " \n" @@ -1326,7 +1327,7 @@ TEST(Parser, connectionErrorNoMapVariablesType) { const std::string in = "\n" - "\n" + "\n" " \n" " \n" " \n" @@ -1353,7 +1354,7 @@ TEST(Parser, invalidImportsAndGetIssue) { const std::string in = "\n" - "\n" + "\n" " \n" " \n" " \n" @@ -1567,7 +1568,7 @@ TEST(Parser, parseIds) }; const std::string in = "\n" - "\n" + "\n" " \n" " \n" " \n" @@ -1768,7 +1769,7 @@ TEST(Parser, parseResets) { const std::string in = "\n" - "\n" + "\n" " \n" " \n" " \n" @@ -1821,7 +1822,7 @@ TEST(Parser, parseResetsWithIssues) { const std::string in = "\n" - "\n" + "\n" " \n" " \n" // reset variable not in the same component " \n" @@ -1918,7 +1919,7 @@ TEST(Parser, parseResetIllegalChild) const std::string e = "Reset in component 'componentA' has an invalid child 'initial_value'."; const std::string in = "\n" - "\n" + "\n" " \n" " \n" " \n" diff --git a/tests/resources/import_units_model.cellml b/tests/resources/import_units_model.cellml index 82fa52bed..00087c920 100644 --- a/tests/resources/import_units_model.cellml +++ b/tests/resources/import_units_model.cellml @@ -1,5 +1,5 @@ - + diff --git a/tests/resources/importer/importing_component_with_imported_units_missing_model.cellml b/tests/resources/importer/importing_component_with_imported_units_missing_model.cellml index 8f94c1862..a54c99623 100644 --- a/tests/resources/importer/importing_component_with_imported_units_missing_model.cellml +++ b/tests/resources/importer/importing_component_with_imported_units_missing_model.cellml @@ -1,5 +1,5 @@ - + diff --git a/tests/resources/importer/importing_component_with_missing_units.cellml b/tests/resources/importer/importing_component_with_missing_units.cellml index 0d6718701..1425ddcdf 100644 --- a/tests/resources/importer/importing_component_with_missing_units.cellml +++ b/tests/resources/importer/importing_component_with_missing_units.cellml @@ -1,5 +1,5 @@ - + diff --git a/tests/validator/validator.cpp b/tests/validator/validator.cpp index 0492e87ff..a561713d4 100644 --- a/tests/validator/validator.cpp +++ b/tests/validator/validator.cpp @@ -49,10 +49,10 @@ TEST(Validator, unnamedModel) "Model '' does not have a valid name attribute. CellML identifiers must contain one or more basic Latin alphabetic characters.", }; const std::vector expectedSpecificationHeadings = { - "2.1.1", + "2.1.1.1", }; const std::vector expectedUrls = { - "https://cellml-specification.readthedocs.io/en/latest/reference/formal_and_informative/specB01.html?issue=MODEL_NAME", + "https://cellml-specification.readthedocs.io/en/latest/reference/formal_and_informative/specB01.html?issue=MODEL_NAME_VALUE", }; libcellml::ValidatorPtr validator = libcellml::Validator::create(); @@ -71,14 +71,14 @@ TEST(Validator, invalidCellMLIdentifiersWithSpecificationHeading) "Component '' does not have a valid name attribute. CellML identifiers must contain one or more basic Latin alphabetic characters.", }; const std::vector expectedSpecificationHeadings = { - "2.1.1", + "2.1.1.1", "2.7.1", "2.7.1", "2.7.1", "2.7.1", }; const std::vector expectedUrls = { - "https://cellml-specification.readthedocs.io/en/latest/reference/formal_and_informative/specB01.html?issue=MODEL_NAME", + "https://cellml-specification.readthedocs.io/en/latest/reference/formal_and_informative/specB01.html?issue=MODEL_NAME_VALUE", "https://cellml-specification.readthedocs.io/en/latest/reference/formal_and_informative/specB07.html?issue=COMPONENT_NAME", "https://cellml-specification.readthedocs.io/en/latest/reference/formal_and_informative/specB07.html?issue=COMPONENT_NAME", "https://cellml-specification.readthedocs.io/en/latest/reference/formal_and_informative/specB07.html?issue=COMPONENT_NAME", diff --git a/tests/variable/variable.cpp b/tests/variable/variable.cpp index 29ed00f44..9da5e2070 100644 --- a/tests/variable/variable.cpp +++ b/tests/variable/variable.cpp @@ -1177,7 +1177,7 @@ TEST(Variable, modelUnitsAttributeBeforeNameAttribute) { const std::string e = "\n" - "\n" + "\n" " \n" " \n" " \n" From c26ba33783ba70a8e11379a00107022f39f5cbf0 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Wed, 10 Apr 2024 11:16:10 +0100 Subject: [PATCH 17/50] Cover all 2.2 validation issues. --- src/parser.cpp | 13 ++++++++++++- src/validator.cpp | 4 ++-- tests/parser/cellml_1_0.cpp | 2 +- tests/parser/parser.cpp | 4 +++- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index f2739a859..c1cbebe2d 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1389,9 +1389,11 @@ void Parser::ParserImpl::loadImport(ImportSourcePtr &importSource, const ModelPt { XmlAttributePtr attribute = node->firstAttribute(); std::string id; + bool hrefAttributePresent = false; while (attribute != nullptr) { if (attribute->isType("href", XLINK_NS)) { importSource->setUrl(attribute->value()); + hrefAttributePresent = true; } else if (isIdAttribute(attribute, mParsing1XVersion)) { id = attribute->value(); importSource->setId(id); @@ -1401,11 +1403,20 @@ void Parser::ParserImpl::loadImport(ImportSourcePtr &importSource, const ModelPt auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Import from '" + node->attribute("href") + "' has an invalid attribute '" + attribute->name() + "'."); issue->mPimpl->mItem->mPimpl->setImportSource(importSource); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_HREF); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_ELEMENT); addIssue(issue); } attribute = attribute->next(); } + + if (!hrefAttributePresent) { + auto issue = Issue::IssueImpl::create(); + issue->mPimpl->setDescription("Import does not specify an xlink href attribute."); + issue->mPimpl->mItem->mPimpl->setImportSource(importSource); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_HREF); + addIssue(issue); + } + XmlNodePtr childNode = node->firstChild(); if (childNode == nullptr) { diff --git a/src/validator.cpp b/src/validator.cpp index 5b6b5b2c7..5b9d0520c 100644 --- a/src/validator.cpp +++ b/src/validator.cpp @@ -807,7 +807,7 @@ void Validator::ValidatorImpl::validateImportSource(const ImportSourcePtr &impor auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Import of " + importType + " '" + importName + "' does not have a valid locator xlink:href attribute."); issue->mPimpl->mItem->mPimpl->setImportSource(importSource); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_HREF); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_HREF_LOCATOR); addIssue(issue); } else { xmlURIPtr uri = xmlParseURI(url.c_str()); @@ -815,7 +815,7 @@ void Validator::ValidatorImpl::validateImportSource(const ImportSourcePtr &impor auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Import of " + importType + " '" + importName + "' has an invalid URI in the xlink:href attribute."); issue->mPimpl->mItem->mPimpl->setImportSource(importSource); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_HREF); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_HREF_LOCATOR); addIssue(issue); } else { diff --git a/tests/parser/cellml_1_0.cpp b/tests/parser/cellml_1_0.cpp index 545852783..ebceadadb 100644 --- a/tests/parser/cellml_1_0.cpp +++ b/tests/parser/cellml_1_0.cpp @@ -115,7 +115,7 @@ TEST(ParserTransform, annotatedCellMl10Model) EXPECT_EQ(size_t(5), model->unitsCount()); EXPECT_EQ(size_t(2), model->componentCount()); - EXPECT_EQ(size_t(77), parser->issueCount()); + EXPECT_EQ(size_t(78), parser->issueCount()); auto validator = libcellml::Validator::create(); validator->validateModel(model); diff --git a/tests/parser/parser.cpp b/tests/parser/parser.cpp index 888332c20..055eebf51 100644 --- a/tests/parser/parser.cpp +++ b/tests/parser/parser.cpp @@ -20,7 +20,6 @@ limitations under the License. #include -#include #include #include @@ -1175,7 +1174,9 @@ TEST(Parser, emptyImportWithAndWithoutId) " \n" "\n"; std::vector e = { + "Import does not specify an xlink href attribute.", "Import from '' is empty and will be disregarded.", + "Import does not specify an xlink href attribute.", "Import from '' has an identifier of 'import_id' but is empty. The import will be disregarded and the associated identifier will be lost.", }; libcellml::ParserPtr parser = libcellml::Parser::create(); @@ -1421,6 +1422,7 @@ TEST(Parser, invalidModelWithDifferentItemTypesOfIssues) const std::vector expectedIssues = { "Model 'starwars' has an invalid attribute 'episode'.", "Import from '' has an invalid attribute 'princess'.", + "Import does not specify an xlink href attribute.", "Import from '' is empty and will be disregarded.", "Units '' has an invalid attribute 'jedi'.", "Component '' has an invalid attribute 'ship'.", From 63250b9c78bf586a801b6ee0664a876c9eb73511 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Wed, 10 Apr 2024 14:33:17 +0100 Subject: [PATCH 18/50] Cover all 2.3 validation issues. --- src/parser.cpp | 14 +++++++++++++- src/validator.cpp | 15 ++++++++++----- tests/model/units_import.cpp | 19 +++++++++++++++++++ 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index c1cbebe2d..ebc8de07f 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1431,6 +1431,7 @@ void Parser::ParserImpl::loadImport(ImportSourcePtr &importSource, const ModelPt issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_CHILD); addIssue(issue); } + bool nameAttributePresent; while (childNode != nullptr) { if (parseNode(childNode, "component")) { ComponentPtr importedComponent = Component::create(); @@ -1457,9 +1458,11 @@ void Parser::ParserImpl::loadImport(ImportSourcePtr &importSource, const ModelPt UnitsPtr importedUnits = Units::create(); XmlAttributePtr childAttribute = childNode->firstAttribute(); importedUnits->setImportSource(importSource); + nameAttributePresent = false; while (childAttribute) { if (childAttribute->isType("name")) { importedUnits->setName(childAttribute->value()); + nameAttributePresent = true; } else if (isIdAttribute(childAttribute, mParsing1XVersion)) { importedUnits->setId(childAttribute->value()); } else if (childAttribute->isType("units_ref")) { @@ -1468,11 +1471,20 @@ void Parser::ParserImpl::loadImport(ImportSourcePtr &importSource, const ModelPt auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Import of units '" + childNode->attribute("name") + "' from '" + node->attribute("href") + "' has an invalid attribute '" + childAttribute->name() + "'."); issue->mPimpl->mItem->mPimpl->setImportSource(importSource); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_CHILD); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_UNITS_ELEMENT); addIssue(issue); } childAttribute = childAttribute->next(); } + + if (!nameAttributePresent) { + auto issue = Issue::IssueImpl::create(); + issue->mPimpl->setDescription("Import of units does not specify a name attribute."); + issue->mPimpl->mItem->mPimpl->setImportSource(importSource); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_UNITS_NAME); + addIssue(issue); + } + model->addUnits(importedUnits); } else if (childNode->isText()) { const std::string textNode = childNode->convertToString(); diff --git a/src/validator.cpp b/src/validator.cpp index 5b9d0520c..e74068e9b 100644 --- a/src/validator.cpp +++ b/src/validator.cpp @@ -1095,7 +1095,7 @@ void Validator::ValidatorImpl::validateUnits(const UnitsPtr &units, History &his auto issue = makeIssueIllegalIdentifier(unitsRef); issue->mPimpl->setDescription("Imported units '" + unitsName + "' does not have a valid units_ref attribute. " + issue->description()); issue->mPimpl->mItem->mPimpl->setUnits(units); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_UNITS_UNITS_REFERENCE); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_UNITS_UNITS_REFERENCE_VALUE); addIssue(issue); } @@ -1144,7 +1144,7 @@ void Validator::ValidatorImpl::validateUnits(const UnitsPtr &units, History &his auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Imported units '" + units->name() + "' refers to units '" + unitsRef + "' which does not appear in '" + importSource->url() + "'."); issue->mPimpl->mItem->mPimpl->setUnits(units); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_UNITS_UNITS_REFERENCE); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_UNITS_UNITS_REFERENCE_VALUE_TARGET); addIssue(issue); } } @@ -1156,7 +1156,12 @@ void Validator::ValidatorImpl::validateUnits(const UnitsPtr &units, History &his auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription(description); issue->mPimpl->mItem->mPimpl->setModel(model); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNITS_NAME_UNIQUE); + if (units->isImport()) { + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_UNITS_NAME_UNIQUE); + } else { + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNITS_NAME_UNIQUE); + } + addIssue(issue); } } @@ -1166,10 +1171,10 @@ void Validator::ValidatorImpl::validateUnits(const UnitsPtr &units, History &his issue->mPimpl->mItem->mPimpl->setUnits(units); if (units->isImport()) { issue->mPimpl->setDescription("Imported units '" + unitsName + "' does not have a valid name attribute. " + issue->description()); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_UNITS_NAME); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_UNITS_NAME_VALUE); } else { issue->mPimpl->setDescription("Units '" + unitsName + "' does not have a valid name attribute. " + issue->description()); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNITS_NAME); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNITS_NAME_VALUE); } addIssue(issue); } else { diff --git a/tests/model/units_import.cpp b/tests/model/units_import.cpp index 9116e641f..5ead39ee5 100644 --- a/tests/model/units_import.cpp +++ b/tests/model/units_import.cpp @@ -16,6 +16,7 @@ limitations under the License. #include "gtest/gtest.h" +#include "test_utils.h" #include TEST(UnitsImport, basics) @@ -146,6 +147,24 @@ TEST(UnitsImport, nonExistentUrl) EXPECT_EQ(e, a); } +TEST(UnitsImport, noNameAttribute) +{ + const std::string in = + "\n" + "\n" + " \n" + " \n" + " \n" + "\n"; + + libcellml::ParserPtr p = libcellml::Parser::create(); + + libcellml::ModelPtr m = p->parseModel(in); + + EXPECT_EQ(size_t(1), p->errorCount()); + printIssues(p); +} + TEST(UnitsImport, importModifyAndParse) { const std::string e = From 2e49fcf37d4315a1bd4ffa6b53f233fadcfe23d6 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Wed, 10 Apr 2024 22:35:57 +0100 Subject: [PATCH 19/50] Cover all 2.4 validation issues. --- src/parser.cpp | 13 ++++++++++- src/validator.cpp | 34 ++++++++++++++++----------- tests/model/component_import.cpp | 40 ++++++++++++++++++++++++++++++++ tests/model/units_import.cpp | 1 - tests/validator/validator.cpp | 16 ++++++------- 5 files changed, 81 insertions(+), 23 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index ebc8de07f..d7785f60d 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1437,9 +1437,11 @@ void Parser::ParserImpl::loadImport(ImportSourcePtr &importSource, const ModelPt ComponentPtr importedComponent = Component::create(); XmlAttributePtr childAttribute = childNode->firstAttribute(); importedComponent->setImportSource(importSource); + nameAttributePresent = false; while (childAttribute) { if (childAttribute->isType("name")) { importedComponent->setName(childAttribute->value()); + nameAttributePresent = true; } else if (isIdAttribute(childAttribute, mParsing1XVersion)) { importedComponent->setId(childAttribute->value()); } else if (childAttribute->isType("component_ref")) { @@ -1448,11 +1450,20 @@ void Parser::ParserImpl::loadImport(ImportSourcePtr &importSource, const ModelPt auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Import of component '" + childNode->attribute("name") + "' from '" + node->attribute("href") + "' has an invalid attribute '" + childAttribute->name() + "'."); issue->mPimpl->mItem->mPimpl->setImportSource(importSource); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_CHILD); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_COMPONENT_ELEMENT); addIssue(issue); } childAttribute = childAttribute->next(); } + + if (!nameAttributePresent) { + auto issue = Issue::IssueImpl::create(); + issue->mPimpl->setDescription("Import of component does not specify a name attribute."); + issue->mPimpl->mItem->mPimpl->setImportSource(importSource); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_COMPONENT_NAME); + addIssue(issue); + } + model->addComponent(importedComponent); } else if (parseNode(childNode, "units")) { UnitsPtr importedUnits = Units::create(); diff --git a/src/validator.cpp b/src/validator.cpp index e74068e9b..262d02bc8 100644 --- a/src/validator.cpp +++ b/src/validator.cpp @@ -300,17 +300,17 @@ class Validator::ValidatorImpl: public LoggerImpl IssuePtr makeIssueIllegalIdentifier(const std::string &name) const; /** - * @brief Validate the given name is unique in the model. + * @brief Validate the given component's name is unique in the model. * - * The @p name is checked against known names in @p names. If - * the @p name already exists an issue is added to the validator - * with the model passed to the issue for further reference. + * The @p component is checked against known names in @p names. If + * the component's name already exists an issue is added to the validator + * with the component passed to the issue for further reference. * - * @param model The model the name is used in. - * @param name The name of the component to validate. + * @param model The model the component is used in. + * @param component The component to validate the name of. * @param names The list of component names already used in the model. */ - void validateUniqueName(const ModelPtr &model, const std::string &name, NameList &names); + void validateUniqueName(const ModelPtr &model, const ComponentPtr &component, NameList &names); /** * @brief Validate the @p component using the CellML 2.0 Specification. @@ -765,14 +765,19 @@ void Validator::validateModel(const ModelPtr &model) } } -void Validator::ValidatorImpl::validateUniqueName(const ModelPtr &model, const std::string &name, NameList &names) +void Validator::ValidatorImpl::validateUniqueName(const ModelPtr &model, const ComponentPtr &component, NameList &names) { + std::string name = component->name(); if (!name.empty()) { if (std::find(names.begin(), names.end(), name) != names.end()) { auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Model '" + model->name() + "' contains multiple components with the name '" + name + "'. Valid component names must be unique to their model."); issue->mPimpl->mItem->mPimpl->setModel(model); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::COMPONENT_NAME_UNIQUE); + if (component->isImport()) { + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_COMPONENT_NAME_UNIQUE); + } else { + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::COMPONENT_NAME_UNIQUE); + } addIssue(issue); } else { names.push_back(name); @@ -782,7 +787,7 @@ void Validator::ValidatorImpl::validateUniqueName(const ModelPtr &model, const s void Validator::ValidatorImpl::validateComponentTree(const ModelPtr &model, const ComponentPtr &component, NameList &componentNames, History &history, std::vector &modelsVisited) { - validateUniqueName(model, component->name(), componentNames); + validateUniqueName(model, component, componentNames); for (size_t i = 0; i < component->componentCount(); ++i) { auto childComponent = component->component(i); validateComponentTree(model, childComponent, componentNames, history, modelsVisited); @@ -907,7 +912,11 @@ void Validator::ValidatorImpl::validateComponent(const ComponentPtr &component, auto issue = makeIssueIllegalIdentifier(componentName); issue->mPimpl->mItem->mPimpl->setComponent(component); issue->mPimpl->setDescription(descriptionPrefix + "'" + componentName + "' does not have a valid name attribute. " + issue->description()); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::COMPONENT_NAME); + if (isImported) { + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_COMPONENT_NAME_VALUE); + } else { + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::COMPONENT_NAME_VALUE); + } addIssue(issue); } // Check for a valid identifier. @@ -927,7 +936,7 @@ void Validator::ValidatorImpl::validateComponent(const ComponentPtr &component, auto issue = makeIssueIllegalIdentifier(componentRef); issue->mPimpl->setDescription(descriptionPrefix + "'" + componentName + "' does not have a valid component_ref attribute. " + issue->description()); issue->mPimpl->mItem->mPimpl->setComponent(component); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_COMPONENT_COMPONENT_REFERENCE); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_COMPONENT_COMPONENT_REFERENCE_VALUE); addIssue(issue); } @@ -961,7 +970,6 @@ void Validator::ValidatorImpl::validateComponent(const ComponentPtr &component, addIssue(issue); } } - } else { // Check for variables in this component. NameList variableNames; diff --git a/tests/model/component_import.cpp b/tests/model/component_import.cpp index 740ed4ea2..510a86e75 100644 --- a/tests/model/component_import.cpp +++ b/tests/model/component_import.cpp @@ -322,3 +322,43 @@ TEST(ComponentImport, complexImportAndParse) const libcellml::ComponentPtr constBob = constDave->component("bob"); EXPECT_EQ(size_t(2), constBob->componentCount()); } + +TEST(ComponentImport, noNameAttribute) +{ + const std::string in = + "\n" + "\n" + " \n" + " \n" + " \n" + "\n"; + + libcellml::ParserPtr p = libcellml::Parser::create(); + + libcellml::ModelPtr m = p->parseModel(in); + + EXPECT_EQ(size_t(1), p->errorCount()); +} + +TEST(ComponentImport, notUniqueImportName) +{ + const std::string in = + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + "\n"; + + libcellml::ParserPtr p = libcellml::Parser::create(); + libcellml::ValidatorPtr v = libcellml::Validator::create(); + + libcellml::ModelPtr m = p->parseModel(in); + + EXPECT_EQ(size_t(0), p->errorCount()); + + v->validateModel(m); + + EXPECT_EQ(size_t(1), v->errorCount()); +} diff --git a/tests/model/units_import.cpp b/tests/model/units_import.cpp index 5ead39ee5..874bc4c46 100644 --- a/tests/model/units_import.cpp +++ b/tests/model/units_import.cpp @@ -162,7 +162,6 @@ TEST(UnitsImport, noNameAttribute) libcellml::ModelPtr m = p->parseModel(in); EXPECT_EQ(size_t(1), p->errorCount()); - printIssues(p); } TEST(UnitsImport, importModifyAndParse) diff --git a/tests/validator/validator.cpp b/tests/validator/validator.cpp index a561713d4..ab48a8b23 100644 --- a/tests/validator/validator.cpp +++ b/tests/validator/validator.cpp @@ -72,17 +72,17 @@ TEST(Validator, invalidCellMLIdentifiersWithSpecificationHeading) }; const std::vector expectedSpecificationHeadings = { "2.1.1.1", - "2.7.1", - "2.7.1", - "2.7.1", - "2.7.1", + "2.7.1.1", + "2.7.1.1", + "2.7.1.1", + "2.7.1.1", }; const std::vector expectedUrls = { "https://cellml-specification.readthedocs.io/en/latest/reference/formal_and_informative/specB01.html?issue=MODEL_NAME_VALUE", - "https://cellml-specification.readthedocs.io/en/latest/reference/formal_and_informative/specB07.html?issue=COMPONENT_NAME", - "https://cellml-specification.readthedocs.io/en/latest/reference/formal_and_informative/specB07.html?issue=COMPONENT_NAME", - "https://cellml-specification.readthedocs.io/en/latest/reference/formal_and_informative/specB07.html?issue=COMPONENT_NAME", - "https://cellml-specification.readthedocs.io/en/latest/reference/formal_and_informative/specB07.html?issue=COMPONENT_NAME", + "https://cellml-specification.readthedocs.io/en/latest/reference/formal_and_informative/specB07.html?issue=COMPONENT_NAME_VALUE", + "https://cellml-specification.readthedocs.io/en/latest/reference/formal_and_informative/specB07.html?issue=COMPONENT_NAME_VALUE", + "https://cellml-specification.readthedocs.io/en/latest/reference/formal_and_informative/specB07.html?issue=COMPONENT_NAME_VALUE", + "https://cellml-specification.readthedocs.io/en/latest/reference/formal_and_informative/specB07.html?issue=COMPONENT_NAME_VALUE", }; libcellml::ValidatorPtr v = libcellml::Validator::create(); From 9ad6531e584ecc06929fc372b55baad816c6a7fe Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Thu, 11 Apr 2024 09:20:41 +0100 Subject: [PATCH 20/50] Cover all 2.5 validation issues. --- src/parser.cpp | 11 +++++++++++ tests/parser/parser.cpp | 4 +++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/parser.cpp b/src/parser.cpp index d7785f60d..baeb25c99 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -692,9 +692,11 @@ void Parser::ParserImpl::loadUnitsFromComponent(const ModelPtr &model, const Xml void Parser::ParserImpl::loadUnits(const UnitsPtr &units, const XmlNodePtr &node) { XmlAttributePtr attribute = node->firstAttribute(); + bool nameAttributePresent = false; while (attribute != nullptr) { if (attribute->isType("name")) { units->setName(attribute->value()); + nameAttributePresent = true; } else if (isIdAttribute(attribute, mParsing1XVersion)) { units->setId(attribute->value()); } else { @@ -711,6 +713,15 @@ void Parser::ParserImpl::loadUnits(const UnitsPtr &units, const XmlNodePtr &node } attribute = attribute->next(); } + + if (!nameAttributePresent) { + auto issue = Issue::IssueImpl::create(); + issue->mPimpl->setDescription("Units does not specify a name attribute."); + issue->mPimpl->mItem->mPimpl->setUnits(units); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNITS_NAME); + addIssue(issue); + } + XmlNodePtr childNode = node->firstChild(); while (childNode != nullptr) { if (parseNode(childNode, "unit")) { diff --git a/tests/parser/parser.cpp b/tests/parser/parser.cpp index 055eebf51..746a3c691 100644 --- a/tests/parser/parser.cpp +++ b/tests/parser/parser.cpp @@ -328,7 +328,7 @@ TEST(Parser, unitsElementIssues) const std::string in1 = "\n" "\n" - " \n" + " \n" " \n" " \n" "\n"; @@ -624,6 +624,7 @@ TEST(Parser, modelWithInvalidUnits) "Units 'fahrenheitish' has an invalid child element 'bobshouse'.", "Unit referencing '' in units 'fahrenheitish' has an invalid attribute 'GUnit'.", "Units '' has an invalid attribute 'jerry'.", + "Units does not specify a name attribute.", "Unit referencing 'friends' in units '' has an invalid attribute 'neighbor'.", "Unit referencing '' in units '' has an invalid attribute 'george'.", }; @@ -1425,6 +1426,7 @@ TEST(Parser, invalidModelWithDifferentItemTypesOfIssues) "Import does not specify an xlink href attribute.", "Import from '' is empty and will be disregarded.", "Units '' has an invalid attribute 'jedi'.", + "Units does not specify a name attribute.", "Component '' has an invalid attribute 'ship'.", "Variable '' has an invalid attribute 'pilot'.", "Encapsulation in model 'starwars' has an invalid attribute 'yoda'.", From e7d3598120c02250fd45313c142f7f6d7aa99896 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Thu, 11 Apr 2024 09:54:43 +0100 Subject: [PATCH 21/50] Cover all 2.6 validation issues. --- src/issue.cpp | 2 +- src/parser.cpp | 15 +++++++++++++-- tests/parser/parser.cpp | 2 ++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/issue.cpp b/src/issue.cpp index 656a2bcb7..48758212e 100644 --- a/src/issue.cpp +++ b/src/issue.cpp @@ -119,7 +119,7 @@ static const std::map> ruleToInfo {Issue::ReferenceRule::UNIT_ELEMENT, {"UNIT_ELEMENT", "2.6", baseSpecificationUrl, "specB06"}}, {Issue::ReferenceRule::UNIT_UNITS, {"UNIT_UNITS", "2.6.1", baseSpecificationUrl, "specB06"}}, {Issue::ReferenceRule::UNIT_UNITS_REFERENCE, {"UNIT_UNITS_REFERENCE", "2.6.1.1", baseSpecificationUrl, "specB06"}}, - {Issue::ReferenceRule::UNIT_UNITS_CIRCULAR_REFERENCE, {"UNIT_UNITS_CIRCULAR_REFERENCE", "2.6.1.2", baseSpecificationUrl, "specB06"}}, + {Issue::ReferenceRule::UNIT_UNITS_CIRCULAR_REFERENCE, {"UNIT_UNITS_CIRCULAR_REFERENCE", "2.6.1.3", baseSpecificationUrl, "specB06"}}, {Issue::ReferenceRule::UNIT_ATTRIBUTE_OPTIONAL, {"UNIT_ATTRIBUTE_OPTIONAL", "2.6.2", baseSpecificationUrl, "specB06"}}, {Issue::ReferenceRule::UNIT_ATTRIBUTE_PREFIX_VALUE, {"UNIT_ATTRIBUTE_PREFIX_VALUE", "2.6.2.1.1", baseSpecificationUrl, "specB06"}}, {Issue::ReferenceRule::UNIT_ATTRIBUTE_MULTIPLIER_VALUE, {"UNIT_ATTRIBUTE_MULTIPLIER_VALUE", "2.6.2.2.1", baseSpecificationUrl, "specB06"}}, diff --git a/src/parser.cpp b/src/parser.cpp index baeb25c99..0305b92fb 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -766,7 +766,7 @@ void Parser::ParserImpl::loadUnit(const UnitsPtr &units, const XmlNodePtr &node) auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Unit referencing '" + node->attribute("units") + "' in units '" + units->name() + "' has an invalid non-whitespace child text element '" + textNode + "'."); issue->mPimpl->mItem->mPimpl->setUnits(units); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNITS_CHILD); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNIT_ELEMENT); addIssue(issue); } } else if (childNode->isComment()) { @@ -775,13 +775,14 @@ void Parser::ParserImpl::loadUnit(const UnitsPtr &units, const XmlNodePtr &node) auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Unit referencing '" + node->attribute("units") + "' in units '" + units->name() + "' has an invalid child element '" + childNode->name() + "'."); issue->mPimpl->mItem->mPimpl->setUnits(units); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNITS_CHILD); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNIT_ELEMENT); addIssue(issue); } childNode = childNode->next(); } // Parse the unit attributes. XmlAttributePtr attribute = node->firstAttribute(); + bool unitsAttributePresent = false; while (attribute != nullptr) { if (attribute->isType("units")) { if (mParsing1XVersion) { @@ -789,6 +790,7 @@ void Parser::ParserImpl::loadUnit(const UnitsPtr &units, const XmlNodePtr &node) } else { reference = attribute->value(); } + unitsAttributePresent = true; } else if (attribute->isType("prefix")) { prefix = attribute->value(); } else if (attribute->isType("exponent")) { @@ -838,6 +840,15 @@ void Parser::ParserImpl::loadUnit(const UnitsPtr &units, const XmlNodePtr &node) } attribute = attribute->next(); } + + if (!unitsAttributePresent) { + auto issue = Issue::IssueImpl::create(); + issue->mPimpl->setDescription("Unit does not specify a units attribute."); + issue->mPimpl->mItem->mPimpl->setUnits(units); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNIT_UNITS); + addIssue(issue); + } + // Add this unit to the parent units. units->addUnit(reference, prefix, exponent, multiplier, id); } diff --git a/tests/parser/parser.cpp b/tests/parser/parser.cpp index 746a3c691..d91119411 100644 --- a/tests/parser/parser.cpp +++ b/tests/parser/parser.cpp @@ -623,10 +623,12 @@ TEST(Parser, modelWithInvalidUnits) "Unit referencing 'kelvin' in units 'fahrenheitish' has a multiplier with the value '-35.0E+310' that is a representation of a CellML real valued number, but out of range of the 'double' type.", "Units 'fahrenheitish' has an invalid child element 'bobshouse'.", "Unit referencing '' in units 'fahrenheitish' has an invalid attribute 'GUnit'.", + "Unit does not specify a units attribute.", "Units '' has an invalid attribute 'jerry'.", "Units does not specify a name attribute.", "Unit referencing 'friends' in units '' has an invalid attribute 'neighbor'.", "Unit referencing '' in units '' has an invalid attribute 'george'.", + "Unit does not specify a units attribute.", }; libcellml::ParserPtr parser = libcellml::Parser::create(); From d84139f46bdb29803eb064f105e4898647787ec0 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Thu, 11 Apr 2024 10:03:12 +0100 Subject: [PATCH 22/50] Cover all 2.7 validation issues. --- src/parser.cpp | 11 +++++++++++ tests/parser/parser.cpp | 12 +++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index 0305b92fb..818ff8f3c 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -585,9 +585,11 @@ void Parser::ParserImpl::loadModel(const ModelPtr &model, const std::string &inp void Parser::ParserImpl::loadComponent(const ComponentPtr &component, const XmlNodePtr &node) { XmlAttributePtr attribute = node->firstAttribute(); + bool nameAttributePresent = false; while (attribute != nullptr) { if (attribute->isType("name")) { component->setName(attribute->value()); + nameAttributePresent = true; } else if (isIdAttribute(attribute, mParsing1XVersion)) { component->setId(attribute->value()); } else { @@ -604,6 +606,15 @@ void Parser::ParserImpl::loadComponent(const ComponentPtr &component, const XmlN } attribute = attribute->next(); } + + if (!nameAttributePresent) { + auto issue = Issue::IssueImpl::create(); + issue->mPimpl->setDescription("Component does not specify a name attribute."); + issue->mPimpl->mItem->mPimpl->setComponent(component); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::COMPONENT_NAME); + addIssue(issue); + } + XmlNodePtr childNode = node->firstChild(); while (childNode != nullptr) { if (childNode->isCellmlElement("variable")) { diff --git a/tests/parser/parser.cpp b/tests/parser/parser.cpp index d91119411..b30c37fdb 100644 --- a/tests/parser/parser.cpp +++ b/tests/parser/parser.cpp @@ -422,6 +422,7 @@ TEST(Parser, componentAttributeIssues) "\n"; const std::vector expectedIssues1 = { "Component '' has an invalid attribute 'lame'.", + "Component does not specify a name attribute.", }; const std::string in2 = "\n" @@ -456,7 +457,7 @@ TEST(Parser, componentElementIssues) const std::string in1 = "\n" "\n" - " \n" + " \n" " \n" " \n" "\n"; @@ -1430,6 +1431,7 @@ TEST(Parser, invalidModelWithDifferentItemTypesOfIssues) "Units '' has an invalid attribute 'jedi'.", "Units does not specify a name attribute.", "Component '' has an invalid attribute 'ship'.", + "Component does not specify a name attribute.", "Variable '' has an invalid attribute 'pilot'.", "Encapsulation in model 'starwars' has an invalid attribute 'yoda'.", "Encapsulation in model 'starwars' does not contain any child elements.", @@ -2126,7 +2128,7 @@ TEST(Parser, mathWithNamespacesDefinedOnTheMathNode) const std::string in = "\n" "\n" - " \n" + " \n" " \n" " \n" " \n" @@ -2152,7 +2154,7 @@ TEST(Parser, mathWithNamespacesDefinedOnTheNodeThatUsesNamespace) const std::string in = "\n" "\n" - " \n" + " \n" " \n" " \n" " \n" @@ -2178,7 +2180,7 @@ TEST(Parser, mathWithNonStandardCellMLPrefix) const std::string in = "\n" "\n" - " \n" + " \n" " \n" " \n" " \n" @@ -2204,7 +2206,7 @@ TEST(Parser, mathWithMathmlNamespaceOnModel) const std::string in = "\n" "\n" - " \n" + " \n" " \n" " \n" " \n" From c2248cf99499678e6ff992a75009b4b19204fdf1 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Thu, 11 Apr 2024 10:42:00 +0100 Subject: [PATCH 23/50] Cover all 2.8 validation issues. --- src/parser.cpp | 21 +++++++++++++++++++++ src/validator.cpp | 2 +- tests/parser/parser.cpp | 20 +++++++++++--------- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index 818ff8f3c..fdb59445a 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -896,9 +896,12 @@ void Parser::ParserImpl::loadVariable(const VariablePtr &variable, const XmlNode childNode = childNode->next(); } XmlAttributePtr attribute = node->firstAttribute(); + bool nameAttributePresent = false; + bool unitsAttributePresent = false; while (attribute != nullptr) { if (attribute->isType("name")) { variable->setName(attribute->value()); + nameAttributePresent = true; } else if (isIdAttribute(attribute, mParsing1XVersion)) { variable->setId(attribute->value()); } else if (attribute->isType("units")) { @@ -907,6 +910,7 @@ void Parser::ParserImpl::loadVariable(const VariablePtr &variable, const XmlNode } else { variable->setUnits(attribute->value()); } + unitsAttributePresent = true; } else if (attribute->isType("interface")) { variable->setInterfaceType(attribute->value()); } else if (attribute->isType("initial_value")) { @@ -937,6 +941,23 @@ void Parser::ParserImpl::loadVariable(const VariablePtr &variable, const XmlNode } attribute = attribute->next(); } + + if (!nameAttributePresent or !unitsAttributePresent) { + auto issue = Issue::IssueImpl::create(); + std::string description = "Variable "; + if (nameAttributePresent) { + description += "'" + node->attribute("name") + "' does not specify a units attribute."; + } else if (unitsAttributePresent) { + description += "with units '" + node->attribute("units") + "' does not specify a name attribute."; + } else { + description += "does not specify a name attribute or a units attribute."; + } + + issue->mPimpl->setDescription(description); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::VARIABLE_ATTRIBUTE_REQUIRED); + issue->mPimpl->mItem->mPimpl->setVariable(variable); + addIssue(issue); + } } void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr &node) diff --git a/src/validator.cpp b/src/validator.cpp index 262d02bc8..4048c4d7f 100644 --- a/src/validator.cpp +++ b/src/validator.cpp @@ -1298,7 +1298,7 @@ void Validator::ValidatorImpl::validateVariable(const VariablePtr &variable, con auto issue = makeIssueIllegalIdentifier(variableName); issue->mPimpl->setDescription("Variable '" + variableName + "' in component '" + component->name() + "' does not have a valid name attribute. " + issue->description()); issue->mPimpl->mItem->mPimpl->setVariable(variable); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::VARIABLE_ATTRIBUTE_REQUIRED); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::VARIABLE_NAME_VALUE); addIssue(issue); } // Check for a valid identifier. diff --git a/tests/parser/parser.cpp b/tests/parser/parser.cpp index b30c37fdb..11f86df6b 100644 --- a/tests/parser/parser.cpp +++ b/tests/parser/parser.cpp @@ -927,20 +927,22 @@ TEST(Parser, invalidVariableAttributesAndGetVariableIssue) "\n" " \n" " \n" - " \n" + " \n" + " \n" " \n" "\n"; const std::vector expectedIssues = { "Variable 'quixote' has an invalid attribute 'don'.", + "Variable 'quixote' does not specify a units attribute.", "Variable '' has an invalid attribute 'windmill'.", + "Variable with units 'bobs' does not specify a name attribute.", + "Model does not contain the units '' required by variable '' in component 'componentA'.", + "Model does not contain the units 'bobs' required by variable '' in component 'componentA'.", }; libcellml::ParserPtr p = libcellml::Parser::create(); libcellml::ModelPtr model = p->parseModel(in); - EXPECT_EQ(expectedIssues.size(), p->issueCount()); - for (size_t i = 0; i < p->issueCount(); ++i) { - EXPECT_EQ(expectedIssues.at(i), p->issue(i)->description()); - } + EXPECT_EQ_ISSUES(expectedIssues, p); libcellml::VariablePtr variableExpected = model->component("componentA")->variable("quixote"); // Get variable from issue and check. @@ -1433,6 +1435,7 @@ TEST(Parser, invalidModelWithDifferentItemTypesOfIssues) "Component '' has an invalid attribute 'ship'.", "Component does not specify a name attribute.", "Variable '' has an invalid attribute 'pilot'.", + "Variable does not specify a name attribute or a units attribute.", "Encapsulation in model 'starwars' has an invalid attribute 'yoda'.", "Encapsulation in model 'starwars' does not contain any child elements.", "Connection in model 'starwars' has an invalid connection attribute 'wookie'.", @@ -1508,7 +1511,7 @@ TEST(Parser, invalidModelWithTextInAllElements) " \n" " \n" " falcon\n" - " \n" + " \n" " rey\n" " \n" " \n" @@ -1565,7 +1568,6 @@ TEST(Parser, invalidModelWithTextInAllElements) // Parse and check for CellML issues. libcellml::ParserPtr parser = libcellml::Parser::create(); parser->parseModel(in); - EXPECT_EQ_ISSUES(expectedIssues, parser); } @@ -1929,8 +1931,8 @@ TEST(Parser, parseResetIllegalChild) "\n" "\n" " \n" - " \n" - " \n" + " \n" + " \n" " \n" " \n" " \n" From df26df80fc5d0fe4239f7a01fd201c0ecba2eace Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Thu, 11 Apr 2024 14:39:10 +0100 Subject: [PATCH 24/50] Cover all 2.9 validation issues. --- src/internaltypes.h | 2 + src/validator.cpp | 103 ++++++++++++++++++++++++++++++ tests/validator/validator.cpp | 116 +++++++++++++++++++++++++++++++++- 3 files changed, 218 insertions(+), 3 deletions(-) diff --git a/src/internaltypes.h b/src/internaltypes.h index a415f27ce..fea0c48dc 100644 --- a/src/internaltypes.h +++ b/src/internaltypes.h @@ -54,6 +54,8 @@ using IdMap = std::map>>; / using ImportLibrary = std::map; /** Type definition for library map of imported models. */ using IdList = std::unordered_set; /**< Type definition for list of identifiers. */ +using ResetOrderMap = std::map>; /** Type definition for map of variable to reset order. **/ + using AnalyserEquationAstWeakPtr = std::weak_ptr; /**< Type definition for weak analyser equation AST pointer. */ using AnalyserEquationWeakPtr = std::weak_ptr; /**< Type definition for weak analyser equation pointer. */ using ComponentWeakPtr = std::weak_ptr; /**< Type definition for weak component pointer. */ diff --git a/src/validator.cpp b/src/validator.cpp index 4048c4d7f..d26348d5a 100644 --- a/src/validator.cpp +++ b/src/validator.cpp @@ -579,6 +579,14 @@ class Validator::ValidatorImpl: public LoggerImpl */ void checkUniqueIds(const ModelPtr &model); + /** @brief Function to check reset orders within the model scope are unique. + * + * Function to check reset orders within the model scope are unique. + * + * @param model The model to be checked. + */ + void checkUniqueResetOrders(const ModelPtr &model); + /** @brief Utility function to construct a map of identifiers used within the model. * * Utility function to construct a map of identifiers used within the model. @@ -588,6 +596,34 @@ class Validator::ValidatorImpl: public LoggerImpl */ IdMap buildModelIdMap(const ModelPtr &model); + /** @brief Utility function to construct a map of reset orders used within the model. + * + * Utility function to construct a map of reset orders used within the model. + * + * @param model The model to be checked. + * @return A ResetOrderMap of the items in the model with reset orders. + */ + ResetOrderMap buildModelResetOrderMap(const ModelPtr &model); + + /** + * @brief Traverse the component tree populating the reset order map. + * + * Traverse the component tree populating the reset order map. + * + * @param component The component to check and populate from. + * @param resetOrderMap The ResetOrderMap object to construct. + */ + void traverseComponentTree(const ComponentPtr &component, ResetOrderMap &resetOrderMap); + + /** + * @brief Utility function to add an item to the resetOrderMap. + * @param variable The variable to add. + * @param order The order associated with the variable. + * @param resetOrderMap The resetOrderMap under construction. + */ + void addResetOrderMapItem(const VariablePtr &variable, int order, ResetOrderMap &resetOrderMap); + + /** @brief Utility function called recursively to construct a map of identifiers in a component. * * Utility function called recursively to construct a map of identifiers in a component. @@ -762,6 +798,8 @@ void Validator::validateModel(const ModelPtr &model) // Check identifiers across the model are unique. pFunc()->checkUniqueIds(model); + + pFunc()->checkUniqueResetOrders(model); } } @@ -2547,6 +2585,71 @@ void updateBaseUnitCount(const ModelPtr &model, } } +void Validator::ValidatorImpl::checkUniqueResetOrders(const ModelPtr &model) +{ + auto resetOrderMap = buildModelResetOrderMap(model); + for (const auto &variableOrder : resetOrderMap) { + auto variable = variableOrder.first; + auto orders = variableOrder.second; + + std::set ordersSet(orders.begin(), orders.end()); + + if (ordersSet.size() < orders.size()) { + auto issue = Issue::IssueImpl::create(); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_ORDER_UNIQUE); + issue->mPimpl->setDescription("Variable '" + variable->name() + "' used in resets does not have unique order values across the equivalent variable set."); + issue->mPimpl->mItem->mPimpl->setModel(model); + addIssue(issue); + } + } +} + +void Validator::ValidatorImpl::addResetOrderMapItem(const VariablePtr &variable, int order, ResetOrderMap &resetOrderMap) +{ + auto currentVariable = variable; + bool existingVariableFound = resetOrderMap.count(currentVariable) > 0; + size_t i = 0; + + while (i < variable->equivalentVariableCount() && !existingVariableFound) { + currentVariable = variable->equivalentVariable(i); + existingVariableFound = resetOrderMap.count(currentVariable) > 0; + ++i; + } + + if (existingVariableFound) { + resetOrderMap[currentVariable].emplace_back(order); + } else { + std::vector orders = {order}; + resetOrderMap.emplace(variable, orders); + } +} + +void Validator::ValidatorImpl::traverseComponentTree(const ComponentPtr &component, ResetOrderMap &resetOrderMap) +{ + for (size_t j = 0; j < component->resetCount(); ++j) { + auto reset = component->reset(j); + auto currentVariable = reset->variable(); + if ((currentVariable != nullptr) && reset->isOrderSet()) { + addResetOrderMapItem(currentVariable, reset->order(), resetOrderMap); + } + } + + for (size_t i = 0; i < component->componentCount(); ++i) { + traverseComponentTree(component->component(i), resetOrderMap); + } +} + +ResetOrderMap Validator::ValidatorImpl::buildModelResetOrderMap(const ModelPtr &model) +{ + ResetOrderMap resetOrderMap; + for (size_t i = 0; i < model->componentCount(); ++i) { + auto component = model->component(i); + traverseComponentTree(component, resetOrderMap); + } + + return resetOrderMap; +} + void Validator::ValidatorImpl::checkUniqueIds(const ModelPtr &model) { auto idMap = buildModelIdMap(model); diff --git a/tests/validator/validator.cpp b/tests/validator/validator.cpp index ab48a8b23..6ed7686db 100644 --- a/tests/validator/validator.cpp +++ b/tests/validator/validator.cpp @@ -1095,7 +1095,7 @@ TEST(Validator, integerStrings) " \n" " \n" " \n" - " \n" + " \n" " \n" " \n" " \n" @@ -1578,7 +1578,7 @@ TEST(Validator, resetVariableOutsideComponent) { const std::vector expectedIssues = { "Reset in component 'c1' with order '1', with variable 'v2', with test_variable 'v1', refers to a variable 'v2' in a different component 'c2'.", - "Reset in component 'c2' with order '1', with variable 'v2', with test_variable 'v1', refers to a test_variable 'v1' in a different component 'c1'.", + "Reset in component 'c2' with order '2', with variable 'v2', with test_variable 'v1', refers to a test_variable 'v1' in a different component 'c1'.", }; libcellml::ModelPtr m = libcellml::Model::create(); @@ -1612,7 +1612,7 @@ TEST(Validator, resetVariableOutsideComponent) r2->setVariable(v2); r2->setTestVariable(v1); // test_variable outside parent component - r2->setOrder(1); + r2->setOrder(2); r2->setResetValue(EMPTY_MATH); r2->setTestValue(EMPTY_MATH); @@ -1625,6 +1625,116 @@ TEST(Validator, resetVariableOutsideComponent) EXPECT_EQ_ISSUES(expectedIssues, validator); } +libcellml::ModelPtr setupResetOrderModel() +{ + const std::string in = + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + + libcellml::ParserPtr p = libcellml::Parser::create(); + EXPECT_EQ(size_t(0), p->errorCount()); + + return p->parseModel(in); +} + +TEST(Validator, resetOrderSameVariableSetUnique) +{ + libcellml::ValidatorPtr v = libcellml::Validator::create(); + + auto m = setupResetOrderModel(); + + v->validateModel(m); + printIssues(v); + + EXPECT_EQ(size_t(0), v->errorCount()); +} + +TEST(Validator, resetOrderVariableSetInComponentNotUnique) +{ + const std::vector expectedIssues = { + "Variable 'A' used in resets does not have unique order values across the equivalent variable set.", + }; + + libcellml::ValidatorPtr v = libcellml::Validator::create(); + + auto m = setupResetOrderModel(); + + auto c = m->component(0); + auto r = c->reset(1); + r->setOrder(1); + + v->validateModel(m); + printIssues(v); + + EXPECT_EQ_ISSUES(expectedIssues, v); +} + +TEST(Validator, resetOrderVariableSetInEquivalentSetNotUnique) +{ + const std::vector expectedIssues = { + "Variable 'A' used in resets does not have unique order values across the equivalent variable set.", + }; + + libcellml::ValidatorPtr v = libcellml::Validator::create(); + + auto m = setupResetOrderModel(); + + auto c = m->component(1); + auto r = c->reset(0); + r->setOrder(1); + + v->validateModel(m); + printIssues(v); + + EXPECT_EQ_ISSUES(expectedIssues, v); +} + TEST(Validator, validMathCnElements) { const std::string math = From 2b4cda790853fa444ee1db91a5e0f8f1dd0045eb Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Thu, 11 Apr 2024 14:43:34 +0100 Subject: [PATCH 25/50] Cover all 2.10 and 2.11 validation issues. --- src/parser.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/parser.cpp b/src/parser.cpp index fdb59445a..00aaed1be 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1628,7 +1628,11 @@ void Parser::ParserImpl::loadResetChild(const std::string &childType, const Rese auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("The " + childType + " in the reset in component '" + component->name() + "' referencing variable '" + variableName + "' and test_variable '" + testVariableName + "' should have a MathML block as a child."); issue->mPimpl->mItem->mPimpl->setReset(reset); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_CHILD); + if (childType == "test_value") { + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::TEST_VALUE_CHILD); + } else { + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_VALUE_CHILD); + } addIssue(issue); } } From 21e305b289bd73f87e0d1614a5578c168f0e6139 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Thu, 11 Apr 2024 14:50:09 +0100 Subject: [PATCH 26/50] Cover all 2.12 validation issues. --- src/validator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/validator.cpp b/src/validator.cpp index d26348d5a..d2683b399 100644 --- a/src/validator.cpp +++ b/src/validator.cpp @@ -1565,7 +1565,7 @@ void Validator::ValidatorImpl::validateMath(const std::string &input, const Comp auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Math root node is of invalid type '" + node->name() + "' on component '" + component->name() + "'. A valid math root node should be of type 'math'."); issue->mPimpl->mItem->mPimpl->setComponent(component); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::MATH_ELEMENT); addIssue(issue); return; } From b310c32ee96aa4a001569ef546bc24a521075d42 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Thu, 11 Apr 2024 15:27:38 +0100 Subject: [PATCH 27/50] Cover all 2.14 validation issues. --- src/parser.cpp | 23 ++++++++++++++++++----- tests/parser/parser.cpp | 11 ++++++++--- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index 00aaed1be..8e8783695 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -120,10 +120,11 @@ class Parser::ParserImpl: public Logger::LoggerImpl * * @param model The @c ModelPtr to update. * @param node The @c XmlNodePtr to parse and update the model with. + * @param usedNames List of components already used in loading component hierarchy. * * @return A @c ComponentPtr which is the root of the component hierarchy. */ - ComponentPtr loadComponentRef(const ModelPtr &model, const XmlNodePtr &node); + ComponentPtr loadComponentRef(const ModelPtr &model, const XmlNodePtr &node, NameList &usedNames); /** * @brief Update the @p import source with attributes parsed from @p node and add any imported @@ -1295,7 +1296,7 @@ void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr } } -ComponentPtr Parser::ParserImpl::loadComponentRef(const ModelPtr &model, const XmlNodePtr &node) +ComponentPtr Parser::ParserImpl::loadComponentRef(const ModelPtr &model, const XmlNodePtr &node, NameList &usedNames) { ComponentPtr parentComponent = nullptr; std::string parentComponentName; @@ -1305,6 +1306,17 @@ ComponentPtr Parser::ParserImpl::loadComponentRef(const ModelPtr &model, const X while (attribute != nullptr) { if (attribute->isType("component")) { parentComponentName = attribute->value(); + + if (std::find(usedNames.begin(), usedNames.end(), parentComponentName) == usedNames.end()) { + usedNames.emplace_back(parentComponentName); + } else { + auto issue = Issue::IssueImpl::create(); + issue->mPimpl->setDescription("Encapsulation in model '" + model->name() + "' specifies '" + parentComponentName + "' as a component in a component_ref but it is not unique."); + issue->mPimpl->mItem->mPimpl->setEncapsulation(model); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::COMPONENT_REF_COMPONENT_ATTRIBUTE_UNIQUE); + addIssue(issue); + } + if (model->containsComponent(parentComponentName)) { // Will re-add this to the model once we encapsulate the child(ren). parentComponent = model->takeComponent(parentComponentName); @@ -1321,7 +1333,7 @@ ComponentPtr Parser::ParserImpl::loadComponentRef(const ModelPtr &model, const X auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Encapsulation in model '" + model->name() + "' has an invalid component_ref attribute '" + attribute->name() + "'."); issue->mPimpl->mItem->mPimpl->setEncapsulation(model); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::COMPONENT_REF_COMPONENT_ATTRIBUTE); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::COMPONENT_REF_ELEMENT); addIssue(issue); } attribute = attribute->next(); @@ -1344,7 +1356,7 @@ ComponentPtr Parser::ParserImpl::loadComponentRef(const ModelPtr &model, const X while (childComponentNode) { ComponentPtr childComponent = nullptr; if (parseNode(childComponentNode, "component_ref")) { - childComponent = loadComponentRef(model, childComponentNode); + childComponent = loadComponentRef(model, childComponentNode, usedNames); } else if (childComponentNode->isText()) { const std::string textNode = childComponentNode->convertToString(); // Ignore whitespace when parsing. @@ -1383,6 +1395,7 @@ ComponentPtr Parser::ParserImpl::loadComponentRef(const ModelPtr &model, const X void Parser::ParserImpl::loadEncapsulation(const ModelPtr &model, const XmlNodePtr &node) { + NameList usedNames; XmlNodePtr componentRefNode = node->firstChild(); while (componentRefNode != nullptr) { ComponentPtr parentComponent = nullptr; @@ -1390,7 +1403,7 @@ void Parser::ParserImpl::loadEncapsulation(const ModelPtr &model, const XmlNodeP bool haveComponentRef = false; if (parseNode(componentRefNode, "component_ref")) { haveComponentRef = true; - parentComponent = loadComponentRef(model, componentRefNode); + parentComponent = loadComponentRef(model, componentRefNode, usedNames); } else if (componentRefNode->isText()) { const std::string textNode = componentRefNode->convertToString(); // Ignore whitespace when parsing. diff --git a/tests/parser/parser.cpp b/tests/parser/parser.cpp index 11f86df6b..cb71ec0d6 100644 --- a/tests/parser/parser.cpp +++ b/tests/parser/parser.cpp @@ -701,14 +701,19 @@ TEST(Parser, encapsulationWithCycleDefined) " \n" "\n"; - const std::vector expectedIssues = { + const std::vector expectedIssuesParser = { + "Encapsulation in model 'model_name' specifies 'bob' as a component in a component_ref but it is not unique.", + }; + + const std::vector expectedIssuesValidator = { "Model 'model_name' contains multiple components with the name 'bob'. Valid component names must be unique to their model.", }; libcellml::ParserPtr p = libcellml::Parser::create(); auto m = p->parseModel(in); - EXPECT_EQ(size_t(0), p->issueCount()); + EXPECT_EQ(size_t(1), p->issueCount()); + EXPECT_EQ_ISSUES(expectedIssuesParser, p); libcellml::PrinterPtr printer = libcellml::Printer::create(); auto output = printer->printModel(m); @@ -717,7 +722,7 @@ TEST(Parser, encapsulationWithCycleDefined) libcellml::ValidatorPtr v = libcellml::Validator::create(); v->validateModel(m); - EXPECT_EQ_ISSUES(expectedIssues, v); + EXPECT_EQ_ISSUES(expectedIssuesValidator, v); } TEST(Parser, encapsulationWithNoComponentAttribute) From 9ca44bbdd766dffdc3e542391cc5cc82b9b4ffa4 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Thu, 11 Apr 2024 16:37:25 +0100 Subject: [PATCH 28/50] Cover all 2.15 validation issues. --- src/internaltypes.h | 1 + src/parser.cpp | 39 ++++++++++++++++-- tests/connection/connection.cpp | 72 +++++++++++++++++++++++---------- tests/parser/parser.cpp | 3 ++ tests/validator/validator.cpp | 3 -- 5 files changed, 91 insertions(+), 27 deletions(-) diff --git a/src/internaltypes.h b/src/internaltypes.h index fea0c48dc..2b2fe1088 100644 --- a/src/internaltypes.h +++ b/src/internaltypes.h @@ -73,6 +73,7 @@ using ParentedEntityConstPtr = std::shared_ptr; /**< Type using UnitsConstPtr = std::shared_ptr; /**< Type definition for shared units const pointer. */ using ConnectionMap = std::map; /**< Type definition for a connection map.*/ +using ConnectionList = std::vector>; /**< Type definition for a list of connections. */ /** * @brief Class for defining an epoch in the history of a @ref Component or @ref Units. diff --git a/src/parser.cpp b/src/parser.cpp index 8e8783695..df2448bb9 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -97,8 +97,9 @@ class Parser::ParserImpl: public Logger::LoggerImpl * * @param model The @c ModelPtr to update. * @param node The @c XmlNodePtr to parse and update the model with. + * @param usedConnections A list of connections that have already been used. */ - void loadConnection(const ModelPtr &model, const XmlNodePtr &node); + void loadConnection(const ModelPtr &model, const XmlNodePtr &node, ConnectionList &usedConnections); /** * @brief Update the @p model with an encapsulation parsed from @p node. @@ -566,8 +567,10 @@ void Parser::ParserImpl::loadModel(const ModelPtr &model, const std::string &inp addIssue(issue); } } + + ConnectionList usedConnections; for (const auto &connectionNode : connectionNodes) { - loadConnection(model, connectionNode); + loadConnection(model, connectionNode, usedConnections); } // Link units to their names. @@ -961,7 +964,7 @@ void Parser::ParserImpl::loadVariable(const VariablePtr &variable, const XmlNode } } -void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr &node) +void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr &node, ConnectionList &usedConnections) { // Define types for variable and component pairs, and their identifiers. using NameInfo = std::vector; @@ -1066,6 +1069,36 @@ void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr componentNamePair = std::make_pair(component1Name, component2Name); + if (!component1Missing && !component2Missing) { + + if (component1Name == component2Name) { + auto issue = Issue::IssueImpl::create(); + issue->mPimpl->setDescription("Connection in model '" + model->name() + "' has a connection to itself, the at fault component is '" + component1Name + "'."); + issue->mPimpl->mItem->mPimpl->setModel(model); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::CONNECTION_EXCLUDE_SELF); + addIssue(issue); + } + + ConnectionList::const_iterator it; + if (component1Name < component2Name) { + it = std::find_if(usedConnections.begin(), usedConnections.end(), + [&componentNamePair](const std::pair& element){ return element.first == componentNamePair.first && element.second == componentNamePair.second;}); + } else { + it = std::find_if(usedConnections.begin(), usedConnections.end(), + [&componentNamePair](const std::pair& element){ return element.first == componentNamePair.second && element.second == componentNamePair.first;}); + } + + if (it == usedConnections.end()) { + usedConnections.emplace_back(componentNamePair); + } else { + auto issue = Issue::IssueImpl::create(); + issue->mPimpl->setDescription("Connection in model '" + model->name() + "' between '" + component1Name + "' and '" + component2Name + "' is not unique."); + issue->mPimpl->mItem->mPimpl->setModel(model); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::CONNECTION_UNIQUE); + addIssue(issue); + } + } + XmlNodePtr childNode = node->firstChild(); if (childNode == nullptr) { diff --git a/tests/connection/connection.cpp b/tests/connection/connection.cpp index c478fb53c..73c085c20 100644 --- a/tests/connection/connection.cpp +++ b/tests/connection/connection.cpp @@ -16,6 +16,7 @@ limitations under the License. #include "gtest/gtest.h" +#include "test_utils.h" #include TEST(Variable, addEquivalenceNullptrFirstParameter) @@ -1312,27 +1313,28 @@ TEST(Connection, componentConnectionAndParseMissingVariable) TEST(Connection, mappingId) { - const std::string in = "\n" - "\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - - "\n"; + const std::string in = + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + auto parser = libcellml::Parser::create(); auto model = parser->parseModel(in); EXPECT_EQ("id12a", @@ -1348,3 +1350,31 @@ TEST(Connection, mappingId) model->component("c1")->variable("v1"), model->component("c3")->variable("v3"))); } + +TEST(Connection, repeatedConnection) +{ + const std::string in = + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + + libcellml::ParserPtr p = libcellml::Parser::create(); + libcellml::ModelPtr m = p->parseModel(in); + + const std::string expectedIssue = "Connection in model 'connection' between 'component1' and 'component2' is not unique."; + + EXPECT_EQ(size_t(1), p->errorCount()); + EXPECT_EQ(expectedIssue, p->error(0)->description()); +} diff --git a/tests/parser/parser.cpp b/tests/parser/parser.cpp index cb71ec0d6..f3366a03a 100644 --- a/tests/parser/parser.cpp +++ b/tests/parser/parser.cpp @@ -1145,7 +1145,10 @@ TEST(Parser, connectionErrorNoMapVariables) "\n"; const std::vector expectedIssues = { "Connection in model '' has an invalid connection attribute 'component_3'.", + "Connection in model '' has a connection to itself, the at fault component is 'componentA'.", "Connection in model '' does not contain any 'map_variables' elements and will be disregarded.", + "Connection in model '' has a connection to itself, the at fault component is 'componentA'.", + "Connection in model '' between 'componentA' and 'componentA' is not unique.", "Connection in model '' does not contain any 'map_variables' elements and will be disregarded.", }; diff --git a/tests/validator/validator.cpp b/tests/validator/validator.cpp index 6ed7686db..e7d4ec9d2 100644 --- a/tests/validator/validator.cpp +++ b/tests/validator/validator.cpp @@ -1690,7 +1690,6 @@ TEST(Validator, resetOrderSameVariableSetUnique) auto m = setupResetOrderModel(); v->validateModel(m); - printIssues(v); EXPECT_EQ(size_t(0), v->errorCount()); } @@ -1710,7 +1709,6 @@ TEST(Validator, resetOrderVariableSetInComponentNotUnique) r->setOrder(1); v->validateModel(m); - printIssues(v); EXPECT_EQ_ISSUES(expectedIssues, v); } @@ -1730,7 +1728,6 @@ TEST(Validator, resetOrderVariableSetInEquivalentSetNotUnique) r->setOrder(1); v->validateModel(m); - printIssues(v); EXPECT_EQ_ISSUES(expectedIssues, v); } From e50dc61a837ec24e5d2eeb7a312641b66423cf8c Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Thu, 11 Apr 2024 19:06:47 +0100 Subject: [PATCH 29/50] Cover all 2.16 validation issues. --- src/parser.cpp | 58 +++++++++++++++++++++++---------- tests/connection/connection.cpp | 35 ++++++++++++++++++++ tests/parser/parser.cpp | 1 - 3 files changed, 76 insertions(+), 18 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index df2448bb9..d10b4e1ed 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1077,25 +1077,25 @@ void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr issue->mPimpl->mItem->mPimpl->setModel(model); issue->mPimpl->setReferenceRule(Issue::ReferenceRule::CONNECTION_EXCLUDE_SELF); addIssue(issue); - } - - ConnectionList::const_iterator it; - if (component1Name < component2Name) { - it = std::find_if(usedConnections.begin(), usedConnections.end(), - [&componentNamePair](const std::pair& element){ return element.first == componentNamePair.first && element.second == componentNamePair.second;}); } else { - it = std::find_if(usedConnections.begin(), usedConnections.end(), - [&componentNamePair](const std::pair& element){ return element.first == componentNamePair.second && element.second == componentNamePair.first;}); - } + if (component1Name > component2Name) { + std::string tmp = component1Name; + component1Name = component2Name; + component2Name = tmp; + } - if (it == usedConnections.end()) { - usedConnections.emplace_back(componentNamePair); - } else { - auto issue = Issue::IssueImpl::create(); - issue->mPimpl->setDescription("Connection in model '" + model->name() + "' between '" + component1Name + "' and '" + component2Name + "' is not unique."); - issue->mPimpl->mItem->mPimpl->setModel(model); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::CONNECTION_UNIQUE); - addIssue(issue); + ConnectionList::const_iterator it = std::find_if(usedConnections.begin(), usedConnections.end(), + [&component1Name, &component2Name](const std::pair& element){ return element.first == component1Name && element.second == component2Name;}); + + if (it == usedConnections.end()) { + usedConnections.emplace_back(componentNamePair); + } else { + auto issue = Issue::IssueImpl::create(); + issue->mPimpl->setDescription("Connection in model '" + model->name() + "' between '" + component1Name + "' and '" + component2Name + "' is not unique."); + issue->mPimpl->mItem->mPimpl->setModel(model); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::CONNECTION_UNIQUE); + addIssue(issue); + } } } @@ -1119,6 +1119,7 @@ void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr } // Iterate over connection child XML nodes. + ConnectionList usedMapVariables; while (childNode != nullptr) { // Connection map XML nodes should not have further children. XmlNodePtr grandchildNode = childNode->firstChild(); @@ -1207,6 +1208,29 @@ void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr variableNameMap.push_back(variableNameInfo); mapVariablesFound = true; + if (!variable1Missing && !variable2Missing) { + if (variable1Name > variable2Name) { + std::string tmp = variable1Name; + variable1Name = variable2Name; + variable2Name = tmp; + } + + auto variableNamePair = std::make_pair(variable1Name, variable2Name); + + ConnectionList::const_iterator it = std::find_if(usedMapVariables.begin(), usedMapVariables.end(), + [&variableNamePair](const std::pair& element){ return element.first == variableNamePair.first && element.second == variableNamePair.second;}); + + if (it == usedMapVariables.end()) { + usedMapVariables.emplace_back(variableNamePair); + } else { + auto issue = Issue::IssueImpl::create(); + issue->mPimpl->setDescription("Connection in model '" + model->name() + "' between '" + variableNamePair.first + "' and '" + variableNamePair.second + "' is not unique."); + issue->mPimpl->mItem->mPimpl->setModel(model); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::MAP_VARIABLES_UNIQUE); + addIssue(issue); + } + } + } else if (childNode->isText()) { const std::string textNode = childNode->convertToString(); // Ignore whitespace when parsing. diff --git a/tests/connection/connection.cpp b/tests/connection/connection.cpp index 73c085c20..d138c643c 100644 --- a/tests/connection/connection.cpp +++ b/tests/connection/connection.cpp @@ -1378,3 +1378,38 @@ TEST(Connection, repeatedConnection) EXPECT_EQ(size_t(1), p->errorCount()); EXPECT_EQ(expectedIssue, p->error(0)->description()); } + +TEST(Connection, repeatedMapVariables) +{ + const std::string in = + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + + libcellml::ParserPtr p = libcellml::Parser::create(); + libcellml::ModelPtr m = p->parseModel(in); + + 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.", + }; + + printIssues(p); + EXPECT_EQ_ISSUES(expectedIssues, p); +} diff --git a/tests/parser/parser.cpp b/tests/parser/parser.cpp index f3366a03a..afe8d8b2c 100644 --- a/tests/parser/parser.cpp +++ b/tests/parser/parser.cpp @@ -1148,7 +1148,6 @@ TEST(Parser, connectionErrorNoMapVariables) "Connection in model '' has a connection to itself, the at fault component is 'componentA'.", "Connection in model '' does not contain any 'map_variables' elements and will be disregarded.", "Connection in model '' has a connection to itself, the at fault component is 'componentA'.", - "Connection in model '' between 'componentA' and 'componentA' is not unique.", "Connection in model '' does not contain any 'map_variables' elements and will be disregarded.", }; From ffafd874cb870cabe795baf9cad4c554651ca361 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Thu, 11 Apr 2024 19:17:37 +0100 Subject: [PATCH 30/50] Rename typedef ConnectionList to NamePairList. --- src/internaltypes.h | 3 ++- src/parser.cpp | 15 +++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/internaltypes.h b/src/internaltypes.h index 2b2fe1088..367bd4d9e 100644 --- a/src/internaltypes.h +++ b/src/internaltypes.h @@ -34,6 +34,7 @@ using ComponentNameMap = std::map; /**< Type definiti using IndexStack = std::vector; /**< Type definition for tracking indicies. */ using EquivalenceMap = std::map>; /**< Type definition for map of variable equivalences defined over model. */ +using NamePair = std::pair; /**< Type definition for pair of names. */ using NameList = std::vector; /**< Type definition for list of names. */ using DescriptionList = std::vector>; /**< Type definition for list of variables and associated description. */ using StringStringMap = std::map; /**< Type definition for map of string to string. */ @@ -73,7 +74,7 @@ using ParentedEntityConstPtr = std::shared_ptr; /**< Type using UnitsConstPtr = std::shared_ptr; /**< Type definition for shared units const pointer. */ using ConnectionMap = std::map; /**< Type definition for a connection map.*/ -using ConnectionList = std::vector>; /**< Type definition for a list of connections. */ +using NamePairList = std::vector; /**< Type definition for a list of a pair of names. */ /** * @brief Class for defining an epoch in the history of a @ref Component or @ref Units. diff --git a/src/parser.cpp b/src/parser.cpp index d10b4e1ed..211408943 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -99,7 +99,7 @@ class Parser::ParserImpl: public Logger::LoggerImpl * @param node The @c XmlNodePtr to parse and update the model with. * @param usedConnections A list of connections that have already been used. */ - void loadConnection(const ModelPtr &model, const XmlNodePtr &node, ConnectionList &usedConnections); + void loadConnection(const ModelPtr &model, const XmlNodePtr &node, NamePairList &usedConnections); /** * @brief Update the @p model with an encapsulation parsed from @p node. @@ -568,7 +568,7 @@ void Parser::ParserImpl::loadModel(const ModelPtr &model, const std::string &inp } } - ConnectionList usedConnections; + NamePairList usedConnections; for (const auto &connectionNode : connectionNodes) { loadConnection(model, connectionNode, usedConnections); } @@ -964,12 +964,11 @@ void Parser::ParserImpl::loadVariable(const VariablePtr &variable, const XmlNode } } -void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr &node, ConnectionList &usedConnections) +void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr &node, NamePairList &usedConnections) { // Define types for variable and component pairs, and their identifiers. using NameInfo = std::vector; using NameInfoMap = std::vector; - using NamePair = std::pair; // Initialise name pairs and flags. NamePair componentNamePair; @@ -1084,7 +1083,7 @@ void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr component2Name = tmp; } - ConnectionList::const_iterator it = std::find_if(usedConnections.begin(), usedConnections.end(), + NamePairList::const_iterator it = std::find_if(usedConnections.begin(), usedConnections.end(), [&component1Name, &component2Name](const std::pair& element){ return element.first == component1Name && element.second == component2Name;}); if (it == usedConnections.end()) { @@ -1119,7 +1118,7 @@ void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr } // Iterate over connection child XML nodes. - ConnectionList usedMapVariables; + NamePairList usedMapVariables; while (childNode != nullptr) { // Connection map XML nodes should not have further children. XmlNodePtr grandchildNode = childNode->firstChild(); @@ -1217,8 +1216,8 @@ void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr auto variableNamePair = std::make_pair(variable1Name, variable2Name); - ConnectionList::const_iterator it = std::find_if(usedMapVariables.begin(), usedMapVariables.end(), - [&variableNamePair](const std::pair& element){ return element.first == variableNamePair.first && element.second == variableNamePair.second;}); + NamePairList::const_iterator it = std::find_if(usedMapVariables.begin(), usedMapVariables.end(), + [&variableNamePair](const std::pair& element){ return element.first == variableNamePair.first && element.second == variableNamePair.second;}); if (it == usedMapVariables.end()) { usedMapVariables.emplace_back(variableNamePair); From 5e3cae79c40f8c9dda57ee21a80b292443706af1 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Thu, 11 Apr 2024 19:32:41 +0100 Subject: [PATCH 31/50] Replace 'or' with '||'. --- src/parser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parser.cpp b/src/parser.cpp index 211408943..99ea10fc7 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -946,7 +946,7 @@ void Parser::ParserImpl::loadVariable(const VariablePtr &variable, const XmlNode attribute = attribute->next(); } - if (!nameAttributePresent or !unitsAttributePresent) { + if (!nameAttributePresent || !unitsAttributePresent) { auto issue = Issue::IssueImpl::create(); std::string description = "Variable "; if (nameAttributePresent) { From dfb9af5fe06299b5d953797e2a40c1d72d77d652 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Thu, 11 Apr 2024 19:41:48 +0100 Subject: [PATCH 32/50] Correct Javascript test answer for number of parse errors. --- tests/bindings/javascript/types.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bindings/javascript/types.test.js b/tests/bindings/javascript/types.test.js index e9070b76a..0232f7c17 100644 --- a/tests/bindings/javascript/types.test.js +++ b/tests/bindings/javascript/types.test.js @@ -49,7 +49,7 @@ describe("Types tests", () => { const p = new libcellml.Parser(true) const m = p.parseModel(modelWithParseErrors) - expect(p.issueCount()).toBe(4) + expect(p.issueCount()).toBe(5) const item = p.issue(2).item() From 41d934602282807c7d13d7d8e880b6e9fcde4085 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Thu, 11 Apr 2024 20:06:54 +0100 Subject: [PATCH 33/50] Apply clang format fixes. --- src/parser.cpp | 7 +++---- src/validator.cpp | 1 - 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index 99ea10fc7..7874d52e6 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -952,7 +952,7 @@ void Parser::ParserImpl::loadVariable(const VariablePtr &variable, const XmlNode if (nameAttributePresent) { description += "'" + node->attribute("name") + "' does not specify a units attribute."; } else if (unitsAttributePresent) { - description += "with units '" + node->attribute("units") + "' does not specify a name attribute."; + description += "with units '" + node->attribute("units") + "' does not specify a name attribute."; } else { description += "does not specify a name attribute or a units attribute."; } @@ -1069,7 +1069,6 @@ void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr componentNamePair = std::make_pair(component1Name, component2Name); if (!component1Missing && !component2Missing) { - if (component1Name == component2Name) { auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Connection in model '" + model->name() + "' has a connection to itself, the at fault component is '" + component1Name + "'."); @@ -1084,7 +1083,7 @@ void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr } NamePairList::const_iterator it = std::find_if(usedConnections.begin(), usedConnections.end(), - [&component1Name, &component2Name](const std::pair& element){ return element.first == component1Name && element.second == component2Name;}); + [&component1Name, &component2Name](const std::pair &element) { return element.first == component1Name && element.second == component2Name; }); if (it == usedConnections.end()) { usedConnections.emplace_back(componentNamePair); @@ -1217,7 +1216,7 @@ void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr auto variableNamePair = std::make_pair(variable1Name, variable2Name); NamePairList::const_iterator it = std::find_if(usedMapVariables.begin(), usedMapVariables.end(), - [&variableNamePair](const std::pair& element){ return element.first == variableNamePair.first && element.second == variableNamePair.second;}); + [&variableNamePair](const std::pair &element) { return element.first == variableNamePair.first && element.second == variableNamePair.second; }); if (it == usedMapVariables.end()) { usedMapVariables.emplace_back(variableNamePair); diff --git a/src/validator.cpp b/src/validator.cpp index d2683b399..56cab52ab 100644 --- a/src/validator.cpp +++ b/src/validator.cpp @@ -623,7 +623,6 @@ class Validator::ValidatorImpl: public LoggerImpl */ void addResetOrderMapItem(const VariablePtr &variable, int order, ResetOrderMap &resetOrderMap); - /** @brief Utility function called recursively to construct a map of identifiers in a component. * * Utility function called recursively to construct a map of identifiers in a component. From dd7392fd3d647ff3d2ca3849a8528aafe127d22f Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Sat, 20 Apr 2024 10:53:59 +1200 Subject: [PATCH 34/50] Add catch for attributes with namespaces that are not allowed by the specification. --- src/api/libcellml/issue.h | 2 +- src/bindings/javascript/issue.cpp | 2 +- src/bindings/python/__init__.py | 2 +- src/internaltypes.h | 1 + src/issue.cpp | 2 +- src/parser.cpp | 23 ++++++++++- src/xmlutils.cpp | 43 +++++++++++++++++---- src/xmlutils.h | 13 +++++++ tests/bindings/python/test_issue.py | 2 +- tests/coverage/coverage.cpp | 59 +++++++++++++++++++++++++++-- tests/parser/parser.cpp | 40 +++++++++++++++++++ 11 files changed, 170 insertions(+), 19 deletions(-) diff --git a/src/api/libcellml/issue.h b/src/api/libcellml/issue.h index 445839728..8194a0f49 100644 --- a/src/api/libcellml/issue.h +++ b/src/api/libcellml/issue.h @@ -73,7 +73,7 @@ class LIBCELLML_EXPORT Issue XML_UNEXPECTED_ELEMENT, XML_UNEXPECTED_CHARACTER, XML_UNEXPECTED_NAMESPACE, - XML_UNEXPECTED_NAMESPACE_PREFIX, + XML_ATTRIBUTE_HAS_NAMESPACE, XML_ID_ATTRIBUTE, MODEL_ELEMENT, MODEL_NAME, diff --git a/src/bindings/javascript/issue.cpp b/src/bindings/javascript/issue.cpp index 48b55d823..01a14768b 100644 --- a/src/bindings/javascript/issue.cpp +++ b/src/bindings/javascript/issue.cpp @@ -160,7 +160,7 @@ EMSCRIPTEN_BINDINGS(libcellml_issue) { .value("XML_UNEXPECTED_CHARACTER", libcellml::Issue::ReferenceRule::XML_UNEXPECTED_CHARACTER) .value("XML_UNEXPECTED_ELEMENT", libcellml::Issue::ReferenceRule::XML_UNEXPECTED_ELEMENT) .value("XML_UNEXPECTED_NAMESPACE", libcellml::Issue::ReferenceRule::XML_UNEXPECTED_NAMESPACE) - .value("XML_UNEXPECTED_NAMESPACE_PREFIX", libcellml::Issue::ReferenceRule::XML_UNEXPECTED_NAMESPACE_PREFIX) + .value("XML_ATTRIBUTE_HAS_NAMESPACE", libcellml::Issue::ReferenceRule::XML_ATTRIBUTE_HAS_NAMESPACE) ; class_("Issue") diff --git a/src/bindings/python/__init__.py b/src/bindings/python/__init__.py index 5f28af5f4..d2ca733cf 100644 --- a/src/bindings/python/__init__.py +++ b/src/bindings/python/__init__.py @@ -200,7 +200,7 @@ class Object: 'XML_UNEXPECTED_ELEMENT', 'XML_UNEXPECTED_CHARACTER', 'XML_UNEXPECTED_NAMESPACE', - 'XML_UNEXPECTED_NAMESPACE_PREFIX', + 'XML_ATTRIBUTE_HAS_NAMESPACE', 'XML_ID_ATTRIBUTE', 'MODEL_ELEMENT', 'MODEL_NAME', diff --git a/src/internaltypes.h b/src/internaltypes.h index 367bd4d9e..c6b440a26 100644 --- a/src/internaltypes.h +++ b/src/internaltypes.h @@ -39,6 +39,7 @@ using NameList = std::vector; /**< Type definition for list of name using DescriptionList = std::vector>; /**< Type definition for list of variables and associated description. */ using StringStringMap = std::map; /**< Type definition for map of string to string. */ using UniqueNames = std::set; /**< Type definition for a set of unique names. */ +using NodeAttributeNamespaceInfo = std::vector>; /**< Type definition for attribute namespace information. */ // VariableMap using VariableMap = std::vector; /**< Type definition for vector of VariablePair.*/ diff --git a/src/issue.cpp b/src/issue.cpp index 48758212e..6d43d195d 100644 --- a/src/issue.cpp +++ b/src/issue.cpp @@ -84,7 +84,7 @@ static const std::map> ruleToInfo {Issue::ReferenceRule::XML_UNEXPECTED_ELEMENT, {"XML_UNEXPECTED_ELEMENT", "1.2.2.2", baseSpecificationUrl, "specA02"}}, {Issue::ReferenceRule::XML_UNEXPECTED_CHARACTER, {"XML_UNEXPECTED_CHARACTER", "1.2.3.2", baseSpecificationUrl, "specA02"}}, {Issue::ReferenceRule::XML_UNEXPECTED_NAMESPACE, {"XML_UNEXPECTED_NAMESPACE", "1.2.4.1", baseSpecificationUrl, "specA02"}}, - {Issue::ReferenceRule::XML_UNEXPECTED_NAMESPACE_PREFIX, {"XML_UNEXPECTED_NAMESPACE_PREFIX", "1.2.4.2", baseSpecificationUrl, "specA02"}}, + {Issue::ReferenceRule::XML_ATTRIBUTE_HAS_NAMESPACE, {"XML_ATTRIBUTE_HAS_NAMESPACE", "1.2.4.2", baseSpecificationUrl, "specA02"}}, {Issue::ReferenceRule::XML_ID_ATTRIBUTE, {"XML_ID_ATTRIBUTE", "1.2.5.1.1", baseSpecificationUrl, "specA02"}}, {Issue::ReferenceRule::MODEL_ELEMENT, {"MODEL_ELEMENT", "2.1", baseSpecificationUrl, "specB01"}}, {Issue::ReferenceRule::MODEL_NAME, {"MODEL_NAME", "2.1.1", baseSpecificationUrl, "specB01"}}, diff --git a/src/parser.cpp b/src/parser.cpp index 7874d52e6..b9a25be57 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -17,8 +17,6 @@ limitations under the License. #include "libcellml/parser.h" #include -#include -#include #include #include @@ -405,6 +403,27 @@ void Parser::ParserImpl::loadModel(const ModelPtr &model, const std::string &inp } mParsing20Version = node->isCellml20Element("model"); + + auto attributeNamespaceMap = traverseTreeForAttributeNamespaces(node); + if (!attributeNamespaceMap.empty() && mParsing20Version) { + for (const auto &e : attributeNamespaceMap) { + std::string nodeName = std::get<0>(e); + std::string nodeUri = std::get<4>(e); + std::string attributeName = std::get<1>(e); + std::string uri = std::get<3>(e); + if (nodeName == "cn" && nodeUri == MATHML_NS && attributeName == "units" && uri == CELLML_2_0_NS) { + // Explicitly allowed attribute namespace prefix. + } else if (nodeName == "import" && nodeUri == CELLML_2_0_NS && attributeName == "href" && uri == XLINK_NS) { + // Explicitly allowed attribute namespace prefix. + } else { + auto issue = Issue::IssueImpl::create(); + issue->mPimpl->setDescription("Element '" + nodeName + "' attribute '" + attributeName + "' has a namespace specified."); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML_ATTRIBUTE_HAS_NAMESPACE); + addIssue(issue); + } + } + } + if ((mParser->isStrict() && !mParsing20Version) || !node->isCellmlElement("model")) { auto issue = Issue::IssueImpl::create(); if (node->name() == "model") { diff --git a/src/xmlutils.cpp b/src/xmlutils.cpp index 086a4d716..18e6e598b 100644 --- a/src/xmlutils.cpp +++ b/src/xmlutils.cpp @@ -23,20 +23,23 @@ limitations under the License. namespace libcellml { /** - * @brief Return a map of namespaces on attributes for this node. + * @brief Return a list of namespaces on attributes for this node. * - * Scans all attributes of the node and records any associated namespace - * attached to the attribute in an @c XmlNamespaceMap. + * Scans all attributes of the node and records anyassociated + * non-empty namespace attached to the attribute in an + * @c NodeAttributeNamespaceInfo list. * * @param node The @c XmlNode to scan attributes of. - * @return @c XmlNamespaceMap of namespaces on attributes for the given @p node. + * @return @c NodeAttributeNamespaceInfo of namespaces on attributes for the given @p node. */ -XmlNamespaceMap attributeNamespaces(const XmlNodePtr &node) +NodeAttributeNamespaceInfo attributeNamespaces(const XmlNodePtr &node) { - XmlNamespaceMap namespaceMap; + NodeAttributeNamespaceInfo namespaceMap; auto tempAttribute = node->firstAttribute(); while (tempAttribute != nullptr) { - namespaceMap.emplace(tempAttribute->namespacePrefix(), tempAttribute->namespaceUri()); + if (!tempAttribute->namespacePrefix().empty()) { + namespaceMap.emplace_back(std::make_tuple(node->name(), tempAttribute->name(), tempAttribute->namespacePrefix(), tempAttribute->namespaceUri(), node->namespaceUri())); + } tempAttribute = tempAttribute->next(); } return namespaceMap; @@ -55,6 +58,25 @@ XmlNamespaceMap determineMissingNamespaces(const XmlNamespaceMap &namespaceMap1, return undefinedNamespaces; } +NodeAttributeNamespaceInfo traverseTreeForAttributeNamespaces(const XmlNodePtr &node) +{ + NodeAttributeNamespaceInfo nodeAttributeNamespaceInfo; + auto tempNode = node; + while (tempNode != nullptr) { + auto attributeNamespaceList = attributeNamespaces(tempNode); + nodeAttributeNamespaceInfo.insert(nodeAttributeNamespaceInfo.end(), attributeNamespaceList.begin(), attributeNamespaceList.end()); + + auto subNodeAttributeNamespaceInfo = traverseTreeForAttributeNamespaces(tempNode->firstChild()); + + nodeAttributeNamespaceInfo.insert(nodeAttributeNamespaceInfo.end(), subNodeAttributeNamespaceInfo.begin(), subNodeAttributeNamespaceInfo.end()); + + tempNode = tempNode->next(); + } + + return nodeAttributeNamespaceInfo; + +} + XmlNamespaceMap traverseTreeForUndefinedNamespaces(const XmlNodePtr &node) { XmlNamespaceMap undefinedNamespaces; @@ -62,7 +84,12 @@ XmlNamespaceMap traverseTreeForUndefinedNamespaces(const XmlNodePtr &node) while (tempNode != nullptr) { auto definedNamespaces = tempNode->definedNamespaces(); auto usedNamespaces = attributeNamespaces(tempNode); - auto missingNamespaces = determineMissingNamespaces(usedNamespaces, definedNamespaces); + XmlNamespaceMap usedNamespaceMap; + for (const auto &entry : usedNamespaces) { + usedNamespaceMap.emplace(std::get<2>(entry), std::get<3>(entry)); + } + + auto missingNamespaces = determineMissingNamespaces(usedNamespaceMap, definedNamespaces); // Update undefined namespaces with missing namespaces. missingNamespaces.insert(undefinedNamespaces.begin(), undefinedNamespaces.end()); diff --git a/src/xmlutils.h b/src/xmlutils.h index dfe1dec60..f973fd2ce 100644 --- a/src/xmlutils.h +++ b/src/xmlutils.h @@ -18,6 +18,7 @@ limitations under the License. #include +#include "internaltypes.h" #include "xmldoc.h" namespace libcellml { @@ -36,6 +37,18 @@ namespace libcellml { */ XmlNamespaceMap determineMissingNamespaces(const XmlNamespaceMap &namespaceMap1, const XmlNamespaceMap &namespaceMap2); +/** + * @brief Traverse the tree and return an @c NodeAttributeNamespaceInfo of attribute namespaces. + * + * From the root node of the tree given by the @p node, traverse the tree + * searching for attribute namespaces. Returning information on any non-empty + * attribute namespaces. + * + * @param node The root node of the tree to traverse. + * @return @c NodeAttributeNamespaceInfo of attribute namespaces. + */ +NodeAttributeNamespaceInfo traverseTreeForAttributeNamespaces(const XmlNodePtr &node); + /** * @brief Traverse the tree and return an @c XmlNamespaceMap of any undefined namespaces. * diff --git a/tests/bindings/python/test_issue.py b/tests/bindings/python/test_issue.py index 6eca2474b..3de5258c4 100644 --- a/tests/bindings/python/test_issue.py +++ b/tests/bindings/python/test_issue.py @@ -155,7 +155,7 @@ def test_reference_rule_enum(self): self.assertIsInstance(Issue.ReferenceRule.XML_UNEXPECTED_CHARACTER, int) self.assertIsInstance(Issue.ReferenceRule.XML_UNEXPECTED_ELEMENT, int) self.assertIsInstance(Issue.ReferenceRule.XML_UNEXPECTED_NAMESPACE, int) - self.assertIsInstance(Issue.ReferenceRule.XML_UNEXPECTED_NAMESPACE_PREFIX, int) + self.assertIsInstance(Issue.ReferenceRule.XML_ATTRIBUTE_HAS_NAMESPACE, int) def test_coverage(self): from libcellml import Issue diff --git a/tests/coverage/coverage.cpp b/tests/coverage/coverage.cpp index 628beab4e..70e4b3a34 100644 --- a/tests/coverage/coverage.cpp +++ b/tests/coverage/coverage.cpp @@ -46,7 +46,7 @@ TEST(Coverage, connectionComment) TEST(Coverage, importWithNonHrefXlink) { - const std::string e = + const std::string in = "\n" "\n" " \n" @@ -61,10 +61,61 @@ TEST(Coverage, importWithNonHrefXlink) " \n" "\n"; - // Parse libcellml::ParserPtr parser = libcellml::Parser::create(); - parser->parseModel(e); - EXPECT_EQ(size_t(0), parser->issueCount()); + parser->parseModel(in); + EXPECT_EQ(size_t(1), parser->issueCount()); +} + +TEST(Coverage, importWithNamespaceViolations) +{ + const std::string in = + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + + libcellml::ParserPtr parser = libcellml::Parser::create(); + parser->parseModel(in); + EXPECT_EQ(size_t(5), parser->issueCount()); +} + +TEST(Coverage, importWithCnWrongNamespace) +{ + const std::string in = + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " " + " \n" + " a\n" + " 1\n" + " 1\n" + " \n" + " \n" + " \n" + ""; + + libcellml::ParserPtr parser = libcellml::Parser::create(); + parser->parseModel(in); + EXPECT_EQ(size_t(3), parser->issueCount()); } TEST(Coverage, entityHasParent) diff --git a/tests/parser/parser.cpp b/tests/parser/parser.cpp index afe8d8b2c..36a9e2a25 100644 --- a/tests/parser/parser.cpp +++ b/tests/parser/parser.cpp @@ -65,6 +65,46 @@ TEST(Parser, invalidXMLElements) } } +TEST(Parser, xmlAttributesWithNamespacePrefixDefault) +{ + const std::string in = + "\n" + "\n" + " \n" + "\n"; + + const std::vector expectedIssues = { + "Element 'component' attribute 'name' has a namespace specified.", + "Component '' has an invalid attribute 'name'.", + "Component does not specify a name attribute.", + }; + + libcellml::ParserPtr p = libcellml::Parser::create(); + p->parseModel(in); + + EXPECT_EQ_ISSUES(expectedIssues, p); +} + +TEST(Parser, xmlAttributesWithNamespacePrefix) +{ + const std::string in = + "\n" + "\n" + " \n" + "\n"; + + const std::vector expectedIssues = { + "Element 'component' attribute 'name' has a namespace specified.", + "Component '' has an invalid attribute 'name'.", + "Component does not specify a name attribute.", + }; + + libcellml::ParserPtr p = libcellml::Parser::create(); + p->parseModel(in); + + EXPECT_EQ_ISSUES(expectedIssues, p); +} + TEST(Parser, parse) { const std::string e = From dab790820290411e218ac18a3e7559775a76ab21 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Sat, 20 Apr 2024 11:30:27 +1200 Subject: [PATCH 35/50] Catch unexpected element namespaces. --- src/parser.cpp | 16 +++++++++++++++- src/xmlutils.cpp | 20 +++++++++++++++++++- src/xmlutils.h | 12 ++++++++++++ tests/coverage/coverage.cpp | 17 ++++++++++++++++- 4 files changed, 62 insertions(+), 3 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index b9a25be57..5fe64732a 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -404,8 +404,22 @@ void Parser::ParserImpl::loadModel(const ModelPtr &model, const std::string &inp mParsing20Version = node->isCellml20Element("model"); + auto elementNamespaceMap = traverseTreeForElementNamespaces(node); + if (mParsing20Version) { + for (const auto &e : elementNamespaceMap) { + std::string name = e.first; + std::string uri = e.second; + if (uri != CELLML_2_0_NS && uri != MATHML_NS) { + auto issue = Issue::IssueImpl::create(); + issue->mPimpl->setDescription("Element '" + name + "' uses namespace '" + uri + "' which does not belong to an allowed namespace. "); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML_UNEXPECTED_NAMESPACE); + addIssue(issue); + } + } + } + auto attributeNamespaceMap = traverseTreeForAttributeNamespaces(node); - if (!attributeNamespaceMap.empty() && mParsing20Version) { + if (mParsing20Version) { for (const auto &e : attributeNamespaceMap) { std::string nodeName = std::get<0>(e); std::string nodeUri = std::get<4>(e); diff --git a/src/xmlutils.cpp b/src/xmlutils.cpp index 18e6e598b..c134fc610 100644 --- a/src/xmlutils.cpp +++ b/src/xmlutils.cpp @@ -58,6 +58,25 @@ XmlNamespaceMap determineMissingNamespaces(const XmlNamespaceMap &namespaceMap1, return undefinedNamespaces; } +XmlNamespaceMap traverseTreeForElementNamespaces(const XmlNodePtr &node) +{ + XmlNamespaceMap nodeNamespaceMap; + auto tempNode = node; + while (tempNode != nullptr) { + if (!tempNode->isText() && !tempNode->isComment()) { + nodeNamespaceMap.emplace(tempNode->name(), tempNode->namespaceUri()); + } + + auto subNodeNamespaceMap = traverseTreeForElementNamespaces(tempNode->firstChild()); + + nodeNamespaceMap.insert(subNodeNamespaceMap.begin(), subNodeNamespaceMap.end()); + + tempNode = tempNode->next(); + } + + return nodeNamespaceMap; +} + NodeAttributeNamespaceInfo traverseTreeForAttributeNamespaces(const XmlNodePtr &node) { NodeAttributeNamespaceInfo nodeAttributeNamespaceInfo; @@ -74,7 +93,6 @@ NodeAttributeNamespaceInfo traverseTreeForAttributeNamespaces(const XmlNodePtr & } return nodeAttributeNamespaceInfo; - } XmlNamespaceMap traverseTreeForUndefinedNamespaces(const XmlNodePtr &node) diff --git a/src/xmlutils.h b/src/xmlutils.h index f973fd2ce..36a99e4dc 100644 --- a/src/xmlutils.h +++ b/src/xmlutils.h @@ -37,6 +37,18 @@ namespace libcellml { */ XmlNamespaceMap determineMissingNamespaces(const XmlNamespaceMap &namespaceMap1, const XmlNamespaceMap &namespaceMap2); +/** + * @brief Traverse the tree and return an @c XmlNamespaceMap of element namespaces. + * + * From the root node of the tree given by the @p node, traverse the tree + * recording element namespaces. Returning information on any element namespace. + * Text nodes and comment nodes are ignored. + * + * @param node The root node of the tree to traverse. + * @return @c XmlNamespaceMap of element namespaces. + */ +XmlNamespaceMap traverseTreeForElementNamespaces(const XmlNodePtr &node); + /** * @brief Traverse the tree and return an @c NodeAttributeNamespaceInfo of attribute namespaces. * diff --git a/tests/coverage/coverage.cpp b/tests/coverage/coverage.cpp index 70e4b3a34..0b1b24495 100644 --- a/tests/coverage/coverage.cpp +++ b/tests/coverage/coverage.cpp @@ -92,7 +92,7 @@ TEST(Coverage, importWithNamespaceViolations) EXPECT_EQ(size_t(5), parser->issueCount()); } -TEST(Coverage, importWithCnWrongNamespace) +TEST(Coverage, mathCnWithNamespaceViolations) { const std::string in = "\n" @@ -118,6 +118,21 @@ TEST(Coverage, importWithCnWrongNamespace) EXPECT_EQ(size_t(3), parser->issueCount()); } +TEST(Coverage, invalidNamespaceElement) +{ + const std::string in = + "\n" + "\n" + " \n" + " \n" + " \n" + "\n"; + + libcellml::ParserPtr p = libcellml::Parser::create(); + p->parseModel(in); + EXPECT_EQ(size_t(3), p->issueCount()); +} + TEST(Coverage, entityHasParent) { libcellml::ModelPtr m = libcellml::Model::create(); From 4f69c679ac17b8304d4f9b196d632b7cecb5487b Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Sat, 20 Apr 2024 12:19:37 +1200 Subject: [PATCH 36/50] Detect unexpected text when parsing document. --- src/parser.cpp | 47 +++++++++++++++++++-------------- tests/connection/connection.cpp | 1 - tests/parser/parser.cpp | 46 +++++++++++++++----------------- 3 files changed, 48 insertions(+), 46 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index 5fe64732a..17517e4f2 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -564,7 +564,7 @@ void Parser::ParserImpl::loadModel(const ModelPtr &model, const std::string &inp auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Model '" + model->name() + "' has an invalid non-whitespace child text element '" + textNode + "'."); issue->mPimpl->mItem->mPimpl->setModel(model); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::MODEL_CHILD); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML_UNEXPECTED_CHARACTER); addIssue(issue); } } else if (mParsing1XVersion && childNode->isCellml1XElement("group")) { @@ -701,7 +701,7 @@ void Parser::ParserImpl::loadComponent(const ComponentPtr &component, const XmlN auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Component '" + component->name() + "' has an invalid non-whitespace child text element '" + textNode + "'."); issue->mPimpl->mItem->mPimpl->setComponent(component); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::COMPONENT_CHILD); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML_UNEXPECTED_CHARACTER); addIssue(issue); } } else if (childNode->isComment()) { @@ -781,7 +781,7 @@ void Parser::ParserImpl::loadUnits(const UnitsPtr &units, const XmlNodePtr &node auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Units '" + units->name() + "' has an invalid non-whitespace child text element '" + textNode + "'."); issue->mPimpl->mItem->mPimpl->setUnits(units); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNITS_CHILD); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML_UNEXPECTED_CHARACTER); addIssue(issue); } } else if (childNode->isComment()) { @@ -814,7 +814,7 @@ void Parser::ParserImpl::loadUnit(const UnitsPtr &units, const XmlNodePtr &node) auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Unit referencing '" + node->attribute("units") + "' in units '" + units->name() + "' has an invalid non-whitespace child text element '" + textNode + "'."); issue->mPimpl->mItem->mPimpl->setUnits(units); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNIT_ELEMENT); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML_UNEXPECTED_CHARACTER); addIssue(issue); } } else if (childNode->isComment()) { @@ -913,7 +913,7 @@ void Parser::ParserImpl::loadVariable(const VariablePtr &variable, const XmlNode auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Variable '" + node->attribute("name") + "' has an invalid non-whitespace child text element '" + textNode + "'."); issue->mPimpl->mItem->mPimpl->setVariable(variable); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::VARIABLE_ELEMENT); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML_UNEXPECTED_CHARACTER); addIssue(issue); } } else if (childNode->isComment()) { @@ -1161,7 +1161,7 @@ void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr if (hasNonWhitespaceCharacters(textNode)) { auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Connection in model '" + model->name() + "' has an invalid non-whitespace child text element '" + textNode + "'."); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::CONNECTION_CHILD); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML_UNEXPECTED_CHARACTER); issue->mPimpl->mItem->mPimpl->setModel(model); addIssue(issue); } @@ -1269,7 +1269,7 @@ void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Connection in model '" + model->name() + "' has an invalid non-whitespace child text element '" + textNode + "'."); issue->mPimpl->mItem->mPimpl->setModel(model); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::CONNECTION_CHILD); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML_UNEXPECTED_CHARACTER); addIssue(issue); } } else if (childNode->isComment()) { @@ -1452,7 +1452,7 @@ ComponentPtr Parser::ParserImpl::loadComponentRef(const ModelPtr &model, const X auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Encapsulation in model '" + model->name() + "' has an invalid non-whitespace child text element '" + textNode + "'."); issue->mPimpl->mItem->mPimpl->setEncapsulation(model); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::ENCAPSULATION_CHILD); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML_UNEXPECTED_CHARACTER); addIssue(issue); } } else if (childComponentNode->isComment()) { @@ -1499,7 +1499,7 @@ void Parser::ParserImpl::loadEncapsulation(const ModelPtr &model, const XmlNodeP auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Encapsulation in model '" + model->name() + "' has an invalid non-whitespace child text element '" + textNode + "'."); issue->mPimpl->mItem->mPimpl->setEncapsulation(model); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::COMPONENT_REF_CHILD); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML_UNEXPECTED_CHARACTER); addIssue(issue); } else { // Continue to next node if this is whitespace (don't try to parse children of whitespace). @@ -1659,7 +1659,7 @@ void Parser::ParserImpl::loadImport(ImportSourcePtr &importSource, const ModelPt auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Import from '" + node->attribute("href") + "' has an invalid non-whitespace child text element '" + textNode + "'."); issue->mPimpl->mItem->mPimpl->setImportSource(importSource); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_CHILD); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML_UNEXPECTED_CHARACTER); addIssue(issue); } } else if (childNode->isComment()) { @@ -1720,22 +1720,29 @@ void Parser::ParserImpl::loadResetChild(const std::string &childType, const Rese } else { reset->appendResetValue(math); } - } else if (mathNode->isComment()) { - // Do nothing - } else { + } else if (mathNode->isText()) { std::string textNode = mathNode->convertToString(); // Ignore whitespace when parsing. if (hasNonWhitespaceCharacters(textNode)) { auto issue = Issue::IssueImpl::create(); - issue->mPimpl->setDescription("The " + childType + " in the reset in component '" + component->name() + "' referencing variable '" + variableName + "' and test_variable '" + testVariableName + "' should have a MathML block as a child."); + issue->mPimpl->setDescription(childType + " has an invalid non-whitespace child text element '" + textNode + "'."); issue->mPimpl->mItem->mPimpl->setReset(reset); - if (childType == "test_value") { - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::TEST_VALUE_CHILD); - } else { - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_VALUE_CHILD); - } + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML_UNEXPECTED_CHARACTER); addIssue(issue); } + } else if (mathNode->isComment()) { + // Do nothing + } else { + std::string textNode = mathNode->convertToString(); + auto issue = Issue::IssueImpl::create(); + issue->mPimpl->setDescription("The " + childType + " in the reset in component '" + component->name() + "' referencing variable '" + variableName + "' and test_variable '" + testVariableName + "' should have a MathML block as a child."); + issue->mPimpl->mItem->mPimpl->setReset(reset); + if (childType == "test_value") { + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::TEST_VALUE_CHILD); + } else { + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_VALUE_CHILD); + } + addIssue(issue); } mathNode = mathNode->next(); } @@ -1885,7 +1892,7 @@ void Parser::ParserImpl::loadReset(const ResetPtr &reset, const ComponentPtr &co auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Reset has an invalid non-whitespace child text element '" + textNode + "'. Either a test_value block or a reset_value block is expected."); issue->mPimpl->mItem->mPimpl->setReset(reset); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_CHILD); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML_UNEXPECTED_CHARACTER); addIssue(issue); } } else if (childNode->isComment()) { diff --git a/tests/connection/connection.cpp b/tests/connection/connection.cpp index d138c643c..0023960e0 100644 --- a/tests/connection/connection.cpp +++ b/tests/connection/connection.cpp @@ -1410,6 +1410,5 @@ TEST(Connection, repeatedMapVariables) "Connection in model 'connection' between 'variable3' and 'variable6' is not unique.", }; - printIssues(p); EXPECT_EQ_ISSUES(expectedIssues, p); } diff --git a/tests/parser/parser.cpp b/tests/parser/parser.cpp index 36a9e2a25..b3380e5b8 100644 --- a/tests/parser/parser.cpp +++ b/tests/parser/parser.cpp @@ -1595,9 +1595,9 @@ TEST(Parser, invalidModelWithTextInAllElements) "Component 'ship' has an invalid non-whitespace child text element '\n falcon\n '.", "Variable 'jedi' has an invalid non-whitespace child text element '\n rey\n '.", "Reset has an invalid non-whitespace child text element '\n boba fet\n '. Either a test_value block or a reset_value block is expected.", + "test_value has an invalid non-whitespace child text element '\n boba fet\n '.", "The test_value in the reset in component 'ship' referencing variable 'jedi' and test_variable 'jedi' should have a MathML block as a child.", - "The test_value in the reset in component 'ship' referencing variable 'jedi' and test_variable 'jedi' should have a MathML block as a child.", - "The reset_value in the reset in component 'ship' referencing variable 'jedi' and test_variable 'jedi' should have a MathML block as a child.", + "reset_value has an invalid non-whitespace child text element '\n boba fet\n '.", "The reset_value in the reset in component 'ship' referencing variable 'jedi' and test_variable 'jedi' should have a MathML block as a child.", "Encapsulation in model 'starwars' has an invalid non-whitespace child text element '\n awakens\n '.", "Encapsulation in model 'starwars' has an invalid non-whitespace child text element '\n force\n '.", @@ -1833,12 +1833,12 @@ TEST(Parser, parseResets) " \n" " \n" " \n" - " some condition in mathml\n" + " \n" " \n" " \n" " \n" " \n" - " some value in mathml\n" + " \n" " \n" " \n" " \n" @@ -1862,16 +1862,12 @@ TEST(Parser, parseResets) std::string testValueString = r->testValue(); std::string t = - "\n" - " some condition in mathml\n" - " \n"; + "\n"; EXPECT_EQ(t, testValueString); std::string resetValueString = r->resetValue(); std::string rt = - "\n" - " some value in mathml\n" - " \n"; + "\n"; EXPECT_EQ(rt, resetValueString); } @@ -1904,22 +1900,22 @@ TEST(Parser, parseResetsWithIssues) " \n" " \n" // duplicated test_value block inside reset " \n" - " some value in mathml\n" + " \n" " \n" " \n" " \n" // invalid attribute " \n" - " some value in mathml\n" + " \n" " \n" " \n" " \n" // duplicated test_value block inside reset " \n" - " some value in mathml\n" + " \n" " \n" " \n" " \n" " \n" - " some value in mathml\n" + " \n" " \n" " \n" // duplicated reset_value block inside reset " \n" @@ -1983,17 +1979,17 @@ TEST(Parser, parseResetIllegalChild) " \n" " \n" " \n" - " some condition in mathml\n" + " \n" " \n" " \n" " \n" " \n" - " some value in mathml\n" + " \n" " \n" " \n" " \n" " \n" - " some value in mathml\n" + " \n" " \n" " \n" " \n" @@ -2021,14 +2017,14 @@ TEST(Parser, parseResetIllegalChild) std::string testValueString = r->testValue(); const std::string t = "\n" - " some condition in mathml\n" + " \n" " \n"; EXPECT_EQ(t, testValueString); std::string resetValueString = r->resetValue(); const std::string rt = "\n" - " some value in mathml\n" + " \n" " \n"; EXPECT_EQ(rt, resetValueString); } @@ -2044,24 +2040,24 @@ TEST(Parser, parseResetsWithOrderIssues) " \n" " \n" " \n" - " some condition in mathml\n" + " \n" " \n" " \n" " \n" " \n" - " some value in mathml\n" + " \n" " \n" " \n" " \n" " \n" " \n" " \n" - " some condition in mathml\n" + " \n" " \n" " \n" " \n" " \n" - " some value in mathml\n" + " \n" " \n" " \n" " \n" @@ -2145,13 +2141,13 @@ TEST(Parser, xmlComments) " \n" " \n" " \n" - " some condition in mathml\n" + " \n" " \n" " \n" " \n" " \n" " \n" - " some condition in mathml\n" + " \n" " \n" " \n" " \n" From c8d4510a3522b69952005f3230d96772867b8a4a Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Sat, 20 Apr 2024 12:26:18 +1200 Subject: [PATCH 37/50] Use correct reference rule for component_ref child issue. --- src/parser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parser.cpp b/src/parser.cpp index 17517e4f2..33672d2df 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1461,7 +1461,7 @@ ComponentPtr Parser::ParserImpl::loadComponentRef(const ModelPtr &model, const X auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Encapsulation in model '" + model->name() + "' has an invalid child element '" + childComponentNode->name() + "'."); issue->mPimpl->mItem->mPimpl->setEncapsulation(model); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::ENCAPSULATION_CHILD); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::COMPONENT_REF_CHILD); addIssue(issue); } From e572c5ac8184daf1b626bb87825c59e254e46194 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Sat, 20 Apr 2024 12:40:31 +1200 Subject: [PATCH 38/50] Consolidate checking of MathML elements. --- src/validator.cpp | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/src/validator.cpp b/src/validator.cpp index 56cab52ab..5bd7d84ab 100644 --- a/src/validator.cpp +++ b/src/validator.cpp @@ -438,6 +438,17 @@ class Validator::ValidatorImpl: public LoggerImpl */ void validateMath(const std::string &input, const ComponentPtr &component); + /** + * @brief Validate an individual MathML math element. + * + * Validate the MathML to determine that all MathML elements are listed in the + * supported MathML elements table from the CellML specification 2.0 document. + * + * @param node The node to check children and sibling nodes. + * @param component The component the MathML belongs to. + */ + void validateMathMLElement(const XmlNodePtr &node, const ComponentPtr &component); + /** * @brief Traverse the node tree for invalid MathML elements. * @@ -1735,31 +1746,24 @@ void Validator::ValidatorImpl::validateAndCleanMathCiCnNodes(XmlNodePtr &node, c } } -void Validator::ValidatorImpl::validateMathMLElements(const XmlNodePtr &node, const ComponentPtr &component) +void Validator::ValidatorImpl::validateMathMLElement(const XmlNodePtr &node, const ComponentPtr &component) { - XmlNodePtr childNode = node->firstChild(); - if (childNode != nullptr) { - if (!childNode->isComment() && !childNode->isText() && !isSupportedMathMLElement(childNode)) { + if (node != nullptr) { + if (!node->isComment() && !node->isText() && !isSupportedMathMLElement(node)) { auto issue = Issue::IssueImpl::create(); - issue->mPimpl->setDescription("Math has a '" + childNode->name() + "' element that is not a supported MathML element."); + issue->mPimpl->setDescription("Math has a '" + node->name() + "' element that is not a supported MathML element."); issue->mPimpl->mItem->mPimpl->setMath(component); issue->mPimpl->setReferenceRule(Issue::ReferenceRule::MATH_CHILD); addIssue(issue); } - validateMathMLElements(childNode, component); + validateMathMLElements(node, component); } +} - XmlNodePtr nextNode = node->next(); - if (nextNode != nullptr) { - if (!nextNode->isComment() && !nextNode->isText() && !isSupportedMathMLElement(nextNode)) { - auto issue = Issue::IssueImpl::create(); - issue->mPimpl->setDescription("Math has a '" + nextNode->name() + "' element that is not a supported MathML element."); - issue->mPimpl->mItem->mPimpl->setMath(component); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::MATH_CHILD); - addIssue(issue); - } - validateMathMLElements(nextNode, component); - } +void Validator::ValidatorImpl::validateMathMLElements(const XmlNodePtr &node, const ComponentPtr &component) +{ + validateMathMLElement(node->firstChild(), component); + validateMathMLElement(node->next(), component); } void Validator::ValidatorImpl::addMathmlIssue(const std::string &description, From da10508ff982c62ccb4c90d34e3b98cad1119c86 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Sat, 20 Apr 2024 13:36:39 +1200 Subject: [PATCH 39/50] Add comparison to nullptr for consistency in Parser::ParserImpl::loadResetChild. --- src/parser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parser.cpp b/src/parser.cpp index 33672d2df..ee949a6ee 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1712,7 +1712,7 @@ void Parser::ParserImpl::loadResetChild(const std::string &childType, const Rese } XmlNodePtr mathNode = node->firstChild(); - while (mathNode) { + while (mathNode != nullptr) { if (mathNode->isMathmlElement("math")) { std::string math = mathNode->convertToString() + "\n"; if (childType == "test_value") { From 05f566e56c014fd9db5e71efeada12ac5873165a Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Sat, 20 Apr 2024 14:43:42 +1200 Subject: [PATCH 40/50] Use XML_UNEXPECTED_ELEMENT issue enumeration. --- src/parser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parser.cpp b/src/parser.cpp index ee949a6ee..5bef80304 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -459,7 +459,7 @@ void Parser::ParserImpl::loadModel(const ModelPtr &model, const std::string &inp } issue->mPimpl->mItem->mPimpl->setModel(model); if (mParser->isStrict()) { - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::MODEL_ELEMENT); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML_UNEXPECTED_ELEMENT); } addIssue(issue); return; From 96592425ebe646f73d92682a0d6502e1708b642e Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Thu, 2 May 2024 11:47:00 +1200 Subject: [PATCH 41/50] Use XML_UNEXPECTED_ELEMENT when invalid elements are found when parsing. --- src/parser.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index 5bef80304..479778bdf 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -582,7 +582,7 @@ void Parser::ParserImpl::loadModel(const ModelPtr &model, const std::string &inp issue->mPimpl->setLevel(Issue::Level::MESSAGE); } else { issue->mPimpl->setDescription("Model '" + model->name() + "' has an invalid child element '" + childNode->name() + "'."); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::MODEL_CHILD); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML_UNEXPECTED_ELEMENT); } issue->mPimpl->mItem->mPimpl->setModel(model); addIssue(issue); @@ -715,7 +715,7 @@ void Parser::ParserImpl::loadComponent(const ComponentPtr &component, const XmlN issue->mPimpl->setLevel(Issue::Level::MESSAGE); } else { issue->mPimpl->setDescription("Component '" + component->name() + "' has an invalid child element '" + childNode->name() + "'."); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::COMPONENT_CHILD); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML_UNEXPECTED_ELEMENT); } issue->mPimpl->mItem->mPimpl->setComponent(component); addIssue(issue); @@ -790,7 +790,7 @@ void Parser::ParserImpl::loadUnits(const UnitsPtr &units, const XmlNodePtr &node auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Units '" + units->name() + "' has an invalid child element '" + childNode->name() + "'."); issue->mPimpl->mItem->mPimpl->setUnits(units); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNITS_CHILD); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML_UNEXPECTED_ELEMENT); addIssue(issue); } childNode = childNode->next(); @@ -823,7 +823,7 @@ void Parser::ParserImpl::loadUnit(const UnitsPtr &units, const XmlNodePtr &node) auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Unit referencing '" + node->attribute("units") + "' in units '" + units->name() + "' has an invalid child element '" + childNode->name() + "'."); issue->mPimpl->mItem->mPimpl->setUnits(units); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::UNIT_ELEMENT); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML_UNEXPECTED_ELEMENT); addIssue(issue); } childNode = childNode->next(); @@ -925,7 +925,7 @@ void Parser::ParserImpl::loadVariable(const VariablePtr &variable, const XmlNode issue->mPimpl->setLevel(Issue::Level::MESSAGE); } else { issue->mPimpl->setDescription("Variable '" + node->attribute("name") + "' has an invalid child element '" + childNode->name() + "'."); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::VARIABLE_ELEMENT); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML_UNEXPECTED_ELEMENT); } issue->mPimpl->mItem->mPimpl->setVariable(variable); addIssue(issue); @@ -1170,7 +1170,7 @@ void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr } else { auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Connection in model '" + model->name() + "' has an invalid child element '" + grandchildNode->name() + "' of element '" + childNode->name() + "'."); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::CONNECTION_CHILD); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML_UNEXPECTED_ELEMENT); issue->mPimpl->mItem->mPimpl->setModel(model); addIssue(issue); } @@ -1671,7 +1671,7 @@ void Parser::ParserImpl::loadImport(ImportSourcePtr &importSource, const ModelPt issue->mPimpl->setLevel(Issue::Level::MESSAGE); } else { issue->mPimpl->setDescription("Import from '" + node->attribute("href") + "' has an invalid child element '" + childNode->name() + "'."); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_CHILD); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML_UNEXPECTED_ELEMENT); } issue->mPimpl->mItem->mPimpl->setImportSource(importSource); addIssue(issue); @@ -1901,7 +1901,7 @@ void Parser::ParserImpl::loadReset(const ResetPtr &reset, const ComponentPtr &co auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Reset in component '" + component->name() + "' has an invalid child '" + childNode->name() + "'."); issue->mPimpl->mItem->mPimpl->setReset(reset); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_CHILD); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML_UNEXPECTED_ELEMENT); addIssue(issue); } childNode = childNode->next(); From 0050a758a44e86f1ea9325973c36f9aaa0dce2f4 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Thu, 9 May 2024 09:12:50 +1200 Subject: [PATCH 42/50] Add #. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b151e33a6..94896b473 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - +# cmake_minimum_required(VERSION 3.18.0) set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15 CACHE STRING "Minimum OS X deployment version.") From 48d7eeded6ed8c59a987483eb1be725b4a0dc2cd Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Thu, 9 May 2024 09:13:09 +1200 Subject: [PATCH 43/50] Remove #. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 94896b473..b151e33a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -# + cmake_minimum_required(VERSION 3.18.0) set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15 CACHE STRING "Minimum OS X deployment version.") From fc419b6a28309e398913a2ed733f4a7cea9546f0 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Tue, 14 May 2024 21:26:16 +1200 Subject: [PATCH 44/50] Replace xlink href with xlink:href. --- src/parser.cpp | 2 +- tests/parser/parser.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index f12840aa7..9b29f63c3 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1566,7 +1566,7 @@ void Parser::ParserImpl::loadImport(ImportSourcePtr &importSource, const ModelPt if (!hrefAttributePresent) { auto issue = Issue::IssueImpl::create(); - issue->mPimpl->setDescription("Import does not specify an xlink href attribute."); + issue->mPimpl->setDescription("Import does not specify an xlink:href attribute."); issue->mPimpl->mItem->mPimpl->setImportSource(importSource); issue->mPimpl->setReferenceRule(Issue::ReferenceRule::IMPORT_HREF); addIssue(issue); diff --git a/tests/parser/parser.cpp b/tests/parser/parser.cpp index b3380e5b8..c73e34111 100644 --- a/tests/parser/parser.cpp +++ b/tests/parser/parser.cpp @@ -1227,9 +1227,9 @@ TEST(Parser, emptyImportWithAndWithoutId) " \n" "\n"; std::vector e = { - "Import does not specify an xlink href attribute.", + "Import does not specify an xlink:href attribute.", "Import from '' is empty and will be disregarded.", - "Import does not specify an xlink href attribute.", + "Import does not specify an xlink:href attribute.", "Import from '' has an identifier of 'import_id' but is empty. The import will be disregarded and the associated identifier will be lost.", }; libcellml::ParserPtr parser = libcellml::Parser::create(); @@ -1475,7 +1475,7 @@ TEST(Parser, invalidModelWithDifferentItemTypesOfIssues) const std::vector expectedIssues = { "Model 'starwars' has an invalid attribute 'episode'.", "Import from '' has an invalid attribute 'princess'.", - "Import does not specify an xlink href attribute.", + "Import does not specify an xlink:href attribute.", "Import from '' is empty and will be disregarded.", "Units '' has an invalid attribute 'jedi'.", "Units does not specify a name attribute.", From c54d8e922f2f542ba75e90245e0119e01f95923d Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Tue, 14 May 2024 21:26:57 +1200 Subject: [PATCH 45/50] Fix typo anyassociated. --- src/xmlutils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xmlutils.cpp b/src/xmlutils.cpp index c134fc610..0b7ae1954 100644 --- a/src/xmlutils.cpp +++ b/src/xmlutils.cpp @@ -25,7 +25,7 @@ namespace libcellml { /** * @brief Return a list of namespaces on attributes for this node. * - * Scans all attributes of the node and records anyassociated + * Scans all attributes of the node and records any associated * non-empty namespace attached to the attribute in an * @c NodeAttributeNamespaceInfo list. * From 8d263f5fc4e1177e26a822d743ac1b9c49c834a7 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Tue, 14 May 2024 22:15:01 +1200 Subject: [PATCH 46/50] Check the exact issue descriptions of errors. --- tests/model/component_import.cpp | 2 ++ tests/model/units_import.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/tests/model/component_import.cpp b/tests/model/component_import.cpp index 510a86e75..586114dad 100644 --- a/tests/model/component_import.cpp +++ b/tests/model/component_import.cpp @@ -338,6 +338,7 @@ TEST(ComponentImport, noNameAttribute) libcellml::ModelPtr m = p->parseModel(in); EXPECT_EQ(size_t(1), p->errorCount()); + EXPECT_EQ("Import of component does not specify a name attribute.", p->error(0)->description()); } TEST(ComponentImport, notUniqueImportName) @@ -361,4 +362,5 @@ TEST(ComponentImport, notUniqueImportName) v->validateModel(m); EXPECT_EQ(size_t(1), v->errorCount()); + EXPECT_EQ("Model 'model' contains multiple components with the name 'bob'. Valid component names must be unique to their model.", v->error(0)->description()); } diff --git a/tests/model/units_import.cpp b/tests/model/units_import.cpp index 874bc4c46..c19328418 100644 --- a/tests/model/units_import.cpp +++ b/tests/model/units_import.cpp @@ -162,6 +162,7 @@ TEST(UnitsImport, noNameAttribute) libcellml::ModelPtr m = p->parseModel(in); EXPECT_EQ(size_t(1), p->errorCount()); + EXPECT_EQ("Import of units does not specify a name attribute.", p->error(0)->description()); } TEST(UnitsImport, importModifyAndParse) From f1e2c3a294e78530e35c2071d73f9dd1943577ff Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Tue, 14 May 2024 22:20:58 +1200 Subject: [PATCH 47/50] Shorten documentation for xmllutils.h functions. --- src/xmlutils.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/xmlutils.h b/src/xmlutils.h index 36a99e4dc..8fea6a3cb 100644 --- a/src/xmlutils.h +++ b/src/xmlutils.h @@ -40,8 +40,8 @@ XmlNamespaceMap determineMissingNamespaces(const XmlNamespaceMap &namespaceMap1, /** * @brief Traverse the tree and return an @c XmlNamespaceMap of element namespaces. * - * From the root node of the tree given by the @p node, traverse the tree - * recording element namespaces. Returning information on any element namespace. + * Traverse the tree from the root @p node recording element namespaces. + * Returning information on any element namespace. * Text nodes and comment nodes are ignored. * * @param node The root node of the tree to traverse. @@ -52,9 +52,8 @@ XmlNamespaceMap traverseTreeForElementNamespaces(const XmlNodePtr &node); /** * @brief Traverse the tree and return an @c NodeAttributeNamespaceInfo of attribute namespaces. * - * From the root node of the tree given by the @p node, traverse the tree - * searching for attribute namespaces. Returning information on any non-empty - * attribute namespaces. + * Traverse the tree from the root @p node searching for attribute namespaces. + * Returning information on any non-empty attribute namespaces. * * @param node The root node of the tree to traverse. * @return @c NodeAttributeNamespaceInfo of attribute namespaces. From 13f840804dfd8e8b98a5efc315db60ef720be7b3 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Tue, 14 May 2024 22:24:57 +1200 Subject: [PATCH 48/50] Parentheses. --- src/parser.cpp | 6 +++--- src/validator.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index 9b29f63c3..c079dfba1 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -409,7 +409,7 @@ void Parser::ParserImpl::loadModel(const ModelPtr &model, const std::string &inp for (const auto &e : elementNamespaceMap) { std::string name = e.first; std::string uri = e.second; - if (uri != CELLML_2_0_NS && uri != MATHML_NS) { + if ((uri != CELLML_2_0_NS) && (uri != MATHML_NS)) { auto issue = Issue::IssueImpl::create(); issue->mPimpl->setDescription("Element '" + name + "' uses namespace '" + uri + "' which does not belong to an allowed namespace. "); issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML_UNEXPECTED_NAMESPACE); @@ -425,9 +425,9 @@ void Parser::ParserImpl::loadModel(const ModelPtr &model, const std::string &inp std::string nodeUri = std::get<4>(e); std::string attributeName = std::get<1>(e); std::string uri = std::get<3>(e); - if (nodeName == "cn" && nodeUri == MATHML_NS && attributeName == "units" && uri == CELLML_2_0_NS) { + if ((nodeName == "cn") && (nodeUri == MATHML_NS) && (attributeName == "units") && (uri == CELLML_2_0_NS)) { // Explicitly allowed attribute namespace prefix. - } else if (nodeName == "import" && nodeUri == CELLML_2_0_NS && attributeName == "href" && uri == XLINK_NS) { + } else if ((nodeName == "import") && (nodeUri == CELLML_2_0_NS) && (attributeName == "href") && (uri == XLINK_NS)) { // Explicitly allowed attribute namespace prefix. } else { auto issue = Issue::IssueImpl::create(); diff --git a/src/validator.cpp b/src/validator.cpp index 2e317b0ee..10cf48873 100644 --- a/src/validator.cpp +++ b/src/validator.cpp @@ -2613,7 +2613,7 @@ void Validator::ValidatorImpl::addResetOrderMapItem(const VariablePtr &variable, bool existingVariableFound = resetOrderMap.count(currentVariable) > 0; size_t i = 0; - while (i < variable->equivalentVariableCount() && !existingVariableFound) { + while ((i < variable->equivalentVariableCount()) && !existingVariableFound) { currentVariable = variable->equivalentVariable(i); existingVariableFound = resetOrderMap.count(currentVariable) > 0; ++i; From 9deffb34ed15cf65a72858c9f558bd22288fb982 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Tue, 14 May 2024 22:33:02 +1200 Subject: [PATCH 49/50] Add namespace information to error description. --- src/parser.cpp | 2 +- tests/parser/parser.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index c079dfba1..c24d51a00 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -431,7 +431,7 @@ void Parser::ParserImpl::loadModel(const ModelPtr &model, const std::string &inp // Explicitly allowed attribute namespace prefix. } else { auto issue = Issue::IssueImpl::create(); - issue->mPimpl->setDescription("Element '" + nodeName + "' attribute '" + attributeName + "' has a namespace specified."); + issue->mPimpl->setDescription("Element '" + nodeName + "' attribute '" + attributeName + "' has a namespace '" + uri + "' specified."); issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML_ATTRIBUTE_HAS_NAMESPACE); addIssue(issue); } diff --git a/tests/parser/parser.cpp b/tests/parser/parser.cpp index c73e34111..531cb3c67 100644 --- a/tests/parser/parser.cpp +++ b/tests/parser/parser.cpp @@ -74,7 +74,7 @@ TEST(Parser, xmlAttributesWithNamespacePrefixDefault) "\n"; const std::vector expectedIssues = { - "Element 'component' attribute 'name' has a namespace specified.", + "Element 'component' attribute 'name' has a namespace 'http://www.cellml.org/cellml/2.0#' specified.", "Component '' has an invalid attribute 'name'.", "Component does not specify a name attribute.", }; @@ -94,7 +94,7 @@ TEST(Parser, xmlAttributesWithNamespacePrefix) "\n"; const std::vector expectedIssues = { - "Element 'component' attribute 'name' has a namespace specified.", + "Element 'component' attribute 'name' has a namespace 'http://www.example.com/' specified.", "Component '' has an invalid attribute 'name'.", "Component does not specify a name attribute.", }; From ef6ab6fbb75f6cb433892a08443e9948f1d5d464 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Wed, 15 May 2024 18:24:54 +1200 Subject: [PATCH 50/50] Add repeatedConnectionCross test. --- tests/connection/connection.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/connection/connection.cpp b/tests/connection/connection.cpp index 0023960e0..64ce2ea81 100644 --- a/tests/connection/connection.cpp +++ b/tests/connection/connection.cpp @@ -1379,6 +1379,34 @@ TEST(Connection, repeatedConnection) EXPECT_EQ(expectedIssue, p->error(0)->description()); } +TEST(Connection, repeatedConnectionCross) +{ + const std::string in = + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + + libcellml::ParserPtr p = libcellml::Parser::create(); + libcellml::ModelPtr m = p->parseModel(in); + + const std::string expectedIssue = "Connection in model 'connection' between 'component1' and 'component2' is not unique."; + + EXPECT_EQ(size_t(1), p->errorCount()); + EXPECT_EQ(expectedIssue, p->error(0)->description()); +} + TEST(Connection, repeatedMapVariables) { const std::string in =