From c9f69b111aa6dc7f9f168d08fdeeaa44fc23697a Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Thu, 21 Nov 2024 11:06:15 +1300 Subject: [PATCH 1/6] Minimal example showing segfault on model flattening over multiple directories (with some debugging). --- src/CMakeLists.txt | 2 +- src/debug.cpp | 98 +++++++++++++++++++ src/debug.h | 10 +- src/importer.cpp | 15 ++- src/utilities.cpp | 5 + tests/importer/model_flattening.cpp | 25 +++++ .../periodicstimulus/components/INa.xml | 9 ++ .../components/stimulated.xml | 23 +++++ .../periodicstimulus/components/units.xml | 13 +++ .../experiments/periodic-stimulus.xml | 9 ++ tests/test_utils.cpp | 98 ------------------- tests/test_utils.h | 3 - 12 files changed, 203 insertions(+), 107 deletions(-) create mode 100644 tests/resources/importer/periodicstimulus/components/INa.xml create mode 100644 tests/resources/importer/periodicstimulus/components/stimulated.xml create mode 100644 tests/resources/importer/periodicstimulus/components/units.xml create mode 100644 tests/resources/importer/periodicstimulus/experiments/periodic-stimulus.xml diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e89a672648..4dfbb2f0d6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -245,7 +245,7 @@ set_target_properties(cellml_debug_utilities PROPERTIES VISIBILITY_INLINES_HIDDEN 1 ) -target_link_libraries(cellml PRIVATE debug $) +target_link_libraries(cellml PUBLIC debug $) group_source_to_dir_structure( ${DEBUG_SOURCE_FILES} diff --git a/src/debug.cpp b/src/debug.cpp index b78d788535..3b45a3a378 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -768,4 +768,102 @@ void listModelsUnits(const ModelPtr &model) } } +static const std::string FIXED_INDENT = " "; + +void printComponent(const libcellml::ComponentPtr &component, size_t c, const std::string &indent, bool includeMaths) +{ + if (c == -1) { + std::cout << "COMPONENT: '" << component->name() << "'"; + } else { + std::cout << indent << "[" << c + 1 << "]: " << component->name(); + } + + if (component->id() != "") { + std::cout << ", id: " << component->id(); + } + + std::cout << std::endl; + std::cout << indent << FIXED_INDENT << "VARIABLES: " << component->variableCount() << " variables" << std::endl; + + // Printing the variables within the component. + for (size_t v = 0; v < component->variableCount(); ++v) { + std::cout << indent << FIXED_INDENT << FIXED_INDENT; + std::cout << "[" << v + 1 << "]: " << component->variable(v)->name(); + if (component->variable(v)->units() != nullptr) { + std::cout << " [" << component->variable(v)->units()->name() << "]"; + } + if (component->variable(v)->initialValue() != "") { + std::cout << ", initial = " << component->variable(v)->initialValue(); + } + std::cout << std::endl; + if (component->variable(v)->equivalentVariableCount() > 0) { + std::cout << indent << FIXED_INDENT << FIXED_INDENT << FIXED_INDENT; + std::string con = " └──> "; + for (size_t e = 0; e < component->variable(v)->equivalentVariableCount(); ++e) { + auto ev = component->variable(v)->equivalentVariable(e); + if (ev == nullptr) { + std::cout << "WHOOPS! Null equivalent variable!"; + continue; + } + libcellml::ComponentPtr ev_parent = std::dynamic_pointer_cast(ev->parent()); + if (ev_parent == nullptr) { + std::cout << "WHOOPS! Null parent component for equivalent variable!"; + continue; + } + std::cout << con << ev_parent->name() << ":" << ev->name(); + if (ev->units() != nullptr) { + std::cout << " [" << ev->units()->name() << "]"; + } + con = ", "; + } + std::cout << std::endl; + } + } + + // Print the maths within the component. + if (includeMaths) { + if (component->math() != "") { + std::cout << indent << " Maths in the component is:" << std::endl; + std::cout << component->math() << std::endl; + } + } + + // Print the encapsulated components + if (component->componentCount() > 0) { + std::cout << indent << FIXED_INDENT << "CHILD COMPONENTS: " << component->componentCount() + << " child components" << std::endl; + std::string newIndent = indent + FIXED_INDENT + FIXED_INDENT; + + for (size_t c2 = 0; c2 < component->componentCount(); ++c2) { + auto child = component->component(c2); + printComponent(child, c2, newIndent, includeMaths); + } + } +} + +void printComponent(const ComponentPtr &component, bool includeMaths) +{ + printComponent(component, -1, {}, includeMaths); +} + +void printModel(const ModelPtr &model, bool includeMaths) +{ + std::cout << "MODEL: '" << model->name() << "'"; + if (model->id() != "") { + std::cout << ", id: '" << model->id() << "'"; + } + std::cout << std::endl; + + std::cout << FIXED_INDENT << "UNITS: " << model->unitsCount() << " custom units" << std::endl; + for (size_t u = 0; u < model->unitsCount(); ++u) { + std::cout << FIXED_INDENT << FIXED_INDENT << "[" << u + 1 << "]: " << model->units(u)->name() << std::endl; + } + + std::cout << FIXED_INDENT << "COMPONENTS: " << model->componentCount() << " components" << std::endl; + for (size_t c = 0; c < model->componentCount(); ++c) { + auto component = model->component(c); + printComponent(component, c, FIXED_INDENT + FIXED_INDENT, includeMaths); + } +} + } // namespace libcellml diff --git a/src/debug.h b/src/debug.h index 0c6f861ad4..e29b936992 100644 --- a/src/debug.h +++ b/src/debug.h @@ -93,24 +93,26 @@ struct Debug bool mNewLine; }; +void listModelsUnits(const ModelPtr &model); void printAnalyserModelEquations(const AnalyserModelPtr &model); void printAnalyserModelVariables(const AnalyserModelPtr &model); void printAstAsTree(const AnalyserEquationAstPtr &ast); void printAstAsCode(const AnalyserEquationAstPtr &ast); +void printComponent(const ComponentPtr &component, bool includeMaths = true); void printComponentMap(const ComponentMap &map); void printConnectionMap(const ConnectionMap &map); void printEquivalenceMap(const EquivalenceMap &map); void printEquivalenceMapWithModelInfo(const EquivalenceMap &map, const ModelPtr &model); +void printEquivalences(const VariablePtr &variable); void printHistory(const History &history); void printHistoryEpoch(const HistoryEpochPtr &historyEpoch); void printImportLibrary(const ImportLibrary &importlibrary); +void printModel(const ModelPtr &model, bool includeMaths = true); +void printNamedPath(const ParentedEntityPtr &parented); void printStack(const IndexStack &stack); void printStackWithModelInfo(const IndexStack &stack, const ModelPtr &model); void printStringStringMap(const StringStringMap &map); -void printVariableMap(const VariableMap &map); void printUnits(const UnitsPtr &units); -void listModelsUnits(const ModelPtr &model); -void printNamedPath(const ParentedEntityPtr &parented); -void printEquivalences(const VariablePtr &variable); +void printVariableMap(const VariableMap &map); } // namespace libcellml diff --git a/src/importer.cpp b/src/importer.cpp index 7e74657fa5..7316dd1dc5 100644 --- a/src/importer.cpp +++ b/src/importer.cpp @@ -18,6 +18,7 @@ limitations under the License. #include #include +#include #include #include #include @@ -37,6 +38,8 @@ limitations under the License. #include "logger_p.h" #include "utilities.h" +#include "debug.h" + namespace libcellml { /** @@ -329,14 +332,18 @@ std::string pathFromUrl(const std::string &url) */ std::string resolvePath(const std::string &filename, const std::string &base) { - return pathFromUrl(base) + filename; + return std::filesystem::canonical(pathFromUrl(base) + filename).generic_string(); } bool Importer::ImporterImpl::fetchModel(const ImportSourcePtr &importSource, const std::string &baseFile) { std::string url = normaliseDirectorySeparator(importSource->url()); + Debug() << "Fetch model: " << importSource->url(); + Debug() << " norm: " << url; if (mLibrary.count(url) == 0) { url = resolvePath(url, baseFile); + Debug() << "Resolved path: " << url; + Debug() << "now: " << std::filesystem::canonical(url); } ModelPtr model; @@ -481,6 +488,7 @@ bool Importer::ImporterImpl::fetchComponent(const ComponentPtr &importComponent, } std::string resolvingUrl = ImporterImpl::resolvingUrl(importComponent->importSource()); + Debug() << "Component -> resolvingUrl: " << resolvingUrl; if (encounteredRelatedError) { auto issue = Issue::IssueImpl::create(); @@ -572,6 +580,7 @@ bool Importer::ImporterImpl::fetchUnits(const UnitsPtr &importUnits, const std:: } std::string resolvingUrl = ImporterImpl::resolvingUrl(importUnits->importSource()); + Debug() << "Units -> resolvingUrl: " << resolvingUrl; if (encounteredRelatedError) { auto issue = Issue::IssueImpl::create(); @@ -653,6 +662,7 @@ bool Importer::resolveImports(ModelPtr &model, const std::string &basePath) clearImports(model); auto normalisedBasePath = normalisePath(basePath); + Debug() << "normalisedBasePath: " << normalisedBasePath; for (const UnitsPtr &units : getImportedUnits(model)) { history.clear(); @@ -670,6 +680,7 @@ bool Importer::resolveImports(ModelPtr &model, const std::string &basePath) status = false; } } + printImportLibrary(pFunc()->mLibrary); return status; } @@ -842,6 +853,8 @@ ComponentPtr flattenComponent(const ComponentEntityPtr &parent, ComponentPtr &co } // Get list of required units from component's variables and math cn elements. + printModel(clonedImportModel); + printComponent(importedComponentCopy); std::vector requiredUnits = unitsUsed(clonedImportModel, importedComponentCopy); std::vector uniqueRequiredUnits; diff --git a/src/utilities.cpp b/src/utilities.cpp index 51cb29a65c..8b52968c76 100644 --- a/src/utilities.cpp +++ b/src/utilities.cpp @@ -38,6 +38,8 @@ limitations under the License. #include "xmldoc.h" #include "xmlutils.h" +#include "debug.h" + namespace libcellml { static const std::map standardPrefixList = { @@ -749,6 +751,9 @@ std::vector unitsUsed(const ModelPtr &model, const ComponentConstPtr & auto u = v->units(); if ((u != nullptr) && !isStandardUnitName(u->name()) && (model != nullptr)) { auto modelUnits = model->units(u->name()); + Debug() << "Info:"; + Debug() << model->name(); + Debug() << u->name(); auto availableUnits = modelUnits ? modelUnits : u; auto requiredUnits = referencedUnits(model, availableUnits); usedUnits.insert(usedUnits.end(), requiredUnits.begin(), requiredUnits.end()); diff --git a/tests/importer/model_flattening.cpp b/tests/importer/model_flattening.cpp index 80c218df3f..4eb5f63f94 100644 --- a/tests/importer/model_flattening.cpp +++ b/tests/importer/model_flattening.cpp @@ -1918,3 +1918,28 @@ TEST(ModelFlattening, modelWithCnUnitsNotDefinedInImportedComponent) EXPECT_EQ(size_t(1), importer->errorCount()); EXPECT_EQ("The model is not fully defined.", importer->error(0)->description()); } + +TEST(Experiment, periodicStimulus) +{ + auto parser = libcellml::Parser::create(false); + auto model = parser->parseModel(fileContents("importer/periodicstimulus/experiments/periodic-stimulus.xml")); + + EXPECT_EQ(size_t(0), parser->errorCount()); + + auto validator = libcellml::Validator::create(); + + validator->validateModel(model); + + EXPECT_EQ(size_t(0), validator->issueCount()); + EXPECT_TRUE(model->hasUnresolvedImports()); + + auto importer = libcellml::Importer::create(false); + + importer->resolveImports(model, resourcePath("importer/periodicstimulus/experiments")); + + EXPECT_FALSE(model->hasUnresolvedImports()); + + auto flattenModel = importer->flattenModel(model); + + EXPECT_NE(nullptr, flattenModel); +} diff --git a/tests/resources/importer/periodicstimulus/components/INa.xml b/tests/resources/importer/periodicstimulus/components/INa.xml new file mode 100644 index 0000000000..39da14dc55 --- /dev/null +++ b/tests/resources/importer/periodicstimulus/components/INa.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/tests/resources/importer/periodicstimulus/components/stimulated.xml b/tests/resources/importer/periodicstimulus/components/stimulated.xml new file mode 100644 index 0000000000..4c045dec44 --- /dev/null +++ b/tests/resources/importer/periodicstimulus/components/stimulated.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/resources/importer/periodicstimulus/components/units.xml b/tests/resources/importer/periodicstimulus/components/units.xml new file mode 100644 index 0000000000..d0ec64903f --- /dev/null +++ b/tests/resources/importer/periodicstimulus/components/units.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/tests/resources/importer/periodicstimulus/experiments/periodic-stimulus.xml b/tests/resources/importer/periodicstimulus/experiments/periodic-stimulus.xml new file mode 100644 index 0000000000..e5a96f10fc --- /dev/null +++ b/tests/resources/importer/periodicstimulus/experiments/periodic-stimulus.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/tests/test_utils.cpp b/tests/test_utils.cpp index 8aafe6088e..8b9f372efb 100644 --- a/tests/test_utils.cpp +++ b/tests/test_utils.cpp @@ -87,104 +87,6 @@ void printIssues(const libcellml::LoggerPtr &l, bool headings, bool cellmlElemen } } -static const std::string FIXED_INDENT = " "; - -void printComponent(const libcellml::ComponentPtr &component, size_t c, const std::string &indent, bool includeMaths) -{ - if (c == -1) { - std::cout << "COMPONENT: '" << component->name() << "'"; - } else { - std::cout << indent << "[" << c + 1 << "]: " << component->name(); - } - - if (component->id() != "") { - std::cout << ", id: " << component->id(); - } - - std::cout << std::endl; - std::cout << indent << FIXED_INDENT << "VARIABLES: " << component->variableCount() << " variables" << std::endl; - - // Printing the variables within the component. - for (size_t v = 0; v < component->variableCount(); ++v) { - std::cout << indent << FIXED_INDENT << FIXED_INDENT; - std::cout << "[" << v + 1 << "]: " << component->variable(v)->name(); - if (component->variable(v)->units() != nullptr) { - std::cout << " [" << component->variable(v)->units()->name() << "]"; - } - if (component->variable(v)->initialValue() != "") { - std::cout << ", initial = " << component->variable(v)->initialValue(); - } - std::cout << std::endl; - if (component->variable(v)->equivalentVariableCount() > 0) { - std::cout << indent << FIXED_INDENT << FIXED_INDENT << FIXED_INDENT; - std::string con = " └──> "; - for (size_t e = 0; e < component->variable(v)->equivalentVariableCount(); ++e) { - auto ev = component->variable(v)->equivalentVariable(e); - if (ev == nullptr) { - std::cout << "WHOOPS! Null equivalent variable!"; - continue; - } - libcellml::ComponentPtr ev_parent = std::dynamic_pointer_cast(ev->parent()); - if (ev_parent == nullptr) { - std::cout << "WHOOPS! Null parent component for equivalent variable!"; - continue; - } - std::cout << con << ev_parent->name() << ":" << ev->name(); - if (ev->units() != nullptr) { - std::cout << " [" << ev->units()->name() << "]"; - } - con = ", "; - } - std::cout << std::endl; - } - } - - // Print the maths within the component. - if (includeMaths) { - if (component->math() != "") { - std::cout << indent << " Maths in the component is:" << std::endl; - std::cout << component->math() << std::endl; - } - } - - // Print the encapsulated components - if (component->componentCount() > 0) { - std::cout << indent << FIXED_INDENT << "CHILD COMPONENTS: " << component->componentCount() - << " child components" << std::endl; - std::string newIndent = indent + FIXED_INDENT + FIXED_INDENT; - - for (size_t c2 = 0; c2 < component->componentCount(); ++c2) { - auto child = component->component(c2); - printComponent(child, c2, newIndent, includeMaths); - } - } -} - -void printComponent(const libcellml::ComponentPtr &component, bool includeMaths) -{ - printComponent(component, -1, {}, includeMaths); -} - -void printModel(const libcellml::ModelPtr &model, bool includeMaths) -{ - std::cout << "MODEL: '" << model->name() << "'"; - if (model->id() != "") { - std::cout << ", id: '" << model->id() << "'"; - } - std::cout << std::endl; - - std::cout << FIXED_INDENT << "UNITS: " << model->unitsCount() << " custom units" << std::endl; - for (size_t u = 0; u < model->unitsCount(); ++u) { - std::cout << FIXED_INDENT << FIXED_INDENT << "[" << u + 1 << "]: " << model->units(u)->name() << std::endl; - } - - std::cout << FIXED_INDENT << "COMPONENTS: " << model->componentCount() << " components" << std::endl; - for (size_t c = 0; c < model->componentCount(); ++c) { - auto component = model->component(c); - printComponent(component, c, FIXED_INDENT + FIXED_INDENT, includeMaths); - } -} - template std::vector expectedValues(size_t size, T value) { diff --git a/tests/test_utils.h b/tests/test_utils.h index b446ac2384..5f7ae77882 100644 --- a/tests/test_utils.h +++ b/tests/test_utils.h @@ -85,9 +85,6 @@ std::string TEST_EXPORT resourcePath(const std::string &resourceRelativePath = " std::string TEST_EXPORT fileContents(const std::string &fileName); void TEST_EXPORT printIssues(const libcellml::LoggerPtr &l, bool headings = false, bool cellmlElementTypes = false, bool rule = false); -void TEST_EXPORT printModel(const libcellml::ModelPtr &model, bool includeMaths = true); -void TEST_EXPORT printComponent(const libcellml::ComponentPtr &component, bool includeMaths = true); - std::vector TEST_EXPORT expectedCellmlElementTypes(size_t size, libcellml::CellmlElementType type); std::vector TEST_EXPORT expectedLevels(size_t size, libcellml::Issue::Level level); std::vector TEST_EXPORT expectedReferenceRules(size_t size, libcellml::Issue::ReferenceRule rule); From ab2ad8bcc4b860e6f6e18327e95361fc909482c6 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Thu, 21 Nov 2024 21:50:56 +1300 Subject: [PATCH 2/6] Fix bug with flattening units with non-standard unit. --- src/importer.cpp | 17 ++--------------- src/utilities.cpp | 5 ----- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/src/importer.cpp b/src/importer.cpp index 7316dd1dc5..dcd4726207 100644 --- a/src/importer.cpp +++ b/src/importer.cpp @@ -18,7 +18,6 @@ limitations under the License. #include #include -#include #include #include #include @@ -38,8 +37,6 @@ limitations under the License. #include "logger_p.h" #include "utilities.h" -#include "debug.h" - namespace libcellml { /** @@ -332,18 +329,14 @@ std::string pathFromUrl(const std::string &url) */ std::string resolvePath(const std::string &filename, const std::string &base) { - return std::filesystem::canonical(pathFromUrl(base) + filename).generic_string(); + return pathFromUrl(base) + filename; } bool Importer::ImporterImpl::fetchModel(const ImportSourcePtr &importSource, const std::string &baseFile) { std::string url = normaliseDirectorySeparator(importSource->url()); - Debug() << "Fetch model: " << importSource->url(); - Debug() << " norm: " << url; if (mLibrary.count(url) == 0) { url = resolvePath(url, baseFile); - Debug() << "Resolved path: " << url; - Debug() << "now: " << std::filesystem::canonical(url); } ModelPtr model; @@ -488,7 +481,6 @@ bool Importer::ImporterImpl::fetchComponent(const ComponentPtr &importComponent, } std::string resolvingUrl = ImporterImpl::resolvingUrl(importComponent->importSource()); - Debug() << "Component -> resolvingUrl: " << resolvingUrl; if (encounteredRelatedError) { auto issue = Issue::IssueImpl::create(); @@ -580,7 +572,6 @@ bool Importer::ImporterImpl::fetchUnits(const UnitsPtr &importUnits, const std:: } std::string resolvingUrl = ImporterImpl::resolvingUrl(importUnits->importSource()); - Debug() << "Units -> resolvingUrl: " << resolvingUrl; if (encounteredRelatedError) { auto issue = Issue::IssueImpl::create(); @@ -662,7 +653,6 @@ bool Importer::resolveImports(ModelPtr &model, const std::string &basePath) clearImports(model); auto normalisedBasePath = normalisePath(basePath); - Debug() << "normalisedBasePath: " << normalisedBasePath; for (const UnitsPtr &units : getImportedUnits(model)) { history.clear(); @@ -680,7 +670,6 @@ bool Importer::resolveImports(ModelPtr &model, const std::string &basePath) status = false; } } - printImportLibrary(pFunc()->mLibrary); return status; } @@ -853,8 +842,6 @@ ComponentPtr flattenComponent(const ComponentEntityPtr &parent, ComponentPtr &co } // Get list of required units from component's variables and math cn elements. - printModel(clonedImportModel); - printComponent(importedComponentCopy); std::vector requiredUnits = unitsUsed(clonedImportModel, importedComponentCopy); std::vector uniqueRequiredUnits; @@ -922,7 +909,7 @@ ComponentPtr flattenComponent(const ComponentEntityPtr &parent, ComponentPtr &co } } - auto replacementUnits = (flattenedUnits != nullptr) ? flattenedUnits->clone() : units; + auto replacementUnits = (flattenedUnits != nullptr) ? flattenedUnits : units; for (size_t unitIndex = 0; unitIndex < replacementUnits->unitCount(); ++unitIndex) { const std::string ref = replacementUnits->unitAttributeReference(unitIndex); diff --git a/src/utilities.cpp b/src/utilities.cpp index 8b52968c76..51cb29a65c 100644 --- a/src/utilities.cpp +++ b/src/utilities.cpp @@ -38,8 +38,6 @@ limitations under the License. #include "xmldoc.h" #include "xmlutils.h" -#include "debug.h" - namespace libcellml { static const std::map standardPrefixList = { @@ -751,9 +749,6 @@ std::vector unitsUsed(const ModelPtr &model, const ComponentConstPtr & auto u = v->units(); if ((u != nullptr) && !isStandardUnitName(u->name()) && (model != nullptr)) { auto modelUnits = model->units(u->name()); - Debug() << "Info:"; - Debug() << model->name(); - Debug() << u->name(); auto availableUnits = modelUnits ? modelUnits : u; auto requiredUnits = referencedUnits(model, availableUnits); usedUnits.insert(usedUnits.end(), requiredUnits.begin(), requiredUnits.end()); From 8409fc63c4c3ef71189be028bd9a2407f05d9ec3 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Fri, 22 Nov 2024 08:22:57 +1300 Subject: [PATCH 3/6] Revert changes that helped with debugging only. --- src/CMakeLists.txt | 2 +- src/debug.cpp | 98 -------------------------------------------- src/debug.h | 2 - tests/test_utils.cpp | 98 ++++++++++++++++++++++++++++++++++++++++++++ tests/test_utils.h | 3 ++ 5 files changed, 102 insertions(+), 101 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4dfbb2f0d6..e89a672648 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -245,7 +245,7 @@ set_target_properties(cellml_debug_utilities PROPERTIES VISIBILITY_INLINES_HIDDEN 1 ) -target_link_libraries(cellml PUBLIC debug $) +target_link_libraries(cellml PRIVATE debug $) group_source_to_dir_structure( ${DEBUG_SOURCE_FILES} diff --git a/src/debug.cpp b/src/debug.cpp index 3b45a3a378..b78d788535 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -768,102 +768,4 @@ void listModelsUnits(const ModelPtr &model) } } -static const std::string FIXED_INDENT = " "; - -void printComponent(const libcellml::ComponentPtr &component, size_t c, const std::string &indent, bool includeMaths) -{ - if (c == -1) { - std::cout << "COMPONENT: '" << component->name() << "'"; - } else { - std::cout << indent << "[" << c + 1 << "]: " << component->name(); - } - - if (component->id() != "") { - std::cout << ", id: " << component->id(); - } - - std::cout << std::endl; - std::cout << indent << FIXED_INDENT << "VARIABLES: " << component->variableCount() << " variables" << std::endl; - - // Printing the variables within the component. - for (size_t v = 0; v < component->variableCount(); ++v) { - std::cout << indent << FIXED_INDENT << FIXED_INDENT; - std::cout << "[" << v + 1 << "]: " << component->variable(v)->name(); - if (component->variable(v)->units() != nullptr) { - std::cout << " [" << component->variable(v)->units()->name() << "]"; - } - if (component->variable(v)->initialValue() != "") { - std::cout << ", initial = " << component->variable(v)->initialValue(); - } - std::cout << std::endl; - if (component->variable(v)->equivalentVariableCount() > 0) { - std::cout << indent << FIXED_INDENT << FIXED_INDENT << FIXED_INDENT; - std::string con = " └──> "; - for (size_t e = 0; e < component->variable(v)->equivalentVariableCount(); ++e) { - auto ev = component->variable(v)->equivalentVariable(e); - if (ev == nullptr) { - std::cout << "WHOOPS! Null equivalent variable!"; - continue; - } - libcellml::ComponentPtr ev_parent = std::dynamic_pointer_cast(ev->parent()); - if (ev_parent == nullptr) { - std::cout << "WHOOPS! Null parent component for equivalent variable!"; - continue; - } - std::cout << con << ev_parent->name() << ":" << ev->name(); - if (ev->units() != nullptr) { - std::cout << " [" << ev->units()->name() << "]"; - } - con = ", "; - } - std::cout << std::endl; - } - } - - // Print the maths within the component. - if (includeMaths) { - if (component->math() != "") { - std::cout << indent << " Maths in the component is:" << std::endl; - std::cout << component->math() << std::endl; - } - } - - // Print the encapsulated components - if (component->componentCount() > 0) { - std::cout << indent << FIXED_INDENT << "CHILD COMPONENTS: " << component->componentCount() - << " child components" << std::endl; - std::string newIndent = indent + FIXED_INDENT + FIXED_INDENT; - - for (size_t c2 = 0; c2 < component->componentCount(); ++c2) { - auto child = component->component(c2); - printComponent(child, c2, newIndent, includeMaths); - } - } -} - -void printComponent(const ComponentPtr &component, bool includeMaths) -{ - printComponent(component, -1, {}, includeMaths); -} - -void printModel(const ModelPtr &model, bool includeMaths) -{ - std::cout << "MODEL: '" << model->name() << "'"; - if (model->id() != "") { - std::cout << ", id: '" << model->id() << "'"; - } - std::cout << std::endl; - - std::cout << FIXED_INDENT << "UNITS: " << model->unitsCount() << " custom units" << std::endl; - for (size_t u = 0; u < model->unitsCount(); ++u) { - std::cout << FIXED_INDENT << FIXED_INDENT << "[" << u + 1 << "]: " << model->units(u)->name() << std::endl; - } - - std::cout << FIXED_INDENT << "COMPONENTS: " << model->componentCount() << " components" << std::endl; - for (size_t c = 0; c < model->componentCount(); ++c) { - auto component = model->component(c); - printComponent(component, c, FIXED_INDENT + FIXED_INDENT, includeMaths); - } -} - } // namespace libcellml diff --git a/src/debug.h b/src/debug.h index e29b936992..f476b5fcb3 100644 --- a/src/debug.h +++ b/src/debug.h @@ -98,7 +98,6 @@ void printAnalyserModelEquations(const AnalyserModelPtr &model); void printAnalyserModelVariables(const AnalyserModelPtr &model); void printAstAsTree(const AnalyserEquationAstPtr &ast); void printAstAsCode(const AnalyserEquationAstPtr &ast); -void printComponent(const ComponentPtr &component, bool includeMaths = true); void printComponentMap(const ComponentMap &map); void printConnectionMap(const ConnectionMap &map); void printEquivalenceMap(const EquivalenceMap &map); @@ -107,7 +106,6 @@ void printEquivalences(const VariablePtr &variable); void printHistory(const History &history); void printHistoryEpoch(const HistoryEpochPtr &historyEpoch); void printImportLibrary(const ImportLibrary &importlibrary); -void printModel(const ModelPtr &model, bool includeMaths = true); void printNamedPath(const ParentedEntityPtr &parented); void printStack(const IndexStack &stack); void printStackWithModelInfo(const IndexStack &stack, const ModelPtr &model); diff --git a/tests/test_utils.cpp b/tests/test_utils.cpp index 8b9f372efb..bb20e98c6d 100644 --- a/tests/test_utils.cpp +++ b/tests/test_utils.cpp @@ -87,6 +87,104 @@ void printIssues(const libcellml::LoggerPtr &l, bool headings, bool cellmlElemen } } +static const std::string FIXED_INDENT = " "; + +void printComponent(const libcellml::ComponentPtr &component, size_t c, const std::string &indent, bool includeMaths) +{ + if (c == size_t(-1)) { + std::cout << "COMPONENT: '" << component->name() << "'"; + } else { + std::cout << indent << "[" << c + 1 << "]: " << component->name(); + } + + if (component->id() != "") { + std::cout << ", id: " << component->id(); + } + + std::cout << std::endl; + std::cout << indent << FIXED_INDENT << "VARIABLES: " << component->variableCount() << " variables" << std::endl; + + // Printing the variables within the component. + for (size_t v = 0; v < component->variableCount(); ++v) { + std::cout << indent << FIXED_INDENT << FIXED_INDENT; + std::cout << "[" << v + 1 << "]: " << component->variable(v)->name(); + if (component->variable(v)->units() != nullptr) { + std::cout << " [" << component->variable(v)->units()->name() << "]"; + } + if (component->variable(v)->initialValue() != "") { + std::cout << ", initial = " << component->variable(v)->initialValue(); + } + std::cout << std::endl; + if (component->variable(v)->equivalentVariableCount() > 0) { + std::cout << indent << FIXED_INDENT << FIXED_INDENT << FIXED_INDENT; + std::string con = " └──> "; + for (size_t e = 0; e < component->variable(v)->equivalentVariableCount(); ++e) { + auto ev = component->variable(v)->equivalentVariable(e); + if (ev == nullptr) { + std::cout << "WHOOPS! Null equivalent variable!"; + continue; + } + libcellml::ComponentPtr ev_parent = std::dynamic_pointer_cast(ev->parent()); + if (ev_parent == nullptr) { + std::cout << "WHOOPS! Null parent component for equivalent variable!"; + continue; + } + std::cout << con << ev_parent->name() << ":" << ev->name(); + if (ev->units() != nullptr) { + std::cout << " [" << ev->units()->name() << "]"; + } + con = ", "; + } + std::cout << std::endl; + } + } + + // Print the maths within the component. + if (includeMaths) { + if (component->math() != "") { + std::cout << indent << " Maths in the component is:" << std::endl; + std::cout << component->math() << std::endl; + } + } + + // Print the encapsulated components + if (component->componentCount() > 0) { + std::cout << indent << FIXED_INDENT << "CHILD COMPONENTS: " << component->componentCount() + << " child components" << std::endl; + std::string newIndent = indent + FIXED_INDENT + FIXED_INDENT; + + for (size_t c2 = 0; c2 < component->componentCount(); ++c2) { + auto child = component->component(c2); + printComponent(child, c2, newIndent, includeMaths); + } + } +} + +void printComponent(const ComponentPtr &component, bool includeMaths) +{ + printComponent(component, -1, {}, includeMaths); +} + +void printModel(const ModelPtr &model, bool includeMaths) +{ + std::cout << "MODEL: '" << model->name() << "'"; + if (model->id() != "") { + std::cout << ", id: '" << model->id() << "'"; + } + std::cout << std::endl; + + std::cout << FIXED_INDENT << "UNITS: " << model->unitsCount() << " custom units" << std::endl; + for (size_t u = 0; u < model->unitsCount(); ++u) { + std::cout << FIXED_INDENT << FIXED_INDENT << "[" << u + 1 << "]: " << model->units(u)->name() << std::endl; + } + + std::cout << FIXED_INDENT << "COMPONENTS: " << model->componentCount() << " components" << std::endl; + for (size_t c = 0; c < model->componentCount(); ++c) { + auto component = model->component(c); + printComponent(component, c, FIXED_INDENT + FIXED_INDENT, includeMaths); + } +} + template std::vector expectedValues(size_t size, T value) { diff --git a/tests/test_utils.h b/tests/test_utils.h index 5f7ae77882..b446ac2384 100644 --- a/tests/test_utils.h +++ b/tests/test_utils.h @@ -85,6 +85,9 @@ std::string TEST_EXPORT resourcePath(const std::string &resourceRelativePath = " std::string TEST_EXPORT fileContents(const std::string &fileName); void TEST_EXPORT printIssues(const libcellml::LoggerPtr &l, bool headings = false, bool cellmlElementTypes = false, bool rule = false); +void TEST_EXPORT printModel(const libcellml::ModelPtr &model, bool includeMaths = true); +void TEST_EXPORT printComponent(const libcellml::ComponentPtr &component, bool includeMaths = true); + std::vector TEST_EXPORT expectedCellmlElementTypes(size_t size, libcellml::CellmlElementType type); std::vector TEST_EXPORT expectedLevels(size_t size, libcellml::Issue::Level level); std::vector TEST_EXPORT expectedReferenceRules(size_t size, libcellml::Issue::ReferenceRule rule); From 231d19ec46bc35f9ec4919c2a6ae41da61c2ef1e Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Fri, 22 Nov 2024 08:24:51 +1300 Subject: [PATCH 4/6] Restore missing namespace in test_utils definition file. --- tests/test_utils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_utils.cpp b/tests/test_utils.cpp index bb20e98c6d..5910d20e8b 100644 --- a/tests/test_utils.cpp +++ b/tests/test_utils.cpp @@ -160,12 +160,12 @@ void printComponent(const libcellml::ComponentPtr &component, size_t c, const st } } -void printComponent(const ComponentPtr &component, bool includeMaths) +void printComponent(const libcellml::ComponentPtr &component, bool includeMaths) { printComponent(component, -1, {}, includeMaths); } -void printModel(const ModelPtr &model, bool includeMaths) +void printModel(const libcellml::ModelPtr &model, bool includeMaths) { std::cout << "MODEL: '" << model->name() << "'"; if (model->id() != "") { From 71f4154bd2b5928aa4331c75ee7de471d32da20b Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Fri, 22 Nov 2024 08:27:53 +1300 Subject: [PATCH 5/6] Rename test producing segfault. --- tests/importer/model_flattening.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/importer/model_flattening.cpp b/tests/importer/model_flattening.cpp index 4eb5f63f94..8cf7935a7c 100644 --- a/tests/importer/model_flattening.cpp +++ b/tests/importer/model_flattening.cpp @@ -1919,7 +1919,7 @@ TEST(ModelFlattening, modelWithCnUnitsNotDefinedInImportedComponent) EXPECT_EQ("The model is not fully defined.", importer->error(0)->description()); } -TEST(Experiment, periodicStimulus) +TEST(ModelFlattening, multiLayeredImportOfNonStandardUnits) { auto parser = libcellml::Parser::create(false); auto model = parser->parseModel(fileContents("importer/periodicstimulus/experiments/periodic-stimulus.xml")); From bd0b2e98adea5483741a0bad26cf7ece07c685cd Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Fri, 22 Nov 2024 10:55:40 +1300 Subject: [PATCH 6/6] Use SIZE_MAX instead of -1 for size_t variable. --- tests/test_utils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_utils.cpp b/tests/test_utils.cpp index 5910d20e8b..c4662caa96 100644 --- a/tests/test_utils.cpp +++ b/tests/test_utils.cpp @@ -91,7 +91,7 @@ static const std::string FIXED_INDENT = " "; void printComponent(const libcellml::ComponentPtr &component, size_t c, const std::string &indent, bool includeMaths) { - if (c == size_t(-1)) { + if (c == SIZE_MAX) { std::cout << "COMPONENT: '" << component->name() << "'"; } else { std::cout << indent << "[" << c + 1 << "]: " << component->name(); @@ -162,7 +162,7 @@ void printComponent(const libcellml::ComponentPtr &component, size_t c, const st void printComponent(const libcellml::ComponentPtr &component, bool includeMaths) { - printComponent(component, -1, {}, includeMaths); + printComponent(component, SIZE_MAX, {}, includeMaths); } void printModel(const libcellml::ModelPtr &model, bool includeMaths)