From beb7c41497de5be4d725ac55cb58a337f4aded27 Mon Sep 17 00:00:00 2001
From: jbajic <jure.bajic@memgraph.com>
Date: Tue, 28 Jun 2022 15:22:56 +0200
Subject: [PATCH] Finish interpreter tests

---
 tests/unit/interpreter.cpp | 153 +++++++++++++++++++++++++++++++++++++
 1 file changed, 153 insertions(+)

diff --git a/tests/unit/interpreter.cpp b/tests/unit/interpreter.cpp
index f5a3e03b3..d72dec47d 100644
--- a/tests/unit/interpreter.cpp
+++ b/tests/unit/interpreter.cpp
@@ -10,8 +10,10 @@
 // licenses/APL.txt.
 
 #include <algorithm>
+#include <cstddef>
 #include <cstdlib>
 #include <filesystem>
+#include <unordered_set>
 
 #include "communication/bolt/v1/value.hpp"
 #include "communication/result_stream_faker.hpp"
@@ -38,6 +40,12 @@ auto ToEdgeList(const memgraph::communication::bolt::Value &v) {
     list.push_back(x.ValueEdge());
   }
   return list;
+}
+
+auto StringToUnorderedSet(const std::string &element, const size_t number_of_split_elements) {
+  const auto element_split = memgraph::utils::Split(element, ", ");
+  MG_ASSERT(element_split.size() == number_of_split_elements);
+  return std::unordered_set<std::string>(element_split.begin(), element_split.end());
 };
 
 struct InterpreterFaker {
@@ -1465,3 +1473,148 @@ TEST_F(InterpreterTest, LoadCsvClauseNotification) {
             "conversion functions such as ToInteger, ToFloat, ToBoolean etc.");
   ASSERT_EQ(notification["description"].ValueString(), "");
 }
+
+TEST_F(InterpreterTest, CreateSchemaMulticommandTransaction) {
+  Interpret("BEGIN");
+  ASSERT_THROW(Interpret("CREATE SCHEMA ON :label(name STRING, age INTEGER)"),
+               memgraph::query::ConstraintInMulticommandTxException);
+  Interpret("ROLLBACK");
+}
+
+TEST_F(InterpreterTest, ShowSchemasMulticommandTransaction) {
+  Interpret("BEGIN");
+  ASSERT_THROW(Interpret("SHOW SCHEMAS"), memgraph::query::ConstraintInMulticommandTxException);
+  Interpret("ROLLBACK");
+}
+
+TEST_F(InterpreterTest, ShowSchemaMulticommandTransaction) {
+  Interpret("BEGIN");
+  ASSERT_THROW(Interpret("SHOW SCHEMA ON :label"), memgraph::query::ConstraintInMulticommandTxException);
+  Interpret("ROLLBACK");
+}
+
+TEST_F(InterpreterTest, DropSchemaMulticommandTransaction) {
+  Interpret("BEGIN");
+  ASSERT_THROW(Interpret("DROP SCHEMA ON :label"), memgraph::query::ConstraintInMulticommandTxException);
+  Interpret("ROLLBACK");
+}
+
+TEST_F(InterpreterTest, SchemaTestCreateAndShow) {
+  // Empty schema type map should result with syntax exception.
+  ASSERT_THROW(Interpret("CREATE SCHEMA ON :label();"), memgraph::query::SyntaxException);
+
+  // Duplicate properties are should also cause an exception
+  ASSERT_THROW(Interpret("CREATE SCHEMA ON :label(name STRING, name STRING);"), memgraph::query::SemanticException);
+  ASSERT_THROW(Interpret("CREATE SCHEMA ON :label(name STRING, name INTEGER);"), memgraph::query::SemanticException);
+
+  {
+    // Cannot create same schema twice
+    Interpret("CREATE SCHEMA ON :label(name STRING, age INTEGER)");
+    ASSERT_THROW(Interpret("CREATE SCHEMA ON :label(name STRING);"), memgraph::query::QueryException);
+  }
+  // Show schema
+  {
+    auto stream = Interpret("SHOW SCHEMA ON :label");
+    ASSERT_EQ(stream.GetHeader().size(), 2U);
+    const auto &header = stream.GetHeader();
+    ASSERT_EQ(header[0], "property_name");
+    ASSERT_EQ(header[1], "property_type");
+    ASSERT_EQ(stream.GetResults().size(), 2U);
+    std::unordered_map<std::string, std::string> result_table{{"age", "Integer"}, {"name", "String"}};
+
+    const auto &result = stream.GetResults().front();
+    ASSERT_EQ(result.size(), 2U);
+    const auto key1 = result[0].ValueString();
+    ASSERT_TRUE(result_table.contains(key1));
+    ASSERT_EQ(result[1].ValueString(), result_table[key1]);
+
+    const auto &result2 = stream.GetResults().front();
+    ASSERT_EQ(result2.size(), 2U);
+    const auto key2 = result2[0].ValueString();
+    ASSERT_TRUE(result_table.contains(key2));
+    ASSERT_EQ(result[1].ValueString(), result_table[key2]);
+  }
+  // Create Another Schema
+  Interpret("CREATE SCHEMA ON :label2(place STRING, dur DURATION)");
+
+  // Show schemas
+  {
+    auto stream = Interpret("SHOW SCHEMAS");
+    ASSERT_EQ(stream.GetHeader().size(), 3U);
+    const auto &header = stream.GetHeader();
+    ASSERT_EQ(header[0], "label");
+    ASSERT_EQ(header[1], "primary_key");
+    ASSERT_EQ(header[2], "primary_key_type");
+    ASSERT_EQ(stream.GetResults().size(), 2U);
+    std::unordered_map<std::string, std::pair<std::unordered_set<std::string>, std::string>> result_table{
+        {"label", {{"name::String", "age::Integer"}, "Composite"}},
+        {"label2", {{"place::String", "dur::Duration"}, "Composite"}}};
+
+    const auto &result = stream.GetResults().front();
+    ASSERT_EQ(result.size(), 3U);
+    const auto key1 = result[0].ValueString();
+    ASSERT_TRUE(result_table.contains(key1));
+    const auto primary_key_split = StringToUnorderedSet(result[1].ValueString(), 2);
+    ASSERT_TRUE(primary_key_split == result_table[key1].first);
+    ASSERT_EQ(result[2].ValueString(), result_table[key1].second);
+
+    const auto &result2 = stream.GetResults().front();
+    ASSERT_EQ(result2.size(), 3U);
+    const auto key2 = result2[0].ValueString();
+    ASSERT_TRUE(result_table.contains(key2));
+    const auto primary_key_split2 = StringToUnorderedSet(result2[1].ValueString(), 2);
+    ASSERT_TRUE(primary_key_split2 == result_table[key2].first);
+    ASSERT_EQ(result2[2].ValueString(), result_table[key2].second);
+  }
+}
+
+TEST_F(InterpreterTest, SchemaTestCreateDropAndShow) {
+  Interpret("CREATE SCHEMA ON :label(name STRING, age INTEGER)");
+  // Wrong syntax for dropping schema.
+  ASSERT_THROW(Interpret("DROP SCHEMA ON :label();"), memgraph::query::SyntaxException);
+  // Cannot drop non existant schema.
+  ASSERT_THROW(Interpret("DROP SCHEMA ON :label1;"), memgraph::query::QueryException);
+
+  // Create Schema and Drop
+  auto get_number_of_schemas = [this]() {
+    auto stream = Interpret("SHOW SCHEMAS");
+    return stream.GetResults().size();
+  };
+
+  ASSERT_EQ(get_number_of_schemas(), 1);
+  Interpret("CREATE SCHEMA ON :label1(name STRING, age INTEGER)");
+  ASSERT_EQ(get_number_of_schemas(), 2);
+  Interpret("CREATE SCHEMA ON :label2(name STRING, sex BOOL)");
+  ASSERT_EQ(get_number_of_schemas(), 3);
+  Interpret("DROP SCHEMA ON :label1");
+  ASSERT_EQ(get_number_of_schemas(), 2);
+  Interpret("CREATE SCHEMA ON :label3(name STRING, birthday LOCALDATETIME)");
+  ASSERT_EQ(get_number_of_schemas(), 3);
+  Interpret("DROP SCHEMA ON :label2");
+  ASSERT_EQ(get_number_of_schemas(), 2);
+  Interpret("CREATE SCHEMA ON :label4(name STRING, age DURATION)");
+  ASSERT_EQ(get_number_of_schemas(), 3);
+  Interpret("DROP SCHEMA ON :label3");
+  ASSERT_EQ(get_number_of_schemas(), 2);
+  Interpret("DROP SCHEMA ON :label");
+  ASSERT_EQ(get_number_of_schemas(), 1);
+
+  // Show schemas
+  auto stream = Interpret("SHOW SCHEMAS");
+  ASSERT_EQ(stream.GetHeader().size(), 3U);
+  const auto &header = stream.GetHeader();
+  ASSERT_EQ(header[0], "label");
+  ASSERT_EQ(header[1], "primary_key");
+  ASSERT_EQ(header[2], "primary_key_type");
+  ASSERT_EQ(stream.GetResults().size(), 1U);
+  std::unordered_map<std::string, std::pair<std::unordered_set<std::string>, std::string>> result_table{
+      {"label4", {{"name::String", "age::Duration"}, "Composite"}}};
+
+  const auto &result = stream.GetResults().front();
+  ASSERT_EQ(result.size(), 3U);
+  const auto key1 = result[0].ValueString();
+  ASSERT_TRUE(result_table.contains(key1));
+  const auto primary_key_split = StringToUnorderedSet(result[1].ValueString(), 2);
+  ASSERT_TRUE(primary_key_split == result_table[key1].first);
+  ASSERT_EQ(result[2].ValueString(), result_table[key1].second);
+}