From 48a71eadcd7de6f3891156ef7f35f24319d3f506 Mon Sep 17 00:00:00 2001
From: Stephane Del Pino <stephane.delpino44@gmail.com>
Date: Mon, 8 Jun 2020 22:05:47 +0200
Subject: [PATCH] Add lots of tests for ASTNodeNaturalConversionChecker

---
 .../test_ASTNodeNaturalConversionChecker.cpp  | 612 ++++++++++++++++++
 1 file changed, 612 insertions(+)

diff --git a/tests/test_ASTNodeNaturalConversionChecker.cpp b/tests/test_ASTNodeNaturalConversionChecker.cpp
index 373a05909..f37a58b41 100644
--- a/tests/test_ASTNodeNaturalConversionChecker.cpp
+++ b/tests/test_ASTNodeNaturalConversionChecker.cpp
@@ -53,6 +53,18 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
         data_node->m_data_type = ASTNodeDataType::bool_t;
         REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::string_t});
       }
+
+      SECTION("list -> string")
+      {
+        data_node->m_data_type = ASTNodeDataType::list_t;
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::string_t});
+      }
+
+      SECTION("tuple -> string")
+      {
+        data_node->m_data_type = ASTNodeDataType::tuple_t;
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::string_t});
+      }
     }
 
     SECTION("-> R^d")
@@ -221,6 +233,303 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
         REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::bool_t});
       }
     }
+
+    SECTION("-> tuple")
+    {
+      SECTION("B -> tuple(B)")
+      {
+        data_node->m_data_type = ASTNodeDataType::bool_t;
+        REQUIRE_NOTHROW(
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
+                                                                      ASTNodeDataType{ASTNodeDataType::bool_t}}});
+      }
+
+      SECTION("B -> tuple(N)")
+      {
+        data_node->m_data_type = ASTNodeDataType::bool_t;
+        REQUIRE_NOTHROW(
+          ASTNodeNaturalConversionChecker{*data_node,
+                                          ASTNodeDataType{ASTNodeDataType::tuple_t,
+                                                          ASTNodeDataType{ASTNodeDataType::unsigned_int_t}}});
+      }
+
+      SECTION("N -> tuple(N)")
+      {
+        data_node->m_data_type = ASTNodeDataType::unsigned_int_t;
+        REQUIRE_NOTHROW(
+          ASTNodeNaturalConversionChecker{*data_node,
+                                          ASTNodeDataType{ASTNodeDataType::tuple_t,
+                                                          ASTNodeDataType{ASTNodeDataType::unsigned_int_t}}});
+      }
+
+      SECTION("Z -> tuple(N)")
+      {
+        data_node->m_data_type = ASTNodeDataType::int_t;
+        REQUIRE_NOTHROW(
+          ASTNodeNaturalConversionChecker{*data_node,
+                                          ASTNodeDataType{ASTNodeDataType::tuple_t,
+                                                          ASTNodeDataType{ASTNodeDataType::unsigned_int_t}}});
+      }
+
+      SECTION("B -> tuple(Z)")
+      {
+        data_node->m_data_type = ASTNodeDataType::bool_t;
+        REQUIRE_NOTHROW(
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
+                                                                      ASTNodeDataType{ASTNodeDataType::int_t}}});
+      }
+
+      SECTION("N -> tuple(Z)")
+      {
+        data_node->m_data_type = ASTNodeDataType::unsigned_int_t;
+        REQUIRE_NOTHROW(
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
+                                                                      ASTNodeDataType{ASTNodeDataType::int_t}}});
+      }
+
+      SECTION("Z -> tuple(Z)")
+      {
+        data_node->m_data_type = ASTNodeDataType::int_t;
+        REQUIRE_NOTHROW(
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
+                                                                      ASTNodeDataType{ASTNodeDataType::int_t}}});
+      }
+
+      SECTION("B -> tuple(R)")
+      {
+        data_node->m_data_type = ASTNodeDataType::bool_t;
+        REQUIRE_NOTHROW(
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
+                                                                      ASTNodeDataType{ASTNodeDataType::double_t}}});
+      }
+
+      SECTION("N -> tuple(R)")
+      {
+        data_node->m_data_type = ASTNodeDataType::unsigned_int_t;
+        REQUIRE_NOTHROW(
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
+                                                                      ASTNodeDataType{ASTNodeDataType::double_t}}});
+      }
+
+      SECTION("Z -> tuple(R)")
+      {
+        data_node->m_data_type = ASTNodeDataType::int_t;
+        REQUIRE_NOTHROW(
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
+                                                                      ASTNodeDataType{ASTNodeDataType::double_t}}});
+      }
+
+      SECTION("R -> tuple(R)")
+      {
+        data_node->m_data_type = ASTNodeDataType::double_t;
+        REQUIRE_NOTHROW(
+          ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
+                                                                      ASTNodeDataType{ASTNodeDataType::double_t}}});
+      }
+
+      SECTION("R^1 -> tuple(R^1)")
+      {
+        auto R1                = ASTNodeDataType{ASTNodeDataType::vector_t, 1};
+        data_node->m_data_type = R1;
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, R1}});
+      }
+
+      SECTION("R^2 -> tuple(R^2)")
+      {
+        auto R2                = ASTNodeDataType{ASTNodeDataType::vector_t, 2};
+        data_node->m_data_type = R2;
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, R2}});
+      }
+
+      SECTION("R^3 -> tuple(R^3)")
+      {
+        auto R3                = ASTNodeDataType{ASTNodeDataType::vector_t, 2};
+        data_node->m_data_type = R3;
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t, R3}});
+      }
+
+      SECTION("string -> tuple(string)")
+      {
+        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::string_t};
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::string_t}});
+      }
+
+      SECTION("type_id_t -> tuple(type_id_t)")
+      {
+        auto type_id           = ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"};
+        data_node->m_data_type = type_id;
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, type_id});
+      }
+
+      SECTION("(B, B, B) -> tuple(B)")
+      {
+        data_node->m_data_type = ASTNodeDataType::list_t;
+        {
+          std::unique_ptr list0_node = std::make_unique<ASTNode>();
+          list0_node->m_data_type    = ASTNodeDataType::bool_t;
+          data_node->emplace_back(std::move(list0_node));
+
+          std::unique_ptr list1_node = std::make_unique<ASTNode>();
+          list1_node->m_data_type    = ASTNodeDataType::bool_t;
+          data_node->emplace_back(std::move(list1_node));
+
+          std::unique_ptr list2_node = std::make_unique<ASTNode>();
+          list2_node->m_data_type    = ASTNodeDataType::bool_t;
+          data_node->emplace_back(std::move(list2_node));
+        }
+        auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::bool_t}};
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
+      }
+
+      SECTION("(B, N, Z) -> tuple(N)")
+      {
+        data_node->m_data_type = ASTNodeDataType::list_t;
+        {
+          std::unique_ptr list0_node = std::make_unique<ASTNode>();
+          list0_node->m_data_type    = ASTNodeDataType::bool_t;
+          data_node->emplace_back(std::move(list0_node));
+
+          std::unique_ptr list1_node = std::make_unique<ASTNode>();
+          list1_node->m_data_type    = ASTNodeDataType::unsigned_int_t;
+          data_node->emplace_back(std::move(list1_node));
+
+          std::unique_ptr list2_node = std::make_unique<ASTNode>();
+          list2_node->m_data_type    = ASTNodeDataType::int_t;
+          data_node->emplace_back(std::move(list2_node));
+        }
+        auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}};
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
+      }
+
+      SECTION("(B, N, Z) -> tuple(Z)")
+      {
+        data_node->m_data_type = ASTNodeDataType::list_t;
+        {
+          std::unique_ptr list0_node = std::make_unique<ASTNode>();
+          list0_node->m_data_type    = ASTNodeDataType::bool_t;
+          data_node->emplace_back(std::move(list0_node));
+
+          std::unique_ptr list1_node = std::make_unique<ASTNode>();
+          list1_node->m_data_type    = ASTNodeDataType::unsigned_int_t;
+          data_node->emplace_back(std::move(list1_node));
+
+          std::unique_ptr list2_node = std::make_unique<ASTNode>();
+          list2_node->m_data_type    = ASTNodeDataType::int_t;
+          data_node->emplace_back(std::move(list2_node));
+        }
+        auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}};
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
+      }
+
+      SECTION("(R, N, Z) -> tuple(R)")
+      {
+        data_node->m_data_type = ASTNodeDataType::list_t;
+        {
+          std::unique_ptr list0_node = std::make_unique<ASTNode>();
+          list0_node->m_data_type    = ASTNodeDataType::double_t;
+          data_node->emplace_back(std::move(list0_node));
+
+          std::unique_ptr list1_node = std::make_unique<ASTNode>();
+          list1_node->m_data_type    = ASTNodeDataType::unsigned_int_t;
+          data_node->emplace_back(std::move(list1_node));
+
+          std::unique_ptr list2_node = std::make_unique<ASTNode>();
+          list2_node->m_data_type    = ASTNodeDataType::int_t;
+          data_node->emplace_back(std::move(list2_node));
+        }
+        auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}};
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
+      }
+
+      SECTION("(R^1, R^1) -> tuple(R^1)")
+      {
+        auto R1                = ASTNodeDataType{ASTNodeDataType::vector_t, 1};
+        data_node->m_data_type = ASTNodeDataType::list_t;
+        {
+          std::unique_ptr list0_node = std::make_unique<ASTNode>();
+          list0_node->m_data_type    = R1;
+          data_node->emplace_back(std::move(list0_node));
+
+          std::unique_ptr list1_node = std::make_unique<ASTNode>();
+          list1_node->m_data_type    = R1;
+          data_node->emplace_back(std::move(list1_node));
+        }
+        auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, R1};
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
+      }
+
+      SECTION("(R^2, R^2, R^2) -> tuple(R^2)")
+      {
+        auto R2                = ASTNodeDataType{ASTNodeDataType::vector_t, 2};
+        data_node->m_data_type = ASTNodeDataType::list_t;
+        {
+          std::unique_ptr list0_node = std::make_unique<ASTNode>();
+          list0_node->m_data_type    = R2;
+          data_node->emplace_back(std::move(list0_node));
+
+          std::unique_ptr list1_node = std::make_unique<ASTNode>();
+          list1_node->m_data_type    = R2;
+          data_node->emplace_back(std::move(list1_node));
+
+          std::unique_ptr list2_node = std::make_unique<ASTNode>();
+          list2_node->m_data_type    = R2;
+          data_node->emplace_back(std::move(list2_node));
+        }
+        auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, R2};
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
+      }
+
+      SECTION("(R^3, R^3) -> tuple(R^3)")
+      {
+        auto R3                = ASTNodeDataType{ASTNodeDataType::vector_t, 2};
+        data_node->m_data_type = ASTNodeDataType::list_t;
+        {
+          std::unique_ptr list0_node = std::make_unique<ASTNode>();
+          list0_node->m_data_type    = R3;
+          data_node->emplace_back(std::move(list0_node));
+
+          std::unique_ptr list1_node = std::make_unique<ASTNode>();
+          list1_node->m_data_type    = R3;
+          data_node->emplace_back(std::move(list1_node));
+        }
+        auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, R3};
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
+      }
+
+      SECTION("(string, string) -> tuple(string)")
+      {
+        auto str_t             = ASTNodeDataType{ASTNodeDataType::string_t};
+        data_node->m_data_type = ASTNodeDataType::list_t;
+        {
+          std::unique_ptr list0_node = std::make_unique<ASTNode>();
+          list0_node->m_data_type    = str_t;
+          data_node->emplace_back(std::move(list0_node));
+
+          std::unique_ptr list1_node = std::make_unique<ASTNode>();
+          list1_node->m_data_type    = str_t;
+          data_node->emplace_back(std::move(list1_node));
+        }
+        auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, str_t};
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
+      }
+
+      SECTION("(type_id_t, type_id_t)-> tuple(type_id_t)")
+      {
+        auto type_id           = ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"};
+        data_node->m_data_type = ASTNodeDataType::list_t;
+        {
+          std::unique_ptr list0_node = std::make_unique<ASTNode>();
+          list0_node->m_data_type    = type_id;
+          data_node->emplace_back(std::move(list0_node));
+
+          std::unique_ptr list1_node = std::make_unique<ASTNode>();
+          list1_node->m_data_type    = type_id;
+          data_node->emplace_back(std::move(list1_node));
+        }
+        auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, type_id};
+        REQUIRE_NOTHROW(ASTNodeNaturalConversionChecker{*data_node, tuple_t});
+      }
+    }
   }
 
   SECTION("Invalid conversions")
@@ -361,6 +670,61 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
         }
       }
 
+      SECTION("tuple -> R^d")
+      {
+        SECTION("tuple(N) -> R^1")
+        {
+          data_node->m_data_type =
+            ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}};
+          REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
+                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 1}}),
+                              "invalid implicit conversion: tuple(N) -> R^1");
+        }
+
+        SECTION("tuple(R) -> R^1")
+        {
+          data_node->m_data_type =
+            ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}};
+          REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
+                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 1}}),
+                              "invalid implicit conversion: tuple(R) -> R^1");
+        }
+
+        SECTION("tuple(R) -> R^2")
+        {
+          data_node->m_data_type =
+            ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}};
+          REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
+                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 2}}),
+                              "invalid implicit conversion: tuple(R) -> R^2");
+        }
+
+        SECTION("tuple(B) -> R^2")
+        {
+          data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::bool_t}};
+          REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
+                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 2}}),
+                              "invalid implicit conversion: tuple(B) -> R^2");
+        }
+
+        SECTION("tuple(Z) -> R^3")
+        {
+          data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}};
+          REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
+                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 3}}),
+                              "invalid implicit conversion: tuple(Z) -> R^3");
+        }
+
+        SECTION("tuple(R) -> R^3")
+        {
+          data_node->m_data_type =
+            ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}};
+          REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
+                                                               ASTNodeDataType{ASTNodeDataType::vector_t, 3}}),
+                              "invalid implicit conversion: tuple(R) -> R^3");
+        }
+      }
+
       SECTION("R -> R^d")
       {
         data_node->m_data_type = ASTNodeDataType::double_t;
@@ -526,6 +890,21 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
         REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::double_t}),
                             "invalid implicit conversion: R^3 -> R");
       }
+
+      SECTION("tuple(N) -> R")
+      {
+        data_node->m_data_type =
+          ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}};
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::double_t}),
+                            "invalid implicit conversion: tuple(N) -> R");
+      }
+
+      SECTION("tuple(R) -> R")
+      {
+        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::double_t}};
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::double_t}),
+                            "invalid implicit conversion: tuple(R) -> R");
+      }
     }
 
     SECTION("-> Z")
@@ -564,6 +943,21 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
         REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::int_t}),
                             "invalid implicit conversion: R -> Z");
       }
+
+      SECTION("tuple(N) -> Z")
+      {
+        data_node->m_data_type =
+          ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}};
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::int_t}),
+                            "invalid implicit conversion: tuple(N) -> Z");
+      }
+
+      SECTION("tuple(Z) -> Z")
+      {
+        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}};
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::int_t}),
+                            "invalid implicit conversion: tuple(Z) -> Z");
+      }
     }
 
     SECTION("-> N")
@@ -602,6 +996,21 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
         REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::unsigned_int_t}),
                             "invalid implicit conversion: R -> N");
       }
+
+      SECTION("tuple(Z) -> N")
+      {
+        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}};
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::unsigned_int_t}),
+                            "invalid implicit conversion: tuple(Z) -> N");
+      }
+
+      SECTION("tuple(N) -> N")
+      {
+        data_node->m_data_type =
+          ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}};
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::unsigned_int_t}),
+                            "invalid implicit conversion: tuple(N) -> N");
+      }
     }
 
     SECTION("-> B")
@@ -647,12 +1056,215 @@ TEST_CASE("ASTNodeNaturalConversionChecker", "[language]")
         REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::bool_t}),
                             "invalid implicit conversion: Z -> B");
       }
+
       SECTION("N -> B")
       {
         data_node->m_data_type = ASTNodeDataType::unsigned_int_t;
         REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::bool_t}),
                             "invalid implicit conversion: N -> B");
       }
+
+      SECTION("tuple(Z) -> B")
+      {
+        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}};
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::bool_t}),
+                            "invalid implicit conversion: tuple(Z) -> B");
+      }
+
+      SECTION("tuple(B) -> B")
+      {
+        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::bool_t}};
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType::bool_t}),
+                            "invalid implicit conversion: tuple(B) -> B");
+      }
+    }
+
+    SECTION("-> tuple")
+    {
+      SECTION("N -> tuple(B)")
+      {
+        data_node->m_data_type = ASTNodeDataType::unsigned_int_t;
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
+                                                                                         ASTNodeDataType{
+                                                                                           ASTNodeDataType::bool_t}}}),
+                            "invalid implicit conversion: N -> tuple(B)");
+      }
+
+      SECTION("Z -> tuple(B)")
+      {
+        data_node->m_data_type = ASTNodeDataType::int_t;
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
+                                                                                         ASTNodeDataType{
+                                                                                           ASTNodeDataType::bool_t}}}),
+                            "invalid implicit conversion: Z -> tuple(B)");
+      }
+
+      SECTION("R -> tuple(B)")
+      {
+        data_node->m_data_type = ASTNodeDataType::double_t;
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
+                                                                                         ASTNodeDataType{
+                                                                                           ASTNodeDataType::bool_t}}}),
+                            "invalid implicit conversion: R -> tuple(B)");
+      }
+
+      SECTION("string -> tuple(B)")
+      {
+        data_node->m_data_type = ASTNodeDataType::string_t;
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
+                                                                                         ASTNodeDataType{
+                                                                                           ASTNodeDataType::bool_t}}}),
+                            "invalid implicit conversion: string -> tuple(B)");
+      }
+
+      SECTION("R^1 -> tuple(B)")
+      {
+        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 1};
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
+                                                                                         ASTNodeDataType{
+                                                                                           ASTNodeDataType::bool_t}}}),
+                            "invalid implicit conversion: R^1 -> tuple(B)");
+      }
+
+      SECTION("R^2 -> tuple(B)")
+      {
+        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 2};
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
+                                                                                         ASTNodeDataType{
+                                                                                           ASTNodeDataType::bool_t}}}),
+                            "invalid implicit conversion: R^2 -> tuple(B)");
+      }
+
+      SECTION("R^3 -> tuple(B)")
+      {
+        data_node->m_data_type = ASTNodeDataType{ASTNodeDataType::vector_t, 3};
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, ASTNodeDataType{ASTNodeDataType::tuple_t,
+                                                                                         ASTNodeDataType{
+                                                                                           ASTNodeDataType::bool_t}}}),
+                            "invalid implicit conversion: R^3 -> tuple(B)");
+      }
+
+      SECTION("R -> tuple(N)")
+      {
+        data_node->m_data_type = ASTNodeDataType::double_t;
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
+                                                             ASTNodeDataType{ASTNodeDataType::tuple_t,
+                                                                             ASTNodeDataType{
+                                                                               ASTNodeDataType::unsigned_int_t}}}),
+                            "invalid implicit conversion: R -> tuple(N)");
+      }
+
+      SECTION("R^1 -> tuple(R^2)")
+      {
+        auto R1                = ASTNodeDataType{ASTNodeDataType::vector_t, 1};
+        auto R2                = ASTNodeDataType{ASTNodeDataType::vector_t, 2};
+        data_node->m_data_type = R1;
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
+                                                             ASTNodeDataType{ASTNodeDataType::tuple_t, R2}}),
+                            "invalid implicit conversion: R^1 -> tuple(R^2)");
+      }
+
+      SECTION("R^2 -> tuple(R^3)")
+      {
+        auto R2                = ASTNodeDataType{ASTNodeDataType::vector_t, 2};
+        auto R3                = ASTNodeDataType{ASTNodeDataType::vector_t, 3};
+        data_node->m_data_type = R2;
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
+                                                             ASTNodeDataType{ASTNodeDataType::tuple_t, R3}}),
+                            "invalid implicit conversion: R^2 -> tuple(R^3)");
+      }
+
+      SECTION("R^3 -> tuple(R^2)")
+      {
+        auto R3                = ASTNodeDataType{ASTNodeDataType::vector_t, 3};
+        auto R2                = ASTNodeDataType{ASTNodeDataType::vector_t, 2};
+        data_node->m_data_type = R3;
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node,
+                                                             ASTNodeDataType{ASTNodeDataType::tuple_t, R2}}),
+                            "invalid implicit conversion: R^3 -> tuple(R^2)");
+      }
+
+      SECTION("(B, R, Z) -> tuple(N)")
+      {
+        data_node->m_data_type = ASTNodeDataType::list_t;
+        {
+          std::unique_ptr list0_node = std::make_unique<ASTNode>();
+          list0_node->m_data_type    = ASTNodeDataType::bool_t;
+          data_node->emplace_back(std::move(list0_node));
+
+          std::unique_ptr list1_node = std::make_unique<ASTNode>();
+          list1_node->m_data_type    = ASTNodeDataType::double_t;
+          data_node->emplace_back(std::move(list1_node));
+
+          std::unique_ptr list2_node = std::make_unique<ASTNode>();
+          list2_node->m_data_type    = ASTNodeDataType::int_t;
+          data_node->emplace_back(std::move(list2_node));
+        }
+        auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}};
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, tuple_t}),
+                            "invalid implicit conversion: R -> N");
+      }
+
+      SECTION("(R, N, Z) -> tuple(Z)")
+      {
+        data_node->m_data_type = ASTNodeDataType::list_t;
+        {
+          std::unique_ptr list0_node = std::make_unique<ASTNode>();
+          list0_node->m_data_type    = ASTNodeDataType::double_t;
+          data_node->emplace_back(std::move(list0_node));
+
+          std::unique_ptr list1_node = std::make_unique<ASTNode>();
+          list1_node->m_data_type    = ASTNodeDataType::unsigned_int_t;
+          data_node->emplace_back(std::move(list1_node));
+
+          std::unique_ptr list2_node = std::make_unique<ASTNode>();
+          list2_node->m_data_type    = ASTNodeDataType::int_t;
+          data_node->emplace_back(std::move(list2_node));
+        }
+        auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::int_t}};
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, tuple_t}),
+                            "invalid implicit conversion: R -> Z");
+      }
+
+      SECTION("(B, N, R) -> tuple(N)")
+      {
+        data_node->m_data_type = ASTNodeDataType::list_t;
+        {
+          std::unique_ptr list0_node = std::make_unique<ASTNode>();
+          list0_node->m_data_type    = ASTNodeDataType::bool_t;
+          data_node->emplace_back(std::move(list0_node));
+
+          std::unique_ptr list1_node = std::make_unique<ASTNode>();
+          list1_node->m_data_type    = ASTNodeDataType::unsigned_int_t;
+          data_node->emplace_back(std::move(list1_node));
+
+          std::unique_ptr list2_node = std::make_unique<ASTNode>();
+          list2_node->m_data_type    = ASTNodeDataType::double_t;
+          data_node->emplace_back(std::move(list2_node));
+        }
+        auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, ASTNodeDataType{ASTNodeDataType::unsigned_int_t}};
+        REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, tuple_t}),
+                            "invalid implicit conversion: R -> N");
+      }
+    }
+
+    SECTION("(type_id_t, type_id_t) -> tuple(type_id_t)")
+    {
+      auto type_id1          = ASTNodeDataType{ASTNodeDataType::type_id_t, "foo"};
+      auto type_id2          = ASTNodeDataType{ASTNodeDataType::type_id_t, "bar"};
+      data_node->m_data_type = ASTNodeDataType::list_t;
+      {
+        std::unique_ptr list0_node = std::make_unique<ASTNode>();
+        list0_node->m_data_type    = type_id1;
+        data_node->emplace_back(std::move(list0_node));
+
+        std::unique_ptr list1_node = std::make_unique<ASTNode>();
+        list1_node->m_data_type    = type_id2;
+        data_node->emplace_back(std::move(list1_node));
+      }
+      auto tuple_t = ASTNodeDataType{ASTNodeDataType::tuple_t, type_id2};
+      REQUIRE_THROWS_WITH((ASTNodeNaturalConversionChecker{*data_node, tuple_t}),
+                          "invalid implicit conversion: foo -> bar");
     }
   }
 }
-- 
GitLab