/*
- * 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.
#include <folly/dynamic.h>
+#include <folly/portability/GTest.h>
+
#include <boost/next_prior.hpp>
-#include <gtest/gtest.h>
using folly::dynamic;
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);
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());
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);
}
}
-folly::fbstring make_long_string() {
- return folly::fbstring(100, 'a');
+std::string make_long_string() {
+ return std::string(100, 'a');
}
TEST(Dynamic, GetDefault) {
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);
}
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) {
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"));
}
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"]);
}
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);
+}