Fixes RCU test cases error (loads should use Consume ordering)
[folly.git] / folly / test / DynamicConverterTest.cpp
index 2e5003dedc6df79d412777de6a92a4fe5452a606..fd0d88b143171a87c45bd26e66b3fb82c4de08c7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 Facebook, Inc.
+ * Copyright 2012-present Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 #include <folly/DynamicConverter.h>
 
+#include <folly/portability/GTest.h>
+
 #include <algorithm>
-#include <gflags/gflags.h>
-#include <gtest/gtest.h>
 #include <map>
 #include <vector>
 
-#include <folly/Benchmark.h>
-
 using namespace folly;
 using namespace folly::dynamicconverter_detail;
 
@@ -102,6 +100,28 @@ TEST(DynamicConverter, arithmetic_types) {
   EXPECT_EQ(i8, false);
 }
 
+TEST(DynamicConverter, enums) {
+  enum enum1 { foo = 1, bar = 2 };
+
+  dynamic d1 = 1;
+  auto i1 = convertTo<enum1>(d1);
+  EXPECT_EQ(i1, foo);
+
+  dynamic d2 = 2;
+  auto i2 = convertTo<enum1>(d2);
+  EXPECT_EQ(i2, bar);
+
+  enum class enum2 { FOO = 1, BAR = 2 };
+
+  dynamic d3 = 1;
+  auto i3 = convertTo<enum2>(d3);
+  EXPECT_EQ(i3, enum2::FOO);
+
+  dynamic d4 = 2;
+  auto i4 = convertTo<enum2>(d4);
+  EXPECT_EQ(i4, enum2::BAR);
+}
+
 TEST(DynamicConverter, simple_builtins) {
   dynamic d1 = "Haskell";
   auto i1 = convertTo<folly::fbstring>(d1);
@@ -111,7 +131,7 @@ TEST(DynamicConverter, simple_builtins) {
   auto i2 = convertTo<std::string>(d2);
   EXPECT_EQ(i2, "13");
 
-  dynamic d3 = { 12, "Scala" };
+  dynamic d3 = dynamic::array(12, "Scala");
   auto i3 = convertTo<std::pair<int, std::string>>(d3);
   EXPECT_EQ(i3.first, 12);
   EXPECT_EQ(i3.second, "Scala");
@@ -123,19 +143,19 @@ TEST(DynamicConverter, simple_builtins) {
 }
 
 TEST(DynamicConverter, simple_fbvector) {
-  dynamic d1 = { 1, 2, 3 };
+  dynamic d1 = dynamic::array(1, 2, 3);
   auto i1 = convertTo<folly::fbvector<int>>(d1);
   decltype(i1) i1b = { 1, 2, 3 };
   EXPECT_EQ(i1, i1b);
 }
 
 TEST(DynamicConverter, simple_container) {
-  dynamic d1 = { 1, 2, 3 };
+  dynamic d1 = dynamic::array(1, 2, 3);
   auto i1 = convertTo<std::vector<int>>(d1);
   decltype(i1) i1b = { 1, 2, 3 };
   EXPECT_EQ(i1, i1b);
 
-  dynamic d2 = { 1, 3, 5, 2, 4 };
+  dynamic d2 = dynamic::array(1, 3, 5, 2, 4);
   auto i2 = convertTo<std::set<int>>(d2);
   decltype(i2) i2b = { 1, 2, 3, 5, 4 };
   EXPECT_EQ(i2, i2b);
@@ -147,7 +167,8 @@ TEST(DynamicConverter, simple_map) {
   decltype(i1) i1b = { { 1, "one" }, { 2, "two" } };
   EXPECT_EQ(i1, i1b);
 
-  dynamic d2 = { { 3, "three" }, { 4, "four" } };
+  dynamic d2 = dynamic::array(dynamic::array(3, "three"),
+                              dynamic::array(4, "four"));
   auto i2 = convertTo<std::unordered_map<int, std::string>>(d2);
   decltype(i2) i2b = { { 3, "three" }, { 4, "four" } };
   EXPECT_EQ(i2, i2b);
@@ -159,7 +180,8 @@ TEST(DynamicConverter, map_keyed_by_string) {
   decltype(i1) i1b = { { "1", "one" }, { "2", "two" } };
   EXPECT_EQ(i1, i1b);
 
-  dynamic d2 = { { "3", "three" }, { "4", "four" } };
+  dynamic d2 = dynamic::array(dynamic::array("3", "three"),
+                              dynamic::array("4", "four"));
   auto i2 = convertTo<std::unordered_map<std::string, std::string>>(d2);
   decltype(i2) i2b = { { "3", "three" }, { "4", "four" } };
   EXPECT_EQ(i2, i2b);
@@ -174,13 +196,15 @@ TEST(DynamicConverter, map_to_vector_of_pairs) {
 }
 
 TEST(DynamicConverter, nested_containers) {
-  dynamic d1 = { { 1 }, { }, { 2, 3 } };
+  dynamic d1 = dynamic::array(dynamic::array(1),
+                              dynamic::array(),
+                              dynamic::array(2, 3));
   auto i1 = convertTo<folly::fbvector<std::vector<uint8_t>>>(d1);
   decltype(i1) i1b = { { 1 }, { }, { 2, 3 } };
   EXPECT_EQ(i1, i1b);
 
-  dynamic h2a = { "3", ".", "1", "4" };
-  dynamic h2b = { "2", ".", "7", "2" };
+  dynamic h2a = dynamic::array("3", ".", "1", "4");
+  dynamic h2b = dynamic::array("2", ".", "7", "2");
   dynamic d2 = dynamic::object(3.14, h2a)(2.72, h2b);
   auto i2 = convertTo<std::map<double, std::vector<folly::fbstring>>>(d2);
   decltype(i2) i2b =
@@ -199,13 +223,14 @@ template <> struct DynamicConverter<A> {
     return { convertTo<int>(d["i"]) };
   }
 };
-}
+} // namespace folly
 TEST(DynamicConverter, custom_class) {
   dynamic d1 = dynamic::object("i", 17);
   auto i1 = convertTo<A>(d1);
   EXPECT_EQ(i1.i, 17);
 
-  dynamic d2 = { dynamic::object("i", 18), dynamic::object("i", 19) };
+  dynamic d2 = dynamic::array(dynamic::object("i", 18),
+                              dynamic::object("i", 19));
   auto i2 = convertTo<std::vector<A>>(d2);
   decltype(i2) i2b = { { 18 }, { 19 } };
   EXPECT_EQ(i2, i2b);
@@ -236,21 +261,21 @@ TEST(DynamicConverter, crazy) {
 
 
   dynamic
-    ds1 = { "a", "e", "i", "o", "u" },
-    ds2 = { "2", "3", "5", "7" },
-    ds3 = { "Hello", "World" };
+    ds1 = dynamic::array("a", "e", "i", "o", "u"),
+    ds2 = dynamic::array("2", "3", "5", "7"),
+    ds3 = dynamic::array("Hello", "World");
 
   dynamic
-    dv1 = {},
-    dv2 = { ds1, ds2 },
-    dv3 = { ds3 };
+    dv1 = dynamic::array,
+    dv2 = dynamic::array(ds1, ds2),
+    dv3(dynamic::array(ds3));
 
   dynamic
     dm1 = dynamic::object(true, dv1)(false, dv2),
-    dm2 = { { true, dv3 } };
+    dm2 = dynamic::array(dynamic::array(true, dv3));
 
   dynamic
-    df1 = { dm1, dm2 };
+    df1 = dynamic::array(dm1, dm2);
 
 
   auto i = convertTo<std::vector<std::unordered_map<bool, std::vector<
@@ -271,13 +296,13 @@ TEST(DynamicConverter, consts) {
 
   dynamic d3 = true;
   auto i3 = convertTo<const bool>(d3);
-  EXPECT_EQ(true, i3);
+  EXPECT_TRUE(i3);
 
   dynamic d4 = "true";
   auto i4 = convertTo<const bool>(d4);
-  EXPECT_EQ(true, i4);
+  EXPECT_TRUE(i4);
 
-  dynamic d5 = { 1, 2 };
+  dynamic d5 = dynamic::array(1, 2);
   auto i5 = convertTo<const std::pair<const int, const int>>(d5);
   decltype(i5) i5b = { 1, 2 };
   EXPECT_EQ(i5b, i5);
@@ -299,7 +324,7 @@ template <> struct DynamicConverter<Token> {
     return Token(k, lex);
   }
 };
-}
+} // namespace folly
 
 TEST(DynamicConverter, example) {
   dynamic d1 = dynamic::object("KIND", 2)("LEXEME", "a token");
@@ -315,7 +340,13 @@ TEST(DynamicConverter, construct) {
   using std::string;
   {
     vector<int> c { 1, 2, 3 };
-    dynamic d = { 1, 2, 3 };
+    dynamic d = dynamic::array(1, 2, 3);
+    EXPECT_EQ(d, toDynamic(c));
+  }
+
+  {
+    vector<float> c{1.0f, 2.0f, 4.0f};
+    dynamic d = dynamic::array(1.0, 2.0, 4.0);
     EXPECT_EQ(d, toDynamic(c));
   }
 
@@ -333,13 +364,13 @@ TEST(DynamicConverter, construct) {
 
   {
     map<string, pair<string, int>> c { { "a", { "b", 3 } } };
-    dynamic d = dynamic::object("a", dynamic { "b", 3 });
+    dynamic d = dynamic::object("a", dynamic::array("b", 3));
     EXPECT_EQ(d, toDynamic(c));
   }
 
   {
     map<string, pair<string, int>> c { { "a", { "b", 3 } } };
-    dynamic d = dynamic::object("a", dynamic { "b", 3 });
+    dynamic d = dynamic::object("a", dynamic::array("b", 3));
     EXPECT_EQ(d, toDynamic(c));
   }
 
@@ -347,9 +378,16 @@ TEST(DynamicConverter, construct) {
     vector<int> vi { 2, 3, 4, 5 };
     auto c = std::make_pair(range(vi.begin(), vi.begin() + 3),
                             range(vi.begin() + 1, vi.begin() + 4));
-    dynamic d = { { 2, 3, 4 }, { 3, 4, 5 } };
+    dynamic d = dynamic::array(dynamic::array(2, 3, 4),
+                               dynamic::array(3, 4, 5));
     EXPECT_EQ(d, toDynamic(c));
   }
+
+  {
+    vector<bool> vb{true, false};
+    dynamic d = dynamic::array(true, false);
+    EXPECT_EQ(d, toDynamic(vb));
+  }
 }
 
 TEST(DynamicConverter, errors) {
@@ -365,11 +403,63 @@ TEST(DynamicConverter, errors) {
   EXPECT_THROW(convertTo<float>(d2), std::range_error);
 }
 
-int main(int argc, char ** argv) {
-  testing::InitGoogleTest(&argc, argv);
-  gflags::ParseCommandLineFlags(&argc, &argv, true);
-  if (FLAGS_benchmark) {
-    folly::runBenchmarks();
+TEST(DynamicConverter, partial_dynamics) {
+  std::vector<dynamic> c{
+      dynamic::array(2, 3, 4), dynamic::array(3, 4, 5),
+  };
+  dynamic d = dynamic::array(dynamic::array(2, 3, 4), dynamic::array(3, 4, 5));
+  EXPECT_EQ(d, toDynamic(c));
+
+  std::unordered_map<std::string, dynamic> m{{"one", 1}, {"two", 2}};
+  dynamic md = dynamic::object("one", 1)("two", 2);
+  EXPECT_EQ(md, toDynamic(m));
+}
+
+TEST(DynamicConverter, asan_exception_case_umap) {
+  EXPECT_THROW(
+      (convertTo<std::unordered_map<int, int>>(dynamic::array(1))), TypeError);
+}
+
+TEST(DynamicConverter, asan_exception_case_uset) {
+  EXPECT_THROW(
+      (convertTo<std::unordered_set<int>>(
+          dynamic::array(1, dynamic::array(), 3))),
+      TypeError);
+}
+
+static int constructB = 0;
+static int destroyB = 0;
+static int ticker = 0;
+struct B {
+  struct BException : std::exception {};
+
+  /* implicit */ B(int x) : x_(x) {
+    if (ticker-- == 0) {
+      throw BException();
+    }
+    constructB++;
   }
-  return RUN_ALL_TESTS();
+  B(const B& o) : x_(o.x_) {
+    constructB++;
+  }
+  ~B() {
+    destroyB++;
+  }
+  int x_;
+};
+namespace folly {
+template <>
+struct DynamicConverter<B> {
+  static B convert(const dynamic& d) {
+    return B(convertTo<int>(d));
+  }
+};
+} // namespace folly
+
+TEST(DynamicConverter, double_destroy) {
+  dynamic d = dynamic::array(1, 3, 5, 7, 9, 11, 13, 15, 17);
+  ticker = 3;
+
+  EXPECT_THROW(convertTo<std::vector<B>>(d), B::BException);
+  EXPECT_EQ(constructB, destroyB);
 }