blob: 39f674570c42ccc1005604b320f5ec6925191380 [file] [log] [blame]
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <map>
#include <set>
#include <string>
#include <vector>
#include <gtest/gtest.h>
#include <stout/jsonify.hpp>
#include <stout/json.hpp>
using std::map;
using std::multimap;
using std::set;
using std::string;
using std::vector;
// Tests that booleans are jsonified correctly.
TEST(JsonifyTest, Boolean)
{
EXPECT_EQ("true", string(jsonify(true)));
EXPECT_EQ("false", string(jsonify(false)));
}
// Tests that `JSON::Boolean`s are jsonified correctly.
TEST(JsonifyTest, JSONBoolean)
{
EXPECT_EQ("true", string(jsonify(JSON::True())));
EXPECT_EQ("false", string(jsonify(JSON::False())));
EXPECT_EQ("true", string(jsonify(JSON::Boolean(true))));
EXPECT_EQ("false", string(jsonify(JSON::Boolean(false))));
}
// Tests that `JSON::Boolean`s wrapped in `JSON::Value` are jsonified correctly.
TEST(JsonifyTest, JSONBooleanValue)
{
EXPECT_EQ("true", string(jsonify(JSON::Value(true))));
EXPECT_EQ("false", string(jsonify(JSON::Value(false))));
}
// Tests that numbers are jsonified correctly.
TEST(JsonifyTest, Number)
{
// Test whole numbers (as doubles).
EXPECT_EQ("0.0", string(jsonify(0.0)));
EXPECT_EQ("1.0", string(jsonify(1.0)));
// Negative.
EXPECT_EQ("-1.0", string(jsonify(-1.0)));
// Test integers.
EXPECT_EQ("0", string(jsonify(0)));
EXPECT_EQ("2", string(jsonify(2)));
EXPECT_EQ("-2", string(jsonify(-2)));
// Expect at least 15 digits of precision.
EXPECT_EQ("1234567890.12345", string(jsonify(1234567890.12345)));
}
// Tests that `JSON::Number`s are jsonified correctly.
TEST(JsonifyTest, JSONNumber)
{
// Test whole numbers (as doubles).
EXPECT_EQ("0.0", string(jsonify(JSON::Number(0.0))));
EXPECT_EQ("1.0", string(jsonify(JSON::Number(1.0))));
// Negative.
EXPECT_EQ("-1.0", string(jsonify(JSON::Number(-1.0))));
// Test integers.
EXPECT_EQ("0", string(jsonify(JSON::Number(0))));
EXPECT_EQ("2", string(jsonify(JSON::Number(2))));
EXPECT_EQ("-2", string(jsonify(JSON::Number(-2))));
// Expect at least 15 digits of precision.
EXPECT_EQ(
"1234567890.12345", string(jsonify(JSON::Number(1234567890.12345))));
}
// Tests that `JSON::Number`s wrapped in `JSON::Value` are jsonified correctly.
TEST(JsonifyTest, JSONNumberValue)
{
// Test whole numbers (as doubles).
EXPECT_EQ("0.0", string(jsonify(JSON::Value(0.0))));
EXPECT_EQ("1.0", string(jsonify(JSON::Value(1.0))));
// Negative.
EXPECT_EQ("-1.0", string(jsonify(JSON::Value(-1.0))));
// Test integers.
EXPECT_EQ("0", string(jsonify(JSON::Value(0))));
EXPECT_EQ("2", string(jsonify(JSON::Value(2))));
EXPECT_EQ("-2", string(jsonify(JSON::Value(-2))));
// Expect at least 15 digits of precision.
EXPECT_EQ("1234567890.12345", string(jsonify(JSON::Value(1234567890.12345))));
}
// Tests that strings are jsonified correctly, including escaping.
TEST(JsonifyTest, String)
{
EXPECT_EQ("\"hello world!\"", string(jsonify("hello world!")));
// We don't use the optional \uXXXX escaping for UTF-8,
// unless required (" U+0022, \ U+005C, and the control
// characters U+0000 to U+001F).
EXPECT_EQ(
"\"Hello! \\u0001\\u001F\\\"\\\\ \xF0\x9F\x98\x80\"",
string(jsonify("Hello! \x01\x1F\x22\x5C \xF0\x9F\x98\x80")));
// There currently is no validation either when constructing
// invalid UTF-8 string, or during serialization. Here, we
// use a 4 byte sequence but only provide the first byte.
// For now, this just gets passed through.
EXPECT_EQ("\"\xF0\"", string(jsonify("\xF0")));
}
// Tests that `JSON::String`s are jsonified correctly, including escaping.
TEST(JsonifyTest, JSONString)
{
EXPECT_EQ("\"hello world!\"", string(jsonify(JSON::String("hello world!"))));
// We don't use the optional \uXXXX escaping for UTF-8,
// unless required (" U+0022, \ U+005C, and the control
// characters U+0000 to U+001F).
EXPECT_EQ(
"\"Hello! \\u0001\\u001F\\\"\\\\ \xF0\x9F\x98\x80\"",
string(jsonify(
JSON::String("Hello! \x01\x1F\x22\x5C \xF0\x9F\x98\x80"))));
// There currently is no validation either when constructing
// invalid UTF-8 string, or during serialization. Here, we
// use a 4 byte sequence but only provide the first byte.
// For now, this just gets passed through.
EXPECT_EQ("\"\xF0\"", string(jsonify(JSON::String("\xF0"))));
}
// Tests that `JSON::String`s wrapped in `JSON::Value` are jsonified correctly,
// including escaping.
TEST(JsonifyTest, JSONStringValue)
{
EXPECT_EQ("\"hello world!\"", string(jsonify(JSON::Value("hello world!"))));
// We don't use the optional \uXXXX escaping for UTF-8,
// unless required (" U+0022, \ U+005C, and the control
// characters U+0000 to U+001F).
EXPECT_EQ(
"\"Hello! \\u0001\\u001F\\\"\\\\ \xF0\x9F\x98\x80\"",
string(jsonify(JSON::Value("Hello! \x01\x1F\x22\x5C \xF0\x9F\x98\x80"))));
// There currently is no validation either when constructing
// invalid UTF-8 string, or during serialization. Here, we
// use a 4 byte sequence but only provide the first byte.
// For now, this just gets passed through.
EXPECT_EQ("\"\xF0\"", string(jsonify(JSON::Value("\xF0"))));
}
namespace store {
// A simple object consisting of primitive types.
struct Name
{
string first;
string last;
};
// A simple object consisting of primitive types as well as a sub-object.
struct Customer
{
Name name;
int age;
};
// `json` overload for `Name`.
void json(JSON::ObjectWriter* writer, const Name& name)
{
writer->field("first_name", name.first);
writer->field("last_name", name.last);
}
// `json` overload for `Customer`.
void json(JSON::ObjectWriter* writer, const Customer& customer)
{
json(writer, customer.name); // Composition of `json` functions!
writer->field("age", customer.age);
}
} // namespace store {
// Tests that objects are jsonified correctly.
TEST(JsonifyTest, Object)
{
store::Name name{"michael", "park"};
EXPECT_EQ(
"{\"first_name\":\"michael\",\"last_name\":\"park\"}",
string(jsonify(name)));
store::Customer customer{name, 25};
EXPECT_EQ(
"{\"first_name\":\"michael\",\"last_name\":\"park\",\"age\":25}",
string(jsonify(customer)));
}
// Tests that `JSON::Object`s are jsonified correctly.
TEST(JsonifyTest, JSONObject)
{
JSON::Object name = {{"first_name", "michael"}, {"last_name", "park"}};
EXPECT_EQ(
"{\"first_name\":\"michael\",\"last_name\":\"park\"}",
string(jsonify(name)));
JSON::Object customer = {
{"age", 25}, {"first_name", "michael"}, {"last_name", "park"}};
EXPECT_EQ(
"{\"age\":25,\"first_name\":\"michael\",\"last_name\":\"park\"}",
string(jsonify(customer)));
}
// Tests that `JSON::Object`s wrapped in `JSON::Value` are jsonified correctly.
TEST(JsonifyTest, JSONObjectValue)
{
JSON::Value name =
JSON::Object{{"first_name", "michael"}, {"last_name", "park"}};
EXPECT_EQ(
"{\"first_name\":\"michael\",\"last_name\":\"park\"}",
string(jsonify(name)));
JSON::Value customer =
JSON::Object{{"first_name", "michael"}, {"last_name", "park"}, {"age", 25}};
EXPECT_EQ(
"{\"age\":25,\"first_name\":\"michael\",\"last_name\":\"park\"}",
string(jsonify(customer)));
}
// Tests that iterable types are jsonified as array correctly.
TEST(JsonifyTest, Array)
{
bool booleans[] = {true, true, false};
EXPECT_EQ("[true,true,false]", string(jsonify(booleans)));
vector<int> numbers = {1, 2, 3};
EXPECT_EQ("[1,2,3]", string(jsonify(numbers)));
set<string> strings = {"there", "hello"};
EXPECT_EQ("[\"hello\",\"there\"]", string(jsonify(strings)));
vector<set<int>> numbers_list = {{1, 2, 3}, {1, 1, 1}};
EXPECT_EQ("[[1,2,3],[1]]", string(jsonify(numbers_list)));
vector<store::Customer> names = {{{"michael", "park"}, 25}};
EXPECT_EQ(
"[{\"first_name\":\"michael\",\"last_name\":\"park\",\"age\":25}]",
string(jsonify(names)));
}
// Tests that `JSON::Array`s types are jsonified as array correctly.
TEST(JsonifyTest, JSONArray)
{
JSON::Array booleans = {true, true, false};
EXPECT_EQ("[true,true,false]", string(jsonify(booleans)));
JSON::Array numbers = {1, 2, 3};
EXPECT_EQ("[1,2,3]", string(jsonify(numbers)));
JSON::Array numbers_list = {JSON::Array{1, 2, 3}, JSON::Array{1, 1, 1}};
EXPECT_EQ("[[1,2,3],[1,1,1]]", string(jsonify(numbers_list)));
JSON::Array names = {JSON::Object{
{"first_name", "michael"}, {"last_name", "park"}, {"age", 25}}};
EXPECT_EQ(
"[{\"age\":25,\"first_name\":\"michael\",\"last_name\":\"park\"}]",
string(jsonify(names)));
}
// Tests that `JSON::Array`s wrapped in `JSON::Value` types are jsonified as
// array correctly.
TEST(JsonifyTest, JSONArrayValue)
{
JSON::Value booleans = JSON::Array{true, true, false};
EXPECT_EQ("[true,true,false]", string(jsonify(booleans)));
JSON::Value numbers = JSON::Array{1, 2, 3};
EXPECT_EQ("[1,2,3]", string(jsonify(numbers)));
JSON::Value numbers_list =
JSON::Array{JSON::Array{1, 2, 3}, JSON::Array{1, 1, 1}};
EXPECT_EQ("[[1,2,3],[1,1,1]]", string(jsonify(numbers_list)));
JSON::Value names = JSON::Array{JSON::Object{
{"first_name", "michael"}, {"last_name", "park"}, {"age", 25}}};
EXPECT_EQ(
"[{\"age\":25,\"first_name\":\"michael\",\"last_name\":\"park\"}]",
string(jsonify(names)));
}
// Tests that dictionary types of primitive a member typedef `mapped_type` are
// considered dictionaries and therefore are jsonified as objects correctly.
TEST(JsonifyTest, Dictionary)
{
map<string, bool> booleans = {{"x", true}, {"y", false}};
EXPECT_EQ("{\"x\":true,\"y\":false}", string(jsonify(booleans)));
map<string, map<string, int>> nested_numbers = {{"foo", {{"x", 1}}}};
EXPECT_EQ("{\"foo\":{\"x\":1}}", string(jsonify(nested_numbers)));
multimap<string, store::Name> names = {
{"kobe", {"kobe", "bryant"}},
{"michael", {"michael", "jordan"}},
{"michael", {"michael", "park"}}
};
string expected = strings::remove(
"{"
" \"kobe\":{\"first_name\":\"kobe\",\"last_name\":\"bryant\"},"
" \"michael\":{\"first_name\":\"michael\",\"last_name\":\"jordan\"},"
" \"michael\":{\"first_name\":\"michael\",\"last_name\":\"park\"}"
"}",
" ");
EXPECT_EQ(expected, string(jsonify(names)));
}
// Tests that `JSON::Null`s are jsonified as array correctly.
TEST(JsonifyTest, JSONNull)
{
JSON::Null null;
EXPECT_EQ("null", string(jsonify(null)));
JSON::Array numbers = JSON::Array{1, JSON::Null(), 3};
EXPECT_EQ("[1,null,3]", string(jsonify(numbers)));
}