MathExpressionTests.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AzCore/UnitTest/TestTypes.h>
  9. #include <gtest/gtest-param-test.h>
  10. #include <ExpressionEvaluation/ExpressionEngine.h>
  11. #include <Tests/ExpressionEngineTestFixture.h>
  12. #include <ExpressionEngine/MathOperators/MathExpressionOperators.h>
  13. namespace ExpressionEvaluation
  14. {
  15. using namespace UnitTest;
  16. TEST_F(ExpressionEngineTestFixture, ExpressionEngine_MathOperatorTest_AddOperator)
  17. {
  18. MathExpressionOperators operatorInterface;
  19. ElementInformation operatorInformation = MathExpressionOperators::AddOperator();
  20. ExpressionResultStack resultStack;
  21. {
  22. resultStack.emplace(3.0);
  23. resultStack.emplace(1.0);
  24. EXPECT_EQ(resultStack.size(), 2);
  25. operatorInterface.EvaluateToken(operatorInformation, resultStack);
  26. EXPECT_EQ(resultStack.size(), 1);
  27. auto treeResult = resultStack.PopAndReturn();
  28. ConfirmResult<double>(treeResult, 3.0+1.0);
  29. }
  30. {
  31. resultStack.emplace(1.0);
  32. resultStack.emplace(3.0);
  33. EXPECT_EQ(resultStack.size(), 2);
  34. operatorInterface.EvaluateToken(operatorInformation, resultStack);
  35. EXPECT_EQ(resultStack.size(), 1);
  36. auto treeResult = resultStack.PopAndReturn();
  37. ConfirmResult<double>(treeResult, 1.0+3.0);
  38. }
  39. }
  40. TEST_F(ExpressionEngineTestFixture, ExpressionEngine_MathOperatorTest_SubtractOperator)
  41. {
  42. MathExpressionOperators operatorInterface;
  43. ElementInformation operatorInformation = MathExpressionOperators::SubtractOperator();
  44. ExpressionResultStack resultStack;
  45. {
  46. resultStack.emplace(3.0);
  47. resultStack.emplace(1.0);
  48. EXPECT_EQ(resultStack.size(), 2);
  49. operatorInterface.EvaluateToken(operatorInformation, resultStack);
  50. EXPECT_EQ(resultStack.size(), 1);
  51. auto treeResult = resultStack.PopAndReturn();
  52. ConfirmResult<double>(treeResult, 3.0-1.0);
  53. }
  54. {
  55. resultStack.emplace(1.0);
  56. resultStack.emplace(3.0);
  57. EXPECT_EQ(resultStack.size(), 2);
  58. operatorInterface.EvaluateToken(operatorInformation, resultStack);
  59. EXPECT_EQ(resultStack.size(), 1);
  60. auto treeResult = resultStack.PopAndReturn();
  61. ConfirmResult<double>(treeResult, 1.0-3.0);
  62. }
  63. }
  64. TEST_F(ExpressionEngineTestFixture, ExpressionEngine_MathOperatorTest_MultiplyOperator)
  65. {
  66. MathExpressionOperators operatorInterface;
  67. ElementInformation operatorInformation = MathExpressionOperators::MultiplyOperator();
  68. ExpressionResultStack resultStack;
  69. {
  70. resultStack.emplace(2.0);
  71. resultStack.emplace(3.0);
  72. EXPECT_EQ(resultStack.size(), 2);
  73. operatorInterface.EvaluateToken(operatorInformation, resultStack);
  74. EXPECT_EQ(resultStack.size(), 1);
  75. auto treeResult = resultStack.PopAndReturn();
  76. ConfirmResult<double>(treeResult, 2.0*3.0);
  77. }
  78. {
  79. resultStack.emplace(3.0);
  80. resultStack.emplace(2.0);
  81. EXPECT_EQ(resultStack.size(), 2);
  82. operatorInterface.EvaluateToken(operatorInformation, resultStack);
  83. EXPECT_EQ(resultStack.size(), 1);
  84. auto treeResult = resultStack.PopAndReturn();
  85. ConfirmResult<double>(treeResult, 3.0*2.0);
  86. }
  87. }
  88. TEST_F(ExpressionEngineTestFixture, ExpressionEngine_MathOperatorTest_DivideOperator)
  89. {
  90. MathExpressionOperators operatorInterface;
  91. ElementInformation operatorInformation = MathExpressionOperators::DivideOperator();
  92. ExpressionResultStack resultStack;
  93. {
  94. resultStack.emplace(4.0);
  95. resultStack.emplace(2.0);
  96. EXPECT_EQ(resultStack.size(), 2);
  97. operatorInterface.EvaluateToken(operatorInformation, resultStack);
  98. EXPECT_EQ(resultStack.size(), 1);
  99. auto treeResult = resultStack.PopAndReturn();
  100. ConfirmResult<double>(treeResult, 4.0/2.0);
  101. }
  102. {
  103. resultStack.emplace(2.0);
  104. resultStack.emplace(4.0);
  105. EXPECT_EQ(resultStack.size(), 2);
  106. operatorInterface.EvaluateToken(operatorInformation, resultStack);
  107. EXPECT_EQ(resultStack.size(), 1);
  108. auto treeResult = resultStack.PopAndReturn();
  109. ConfirmResult<double>(treeResult, 2.0/4.0);
  110. }
  111. {
  112. resultStack.emplace(2.0);
  113. resultStack.emplace(0.0);
  114. EXPECT_EQ(resultStack.size(), 2);
  115. operatorInterface.EvaluateToken(operatorInformation, resultStack);
  116. EXPECT_EQ(resultStack.size(), 0);
  117. }
  118. }
  119. TEST_F(ExpressionEngineTestFixture, ExpressionEngine_MathOperatorTest_ModuloOperator)
  120. {
  121. MathExpressionOperators advandedMathInterface;
  122. ElementInformation operatorInformation = MathExpressionOperators::ModuloOperator();
  123. ExpressionResultStack resultStack;
  124. {
  125. resultStack.emplace(4.0);
  126. resultStack.emplace(2.0);
  127. EXPECT_EQ(resultStack.size(), 2);
  128. advandedMathInterface.EvaluateToken(operatorInformation, resultStack);
  129. EXPECT_EQ(resultStack.size(), 1);
  130. auto treeResult = resultStack.PopAndReturn();
  131. ConfirmResult<double>(treeResult, 4%2);
  132. }
  133. {
  134. resultStack.emplace(2.0);
  135. resultStack.emplace(4.0);
  136. EXPECT_EQ(resultStack.size(), 2);
  137. advandedMathInterface.EvaluateToken(operatorInformation, resultStack);
  138. EXPECT_EQ(resultStack.size(), 1);
  139. auto treeResult = resultStack.PopAndReturn();
  140. ConfirmResult<double>(treeResult, 2 % 4);
  141. }
  142. {
  143. resultStack.emplace(2.0);
  144. resultStack.emplace(0.0);
  145. EXPECT_EQ(resultStack.size(), 2);
  146. advandedMathInterface.EvaluateToken(operatorInformation, resultStack);
  147. EXPECT_EQ(resultStack.size(), 0);
  148. }
  149. }
  150. TEST_F(ExpressionEngineTestFixture, ExpressionEngine_MathOperatorTest_BasicMathParser)
  151. {
  152. MathExpressionOperators mathParser;
  153. {
  154. ExpressionElementParser::ParseResult result = mathParser.ParseElement("+", 0);
  155. EXPECT_EQ(result.m_charactersConsumed, 1);
  156. EXPECT_EQ(result.m_element.m_id, MathExpressionOperators::MathOperatorId::Add);
  157. EXPECT_TRUE(result.m_element.m_extraStore.empty());
  158. }
  159. {
  160. ExpressionElementParser::ParseResult result = mathParser.ParseElement("-", 0);
  161. EXPECT_EQ(result.m_charactersConsumed, 1);
  162. EXPECT_EQ(result.m_element.m_id, MathExpressionOperators::MathOperatorId::Subtract);
  163. EXPECT_TRUE(result.m_element.m_extraStore.empty());
  164. }
  165. {
  166. ExpressionElementParser::ParseResult result = mathParser.ParseElement("*", 0);
  167. EXPECT_EQ(result.m_charactersConsumed, 1);
  168. EXPECT_EQ(result.m_element.m_id, MathExpressionOperators::MathOperatorId::Multiply);
  169. EXPECT_TRUE(result.m_element.m_extraStore.empty());
  170. }
  171. {
  172. ExpressionElementParser::ParseResult result = mathParser.ParseElement("/", 0);
  173. EXPECT_EQ(result.m_charactersConsumed, 1);
  174. EXPECT_EQ(result.m_element.m_id, MathExpressionOperators::MathOperatorId::Divide);
  175. EXPECT_TRUE(result.m_element.m_extraStore.empty());
  176. }
  177. {
  178. ExpressionElementParser::ParseResult result = mathParser.ParseElement("%", 0);
  179. EXPECT_EQ(result.m_charactersConsumed, 1);
  180. EXPECT_EQ(result.m_element.m_id, MathExpressionOperators::MathOperatorId::Modulo);
  181. EXPECT_TRUE(result.m_element.m_extraStore.empty());
  182. }
  183. {
  184. ExpressionElementParser::ParseResult result = mathParser.ParseElement("(", 0);
  185. EXPECT_EQ(result.m_charactersConsumed, 0);
  186. }
  187. {
  188. ExpressionElementParser::ParseResult result = mathParser.ParseElement("ABCDEFG", 0);
  189. EXPECT_EQ(result.m_charactersConsumed, 0);
  190. }
  191. }
  192. TEST_F(ExpressionEngineTestFixture, ExpressionEngine_MathTest_SimpleTreeEvaluation)
  193. {
  194. {
  195. ExpressionTree tree;
  196. PushPrimitive(tree, 3.0);
  197. PushPrimitive(tree, 1.0);
  198. PushOperator(tree, Interfaces::MathOperators, MathExpressionOperators::AddOperator());
  199. auto result = GetExpressionEvaluationRequests()->Evaluate(tree);
  200. ConfirmResult<double>(result, 3.0+1.0);
  201. }
  202. }
  203. TEST_F(ExpressionEngineTestFixture, ExpressionEngine_MathTest_ComplexTreeEvaluation)
  204. {
  205. {
  206. ExpressionTree tree;
  207. PushPrimitive(tree, 2.0);
  208. PushPrimitive(tree, 2.0);
  209. PushOperator(tree, Interfaces::MathOperators, MathExpressionOperators::AddOperator());
  210. PushPrimitive(tree, 4.0);
  211. PushPrimitive(tree, 3.0);
  212. PushOperator(tree, Interfaces::MathOperators, MathExpressionOperators::SubtractOperator());
  213. PushOperator(tree, Interfaces::MathOperators, MathExpressionOperators::MultiplyOperator());
  214. PushPrimitive(tree, 2.0);
  215. PushOperator(tree, Interfaces::MathOperators, MathExpressionOperators::DivideOperator());
  216. auto result = GetExpressionEvaluationRequests()->Evaluate(tree);
  217. ConfirmResult<double>(result, ((2.0 + 2.0)*(4.0 - 3.0)) / 2.0);
  218. }
  219. }
  220. TEST_F(ExpressionEngineTestFixture, ExpressionEngine_MathTest_BasicParserPass)
  221. {
  222. AZ::Outcome<ExpressionTree, ParsingError> treeOutcome = GetExpressionEvaluationRequests()->ParseExpression("3+1");
  223. EXPECT_TRUE(treeOutcome.IsSuccess());
  224. const ExpressionTree& tree = treeOutcome.GetValue();
  225. EXPECT_EQ(tree.GetTreeSize(), 3);
  226. auto result = GetExpressionEvaluationRequests()->Evaluate(tree);
  227. ConfirmResult<double>(result, 3+1);
  228. }
  229. TEST_F(ExpressionEngineTestFixture, ExpressionEngine_MathTest_BasicParserPassMultiOperator)
  230. {
  231. AZ::Outcome<ExpressionTree, ParsingError> treeOutcome = GetExpressionEvaluationRequests()->ParseExpression("3+1*5");
  232. EXPECT_TRUE(treeOutcome.IsSuccess());
  233. const ExpressionTree& tree = treeOutcome.GetValue();
  234. // 3 Values + 2 Operators
  235. EXPECT_EQ(tree.GetTreeSize(), 3 + 2);
  236. auto result = GetExpressionEvaluationRequests()->Evaluate(tree);
  237. ConfirmResult<double>(result, 3 + 1 * 5);
  238. }
  239. TEST_F(ExpressionEngineTestFixture, ExpressionEngine_NumericParser_ComplexParserPass)
  240. {
  241. AZ::Outcome<ExpressionTree, ParsingError> treeOutcome = GetExpressionEvaluationRequests()->ParseExpression("(3 + 1)");
  242. EXPECT_TRUE(treeOutcome.IsSuccess());
  243. const ExpressionTree& tree = treeOutcome.GetValue();
  244. EXPECT_EQ(tree.GetTreeSize(), 3);
  245. auto result = GetExpressionEvaluationRequests()->Evaluate(tree);
  246. ConfirmResult<double>(result, (3.0 + 1.0));
  247. }
  248. TEST_F(ExpressionEngineTestFixture, ExpressionEngine_NumericParser_ComplexParserPassMultiOperator)
  249. {
  250. AZ::Outcome<ExpressionTree, ParsingError> treeOutcome = GetExpressionEvaluationRequests()->ParseExpression("((2.0 + 2.0)*(4.0 - 3.0)) / 2.0");
  251. EXPECT_TRUE(treeOutcome.IsSuccess());
  252. const ExpressionTree& tree = treeOutcome.GetValue();
  253. // 5 values + 4 operators
  254. EXPECT_EQ(tree.GetTreeSize(), 5 + 4);
  255. auto result = GetExpressionEvaluationRequests()->Evaluate(tree);
  256. ConfirmResult<double>(result, ((2.0 + 2.0)*(4.0 - 3.0)) / 2.0);
  257. }
  258. TEST_F(ExpressionEngineTestFixture, ExpressionEngine_NumericParser_ObtuseParserPassMultiOperator)
  259. {
  260. AZ::Outcome<ExpressionTree, ParsingError> treeOutcome = GetExpressionEvaluationRequests()->ParseExpression("(( (( ) )( 2.0) + 2.0)*(4.0 - 3.0)) / (((2.0 )))");
  261. EXPECT_TRUE(treeOutcome.IsSuccess());
  262. const ExpressionTree& tree = treeOutcome.GetValue();
  263. // 5 values + 4 operators
  264. EXPECT_EQ(tree.GetTreeSize(), 5 + 4);
  265. auto result = GetExpressionEvaluationRequests()->Evaluate(tree);
  266. ConfirmResult<double>(result, ((2.0 + 2.0)*(4.0 - 3.0)) / 2.0);
  267. }
  268. TEST_F(ExpressionEngineTestFixture, ExpressionEngine_NumericParser_AdvancedParserPass)
  269. {
  270. AZ::Outcome<ExpressionTree, ParsingError> treeOutcome = GetExpressionEvaluationRequests()->ParseExpression("(3 + 1) % 2");
  271. EXPECT_TRUE(treeOutcome.IsSuccess());
  272. const ExpressionTree& tree = treeOutcome.GetValue();
  273. EXPECT_EQ(tree.GetTreeSize(), 3 + 2);
  274. auto result = GetExpressionEvaluationRequests()->Evaluate(tree);
  275. ConfirmResult<double>(result, (3+1)%2);
  276. }
  277. TEST_F(ExpressionEngineTestFixture, ExpressionEngine_NumericParser_BasicVariablePass)
  278. {
  279. AZ::Outcome<ExpressionTree, ParsingError> treeOutcome = GetExpressionEvaluationRequests()->ParseExpression("{A}+{B}");
  280. EXPECT_TRUE(treeOutcome.IsSuccess());
  281. ExpressionTree& tree = treeOutcome.GetValue();
  282. EXPECT_EQ(tree.GetTreeSize(), 2 + 1);
  283. auto variables = tree.GetVariables();
  284. EXPECT_EQ(static_cast<int>(variables.size()), 2);
  285. {
  286. AZStd::string variable = variables[0];
  287. EXPECT_EQ(variable, AZStd::string("A"));
  288. tree.SetVariable(variable, 3.0);
  289. }
  290. {
  291. AZStd::string variable = variables[1];
  292. EXPECT_EQ(variable, AZStd::string("B"));
  293. tree.SetVariable(variable, 1.0);
  294. }
  295. auto result = GetExpressionEvaluationRequests()->Evaluate(tree);
  296. ConfirmResult<double>(result, 3.0+1.0);
  297. }
  298. TEST_F(ExpressionEngineTestFixture, ExpressionEngine_NumericParser_BasicRepeatedVariablePass)
  299. {
  300. AZ::Outcome<ExpressionTree, ParsingError> treeOutcome = GetExpressionEvaluationRequests()->ParseExpression("{A}+{B}+{A}");
  301. EXPECT_TRUE(treeOutcome.IsSuccess());
  302. ExpressionTree& tree = treeOutcome.GetValue();
  303. EXPECT_EQ(tree.GetTreeSize(), 3 + 2);
  304. auto variables = tree.GetVariables();
  305. EXPECT_EQ(static_cast<int>(variables.size()), 2);
  306. {
  307. AZStd::string variable = variables[0];
  308. EXPECT_EQ(variable, AZStd::string("A"));
  309. tree.SetVariable(variable, 3.0);
  310. }
  311. {
  312. AZStd::string variable = variables[1];
  313. EXPECT_EQ(variable, AZStd::string("B"));
  314. tree.SetVariable(variable, 1.0);
  315. }
  316. auto result = GetExpressionEvaluationRequests()->Evaluate(tree);
  317. ConfirmResult<double>(result, 3.0 + 1.0 + 3.0);
  318. }
  319. TEST_F(ExpressionEngineTestFixture, ExpressionEngine_NumericParser_BasicFail)
  320. {
  321. AZ::Outcome<ExpressionTree, ParsingError> treeOutcome = GetExpressionEvaluationRequests()->ParseRestrictedExpression(MathOnlyOperatorRestrictions(), "true || false");
  322. EXPECT_FALSE(treeOutcome.IsSuccess());
  323. EXPECT_EQ(treeOutcome.GetError().m_offsetIndex, 0);
  324. }
  325. TEST_F(ExpressionEngineTestFixture, ExpressionEngine_NumericParser_ComplexFail)
  326. {
  327. AZ::Outcome<ExpressionTree, ParsingError> treeOutcome = GetExpressionEvaluationRequests()->ParseRestrictedExpression(MathOnlyOperatorRestrictions(), "2+2 || 1+3");
  328. EXPECT_FALSE(treeOutcome.IsSuccess());
  329. EXPECT_EQ(treeOutcome.GetError().m_offsetIndex, 4);
  330. }
  331. TEST_F(ExpressionEngineTestFixture, ExpressionEngine_ParenParser_UnbalancedCloseFail)
  332. {
  333. AZ::Outcome<ExpressionTree, ParsingError> treeOutcome = GetExpressionEvaluationRequests()->ParseRestrictedExpression(MathOnlyOperatorRestrictions(), "1+1)");
  334. EXPECT_FALSE(treeOutcome.IsSuccess());
  335. EXPECT_EQ(treeOutcome.GetError().m_offsetIndex, 3);
  336. }
  337. TEST_F(ExpressionEngineTestFixture, ExpressionEngine_ParenParser_UnbalancedOpenFail)
  338. {
  339. AZ::Outcome<ExpressionTree, ParsingError> treeOutcome = GetExpressionEvaluationRequests()->ParseRestrictedExpression(MathOnlyOperatorRestrictions(), "(1+1");
  340. EXPECT_FALSE(treeOutcome.IsSuccess());
  341. EXPECT_EQ(treeOutcome.GetError().m_offsetIndex, 0);
  342. }
  343. }