diff --git a/src/api/libcellml/issue.h b/src/api/libcellml/issue.h index 98eac31a4..8194a0f49 100644 --- a/src/api/libcellml/issue.h +++ b/src/api/libcellml/issue.h @@ -68,92 +68,113 @@ class LIBCELLML_EXPORT Issue { UNDEFINED, - // Specification errors. + // Specification errors: XML, + XML_UNEXPECTED_ELEMENT, + XML_UNEXPECTED_CHARACTER, + XML_UNEXPECTED_NAMESPACE, + XML_ATTRIBUTE_HAS_NAMESPACE, 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_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_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, + + // 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: - MAP_VARIABLES_IDENTICAL_UNIT_REDUCTION, INVALID_ARGUMENT, // Importer class issues: 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" diff --git a/src/bindings/javascript/issue.cpp b/src/bindings/javascript/issue.cpp index fba9ddbdc..01a14768b 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_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 4ae2736eb..d2ca733cf 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_ATTRIBUTE_HAS_NAMESPACE', + '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', [ 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/internaltypes.h b/src/internaltypes.h index 535fea5d3..5acacd213 100644 --- a/src/internaltypes.h +++ b/src/internaltypes.h @@ -34,10 +34,12 @@ using ComponentNameMap = std::map; /**< Type definiti using IndexStack = std::vector; /**< Type definition for tracking indices. */ 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. */ 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.*/ @@ -54,6 +56,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. */ @@ -71,6 +75,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 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/issue.cpp b/src/issue.cpp index 45c4259b2..6d43d195d 100644 --- a/src/issue.cpp +++ b/src/issue.cpp @@ -80,91 +80,112 @@ 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_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"}}, + {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.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"}}, + {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 + // 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, ""}}, // Importer class issues: diff --git a/src/parser.cpp b/src/parser.cpp index 7c355b209..c24d51a00 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 @@ -97,8 +95,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, NamePairList &usedConnections); /** * @brief Update the @p model with an encapsulation parsed from @p node. @@ -120,10 +119,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 @@ -403,6 +403,41 @@ 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 (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 '" + uri + "' 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") { @@ -424,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; @@ -438,10 +473,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 +488,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 +496,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; @@ -489,7 +534,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(); @@ -519,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")) { @@ -537,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); @@ -555,8 +600,10 @@ void Parser::ParserImpl::loadModel(const ModelPtr &model, const std::string &inp addIssue(issue); } } + + NamePairList usedConnections; for (const auto &connectionNode : connectionNodes) { - loadConnection(model, connectionNode); + loadConnection(model, connectionNode, usedConnections); } // Link units to their names. @@ -566,7 +613,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); } @@ -575,9 +622,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 { @@ -587,13 +636,22 @@ 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); } 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")) { @@ -643,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()) { @@ -657,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); @@ -682,9 +740,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 { @@ -694,13 +754,22 @@ 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); } 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")) { @@ -712,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()) { @@ -721,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(); @@ -745,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::UNITS_CHILD); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML_UNEXPECTED_CHARACTER); addIssue(issue); } } else if (childNode->isComment()) { @@ -754,13 +823,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::XML_UNEXPECTED_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) { @@ -768,6 +838,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")) { @@ -777,7 +848,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 +856,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 +866,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 +874,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,11 +883,20 @@ 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(); } + + 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); } @@ -833,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_CHILD); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML_UNEXPECTED_CHARACTER); addIssue(issue); } } else if (childNode->isComment()) { @@ -845,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_CHILD); + issue->mPimpl->setReferenceRule(Issue::ReferenceRule::XML_UNEXPECTED_ELEMENT); } issue->mPimpl->mItem->mPimpl->setVariable(variable); addIssue(issue); @@ -853,9 +933,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")) { @@ -864,6 +947,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")) { @@ -887,21 +971,37 @@ 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); } attribute = attribute->next(); } + + if (!nameAttributePresent || !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) +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; @@ -939,12 +1039,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 +1058,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,25 +1066,70 @@ 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); + 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); + } else { + if (component1Name > component2Name) { + std::string tmp = component1Name; + component1Name = component2Name; + component2Name = tmp; + } + + 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()) { + 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) { @@ -1001,6 +1150,7 @@ void Parser::ParserImpl::loadConnection(const ModelPtr &model, const XmlNodePtr } // Iterate over connection child XML nodes. + NamePairList usedMapVariables; while (childNode != nullptr) { // Connection map XML nodes should not have further children. XmlNodePtr grandchildNode = childNode->firstChild(); @@ -1011,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); } @@ -1020,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); } @@ -1030,38 +1180,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; } @@ -1070,6 +1239,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); + + 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); + } 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. @@ -1077,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()) { @@ -1109,7 +1301,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 +1312,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 +1335,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 +1343,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 +1359,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 +1367,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. @@ -1192,7 +1384,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; @@ -1202,6 +1394,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); @@ -1209,7 +1412,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 +1421,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_ELEMENT); addIssue(issue); } attribute = attribute->next(); @@ -1227,7 +1430,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); @@ -1241,7 +1444,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. @@ -1249,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()) { @@ -1258,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); } @@ -1280,6 +1483,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; @@ -1287,7 +1491,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. @@ -1295,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). @@ -1340,9 +1544,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); @@ -1352,11 +1558,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_ATTRIBUTE); + 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) { @@ -1371,14 +1586,17 @@ 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(); 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")) { @@ -1387,19 +1605,30 @@ 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(); 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")) { @@ -1408,11 +1637,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(); @@ -1421,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()) { @@ -1433,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); @@ -1467,14 +1705,14 @@ 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(); } XmlNodePtr mathNode = node->firstChild(); - while (mathNode) { + while (mathNode != nullptr) { if (mathNode->isMathmlElement("math")) { std::string math = mathNode->convertToString() + "\n"; if (childType == "test_value") { @@ -1482,18 +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); - issue->mPimpl->setReferenceRule(Issue::ReferenceRule::RESET_TEST_VALUE); + 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(); } @@ -1526,7 +1775,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 +1783,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 +1808,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 +1820,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 +1838,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 +1849,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 +1858,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 +1870,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); } @@ -1639,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()) { @@ -1648,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(); diff --git a/src/validator.cpp b/src/validator.cpp index 507344ece..10cf48873 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. @@ -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. * @@ -579,6 +590,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 +607,33 @@ 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. @@ -724,7 +770,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); } @@ -762,17 +808,24 @@ void Validator::validateModel(const ModelPtr &model) // Check identifiers across the model are unique. pFunc()->checkUniqueIds(model); + + pFunc()->checkUniqueResetOrders(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 +835,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); @@ -807,7 +860,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 +868,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 { @@ -907,7 +960,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 +984,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_VALUE); addIssue(issue); } @@ -943,7 +1000,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,11 +1014,10 @@ 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); } } - } else { // Check for variables in this component. NameList variableNames; @@ -1052,7 +1108,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 +1151,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_VALUE); addIssue(issue); } @@ -1112,7 +1168,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 +1188,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 +1200,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_VALUE_TARGET); addIssue(issue); } } @@ -1156,7 +1212,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 +1227,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 { @@ -1224,14 +1285,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 +1309,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 +1319,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 +1336,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 +1346,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_NAME_VALUE); addIssue(issue); } // Check for a valid identifier. @@ -1301,7 +1362,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 +1370,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 +1378,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 +1390,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 +1404,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 +1501,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); } } @@ -1514,7 +1575,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; } @@ -1578,7 +1639,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 +1695,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 +1721,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); } } @@ -1685,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, @@ -2115,7 +2169,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 +2347,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 +2362,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 +2404,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 +2420,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 +2458,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. @@ -2534,6 +2588,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); @@ -2555,7 +2674,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); diff --git a/src/xmlutils.cpp b/src/xmlutils.cpp index 086a4d716..0b7ae1954 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 any associated + * 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,43 @@ 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; + 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 +102,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..8fea6a3cb 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,29 @@ namespace libcellml { */ XmlNamespaceMap determineMissingNamespaces(const XmlNamespaceMap &namespaceMap1, const XmlNamespaceMap &namespaceMap2); +/** + * @brief Traverse the tree and return an @c XmlNamespaceMap of element namespaces. + * + * 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. + * @return @c XmlNamespaceMap of element namespaces. + */ +XmlNamespaceMap traverseTreeForElementNamespaces(const XmlNodePtr &node); + +/** + * @brief Traverse the tree and return an @c NodeAttributeNamespaceInfo of 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. + */ +NodeAttributeNamespaceInfo traverseTreeForAttributeNamespaces(const XmlNodePtr &node); + /** * @brief Traverse the tree and return an @c XmlNamespaceMap of any undefined namespaces. * 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/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() diff --git a/tests/bindings/python/test_issue.py b/tests/bindings/python/test_issue.py index 17d767afc..3de5258c4 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_ATTRIBUTE_HAS_NAMESPACE, 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/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..64ce2ea81 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) @@ -236,7 +237,7 @@ TEST(Connection, parseValidAlternateFormConnection) { const std::string in = "\n" - "\n" + "\n" " \n" " \n" " \n" @@ -1264,7 +1265,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 +1275,7 @@ TEST(Connection, componentConnectionAndParseMissingVariable) { const std::string s = "\n" - "\n" + "\n" " \n" " \n" " \n" @@ -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,93 @@ 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()); +} + +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 = + "\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.", + }; + + EXPECT_EQ_ISSUES(expectedIssues, p); +} diff --git a/tests/coverage/coverage.cpp b/tests/coverage/coverage.cpp index 811dd9ead..0b1b24495 100644 --- a/tests/coverage/coverage.cpp +++ b/tests/coverage/coverage.cpp @@ -46,9 +46,9 @@ TEST(Coverage, connectionComment) TEST(Coverage, importWithNonHrefXlink) { - const std::string e = + const std::string in = "\n" - "\n" + "\n" " \n" " \n" " \n" @@ -61,10 +61,76 @@ 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, mathCnWithNamespaceViolations) +{ + 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, 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) diff --git a/tests/model/component_import.cpp b/tests/model/component_import.cpp index 740ed4ea2..586114dad 100644 --- a/tests/model/component_import.cpp +++ b/tests/model/component_import.cpp @@ -322,3 +322,45 @@ 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()); + EXPECT_EQ("Import of component does not specify a name attribute.", p->error(0)->description()); +} + +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()); + 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 9116e641f..c19328418 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()); + EXPECT_EQ("Import of units does not specify a name attribute.", p->error(0)->description()); +} + TEST(UnitsImport, importModifyAndParse) { const std::string e = 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 218dd4552..531cb3c67 100644 --- a/tests/parser/parser.cpp +++ b/tests/parser/parser.cpp @@ -20,7 +20,6 @@ limitations under the License. #include -#include #include #include @@ -66,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 'http://www.cellml.org/cellml/2.0#' 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 'http://www.example.com/' 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 = @@ -184,6 +223,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 +259,7 @@ TEST(Parser, modelWithInvalidElement) }; const std::string in2 = "\n" - "\n" + "\n" " \n" "\n"; const std::vector expectedIssues2 = { @@ -328,7 +368,7 @@ TEST(Parser, unitsElementIssues) const std::string in1 = "\n" "\n" - " \n" + " \n" " \n" " \n" "\n"; @@ -422,6 +462,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 +497,7 @@ TEST(Parser, componentElementIssues) const std::string in1 = "\n" "\n" - " \n" + " \n" " \n" " \n" "\n"; @@ -623,9 +664,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(); @@ -697,14 +741,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); @@ -713,7 +762,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) @@ -920,23 +969,25 @@ TEST(Parser, invalidVariableAttributesAndGetVariableIssue) { const std::string in = "\n" - "\n" + "\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. @@ -994,8 +1045,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 +1063,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 +1086,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 +1133,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 +1159,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.", @@ -1125,7 +1176,7 @@ TEST(Parser, connectionErrorNoMapVariables) { const std::string in = "\n" - "\n" + "\n" " \n" " \n" " \n" @@ -1134,7 +1185,9 @@ 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 '' does not contain any 'map_variables' elements and will be disregarded.", }; @@ -1145,9 +1198,9 @@ TEST(Parser, connectionErrorNoMapVariables) TEST(Parser, importedComponent2Connection) { - const std::string e = + const std::string in = "\n" - "\n" + "\n" " \n" " \n" " \n" @@ -1161,7 +1214,7 @@ TEST(Parser, importedComponent2Connection) // Parse libcellml::ParserPtr parser = libcellml::Parser::create(); - parser->parseModel(e); + parser->parseModel(in); EXPECT_EQ(size_t(0), parser->issueCount()); } @@ -1174,7 +1227,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(); @@ -1186,7 +1241,7 @@ TEST(Parser, validConnectionMapVariablesFirst) { const std::string e = "\n" - "\n" + "\n" " \n" " \n" " \n" @@ -1205,9 +1260,9 @@ TEST(Parser, validConnectionMapVariablesFirst) TEST(Parser, component2ConnectionVariableMissing) { - const std::string e = + const std::string in = "\n" - "\n" + "\n" " \n" " \n" " \n" @@ -1224,7 +1279,7 @@ TEST(Parser, component2ConnectionVariableMissing) // Parse libcellml::ParserPtr p = libcellml::Parser::create(); - p->parseModel(e); + p->parseModel(in); EXPECT_EQ_ISSUES(expectedIssues, p); } @@ -1232,7 +1287,7 @@ TEST(Parser, component2InConnectionMissing) { const std::string in = "\n" - "\n" + "\n" " \n" " \n" " \n" @@ -1255,7 +1310,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.", }; @@ -1273,7 +1328,7 @@ TEST(Parser, connectionVariable2Missing) { const std::string e = "\n" - "\n" + "\n" " \n" " \n" " \n" @@ -1286,7 +1341,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 @@ -1299,7 +1354,7 @@ TEST(Parser, connectionVariable1Missing) { const std::string e = "\n" - "\n" + "\n" " \n" " \n" " \n" @@ -1311,7 +1366,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'.", }; @@ -1326,7 +1381,7 @@ TEST(Parser, connectionErrorNoMapVariablesType) { const std::string in = "\n" - "\n" + "\n" " \n" " \n" " \n" @@ -1353,7 +1408,7 @@ TEST(Parser, invalidImportsAndGetIssue) { const std::string in = "\n" - "\n" + "\n" " \n" " \n" " \n" @@ -1420,15 +1475,19 @@ 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'.", + "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'.", + "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'.", - "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.", }; @@ -1499,7 +1558,7 @@ TEST(Parser, invalidModelWithTextInAllElements) " \n" " \n" " falcon\n" - " \n" + " \n" " rey\n" " \n" " \n" @@ -1514,9 +1573,9 @@ TEST(Parser, invalidModelWithTextInAllElements) " \n" " \n" " \n" - " \n" + " \n" " finn\n" - " \n" + " \n" " trooper\n" " \n" " \n" @@ -1536,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 '.", @@ -1556,7 +1615,6 @@ TEST(Parser, invalidModelWithTextInAllElements) // Parse and check for CellML issues. libcellml::ParserPtr parser = libcellml::Parser::create(); parser->parseModel(in); - EXPECT_EQ_ISSUES(expectedIssues, parser); } @@ -1567,7 +1625,7 @@ TEST(Parser, parseIds) }; const std::string in = "\n" - "\n" + "\n" " \n" " \n" " \n" @@ -1768,19 +1826,19 @@ TEST(Parser, parseResets) { const std::string in = "\n" - "\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" @@ -1804,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); } @@ -1821,7 +1875,7 @@ TEST(Parser, parseResetsWithIssues) { const std::string in = "\n" - "\n" + "\n" " \n" " \n" // reset variable not in the same component " \n" @@ -1846,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" @@ -1918,24 +1972,24 @@ 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" + " \n" + " \n" " \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" @@ -1963,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); } @@ -1986,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" @@ -2087,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" @@ -2119,7 +2173,7 @@ TEST(Parser, mathWithNamespacesDefinedOnTheMathNode) const std::string in = "\n" "\n" - " \n" + " \n" " \n" " \n" " \n" @@ -2145,7 +2199,7 @@ TEST(Parser, mathWithNamespacesDefinedOnTheNodeThatUsesNamespace) const std::string in = "\n" "\n" - " \n" + " \n" " \n" " \n" " \n" @@ -2171,7 +2225,7 @@ TEST(Parser, mathWithNonStandardCellMLPrefix) const std::string in = "\n" "\n" - " \n" + " \n" " \n" " \n" " \n" @@ -2197,7 +2251,7 @@ TEST(Parser, mathWithMathmlNamespaceOnModel) const std::string in = "\n" "\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 0bc8ee0f4..e7d4ec9d2 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,18 +71,18 @@ 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.7.1", - "2.7.1", - "2.7.1", - "2.7.1", + "2.1.1.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", - "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/specB01.html?issue=MODEL_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", + "https://cellml-specification.readthedocs.io/en/latest/reference/formal_and_informative/specB07.html?issue=COMPONENT_NAME_VALUE", }; libcellml::ValidatorPtr v = libcellml::Validator::create(); @@ -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"); @@ -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,113 @@ 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); + + 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); + + 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); + + EXPECT_EQ_ISSUES(expectedIssues, v); +} + TEST(Validator, validMathCnElements) { const std::string math = 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"