Skip to content

Commit

Permalink
Merge pull request #591 from kerimoyle/i590_print_model_with_imports
Browse files Browse the repository at this point in the history
Printer to print local children of imported components. Closes #590.
  • Loading branch information
hsorby committed Aug 13, 2020
2 parents ab2c6b9 + 47e287c commit 84ebec3
Show file tree
Hide file tree
Showing 10 changed files with 254 additions and 93 deletions.
64 changes: 33 additions & 31 deletions src/printer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,40 +234,41 @@ std::string Printer::PrinterImpl::printUnits(const UnitsPtr &units, IdList &idLi
std::string Printer::PrinterImpl::printComponent(const ComponentPtr &component, IdList &idList, bool autoIds)
{
std::string repr;
if (component->isImport()) {
return repr;
}
repr += "<component";
std::string componentName = component->name();
if (!componentName.empty()) {
repr += " name=\"" + componentName + "\"";
}
if (!component->id().empty()) {
repr += " id=\"" + component->id() + "\"";
} else if (autoIds) {
repr += " id=\"" + makeUniqueId(idList) + "\"";
}
size_t variableCount = component->variableCount();
size_t resetCount = component->resetCount();
bool hasChildren = false;
if (variableCount > 0 || resetCount > 0 || !component->math().empty()) {
hasChildren = true;
}
if (hasChildren) {
repr += ">";
for (size_t i = 0; i < variableCount; ++i) {
repr += printVariable(component->variable(i), idList, autoIds);
if (!component->isImport()) {
repr += "<component";
std::string componentName = component->name();
if (!componentName.empty()) {
repr += " name=\"" + componentName + "\"";
}
if (!component->id().empty()) {
repr += " id=\"" + component->id() + "\"";
} else if (autoIds) {
repr += " id=\"" + makeUniqueId(idList) + "\"";
}
for (size_t i = 0; i < resetCount; ++i) {
repr += printReset(component->reset(i), idList, autoIds);
size_t variableCount = component->variableCount();
size_t resetCount = component->resetCount();
bool hasChildren = false;
if (variableCount > 0 || resetCount > 0 || !component->math().empty()) {
hasChildren = true;
}
if (!component->math().empty()) {
repr += printMath(component->math());
if (hasChildren) {
repr += ">";
for (size_t i = 0; i < variableCount; ++i) {
repr += printVariable(component->variable(i), idList, autoIds);
}
for (size_t i = 0; i < resetCount; ++i) {
repr += printReset(component->reset(i), idList, autoIds);
}
if (!component->math().empty()) {
repr += printMath(component->math());
}

repr += "</component>";
} else {
repr += "/>";
}
repr += "</component>";
} else {
repr += "/>";
}

// Traverse through children of this component and add them to the representation.
for (size_t i = 0; i < component->componentCount(); ++i) {
repr += printComponent(component->component(i), idList, autoIds);
Expand Down Expand Up @@ -495,7 +496,8 @@ std::string Printer::printModel(const ModelPtr &model, bool autoIds) const
}

std::string componentEncapsulation;
// Serialise components of the model, imported components have already been dealt with at this point.
// Serialise components of the model, imported components have already been dealt with at this point,
// ... but their locally-defined children have not.
for (size_t i = 0; i < model->componentCount(); ++i) {
ComponentPtr component = model->component(i);
repr += mPimpl->printComponent(component, idList, autoIds);
Expand Down
12 changes: 12 additions & 0 deletions tests/parser/file_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,15 @@ TEST(Parser, simpleGeneratorModel)
std::string a = model->component("my_component")->math();
EXPECT_EQ(e, a);
}

TEST(Parser, parseModelWithImportedEquivVariables)
{
auto parser = libcellml::Parser::create();
auto modelContents = fileContents("importingModel.cellml");
auto model = parser->parseModel(modelContents);

auto printer = libcellml::Printer::create();
auto serialisedModel = printer->printModel(model);

EXPECT_EQ(modelContents, serialisedModel);
}
34 changes: 34 additions & 0 deletions tests/printer/printer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,40 @@ TEST(Printer, printModelWithStandardUnitsAdded)
EXPECT_EQ(e, printer->printModel(model));
}

TEST(Printer, printModelImportingModelParentComponent)
{
auto parser = libcellml::Parser::create();
auto modelContents = fileContents("importingModelParentComponent.cellml");
auto model = parser->parseModel(modelContents);
EXPECT_EQ(size_t(0), parser->errorCount());

auto validator = libcellml::Validator::create();
validator->validateModel(model);
EXPECT_EQ(size_t(0), validator->issueCount());

auto printer = libcellml::Printer::create();
auto serialisedModel = printer->printModel(model);

EXPECT_EQ(modelContents, serialisedModel);
}

TEST(Printer, printModelImportingModelChildComponent)
{
auto parser = libcellml::Parser::create();
auto modelContents = fileContents("importingModelChildComponent.cellml");
auto model = parser->parseModel(modelContents);

auto validator = libcellml::Validator::create();
validator->validateModel(model);

EXPECT_EQ(size_t(0), validator->issueCount());

auto printer = libcellml::Printer::create();
auto serialisedModel = printer->printModel(model);

EXPECT_EQ(modelContents, serialisedModel);
}

TEST(Printer, printModelWithAutomaticIdsNoMaths)
{
const std::string in = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
Expand Down
21 changes: 21 additions & 0 deletions tests/resources/importedModelWithMaps.cellml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<model xmlns="http://www.cellml.org/cellml/2.0#" name="import_me">
<component name="importMe">
<variable name="x" units="dimensionless" interface="public_and_private"/>
</component>
<component name="child1">
<variable name="x" units="dimensionless" interface="public_and_private"/>
</component>
<component name="child2">
<variable name="x" units="dimensionless" interface="public_and_private"/>
</component>
<connection component_1="child1" component_2="child2">
<map_variables variable_1="x" variable_2="x" />
</connection>
<encapsulation>
<component_ref component="importMe">
<component_ref component="child1" />
<component_ref component="child2" />
</component_ref>
</encapsulation>
</model>
12 changes: 12 additions & 0 deletions tests/resources/importingModel.cellml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<model xmlns="http://www.cellml.org/cellml/2.0#" name="import_example">
<import xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="importedModel.cellml">
<component component_ref="importMe" name="importedComponent"/>
</import>
<component name="localComponent">
<variable name="x" units="dimensionless" interface="public_and_private"/>
</component>
<connection component_1="importedComponent" component_2="localComponent">
<map_variables variable_1="x" variable_2="x"/>
</connection>
</model>
14 changes: 14 additions & 0 deletions tests/resources/importingModelChildComponent.cellml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<model xmlns="http://www.cellml.org/cellml/2.0#" name="import_example">
<import xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="importedModel.cellml">
<component component_ref="importMe" name="importedComponent"/>
</import>
<component name="localComponent">
<variable name="x" units="dimensionless" interface="public_and_private"/>
</component>
<encapsulation>
<component_ref component="importedComponent">
<component_ref component="localComponent"/>
</component_ref>
</encapsulation>
</model>
14 changes: 14 additions & 0 deletions tests/resources/importingModelParentComponent.cellml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<model xmlns="http://www.cellml.org/cellml/2.0#" name="import_example">
<import xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="importedModel.cellml">
<component component_ref="importMe" name="importedComponent"/>
</import>
<component name="localComponent">
<variable name="x" units="dimensionless" interface="public_and_private"/>
</component>
<encapsulation>
<component_ref component="localComponent">
<component_ref component="importedComponent"/>
</component_ref>
</encapsulation>
</model>
137 changes: 77 additions & 60 deletions tests/test_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,87 +76,104 @@ void printIssues(const libcellml::LoggerPtr &l, bool headings, bool causes, bool
}
}

void printModel(const libcellml::ModelPtr &model)
{
std::cout << "The model name is: '" << model->name() << "'" << std::endl;
if (model->id() != "") {
std::cout << "The model id is: '" << model->id() << "'" << std::endl;
}

// 2.a Print any custom units of the model
std::cout << "The model defines " << model->unitsCount()
<< " custom units:" << std::endl;
for (size_t u = 0; u < model->unitsCount(); ++u) {
std::cout << " Units[" << u << "] is '" << model->units(u)->name() << "'"
<< std::endl;
}
static const std::string FIXED_INDENT = " ";

// 2.b Print the components of the model
std::cout << "The model has " << model->componentCount()
<< " components:" << std::endl;
for (size_t c = 0; c < model->componentCount(); ++c) {
// 2.c Printing the attributes of the component
auto component = model->component(c);
std::string spacer = " ";
printComponent(component, c, spacer);
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();
}
}

void printComponent(const libcellml::ComponentPtr &component, size_t const c, std::string const spacer)
{
std::cout << spacer << "Component[" << c << "] has name: '"
<< component->name() << "'" << std::endl;
if (component->id() != "") {
std::cout << spacer << "Component[" << c << "] has id: '"
<< component->id() << "'" << std::endl;
std::cout << ", id: " << component->id();
}

std::cout << spacer << "Component[" << c << "] has "
<< component->variableCount()
<< " variables:" << std::endl;

// Printing the variables within the component
for (size_t vIndex = 0; vIndex < component->variableCount(); vIndex++) {
auto v = component->variable(vIndex);
std::cout << spacer << " Variable[" << vIndex << "] has name: '"
<< v->name() << "'" << std::endl;
if (v->initialValue() != "") {
std::cout << spacer << " Variable[" << vIndex << "] has initial_value: '"
<< v->initialValue() << "'"
<< std::endl;
}
if (v->units() != nullptr) {
std::cout << spacer << " Variable[" << vIndex << "] has units: '"
<< v->units()->name() << "'" << std::endl;
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() << "]";
}
std::cout << spacer << " Variable[" << vIndex << "] has " << v->equivalentVariableCount() << " equivalent variable(s): ";
for (size_t eIndex = 0; eIndex < v->equivalentVariableCount(); ++eIndex) {
auto equivVariable = v->equivalentVariable(eIndex);
std::cout << equivVariable->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<libcellml::Component>(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 (component->math() != "") {
std::cout << spacer << " Maths in the component is:" << std::endl;
std::cout << component->math() << 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 << spacer << "Component[" << c << "] has "
<< component->componentCount()
<< " child components:" << std::endl;
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++) {
for (size_t c2 = 0; c2 < component->componentCount(); ++c2) {
auto child = component->component(c2);
std::string oneMoreSpacer = spacer + " ";
printComponent(child, c2, oneMoreSpacer);
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);
}
}

void expectEqualIssues(const std::vector<std::string> &issues, const libcellml::LoggerPtr &logger)

{
Expand Down
6 changes: 4 additions & 2 deletions tests/test_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,10 @@ struct Debug
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 causes = false, bool rule = false);
void TEST_EXPORT printComponent(const libcellml::ComponentPtr &component, size_t const c, std::string const spacer);
void TEST_EXPORT printModel(const libcellml::ModelPtr &model);

void TEST_EXPORT printModel(const libcellml::ModelPtr &model, bool includeMaths = true);
void TEST_EXPORT printComponent(const libcellml::ComponentPtr &component, bool includeMaths = true);

void TEST_EXPORT expectEqualIssues(const std::vector<std::string> &issues, const libcellml::LoggerPtr &logger);
void TEST_EXPORT expectEqualIssuesSpecificationHeadings(const std::vector<std::string> &issues,
const std::vector<std::string> &specificationHeadings,
Expand Down

0 comments on commit 84ebec3

Please sign in to comment.