Fix copyright lines
[folly.git] / folly / test / DynamicTest.cpp
index fcae9a15e6097751b5483c20610cbb2504226d0b..f367edea6a3a6bd24fe27b1286909717ad9a5888 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 Facebook, Inc.
+ * Copyright 2011-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.
@@ -16,8 +16,9 @@
 
 #include <folly/dynamic.h>
 
+#include <folly/portability/GTest.h>
+
 #include <boost/next_prior.hpp>
-#include <gtest/gtest.h>
 
 using folly::dynamic;
 
@@ -30,6 +31,11 @@ void dynamic::print_as_pseudo_json(std::ostream& out) const {
   out << "<folly::dynamic object of type " << type_ << ">";
 }
 
+TEST(Dynamic, Default) {
+  dynamic obj;
+  EXPECT_TRUE(obj.isNull());
+}
+
 TEST(Dynamic, ObjectBasics) {
   dynamic obj = dynamic::object("a", false);
   EXPECT_EQ(obj.at("a"), false);
@@ -50,7 +56,7 @@ TEST(Dynamic, ObjectBasics) {
 
   EXPECT_EQ(*newObject.keys().begin(), newObject.items().begin()->first);
   EXPECT_EQ(*newObject.values().begin(), newObject.items().begin()->second);
-  std::vector<std::pair<folly::fbstring, dynamic>> found;
+  std::vector<std::pair<std::string, dynamic>> found;
   found.emplace_back(newObject.keys().begin()->asString(),
                      *newObject.values().begin());
 
@@ -246,7 +252,7 @@ TEST(Dynamic, Operator) {
     LOG(ERROR) << "operator < returned "
                << static_cast<int>(foo)
                << " instead of throwing";
-  } catch (std::exception const& e) {
+  } catch (std::exception const&) {
     caught = true;
   }
   EXPECT_TRUE(caught);
@@ -353,8 +359,8 @@ TEST(Dynamic, Assignment) {
   }
 }
 
-folly::fbstring make_long_string() {
-  return folly::fbstring(100, 'a');
+std::string make_long_string() {
+  return std::string(100, 'a');
 }
 
 TEST(Dynamic, GetDefault) {
@@ -407,6 +413,9 @@ TEST(Dynamic, GetString) {
   EXPECT_EQ(s + " hello", d.getString());
 
   EXPECT_EQ(s, std::move(m).getString());
+  EXPECT_EQ(s, m.getString());
+  auto moved = std::move(m).getString();
+  EXPECT_EQ(s, moved);
   EXPECT_NE(dynamic(s), m);
 }
 
@@ -431,10 +440,10 @@ TEST(Dynamic, GetSmallThings) {
   EXPECT_EQ(6.0, ddouble.getDouble());
   EXPECT_EQ(5.0, std::move(mdouble).getDouble());
 
-  EXPECT_EQ(true, cbool.getBool());
+  EXPECT_TRUE(cbool.getBool());
   dbool.getBool() = false;
   EXPECT_FALSE(dbool.getBool());
-  EXPECT_EQ(true, std::move(mbool).getBool());
+  EXPECT_TRUE(std::move(mbool).getBool());
 }
 
 TEST(Dynamic, At) {
@@ -450,7 +459,10 @@ TEST(Dynamic, At) {
   EXPECT_EQ(dynamic(make_long_string() + " hello"), dd.at("key1"));
   EXPECT_EQ(dynamic(make_long_string() + " hello"), dd.at("key1"));
 
-  EXPECT_EQ(ds, std::move(md).at("key1"));
+  EXPECT_EQ(ds, std::move(md).at("key1")); // move available, but not performed
+  EXPECT_EQ(ds, md.at("key1"));
+  dynamic moved = std::move(md).at("key1"); // move performed
+  EXPECT_EQ(ds, moved);
   EXPECT_NE(ds, md.at("key1"));
 }
 
@@ -467,7 +479,10 @@ TEST(Dynamic, Brackets) {
   EXPECT_EQ(dynamic(make_long_string() + " hello"), dd["key1"]);
   EXPECT_EQ(dynamic(make_long_string() + " hello"), dd["key1"]);
 
-  EXPECT_EQ(ds, std::move(md)["key1"]);
+  EXPECT_EQ(ds, std::move(md)["key1"]); // move available, but not performed
+  EXPECT_EQ(ds, md["key1"]);
+  dynamic moved = std::move(md)["key1"]; // move performed
+  EXPECT_EQ(ds, moved);
   EXPECT_NE(ds, md["key1"]);
 }
 
@@ -476,3 +491,135 @@ TEST(Dynamic, PrintNull) {
   ss << folly::dynamic(nullptr);
   EXPECT_EQ("null", ss.str());
 }
+
+TEST(Dynamic, WriteThroughArrayIterators) {
+  dynamic const cint(0);
+  dynamic d = dynamic::array(cint, cint, cint);
+  size_t size = d.size();
+
+  for (auto& val : d) {
+    EXPECT_EQ(val, cint);
+  }
+  EXPECT_EQ(d.size(), size);
+
+  dynamic ds(make_long_string());
+  for (auto& val : d) {
+    val = ds; // assign through reference
+  }
+
+  ds = "short string";
+  dynamic ds2(make_long_string());
+
+  for (auto& val : d) {
+    EXPECT_EQ(val, ds2);
+  }
+  EXPECT_EQ(d.size(), size);
+}
+
+TEST(Dynamic, MoveOutOfArrayIterators) {
+  dynamic ds(make_long_string());
+  dynamic d = dynamic::array(ds, ds, ds);
+  size_t size = d.size();
+
+  for (auto& val : d) {
+    EXPECT_EQ(val, ds);
+  }
+  EXPECT_EQ(d.size(), size);
+
+  for (auto& val : d) {
+    dynamic waste = std::move(val); // force moving out
+    EXPECT_EQ(waste, ds);
+  }
+
+  for (auto& val : d) {
+    EXPECT_NE(val, ds);
+  }
+  EXPECT_EQ(d.size(), size);
+}
+
+TEST(Dynamic, WriteThroughObjectIterators) {
+  dynamic const cint(0);
+  dynamic d = dynamic::object("key1", cint)("key2", cint);
+  size_t size = d.size();
+
+  for (auto& val : d.items()) {
+    EXPECT_EQ(val.second, cint);
+  }
+  EXPECT_EQ(d.size(), size);
+
+  dynamic ds(make_long_string());
+  for (auto& val : d.items()) {
+    val.second = ds; // assign through reference
+  }
+
+  ds = "short string";
+  dynamic ds2(make_long_string());
+  for (auto& val : d.items()) {
+    EXPECT_EQ(val.second, ds2);
+  }
+  EXPECT_EQ(d.size(), size);
+}
+
+TEST(Dynamic, MoveOutOfObjectIterators) {
+  dynamic ds(make_long_string());
+  dynamic d = dynamic::object("key1", ds)("key2", ds);
+  size_t size = d.size();
+
+  for (auto& val : d.items()) {
+    EXPECT_EQ(val.second, ds);
+  }
+  EXPECT_EQ(d.size(), size);
+
+  for (auto& val : d.items()) {
+    dynamic waste = std::move(val.second); // force moving out
+    EXPECT_EQ(waste, ds);
+  }
+
+  for (auto& val : d.items()) {
+    EXPECT_NE(val.second, ds);
+  }
+  EXPECT_EQ(d.size(), size);
+}
+
+TEST(Dynamic, ArrayIteratorInterop) {
+  dynamic d = dynamic::array(0, 1, 2);
+  dynamic const& cdref = d;
+
+  auto it = d.begin();
+  auto cit = cdref.begin();
+
+  EXPECT_EQ(it, cit);
+  EXPECT_EQ(cit, d.begin());
+  EXPECT_EQ(it, cdref.begin());
+
+  // Erase using non-const iterator
+  it = d.erase(it);
+  cit = cdref.begin();
+  EXPECT_EQ(*it, 1);
+  EXPECT_EQ(cit, it);
+
+  // Assign from non-const to const, preserve equality
+  decltype(cit) cit2 = it;
+  EXPECT_EQ(cit, cit2);
+}
+
+TEST(Dynamic, ObjectIteratorInterop) {
+  dynamic ds = make_long_string();
+  dynamic d = dynamic::object(0, ds)(1, ds)(2, ds);
+  dynamic const& cdref = d;
+
+  auto it = d.find(0);
+  auto cit = cdref.find(0);
+  EXPECT_NE(it, cdref.items().end());
+  EXPECT_NE(cit, cdref.items().end());
+  EXPECT_EQ(it, cit);
+
+  ++cit;
+  // Erase using non-const iterator
+  auto it2 = d.erase(it);
+  EXPECT_EQ(cit, it2);
+
+  // Assign from non-const to const, preserve equality
+  decltype(cit) cit2 = it2;
+  EXPECT_EQ(cit, cit2);
+}