From 190a09dccfb8e8e441c6054f5580a01563a047e8 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Tue, 22 Sep 2026 19:05:22 +1200 Subject: [PATCH 1/5] Add unary minus tests. --- tests/generator/generatorunaryminus.cpp | 125 ++++++++++++++++++ tests/generator/tests.cmake | 1 + .../generator/unary_minus/example_01.cellml | 26 ++++ .../generator/unary_minus/example_02.cellml | 33 +++++ .../generator/unary_minus/example_03.cellml | 33 +++++ .../generator/unary_minus/example_04.cellml | 29 ++++ .../generator/unary_minus/example_05.cellml | 33 +++++ 7 files changed, 280 insertions(+) create mode 100644 tests/generator/generatorunaryminus.cpp create mode 100644 tests/resources/generator/unary_minus/example_01.cellml create mode 100644 tests/resources/generator/unary_minus/example_02.cellml create mode 100644 tests/resources/generator/unary_minus/example_03.cellml create mode 100644 tests/resources/generator/unary_minus/example_04.cellml create mode 100644 tests/resources/generator/unary_minus/example_05.cellml diff --git a/tests/generator/generatorunaryminus.cpp b/tests/generator/generatorunaryminus.cpp new file mode 100644 index 0000000000..0d6b9287e6 --- /dev/null +++ b/tests/generator/generatorunaryminus.cpp @@ -0,0 +1,125 @@ +/* +Copyright libCellML Contributors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +#include "test_utils.h" + +#include "gtest/gtest.h" + +#include + +TEST(GeneratorUnaryMinus, example01) +{ + // rates[0] = --1.0; + auto parser = libcellml::Parser::create(); + auto model = parser->parseModel(fileContents("generator/unary_minus/example_01.cellml")); + + EXPECT_NE(nullptr, model); + + auto analyser = libcellml::Analyser::create(); + analyser->analyseModel(model); + + EXPECT_EQ(size_t(0), analyser->issueCount()); + + auto generator = libcellml::Generator::create(); + + auto implementationCode = generator->implementationCode(analyser->analyserModel()); + + + EXPECT_TRUE(implementationCode.find("rates[0] = -(-1.0);\n") != std::string::npos); +} + +TEST(GeneratorUnaryMinus, example02) +{ + // rates[0] = --2.0*constants[0]; + auto parser = libcellml::Parser::create(); + auto model = parser->parseModel(fileContents("generator/unary_minus/example_02.cellml")); + + EXPECT_NE(nullptr, model); + + auto analyser = libcellml::Analyser::create(); + analyser->analyseModel(model); + + EXPECT_EQ(size_t(0), analyser->issueCount()); + + auto generator = libcellml::Generator::create(); + + auto implementationCode = generator->implementationCode(analyser->analyserModel()); + + + EXPECT_TRUE(implementationCode.find("rates[0] = -(-2.0)*constants[0];\n") != std::string::npos); +} + +TEST(GeneratorUnaryMinus, example03) +{ + // rates[0] = --constants[1]/constants[0]; + auto parser = libcellml::Parser::create(); + auto model = parser->parseModel(fileContents("generator/unary_minus/example_03.cellml")); + + EXPECT_NE(nullptr, model); + + auto analyser = libcellml::Analyser::create(); + analyser->analyseModel(model); + + EXPECT_EQ(size_t(0), analyser->issueCount()); + + auto generator = libcellml::Generator::create(); + + auto implementationCode = generator->implementationCode(analyser->analyserModel()); + + + EXPECT_TRUE(implementationCode.find("rates[0] = -(-constants[1])/constants[0];\n") != std::string::npos); +} + +TEST(GeneratorUnaryMinus, example04) +{ + // rates[0] = -(-1.0); + auto parser = libcellml::Parser::create(); + auto model = parser->parseModel(fileContents("generator/unary_minus/example_04.cellml")); + + EXPECT_NE(nullptr, model); + + auto analyser = libcellml::Analyser::create(); + analyser->analyseModel(model); + + EXPECT_EQ(size_t(0), analyser->issueCount()); + + auto generator = libcellml::Generator::create(); + + auto implementationCode = generator->implementationCode(analyser->analyserModel()); + + + EXPECT_TRUE(implementationCode.find("rates[0] = -(-1.0);\n") != std::string::npos); +} + +TEST(GeneratorUnaryMinus, example05) +{ + // rates[0] = -(-constants[1]+constants[0]); + auto parser = libcellml::Parser::create(); + auto model = parser->parseModel(fileContents("generator/unary_minus/example_05.cellml")); + + EXPECT_NE(nullptr, model); + + auto analyser = libcellml::Analyser::create(); + analyser->analyseModel(model); + + EXPECT_EQ(size_t(0), analyser->issueCount()); + + auto generator = libcellml::Generator::create(); + + auto implementationCode = generator->implementationCode(analyser->analyserModel()); + + + EXPECT_TRUE(implementationCode.find("rates[0] = -(-constants[1]+constants[0]);\n") != std::string::npos); +} diff --git a/tests/generator/tests.cmake b/tests/generator/tests.cmake index dc7636fb93..38e5dc0b37 100644 --- a/tests/generator/tests.cmake +++ b/tests/generator/tests.cmake @@ -6,5 +6,6 @@ list(APPEND LIBCELLML_TESTS ${CURRENT_TEST}) set(${CURRENT_TEST}_SRCS ${CMAKE_CURRENT_LIST_DIR}/generator.cpp ${CMAKE_CURRENT_LIST_DIR}/generatorprofile.cpp + ${CMAKE_CURRENT_LIST_DIR}/generatorunaryminus.cpp ${CMAKE_CURRENT_LIST_DIR}/generatorvariabletracker.cpp ) diff --git a/tests/resources/generator/unary_minus/example_01.cellml b/tests/resources/generator/unary_minus/example_01.cellml new file mode 100644 index 0000000000..405be168f8 --- /dev/null +++ b/tests/resources/generator/unary_minus/example_01.cellml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + t + + x + + + + -1 + + + + + + diff --git a/tests/resources/generator/unary_minus/example_02.cellml b/tests/resources/generator/unary_minus/example_02.cellml new file mode 100644 index 0000000000..29f1ca37ad --- /dev/null +++ b/tests/resources/generator/unary_minus/example_02.cellml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + t + + x + + + + + + + + 2 + + a + + + + + + + diff --git a/tests/resources/generator/unary_minus/example_03.cellml b/tests/resources/generator/unary_minus/example_03.cellml new file mode 100644 index 0000000000..553b25b953 --- /dev/null +++ b/tests/resources/generator/unary_minus/example_03.cellml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + t + + x + + + + + + + + a + + b + + + + + + + diff --git a/tests/resources/generator/unary_minus/example_04.cellml b/tests/resources/generator/unary_minus/example_04.cellml new file mode 100644 index 0000000000..63ee3020f2 --- /dev/null +++ b/tests/resources/generator/unary_minus/example_04.cellml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + t + + x + + + + + + 1 + + + + + + + diff --git a/tests/resources/generator/unary_minus/example_05.cellml b/tests/resources/generator/unary_minus/example_05.cellml new file mode 100644 index 0000000000..e46c958a2a --- /dev/null +++ b/tests/resources/generator/unary_minus/example_05.cellml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + t + + x + + + + + + + + a + + b + + + + + + + From 269d16974fbdfd7073ab54936264b3bbaead4552 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Tue, 22 Sep 2026 19:08:55 +1200 Subject: [PATCH 2/5] Fix code formatting issues. --- tests/generator/generatorunaryminus.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/generator/generatorunaryminus.cpp b/tests/generator/generatorunaryminus.cpp index 0d6b9287e6..302a80f0fc 100644 --- a/tests/generator/generatorunaryminus.cpp +++ b/tests/generator/generatorunaryminus.cpp @@ -36,7 +36,6 @@ TEST(GeneratorUnaryMinus, example01) auto implementationCode = generator->implementationCode(analyser->analyserModel()); - EXPECT_TRUE(implementationCode.find("rates[0] = -(-1.0);\n") != std::string::npos); } @@ -57,7 +56,6 @@ TEST(GeneratorUnaryMinus, example02) auto implementationCode = generator->implementationCode(analyser->analyserModel()); - EXPECT_TRUE(implementationCode.find("rates[0] = -(-2.0)*constants[0];\n") != std::string::npos); } @@ -78,7 +76,6 @@ TEST(GeneratorUnaryMinus, example03) auto implementationCode = generator->implementationCode(analyser->analyserModel()); - EXPECT_TRUE(implementationCode.find("rates[0] = -(-constants[1])/constants[0];\n") != std::string::npos); } @@ -99,7 +96,6 @@ TEST(GeneratorUnaryMinus, example04) auto implementationCode = generator->implementationCode(analyser->analyserModel()); - EXPECT_TRUE(implementationCode.find("rates[0] = -(-1.0);\n") != std::string::npos); } @@ -120,6 +116,5 @@ TEST(GeneratorUnaryMinus, example05) auto implementationCode = generator->implementationCode(analyser->analyserModel()); - EXPECT_TRUE(implementationCode.find("rates[0] = -(-constants[1]+constants[0]);\n") != std::string::npos); } From 1868672ba3db9034c78804bb5df2ec7128db0a39 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Tue, 22 Sep 2026 19:14:53 +1200 Subject: [PATCH 3/5] Update test expectations for unary minus handling. --- tests/generator/generatorunaryminus.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/generator/generatorunaryminus.cpp b/tests/generator/generatorunaryminus.cpp index 302a80f0fc..7fbd611c03 100644 --- a/tests/generator/generatorunaryminus.cpp +++ b/tests/generator/generatorunaryminus.cpp @@ -56,7 +56,7 @@ TEST(GeneratorUnaryMinus, example02) auto implementationCode = generator->implementationCode(analyser->analyserModel()); - EXPECT_TRUE(implementationCode.find("rates[0] = -(-2.0)*constants[0];\n") != std::string::npos); + EXPECT_TRUE(implementationCode.find("rates[0] = -(-2.0*constants[0]);\n") != std::string::npos); } TEST(GeneratorUnaryMinus, example03) @@ -76,7 +76,7 @@ TEST(GeneratorUnaryMinus, example03) auto implementationCode = generator->implementationCode(analyser->analyserModel()); - EXPECT_TRUE(implementationCode.find("rates[0] = -(-constants[1])/constants[0];\n") != std::string::npos); + EXPECT_TRUE(implementationCode.find("rates[0] = -(-constants[1]/constants[0]);\n") != std::string::npos); } TEST(GeneratorUnaryMinus, example04) From d4673014561f6a94da4a664099ff80c173f866e2 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Tue, 22 Sep 2026 19:15:20 +1200 Subject: [PATCH 4/5] Handle unary minus generation in generator. --- src/generator.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/generator.cpp b/src/generator.cpp index 4a4ecc2ec4..0b769cf5c7 100644 --- a/src/generator.cpp +++ b/src/generator.cpp @@ -1286,7 +1286,9 @@ std::string Generator::GeneratorImpl::generateMinusUnaryCode(const AnalyserEquat || isLogicalOperator(astLeftChild) || isPlusOperator(astLeftChild) || isMinusOperator(astLeftChild) - || isPiecewiseStatement(astLeftChild)) { + || isNegativeNumber(astLeftChild) + || isPiecewiseStatement(astLeftChild) + || (code.rfind(mProfile->minusString(), 0) == 0)) { code = "(" + code + ")"; } From 6a014e61cb4a69bb642f2834b2ed5e2724bd8775 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Tue, 22 Sep 2026 20:01:46 +1200 Subject: [PATCH 5/5] Add a further two unary minus tests. --- tests/generator/generatorunaryminus.cpp | 40 +++++++++++++++++++ .../generator/unary_minus/example_06.cellml | 33 +++++++++++++++ .../generator/unary_minus/example_07.cellml | 30 ++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 tests/resources/generator/unary_minus/example_06.cellml create mode 100644 tests/resources/generator/unary_minus/example_07.cellml diff --git a/tests/generator/generatorunaryminus.cpp b/tests/generator/generatorunaryminus.cpp index 7fbd611c03..48e198a5b5 100644 --- a/tests/generator/generatorunaryminus.cpp +++ b/tests/generator/generatorunaryminus.cpp @@ -118,3 +118,43 @@ TEST(GeneratorUnaryMinus, example05) EXPECT_TRUE(implementationCode.find("rates[0] = -(-constants[1]+constants[0]);\n") != std::string::npos); } + +TEST(GeneratorUnaryMinus, example06) +{ + // rates[0] = -pow(-constants[1], constants[0]); + auto parser = libcellml::Parser::create(); + auto model = parser->parseModel(fileContents("generator/unary_minus/example_06.cellml")); + + EXPECT_NE(nullptr, model); + + auto analyser = libcellml::Analyser::create(); + analyser->analyseModel(model); + + EXPECT_EQ(size_t(0), analyser->issueCount()); + + auto generator = libcellml::Generator::create(); + + auto implementationCode = generator->implementationCode(analyser->analyserModel()); + + EXPECT_TRUE(implementationCode.find("rates[0] = -pow(-constants[1], constants[0]);\n") != std::string::npos); +} + +TEST(GeneratorUnaryMinus, example07) +{ + // rates[0] = constants[1]-(-constants[0]); + auto parser = libcellml::Parser::create(); + auto model = parser->parseModel(fileContents("generator/unary_minus/example_07.cellml")); + + EXPECT_NE(nullptr, model); + + auto analyser = libcellml::Analyser::create(); + analyser->analyseModel(model); + + EXPECT_EQ(size_t(0), analyser->issueCount()); + + auto generator = libcellml::Generator::create(); + + auto implementationCode = generator->implementationCode(analyser->analyserModel()); + + EXPECT_TRUE(implementationCode.find("rates[0] = constants[1]-(-constants[0]);\n") != std::string::npos); +} diff --git a/tests/resources/generator/unary_minus/example_06.cellml b/tests/resources/generator/unary_minus/example_06.cellml new file mode 100644 index 0000000000..d95003657b --- /dev/null +++ b/tests/resources/generator/unary_minus/example_06.cellml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + t + + x + + + + + + + + a + + b + + + + + + + diff --git a/tests/resources/generator/unary_minus/example_07.cellml b/tests/resources/generator/unary_minus/example_07.cellml new file mode 100644 index 0000000000..6c9359cfb7 --- /dev/null +++ b/tests/resources/generator/unary_minus/example_07.cellml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + t + + x + + + + b + + + a + + + + + + +