Download tests/src/App/Expression.cpp from AbdulElahGwaith/FreeCAD: direct link, hf CLI and curl.
- Browser
- Download file 15.1 kB
-
https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/tests/src/App/Expression.cpp
- Command line
-
hf download hf://AbdulElahGwaith/FreeCAD/tests/src/App/Expression.cpp
-
curl -L -o Expression.cpp https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/tests/src/App/Expression.cpp
15.1 kB
| // SPDX-License-Identifier: LGPL-2.1-or-later | |
| /*************************************************************************** | |
| * Copyright (c) 2023 Werner Mayer <wmayer[at]users.sourceforge.net> * | |
| * Copyright (c) 2025 Pieter Hijma <info@pieterhijma.net> * | |
| * * | |
| * This file is part of FreeCAD. * | |
| * * | |
| * FreeCAD is free software: you can redistribute it and/or modify it * | |
| * under the terms of the GNU Lesser General Public License as * | |
| * published by the Free Software Foundation, either version 2.1 of the * | |
| * License, or (at your option) any later version. * | |
| * * | |
| * FreeCAD is distributed in the hope that it will be useful, but * | |
| * WITHOUT ANY WARRANTY; without even the implied warranty of * | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * | |
| * Lesser General Public License for more details. * | |
| * * | |
| * You should have received a copy of the GNU Lesser General Public * | |
| * License along with FreeCAD. If not, see * | |
| * <https://www.gnu.org/licenses/>. * | |
| * * | |
| **************************************************************************/ | |
| // +------------------------------------------------+ | |
| // | Note: For more expression related tests, see: | | |
| // | src/Mod/Spreadsheet/TestSpreadsheet.py | | |
| // +------------------------------------------------+ | |
| class Expression: public ::testing::Test | |
| { | |
| protected: | |
| static void SetUpTestSuite() | |
| { | |
| tests::initApplication(); | |
| } | |
| }; | |
| // clang-format off | |
| TEST_F(Expression, tokenize) | |
| { | |
| EXPECT_EQ(App::ExpressionTokenizer().perform(QStringLiteral(""), 10), QString()); | |
| // 0.0000 deg- | |
| EXPECT_EQ(App::ExpressionTokenizer().perform(QString::fromUtf8("0.00000 \xC2\xB0-"), 10), QString()); | |
| EXPECT_EQ(App::ExpressionTokenizer().perform(QString::fromUtf8("0.00000 \xC2\xB0-s"), 11), QStringLiteral("s")); | |
| EXPECT_EQ(App::ExpressionTokenizer().perform(QString::fromUtf8("0.00000 \xC2\xB0-ss"), 12), QStringLiteral("ss")); | |
| EXPECT_EQ(App::ExpressionTokenizer().perform(QStringLiteral("0.00000 deg"), 5), QString()); | |
| EXPECT_EQ(App::ExpressionTokenizer().perform(QStringLiteral("0.00000 deg"), 11), QStringLiteral("deg")); | |
| } | |
| TEST_F(Expression, tokenizeCompletion) | |
| { | |
| EXPECT_EQ(App::ExpressionTokenizer().perform(QStringLiteral("My Cube"), 7), QStringLiteral("MyCube")); | |
| EXPECT_EQ(App::ExpressionTokenizer().perform(QStringLiteral("My Cube0"), 8), QStringLiteral("MyCube0")); | |
| EXPECT_EQ(App::ExpressionTokenizer().perform(QStringLiteral("My Cube 0"), 9), QStringLiteral("MyCube0")); | |
| EXPECT_EQ(App::ExpressionTokenizer().perform(QStringLiteral("My Cube1"), 8), QStringLiteral("MyCube1")); | |
| EXPECT_EQ(App::ExpressionTokenizer().perform(QStringLiteral("My Cube 1"), 9), QStringLiteral("MyCube1")); | |
| } | |
| TEST_F(Expression, tokenizeQuantity) | |
| { | |
| auto result = App::ExpressionParser::tokenize("0.00000 deg"); | |
| EXPECT_EQ(result.size(), 2); | |
| EXPECT_EQ(std::get<0>(result[0]), App::ExpressionParser::NUM); | |
| EXPECT_EQ(std::get<1>(result[0]), 0); | |
| EXPECT_EQ(std::get<2>(result[0]), "0.00000"); | |
| EXPECT_EQ(std::get<0>(result[1]), App::ExpressionParser::UNIT); | |
| EXPECT_EQ(std::get<1>(result[1]), 8); | |
| EXPECT_EQ(std::get<2>(result[1]), "deg"); | |
| } | |
| TEST_F(Expression, tokenizeFunc) | |
| { | |
| auto result = App::ExpressionParser::tokenize("sin(0.00000)"); | |
| EXPECT_EQ(result.size(), 3); | |
| EXPECT_EQ(std::get<0>(result[0]), App::ExpressionParser::FUNC); | |
| EXPECT_EQ(std::get<1>(result[0]), 0); | |
| EXPECT_EQ(std::get<2>(result[0]), "sin("); | |
| EXPECT_EQ(std::get<0>(result[1]), App::ExpressionParser::NUM); | |
| EXPECT_EQ(std::get<1>(result[1]), 4); | |
| EXPECT_EQ(std::get<2>(result[1]), "0.00000"); | |
| EXPECT_EQ(std::get<1>(result[2]), 11); | |
| EXPECT_EQ(std::get<2>(result[2]), ")"); | |
| } | |
| TEST_F(Expression, tokenizeOne) | |
| { | |
| auto result = App::ExpressionParser::tokenize("1"); | |
| EXPECT_EQ(result.size(), 1); | |
| EXPECT_EQ(std::get<0>(result[0]), App::ExpressionParser::ONE); | |
| EXPECT_EQ(std::get<1>(result[0]), 0); | |
| EXPECT_EQ(std::get<2>(result[0]), "1"); | |
| } | |
| TEST_F(Expression, tokenizeNum) | |
| { | |
| auto result = App::ExpressionParser::tokenize("1.2341"); | |
| EXPECT_EQ(result.size(), 1); | |
| EXPECT_EQ(std::get<0>(result[0]), App::ExpressionParser::NUM); | |
| EXPECT_EQ(std::get<1>(result[0]), 0); | |
| EXPECT_EQ(std::get<2>(result[0]), "1.2341"); | |
| } | |
| TEST_F(Expression, tokenizeID) | |
| { | |
| auto result = App::ExpressionParser::tokenize("Something"); | |
| EXPECT_EQ(result.size(), 1); | |
| EXPECT_EQ(std::get<0>(result[0]), App::ExpressionParser::IDENTIFIER); | |
| EXPECT_EQ(std::get<1>(result[0]), 0); | |
| EXPECT_EQ(std::get<2>(result[0]), "Something"); | |
| } | |
| TEST_F(Expression, tokenizeUnit) | |
| { | |
| auto result = App::ExpressionParser::tokenize("km"); | |
| EXPECT_EQ(result.size(), 1); | |
| EXPECT_EQ(std::get<0>(result[0]), App::ExpressionParser::UNIT); | |
| EXPECT_EQ(std::get<1>(result[0]), 0); | |
| EXPECT_EQ(std::get<2>(result[0]), "km"); | |
| } | |
| TEST_F(Expression, tokenizeUSUnit) | |
| { | |
| auto result = App::ExpressionParser::tokenize("\""); | |
| EXPECT_EQ(result.size(), 1); | |
| EXPECT_EQ(std::get<0>(result[0]), App::ExpressionParser::USUNIT); | |
| EXPECT_EQ(std::get<1>(result[0]), 0); | |
| EXPECT_EQ(std::get<2>(result[0]), "\""); | |
| } | |
| TEST_F(Expression, tokenizeInt) | |
| { | |
| auto result = App::ExpressionParser::tokenize("123456"); | |
| EXPECT_EQ(result.size(), 1); | |
| EXPECT_EQ(std::get<0>(result[0]), App::ExpressionParser::INTEGER); | |
| EXPECT_EQ(std::get<1>(result[0]), 0); | |
| EXPECT_EQ(std::get<2>(result[0]), "123456"); | |
| } | |
| TEST_F(Expression, tokenizePi) | |
| { | |
| auto result = App::ExpressionParser::tokenize("pi"); | |
| EXPECT_EQ(result.size(), 1); | |
| EXPECT_EQ(std::get<0>(result[0]), App::ExpressionParser::CONSTANT); | |
| EXPECT_EQ(std::get<1>(result[0]), 0); | |
| EXPECT_EQ(std::get<2>(result[0]), "pi"); | |
| } | |
| TEST_F(Expression, tokenizeE) | |
| { | |
| auto result = App::ExpressionParser::tokenize("e"); | |
| EXPECT_EQ(result.size(), 1); | |
| EXPECT_EQ(std::get<0>(result[0]), App::ExpressionParser::CONSTANT); | |
| EXPECT_EQ(std::get<1>(result[0]), 0); | |
| EXPECT_EQ(std::get<2>(result[0]), "e"); | |
| } | |
| TEST_F(Expression, tokenizeConstant) | |
| { | |
| auto result = App::ExpressionParser::tokenize("True False true false None"); | |
| EXPECT_EQ(result.size(), 5); | |
| EXPECT_EQ(std::get<0>(result[0]), App::ExpressionParser::CONSTANT); | |
| EXPECT_EQ(std::get<1>(result[0]), 0); | |
| EXPECT_EQ(std::get<2>(result[0]), "True"); | |
| EXPECT_EQ(std::get<0>(result[1]), App::ExpressionParser::CONSTANT); | |
| EXPECT_EQ(std::get<0>(result[2]), App::ExpressionParser::CONSTANT); | |
| EXPECT_EQ(std::get<0>(result[3]), App::ExpressionParser::CONSTANT); | |
| EXPECT_EQ(std::get<0>(result[4]), App::ExpressionParser::CONSTANT); | |
| } | |
| TEST_F(Expression, tokenizeEqual) | |
| { | |
| auto result = App::ExpressionParser::tokenize("=="); | |
| EXPECT_EQ(result.size(), 1); | |
| EXPECT_EQ(std::get<0>(result[0]), App::ExpressionParser::EQ); | |
| EXPECT_EQ(std::get<1>(result[0]), 0); | |
| EXPECT_EQ(std::get<2>(result[0]), "=="); | |
| } | |
| TEST_F(Expression, tokenizeNotEqual) | |
| { | |
| auto result = App::ExpressionParser::tokenize("!="); | |
| EXPECT_EQ(result.size(), 1); | |
| EXPECT_EQ(std::get<0>(result[0]), App::ExpressionParser::NEQ); | |
| EXPECT_EQ(std::get<1>(result[0]), 0); | |
| EXPECT_EQ(std::get<2>(result[0]), "!="); | |
| } | |
| TEST_F(Expression, tokenizeLessThan) | |
| { | |
| auto result = App::ExpressionParser::tokenize("<"); | |
| EXPECT_EQ(result.size(), 1); | |
| EXPECT_EQ(std::get<0>(result[0]), App::ExpressionParser::LT); | |
| EXPECT_EQ(std::get<1>(result[0]), 0); | |
| EXPECT_EQ(std::get<2>(result[0]), "<"); | |
| } | |
| TEST_F(Expression, tokenizeLessThanEqual) | |
| { | |
| auto result = App::ExpressionParser::tokenize("<="); | |
| EXPECT_EQ(result.size(), 1); | |
| EXPECT_EQ(std::get<0>(result[0]), App::ExpressionParser::LTE); | |
| EXPECT_EQ(std::get<1>(result[0]), 0); | |
| EXPECT_EQ(std::get<2>(result[0]), "<="); | |
| } | |
| TEST_F(Expression, tokenizeGreaterThan) | |
| { | |
| auto result = App::ExpressionParser::tokenize(">"); | |
| EXPECT_EQ(result.size(), 1); | |
| EXPECT_EQ(std::get<0>(result[0]), App::ExpressionParser::GT); | |
| EXPECT_EQ(std::get<1>(result[0]), 0); | |
| EXPECT_EQ(std::get<2>(result[0]), ">"); | |
| } | |
| TEST_F(Expression, tokenizeGreaterThanEqual) | |
| { | |
| auto result = App::ExpressionParser::tokenize(">="); | |
| EXPECT_EQ(result.size(), 1); | |
| EXPECT_EQ(std::get<0>(result[0]), App::ExpressionParser::GTE); | |
| EXPECT_EQ(std::get<1>(result[0]), 0); | |
| EXPECT_EQ(std::get<2>(result[0]), ">="); | |
| } | |
| TEST_F(Expression, tokenizeMinus) | |
| { | |
| auto result = App::ExpressionParser::tokenize("1-1"); | |
| EXPECT_EQ(result.size(), 3); | |
| EXPECT_EQ(std::get<0>(result[1]), App::ExpressionParser::MINUSSIGN); | |
| EXPECT_EQ(std::get<1>(result[1]), 1); | |
| EXPECT_EQ(std::get<2>(result[1]), "-"); | |
| } | |
| TEST_F(Expression, tokenizeCell1) | |
| { | |
| auto result = App::ExpressionParser::tokenize("$A$12"); | |
| EXPECT_EQ(result.size(), 1); | |
| EXPECT_EQ(std::get<0>(result[0]), App::ExpressionParser::CELLADDRESS); | |
| EXPECT_EQ(std::get<1>(result[0]), 0); | |
| EXPECT_EQ(std::get<2>(result[0]), "$A$12"); | |
| } | |
| TEST_F(Expression, tokenizeCell2) | |
| { | |
| auto result = App::ExpressionParser::tokenize("A$12"); | |
| EXPECT_EQ(result.size(), 1); | |
| EXPECT_EQ(std::get<0>(result[0]), App::ExpressionParser::CELLADDRESS); | |
| EXPECT_EQ(std::get<1>(result[0]), 0); | |
| EXPECT_EQ(std::get<2>(result[0]), "A$12"); | |
| } | |
| TEST_F(Expression, tokenizeCell3) | |
| { | |
| auto result = App::ExpressionParser::tokenize("$A12"); | |
| EXPECT_EQ(result.size(), 1); | |
| EXPECT_EQ(std::get<0>(result[0]), App::ExpressionParser::CELLADDRESS); | |
| EXPECT_EQ(std::get<1>(result[0]), 0); | |
| EXPECT_EQ(std::get<2>(result[0]), "$A12"); | |
| } | |
| TEST_F(Expression, tokenizeString) | |
| { | |
| auto result = App::ExpressionParser::tokenize("<<Test>>"); | |
| EXPECT_EQ(result.size(), 1); | |
| EXPECT_EQ(std::get<0>(result[0]), App::ExpressionParser::STRING); | |
| EXPECT_EQ(std::get<1>(result[0]), 0); | |
| EXPECT_EQ(std::get<2>(result[0]), "<<Test>>"); | |
| } | |
| TEST_F(Expression, tokenizeExponent) | |
| { | |
| // TODO | |
| } | |
| TEST_F(Expression, tokenizeNumAndUnit) | |
| { | |
| // TODO | |
| } | |
| TEST_F(Expression, tokenizePos) | |
| { | |
| // TODO | |
| } | |
| TEST_F(Expression, tokenizeNeg) | |
| { | |
| // TODO | |
| } | |
| TEST_F(Expression, tokenizePi_rad) | |
| { | |
| EXPECT_EQ(App::ExpressionTokenizer().perform(QStringLiteral("p"), 1), QStringLiteral("p")); | |
| EXPECT_EQ(App::ExpressionTokenizer().perform(QStringLiteral("pi"), 2), QString()); | |
| EXPECT_EQ(App::ExpressionTokenizer().perform(QStringLiteral("pi "), 3), QString()); | |
| EXPECT_EQ(App::ExpressionTokenizer().perform(QStringLiteral("pi r"), 4), QStringLiteral("r")); | |
| EXPECT_EQ(App::ExpressionTokenizer().perform(QStringLiteral("pi ra"), 5), QStringLiteral("ra")); | |
| EXPECT_EQ(App::ExpressionTokenizer().perform(QStringLiteral("pi rad"), 6), QStringLiteral("rad")); | |
| EXPECT_EQ(App::ExpressionTokenizer().perform(QStringLiteral("pi rad"), 2), QString()); | |
| } | |
| TEST_F(Expression, toString) | |
| { | |
| App::UnitExpression expr{nullptr, Base::Quantity{}, "pi rad"}; | |
| EXPECT_EQ(expr.toString(), "pi rad"); | |
| } | |
| TEST_F(Expression, test_pi_rad) | |
| { | |
| auto constant = std::make_unique<App::ConstantExpression>(nullptr, "pi"); | |
| auto unit = std::make_unique<App::UnitExpression>(nullptr, Base::Quantity{}, "rad"); | |
| auto op = std::make_unique<App::OperatorExpression>(nullptr, constant.get(), App::OperatorExpression::UNIT, unit.get()); | |
| EXPECT_EQ(op->toString(), "pi rad"); | |
| op.release(); | |
| } | |
| TEST_F(Expression, test_e_rad) | |
| { | |
| auto constant = std::make_unique<App::ConstantExpression>(nullptr, "e"); | |
| auto unit = std::make_unique<App::UnitExpression>(nullptr, Base::Quantity{}, "rad"); | |
| auto op = std::make_unique<App::OperatorExpression>(nullptr, constant.get(), App::OperatorExpression::UNIT, unit.get()); | |
| EXPECT_EQ(op->toString(), "e rad"); | |
| op.release(); | |
| } | |
| class Evaluate: public ::testing::Test | |
| { | |
| protected: | |
| static void SetUpTestSuite() | |
| { | |
| tests::initApplication(); | |
| } | |
| void SetUp() override | |
| { | |
| _doc_name = App::GetApplication().getUniqueDocumentName("test"); | |
| _this_doc = App::GetApplication().newDocument(_doc_name.c_str(), "testUser"); | |
| _this_obj = _this_doc->addObject("App::VarSet"); | |
| } | |
| void TearDown() override | |
| { | |
| App::GetApplication().closeDocument(_doc_name.c_str()); | |
| } | |
| App::DocumentObject* this_obj() { return _this_obj; } | |
| private: | |
| std::string _doc_name; | |
| App::Document* _this_doc {}; | |
| App::DocumentObject* _this_obj {}; | |
| }; | |
| // Various test for evaluating and simplifying expressions | |
| // Each "evaluate" test has an equivalent "simplify" test | |
| TEST_F(Evaluate, test_evaluate_simple) | |
| { | |
| App::Expression* e = App::ExpressionParser::parse(this_obj(), "1 + 2"); | |
| App::Expression* evaluated = e->eval(); | |
| EXPECT_EQ(e->toString(), "1 + 2"); | |
| EXPECT_EQ(evaluated->toString(), "3"); | |
| } | |
| TEST_F(Evaluate, test_simplify_simple) | |
| { | |
| App::Expression* e = App::ExpressionParser::parse(this_obj(), "1 + 2"); | |
| App::Expression* simplified = e->simplify(); | |
| EXPECT_EQ(e->toString(), "1 + 2"); | |
| EXPECT_EQ(simplified->toString(), "3"); | |
| } | |
| TEST_F(Evaluate, test_evaluate_function) | |
| { | |
| App::Expression* e = App::ExpressionParser::parse(this_obj(), "sqrt(4)"); | |
| App::Expression* evaluated = e->eval(); | |
| EXPECT_EQ(e->toString(), "sqrt(4)"); | |
| EXPECT_EQ(evaluated->toString(), "2"); | |
| } | |
| TEST_F(Evaluate, test_simplify_function) | |
| { | |
| App::Expression* e = App::ExpressionParser::parse(this_obj(), "sqrt(4)"); | |
| App::Expression* simplified = e->simplify(); | |
| EXPECT_EQ(e->toString(), "sqrt(4)"); | |
| EXPECT_EQ(simplified->toString(), "2"); | |
| } | |
| TEST_F(Evaluate, test_evaluate_refer_to_var) | |
| { | |
| auto* prop = freecad_cast<App::PropertyFloat*>(this_obj()->addDynamicProperty("App::PropertyFloat", "Var")); | |
| prop->setValue(2.0); | |
| App::Expression* e = App::ExpressionParser::parse(this_obj(), "sqrt(2 + Var)"); | |
| App::Expression* evaluated = e->eval(); | |
| EXPECT_EQ(e->toString(), "sqrt(2 + Var)"); | |
| EXPECT_EQ(evaluated->toString(), "2"); | |
| } | |
| TEST_F(Evaluate, test_simplify_refer_to_var) | |
| { | |
| auto* prop = freecad_cast<App::PropertyFloat*>(this_obj()->addDynamicProperty("App::PropertyFloat", "Var")); | |
| prop->setValue(2.0); | |
| App::Expression* e = App::ExpressionParser::parse(this_obj(), "sqrt(2 + Var)"); | |
| App::Expression* simplified = e->simplify(); | |
| EXPECT_EQ(e->toString(), "sqrt(2 + Var)"); | |
| EXPECT_EQ(simplified->toString(), "sqrt(2 + Var)"); | |
| } | |
| // clang-format on | |