From ef148fef573d5ed7d0f1bee660bba9b65f1f6aee Mon Sep 17 00:00:00 2001
From: Stephane Del Pino <stephane.delpino44@gmail.com>
Date: Tue, 29 Oct 2019 18:39:49 +0100
Subject: [PATCH] Add tests for ASTNodeFunctionExpressionBuilder

These tests are somehow only sanity checks (just checking that the code is able
to build the expressions). Testing the results will be performed by
FunctionProcessor dedicated tests.
---
 .../ASTNodeFunctionExpressionBuilder.cpp      |  10 +
 tests/CMakeLists.txt                          |   1 +
 .../test_ASTNodeFunctionExpressionBuilder.cpp | 293 ++++++++++++++++++
 3 files changed, 304 insertions(+)
 create mode 100644 tests/test_ASTNodeFunctionExpressionBuilder.cpp

diff --git a/src/language/ASTNodeFunctionExpressionBuilder.cpp b/src/language/ASTNodeFunctionExpressionBuilder.cpp
index 11183dbad..4a7e09528 100644
--- a/src/language/ASTNodeFunctionExpressionBuilder.cpp
+++ b/src/language/ASTNodeFunctionExpressionBuilder.cpp
@@ -26,9 +26,11 @@ ASTNodeFunctionExpressionBuilder::_getArgumentProcessor(ASTNode& argument_node,
     case ASTNodeDataType::double_t: {
       return std::make_unique<FunctionArgumentProcessor<ArgumentT, double>>(argument_node, parameter_symbol);
     }
+      // LCOV_EXCL_START
     default: {
       throw parse_error("unexpected error: undefined parameter type for function", std::vector{argument_node.begin()});
     }
+      // LCOV_EXCL_STOP
     }
   };
 
@@ -46,9 +48,11 @@ ASTNodeFunctionExpressionBuilder::_getArgumentProcessor(ASTNode& argument_node,
     case ASTNodeDataType::double_t: {
       return get_function_argument_processor_for_parameter_type(double{});
     }
+      // LCOV_EXCL_START
     default: {
       throw parse_error("unexpected error: undefined argument type for function", std::vector{argument_node.begin()});
     }
+      // LCOV_EXCL_STOP
     }
   };
 
@@ -125,10 +129,12 @@ ASTNodeFunctionExpressionBuilder::_getFunctionProcessor(const ASTNodeDataType ex
     case ASTNodeDataType::double_t: {
       return std::make_unique<FunctionExpressionProcessor<ReturnT, double>>(node);
     }
+      // LCOV_EXCL_START
     default: {
       throw parse_error("unexpected error: undefined expression value type for function",
                         std::vector{node.children[1]->begin()});
     }
+      // LCOV_EXCL_STOP
     }
   };
 
@@ -146,9 +152,11 @@ ASTNodeFunctionExpressionBuilder::_getFunctionProcessor(const ASTNodeDataType ex
     case ASTNodeDataType::double_t: {
       return get_function_processor_for_expression_value(double{});
     }
+      // LCOV_EXCL_START
     default: {
       throw parse_error("unexpected error: undefined return type for function", std::vector{node.begin()});
     }
+      // LCOV_EXCL_STOP
     }
   };
 
@@ -166,8 +174,10 @@ ASTNodeFunctionExpressionBuilder::ASTNodeFunctionExpressionBuilder(ASTNode& node
   FunctionDescriptor& function_descriptor = node.m_symbol_table->functionTable()[function_id];
 
   if (function_descriptor.definitionNode().children[1]->is_type<language::expression_list>()) {
+    // LCOV_EXCL_START
     throw parse_error("unexpected error: function expression list is not implemented yet",
                       std::vector{function_descriptor.definitionNode().children[1]->begin()});
+    // LCOV_EXCL_STOP
   }
 
   std::unique_ptr function_processor = std::make_unique<FunctionProcessor>();
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 084dd96ee..952e599ed 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -20,6 +20,7 @@ add_executable (unit_tests
   test_ASTNodeEmptyBlockCleaner.cpp
   test_ASTNodeExpressionBuilder.cpp
   test_ASTNodeFunctionEvaluationExpressionBuilder.cpp
+  test_ASTNodeFunctionExpressionBuilder.cpp
   test_ASTNodeIncDecExpressionBuilder.cpp
   test_ASTNodeJumpPlacementChecker.cpp
   test_ASTNodeListProcessor.cpp
diff --git a/tests/test_ASTNodeFunctionExpressionBuilder.cpp b/tests/test_ASTNodeFunctionExpressionBuilder.cpp
new file mode 100644
index 000000000..3512e2133
--- /dev/null
+++ b/tests/test_ASTNodeFunctionExpressionBuilder.cpp
@@ -0,0 +1,293 @@
+#include <catch2/catch.hpp>
+
+#include <ASTNodeValueBuilder.hpp>
+
+#include <ASTBuilder.hpp>
+#include <ASTNodeDataTypeBuilder.hpp>
+
+#include <ASTModulesImporter.hpp>
+
+#include <ASTNodeExpressionBuilder.hpp>
+#include <ASTNodeFunctionEvaluationExpressionBuilder.hpp>
+#include <ASTNodeFunctionExpressionBuilder.hpp>
+#include <ASTNodeTypeCleaner.hpp>
+
+#include <ASTSymbolTableBuilder.hpp>
+
+#include <ASTPrinter.hpp>
+
+#include <PEGGrammar.hpp>
+
+#include <Demangle.hpp>
+
+#define CHECK_AST(data, expected_output)                                                            \
+  {                                                                                                 \
+    static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>);                  \
+    static_assert((std::is_same_v<std::decay_t<decltype(expected_output)>, std::string_view>) or    \
+                  (std::is_same_v<std::decay_t<decltype(expected_output)>, std::string>));          \
+                                                                                                    \
+    string_input input{data, "test.pgs"};                                                           \
+    auto ast = ASTBuilder::build(input);                                                            \
+                                                                                                    \
+    ASTModulesImporter{*ast};                                                                       \
+    ASTNodeTypeCleaner<language::import_instruction>{*ast};                                         \
+                                                                                                    \
+    ASTSymbolTableBuilder{*ast};                                                                    \
+    ASTNodeDataTypeBuilder{*ast};                                                                   \
+    ASTNodeValueBuilder{*ast};                                                                      \
+                                                                                                    \
+    ASTNodeTypeCleaner<language::declaration>{*ast};                                                \
+    ASTNodeTypeCleaner<language::let_declaration>{*ast};                                            \
+    ASTNodeExpressionBuilder{*ast};                                                                 \
+                                                                                                    \
+    std::stringstream ast_output;                                                                   \
+    ast_output << '\n' << ASTPrinter{*ast, ASTPrinter::Format::raw, {ASTPrinter::Info::exec_type}}; \
+                                                                                                    \
+    REQUIRE(ast_output.str() == expected_output);                                                   \
+  }
+
+#define CHECK_AST_THROWS(data)                                                     \
+  {                                                                                \
+    static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \
+                                                                                   \
+    string_input input{data, "test.pgs"};                                          \
+    auto ast = ASTBuilder::build(input);                                           \
+                                                                                   \
+    ASTModulesImporter{*ast};                                                      \
+    ASTNodeTypeCleaner<language::import_instruction>{*ast};                        \
+                                                                                   \
+    ASTSymbolTableBuilder{*ast};                                                   \
+    ASTNodeDataTypeBuilder{*ast};                                                  \
+    ASTNodeValueBuilder{*ast};                                                     \
+                                                                                   \
+    ASTNodeTypeCleaner<language::declaration>{*ast};                               \
+    ASTNodeTypeCleaner<language::let_declaration>{*ast};                           \
+    REQUIRE_THROWS_AS(ASTNodeExpressionBuilder{*ast}, parse_error);                \
+  }
+
+TEST_CASE("ASTNodeFunctionExpressionBuilder", "[language]")
+{
+  SECTION("return a B")
+  {
+    SECTION("B argument")
+    {
+      SECTION("B parameter")
+      {
+        std::string_view data = R"(
+let not_v : B -> B, a -> not a;
+not_v(true);
+)";
+
+        std::string_view result = R"(
+(root:ASTNodeListProcessor)
+ `-(language::function_evaluation:FunctionProcessor)
+     +-(language::name:not_v:NameProcessor)
+     `-(language::true_kw:FakeProcessor)
+)";
+
+        CHECK_AST(data, result);
+      }
+
+      SECTION("N parameter")
+      {
+        std::string_view data = R"(
+let not_v : B -> B, a -> not a;
+N n = 1;
+not_v(n);
+)";
+
+        std::string_view result = R"(
+(root:ASTNodeListProcessor)
+ `-(language::function_evaluation:FunctionProcessor)
+     +-(language::name:not_v:NameProcessor)
+     `-(language::name:n:NameProcessor)
+)";
+
+        CHECK_AST(data, result);
+      }
+
+      SECTION("Z parameter")
+      {
+        std::string_view data = R"(
+let not_v : B -> B, a -> not a;
+not_v(-1);
+)";
+
+        std::string_view result = R"(
+(root:ASTNodeListProcessor)
+ `-(language::function_evaluation:FunctionProcessor)
+     +-(language::name:not_v:NameProcessor)
+     `-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, long, long>)
+         `-(language::integer:1:FakeProcessor)
+)";
+
+        CHECK_AST(data, result);
+      }
+
+      SECTION("R parameter")
+      {
+        std::string_view data = R"(
+let not_v : B -> B, a -> not a;
+not_v(1.3);
+)";
+
+        std::string_view result = R"(
+(root:ASTNodeListProcessor)
+ `-(language::function_evaluation:FunctionProcessor)
+     +-(language::name:not_v:NameProcessor)
+     `-(language::real:1.3:FakeProcessor)
+)";
+
+        CHECK_AST(data, result);
+      }
+    }
+
+    SECTION("N argument")
+    {
+      std::string_view data = R"(
+let test : N -> B, n -> n<10;
+test(2);
+)";
+
+      std::string_view result = R"(
+(root:ASTNodeListProcessor)
+ `-(language::function_evaluation:FunctionProcessor)
+     +-(language::name:test:NameProcessor)
+     `-(language::integer:2:FakeProcessor)
+)";
+
+      CHECK_AST(data, result);
+    }
+
+    SECTION("Z argument")
+    {
+      std::string_view data = R"(
+let test : Z -> B, z -> z>3;
+test(2);
+)";
+
+      std::string_view result = R"(
+(root:ASTNodeListProcessor)
+ `-(language::function_evaluation:FunctionProcessor)
+     +-(language::name:test:NameProcessor)
+     `-(language::integer:2:FakeProcessor)
+)";
+
+      CHECK_AST(data, result);
+    }
+
+    SECTION("R argument")
+    {
+      std::string_view data = R"(
+let test : R -> B, x -> x>2.3;
+test(2.1);
+)";
+
+      std::string_view result = R"(
+(root:ASTNodeListProcessor)
+ `-(language::function_evaluation:FunctionProcessor)
+     +-(language::name:test:NameProcessor)
+     `-(language::real:2.1:FakeProcessor)
+)";
+
+      CHECK_AST(data, result);
+    }
+  }
+
+  SECTION("return a N")
+  {
+    SECTION("N argument")
+    {
+      std::string_view data = R"(
+let test : N -> N, n -> n+2;
+test(2.1);
+)";
+
+      std::string_view result = R"(
+(root:ASTNodeListProcessor)
+ `-(language::function_evaluation:FunctionProcessor)
+     +-(language::name:test:NameProcessor)
+     `-(language::real:2.1:FakeProcessor)
+)";
+
+      CHECK_AST(data, result);
+    }
+
+    SECTION("Z argument")
+    {
+      std::string_view data = R"(
+let absolute : Z -> N, z -> (z>0)*z -(z<=0)*z;
+absolute(-2);
+)";
+
+      std::string_view result = R"(
+(root:ASTNodeListProcessor)
+ `-(language::function_evaluation:FunctionProcessor)
+     +-(language::name:absolute:NameProcessor)
+     `-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, long, long>)
+         `-(language::integer:2:FakeProcessor)
+)";
+
+      CHECK_AST(data, result);
+    }
+  }
+
+  SECTION("return a Z")
+  {
+    SECTION("N argument")
+    {
+      std::string_view data = R"(
+let minus : N -> Z, n -> -n;
+minus(true);
+)";
+
+      std::string_view result = R"(
+(root:ASTNodeListProcessor)
+ `-(language::function_evaluation:FunctionProcessor)
+     +-(language::name:minus:NameProcessor)
+     `-(language::true_kw:FakeProcessor)
+)";
+
+      CHECK_AST(data, result);
+    }
+
+    SECTION("Z argument")
+    {
+      std::string_view data = R"(
+let times_2_3 : Z -> Z, z -> z*2.3;
+times_2_3(-2);
+)";
+
+      std::string_view result = R"(
+(root:ASTNodeListProcessor)
+ `-(language::function_evaluation:FunctionProcessor)
+     +-(language::name:times_2_3:NameProcessor)
+     `-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, long, long>)
+         `-(language::integer:2:FakeProcessor)
+)";
+
+      CHECK_AST(data, result);
+    }
+  }
+
+  SECTION("errors")
+  {
+    SECTION("wrong argument number")
+    {
+      std::string_view data = R"(
+let Id : Z -> Z, z -> z;
+Id(2,3);
+)";
+      CHECK_AST_THROWS(data);
+    }
+
+    SECTION("wrong argument number 2")
+    {
+      std::string_view data = R"(
+let sum : R*R -> R, (x,y) -> x+y;
+sum(2);
+)";
+      CHECK_AST_THROWS(data);
+    }
+  }
+}
-- 
GitLab