blob: 56f50c6e583c21aa7d123af88ffb9a2da320e29b [file] [log] [blame]
Austin Schuh9d823002019-04-14 12:53:17 -07001// Copyright (c) 2013-2017, Matt Godbolt
Austin Schuh24adb6b2015-09-06 17:37:40 -07002// All rights reserved.
Austin Schuh9d823002019-04-14 12:53:17 -07003//
4// Redistribution and use in source and binary forms, with or without
Austin Schuh24adb6b2015-09-06 17:37:40 -07005// modification, are permitted provided that the following conditions are met:
Austin Schuh9d823002019-04-14 12:53:17 -07006//
7// Redistributions of source code must retain the above copyright notice, this
Austin Schuh24adb6b2015-09-06 17:37:40 -07008// list of conditions and the following disclaimer.
Austin Schuh9d823002019-04-14 12:53:17 -07009//
10// Redistributions in binary form must reproduce the above copyright notice,
11// this list of conditions and the following disclaimer in the documentation
Austin Schuh24adb6b2015-09-06 17:37:40 -070012// and/or other materials provided with the distribution.
Austin Schuh9d823002019-04-14 12:53:17 -070013//
14// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
18// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
Austin Schuh24adb6b2015-09-06 17:37:40 -070024// POSSIBILITY OF SUCH DAMAGE.
25
26#include "seasocks/util/Json.h"
27
Austin Schuh9d823002019-04-14 12:53:17 -070028#include <catch2/catch.hpp>
29
Austin Schuh24adb6b2015-09-06 17:37:40 -070030#include <ostream>
31#include <map>
32#include <unordered_map>
33
Austin Schuh24adb6b2015-09-06 17:37:40 -070034using namespace seasocks;
35
36namespace {
37
Austin Schuh9d823002019-04-14 12:53:17 -070038TEST_CASE("shouldHandleMaps", "[JsonTests]") {
39 CHECK(makeMap("monkey", 12) == "{\"monkey\":12}");
Austin Schuh24adb6b2015-09-06 17:37:40 -070040}
41
Austin Schuh9d823002019-04-14 12:53:17 -070042TEST_CASE("shouldHandleQuotedStrings", "[JsonTests]") {
43 CHECK(makeMap("key", "I have \"quotes\"") ==
44 "{\"key\":\"I have \\\"quotes\\\"\"}");
Austin Schuh24adb6b2015-09-06 17:37:40 -070045}
46
Austin Schuh9d823002019-04-14 12:53:17 -070047TEST_CASE("shouldHandleNewLinesInStrings", "[JsonTests]") {
Austin Schuh24adb6b2015-09-06 17:37:40 -070048 std::stringstream str;
49 jsonToStream(str, "I have\nnew\rlines");
Austin Schuh9d823002019-04-14 12:53:17 -070050 CHECK(str.str() == "\"I have\\nnew\\rlines\"");
Austin Schuh24adb6b2015-09-06 17:37:40 -070051}
52
Austin Schuh9d823002019-04-14 12:53:17 -070053TEST_CASE("shouldHandleAsciiStrings", "[JsonTests]") {
54 std::stringstream str;
55 jsonToStream(str, "0123xyz!$%(/)=_-");
56 CHECK(str.str() == R"("0123xyz!$%(/)=_-")");
57}
58
59TEST_CASE("shouldHandleCrazyChars", "[JsonTests]") {
Austin Schuh24adb6b2015-09-06 17:37:40 -070060 std::stringstream str;
61 jsonToStream(str, "\x01\x02\x1f");
Austin Schuh9d823002019-04-14 12:53:17 -070062 CHECK(str.str() == "\"\\u0001\\u0002\\u001f\"");
Austin Schuh24adb6b2015-09-06 17:37:40 -070063}
64
Austin Schuh9d823002019-04-14 12:53:17 -070065TEST_CASE("shouldHandleDate", "[JsonTests]") {
Austin Schuh24adb6b2015-09-06 17:37:40 -070066 std::stringstream str;
67 jsonToStream(str, EpochTimeAsLocal(209001600));
Austin Schuh9d823002019-04-14 12:53:17 -070068 CHECK(str.str() == "new Date(209001600000).toLocaleString()");
69}
70
71TEST_CASE("shouldHandleNonAsciiChars", "[JsonTests]") {
72 std::stringstream str;
73 jsonToStream(str, "§");
74 CHECK(str.str() == R"("§")");
Austin Schuh24adb6b2015-09-06 17:37:40 -070075}
76
77struct Object {
Austin Schuh9d823002019-04-14 12:53:17 -070078 void jsonToStream(std::ostream& ostr) const {
Austin Schuh24adb6b2015-09-06 17:37:40 -070079 ostr << makeMap("object", true);
80 }
81 // Clang is pernickity about this. We don't want use this function
82 // but it's here to catch errors where we accidentally use it instead of the
83 // jsonToStream.
Austin Schuh9d823002019-04-14 12:53:17 -070084 friend std::ostream& operator<<(std::ostream& o, const Object&) {
Austin Schuh24adb6b2015-09-06 17:37:40 -070085 return o << "Not this one";
86 }
87};
88
89struct Object2 {
Austin Schuh9d823002019-04-14 12:53:17 -070090 friend std::ostream& operator<<(std::ostream& o, const Object2&) {
Austin Schuh24adb6b2015-09-06 17:37:40 -070091 return o << "This is object 2";
92 }
93};
94
95static_assert(is_streamable<Object2>::value, "Should be streamable");
96
Austin Schuh9d823002019-04-14 12:53:17 -070097TEST_CASE("shouldHandleCustomObjects", "[JsonTests]") {
98 CHECK(makeMap("obj", Object()) == R"({"obj":{"object":true}})");
Austin Schuh24adb6b2015-09-06 17:37:40 -070099 Object o;
Austin Schuh9d823002019-04-14 12:53:17 -0700100 CHECK(makeMap("obj", o) == R"({"obj":{"object":true}})");
101 CHECK(makeMap("obj", Object2()) == R"({"obj":"This is object 2"})");
Austin Schuh24adb6b2015-09-06 17:37:40 -0700102 Object2 o2;
Austin Schuh9d823002019-04-14 12:53:17 -0700103 CHECK(makeMap("obj", o2) == R"({"obj":"This is object 2"})");
Austin Schuh24adb6b2015-09-06 17:37:40 -0700104 // Putting a clang-specific pragma to thwart the unused warning in Object
105 // upsets GCC...so we just put a test for this to ensure it's used.
106 std::ostringstream ost;
107 ost << Object();
Austin Schuh9d823002019-04-14 12:53:17 -0700108 CHECK(ost.str() == "Not this one"); // See comment
Austin Schuh24adb6b2015-09-06 17:37:40 -0700109}
110
Austin Schuh9d823002019-04-14 12:53:17 -0700111TEST_CASE("to_json", "[JsonTests]") {
112 CHECK(to_json(1) == "1");
113 CHECK(to_json(3.14) == "3.14");
114 CHECK(to_json("hello") == "\"hello\"");
115 CHECK(to_json(Object()) == R"({"object":true})");
116 CHECK(to_json(Object2()) == R"("This is object 2")");
Austin Schuh24adb6b2015-09-06 17:37:40 -0700117}
118
Austin Schuh9d823002019-04-14 12:53:17 -0700119TEST_CASE("handlesArrays", "[JsonTests]") {
120 CHECK(makeArray() == R"([])");
121 CHECK(makeArray(1) == R"([1])");
122 CHECK(makeArray(1, 2, 3) == R"([1,2,3])");
123 CHECK(makeArray({1, 2, 3}) == R"([1,2,3])");
124 CHECK(makeArray("abc") == R"(["abc"])");
125 CHECK(makeArray("a", "b", "c") == R"(["a","b","c"])");
126 CHECK(makeArray({"a", "b", "c"}) == R"(["a","b","c"])");
127 std::vector<JsonnedString> strs = {to_json(false), to_json(true)};
128 CHECK(makeArrayFromContainer(strs) == R"([false,true])");
129}
130
131TEST_CASE("handlesMaps", "[JsonTests]") {
132 using namespace Catch::Matchers;
133
Austin Schuh24adb6b2015-09-06 17:37:40 -0700134 std::map<std::string, JsonnedString> ordMap;
135 ordMap["hello"] = to_json(true);
136 ordMap["goodbye"] = to_json(false);
Austin Schuh9d823002019-04-14 12:53:17 -0700137 CHECK(makeMapFromContainer(ordMap) == R"({"goodbye":false,"hello":true})");
Austin Schuh24adb6b2015-09-06 17:37:40 -0700138 std::map<std::string, JsonnedString> unordMap;
139 unordMap["hello"] = to_json(true);
140 unordMap["goodbye"] = to_json(false);
Austin Schuh9d823002019-04-14 12:53:17 -0700141 CHECK_THAT(makeMapFromContainer(unordMap), Catch::Equals(R"({"goodbye":false,"hello":true})") || Catch::Equals(R"({"hello":true,"goodbye":false})"));
Austin Schuh24adb6b2015-09-06 17:37:40 -0700142}
143
144}