Austin Schuh | 9d82300 | 2019-04-14 12:53:17 -0700 | [diff] [blame^] | 1 | // Copyright (c) 2013-2017, Matt Godbolt |
Austin Schuh | 24adb6b | 2015-09-06 17:37:40 -0700 | [diff] [blame] | 2 | // All rights reserved. |
Austin Schuh | 9d82300 | 2019-04-14 12:53:17 -0700 | [diff] [blame^] | 3 | // |
| 4 | // Redistribution and use in source and binary forms, with or without |
Austin Schuh | 24adb6b | 2015-09-06 17:37:40 -0700 | [diff] [blame] | 5 | // modification, are permitted provided that the following conditions are met: |
Austin Schuh | 9d82300 | 2019-04-14 12:53:17 -0700 | [diff] [blame^] | 6 | // |
| 7 | // Redistributions of source code must retain the above copyright notice, this |
Austin Schuh | 24adb6b | 2015-09-06 17:37:40 -0700 | [diff] [blame] | 8 | // list of conditions and the following disclaimer. |
Austin Schuh | 9d82300 | 2019-04-14 12:53:17 -0700 | [diff] [blame^] | 9 | // |
| 10 | // Redistributions in binary form must reproduce the above copyright notice, |
| 11 | // this list of conditions and the following disclaimer in the documentation |
Austin Schuh | 24adb6b | 2015-09-06 17:37:40 -0700 | [diff] [blame] | 12 | // and/or other materials provided with the distribution. |
Austin Schuh | 9d82300 | 2019-04-14 12:53:17 -0700 | [diff] [blame^] | 13 | // |
| 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 Schuh | 24adb6b | 2015-09-06 17:37:40 -0700 | [diff] [blame] | 24 | // POSSIBILITY OF SUCH DAMAGE. |
| 25 | |
| 26 | #include "seasocks/util/Json.h" |
| 27 | |
Austin Schuh | 9d82300 | 2019-04-14 12:53:17 -0700 | [diff] [blame^] | 28 | #include <catch2/catch.hpp> |
| 29 | |
Austin Schuh | 24adb6b | 2015-09-06 17:37:40 -0700 | [diff] [blame] | 30 | #include <ostream> |
| 31 | #include <map> |
| 32 | #include <unordered_map> |
| 33 | |
Austin Schuh | 24adb6b | 2015-09-06 17:37:40 -0700 | [diff] [blame] | 34 | using namespace seasocks; |
| 35 | |
| 36 | namespace { |
| 37 | |
Austin Schuh | 9d82300 | 2019-04-14 12:53:17 -0700 | [diff] [blame^] | 38 | TEST_CASE("shouldHandleMaps", "[JsonTests]") { |
| 39 | CHECK(makeMap("monkey", 12) == "{\"monkey\":12}"); |
Austin Schuh | 24adb6b | 2015-09-06 17:37:40 -0700 | [diff] [blame] | 40 | } |
| 41 | |
Austin Schuh | 9d82300 | 2019-04-14 12:53:17 -0700 | [diff] [blame^] | 42 | TEST_CASE("shouldHandleQuotedStrings", "[JsonTests]") { |
| 43 | CHECK(makeMap("key", "I have \"quotes\"") == |
| 44 | "{\"key\":\"I have \\\"quotes\\\"\"}"); |
Austin Schuh | 24adb6b | 2015-09-06 17:37:40 -0700 | [diff] [blame] | 45 | } |
| 46 | |
Austin Schuh | 9d82300 | 2019-04-14 12:53:17 -0700 | [diff] [blame^] | 47 | TEST_CASE("shouldHandleNewLinesInStrings", "[JsonTests]") { |
Austin Schuh | 24adb6b | 2015-09-06 17:37:40 -0700 | [diff] [blame] | 48 | std::stringstream str; |
| 49 | jsonToStream(str, "I have\nnew\rlines"); |
Austin Schuh | 9d82300 | 2019-04-14 12:53:17 -0700 | [diff] [blame^] | 50 | CHECK(str.str() == "\"I have\\nnew\\rlines\""); |
Austin Schuh | 24adb6b | 2015-09-06 17:37:40 -0700 | [diff] [blame] | 51 | } |
| 52 | |
Austin Schuh | 9d82300 | 2019-04-14 12:53:17 -0700 | [diff] [blame^] | 53 | TEST_CASE("shouldHandleAsciiStrings", "[JsonTests]") { |
| 54 | std::stringstream str; |
| 55 | jsonToStream(str, "0123xyz!$%(/)=_-"); |
| 56 | CHECK(str.str() == R"("0123xyz!$%(/)=_-")"); |
| 57 | } |
| 58 | |
| 59 | TEST_CASE("shouldHandleCrazyChars", "[JsonTests]") { |
Austin Schuh | 24adb6b | 2015-09-06 17:37:40 -0700 | [diff] [blame] | 60 | std::stringstream str; |
| 61 | jsonToStream(str, "\x01\x02\x1f"); |
Austin Schuh | 9d82300 | 2019-04-14 12:53:17 -0700 | [diff] [blame^] | 62 | CHECK(str.str() == "\"\\u0001\\u0002\\u001f\""); |
Austin Schuh | 24adb6b | 2015-09-06 17:37:40 -0700 | [diff] [blame] | 63 | } |
| 64 | |
Austin Schuh | 9d82300 | 2019-04-14 12:53:17 -0700 | [diff] [blame^] | 65 | TEST_CASE("shouldHandleDate", "[JsonTests]") { |
Austin Schuh | 24adb6b | 2015-09-06 17:37:40 -0700 | [diff] [blame] | 66 | std::stringstream str; |
| 67 | jsonToStream(str, EpochTimeAsLocal(209001600)); |
Austin Schuh | 9d82300 | 2019-04-14 12:53:17 -0700 | [diff] [blame^] | 68 | CHECK(str.str() == "new Date(209001600000).toLocaleString()"); |
| 69 | } |
| 70 | |
| 71 | TEST_CASE("shouldHandleNonAsciiChars", "[JsonTests]") { |
| 72 | std::stringstream str; |
| 73 | jsonToStream(str, "§"); |
| 74 | CHECK(str.str() == R"("§")"); |
Austin Schuh | 24adb6b | 2015-09-06 17:37:40 -0700 | [diff] [blame] | 75 | } |
| 76 | |
| 77 | struct Object { |
Austin Schuh | 9d82300 | 2019-04-14 12:53:17 -0700 | [diff] [blame^] | 78 | void jsonToStream(std::ostream& ostr) const { |
Austin Schuh | 24adb6b | 2015-09-06 17:37:40 -0700 | [diff] [blame] | 79 | 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 Schuh | 9d82300 | 2019-04-14 12:53:17 -0700 | [diff] [blame^] | 84 | friend std::ostream& operator<<(std::ostream& o, const Object&) { |
Austin Schuh | 24adb6b | 2015-09-06 17:37:40 -0700 | [diff] [blame] | 85 | return o << "Not this one"; |
| 86 | } |
| 87 | }; |
| 88 | |
| 89 | struct Object2 { |
Austin Schuh | 9d82300 | 2019-04-14 12:53:17 -0700 | [diff] [blame^] | 90 | friend std::ostream& operator<<(std::ostream& o, const Object2&) { |
Austin Schuh | 24adb6b | 2015-09-06 17:37:40 -0700 | [diff] [blame] | 91 | return o << "This is object 2"; |
| 92 | } |
| 93 | }; |
| 94 | |
| 95 | static_assert(is_streamable<Object2>::value, "Should be streamable"); |
| 96 | |
Austin Schuh | 9d82300 | 2019-04-14 12:53:17 -0700 | [diff] [blame^] | 97 | TEST_CASE("shouldHandleCustomObjects", "[JsonTests]") { |
| 98 | CHECK(makeMap("obj", Object()) == R"({"obj":{"object":true}})"); |
Austin Schuh | 24adb6b | 2015-09-06 17:37:40 -0700 | [diff] [blame] | 99 | Object o; |
Austin Schuh | 9d82300 | 2019-04-14 12:53:17 -0700 | [diff] [blame^] | 100 | CHECK(makeMap("obj", o) == R"({"obj":{"object":true}})"); |
| 101 | CHECK(makeMap("obj", Object2()) == R"({"obj":"This is object 2"})"); |
Austin Schuh | 24adb6b | 2015-09-06 17:37:40 -0700 | [diff] [blame] | 102 | Object2 o2; |
Austin Schuh | 9d82300 | 2019-04-14 12:53:17 -0700 | [diff] [blame^] | 103 | CHECK(makeMap("obj", o2) == R"({"obj":"This is object 2"})"); |
Austin Schuh | 24adb6b | 2015-09-06 17:37:40 -0700 | [diff] [blame] | 104 | // 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 Schuh | 9d82300 | 2019-04-14 12:53:17 -0700 | [diff] [blame^] | 108 | CHECK(ost.str() == "Not this one"); // See comment |
Austin Schuh | 24adb6b | 2015-09-06 17:37:40 -0700 | [diff] [blame] | 109 | } |
| 110 | |
Austin Schuh | 9d82300 | 2019-04-14 12:53:17 -0700 | [diff] [blame^] | 111 | TEST_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 Schuh | 24adb6b | 2015-09-06 17:37:40 -0700 | [diff] [blame] | 117 | } |
| 118 | |
Austin Schuh | 9d82300 | 2019-04-14 12:53:17 -0700 | [diff] [blame^] | 119 | TEST_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 | |
| 131 | TEST_CASE("handlesMaps", "[JsonTests]") { |
| 132 | using namespace Catch::Matchers; |
| 133 | |
Austin Schuh | 24adb6b | 2015-09-06 17:37:40 -0700 | [diff] [blame] | 134 | std::map<std::string, JsonnedString> ordMap; |
| 135 | ordMap["hello"] = to_json(true); |
| 136 | ordMap["goodbye"] = to_json(false); |
Austin Schuh | 9d82300 | 2019-04-14 12:53:17 -0700 | [diff] [blame^] | 137 | CHECK(makeMapFromContainer(ordMap) == R"({"goodbye":false,"hello":true})"); |
Austin Schuh | 24adb6b | 2015-09-06 17:37:40 -0700 | [diff] [blame] | 138 | std::map<std::string, JsonnedString> unordMap; |
| 139 | unordMap["hello"] = to_json(true); |
| 140 | unordMap["goodbye"] = to_json(false); |
Austin Schuh | 9d82300 | 2019-04-14 12:53:17 -0700 | [diff] [blame^] | 141 | CHECK_THAT(makeMapFromContainer(unordMap), Catch::Equals(R"({"goodbye":false,"hello":true})") || Catch::Equals(R"({"hello":true,"goodbye":false})")); |
Austin Schuh | 24adb6b | 2015-09-06 17:37:40 -0700 | [diff] [blame] | 142 | } |
| 143 | |
| 144 | } |