| 1 | /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ |
| 2 | /* If you are missing that file, acquire a complete release at teeworlds.com. */ |
| 3 | #include "test.h" |
| 4 | |
| 5 | #include <base/system.h> |
| 6 | |
| 7 | #include <engine/shared/jsonwriter.h> |
| 8 | |
| 9 | #include <gtest/gtest.h> |
| 10 | |
| 11 | #include <limits> |
| 12 | |
| 13 | class JsonFileWriter |
| 14 | { |
| 15 | public: |
| 16 | CTestInfo m_Info; |
| 17 | CJsonFileWriter *m_pJson; |
| 18 | char m_aOutputFilename[IO_MAX_PATH_LENGTH]; |
| 19 | |
| 20 | JsonFileWriter() : |
| 21 | m_pJson(nullptr) |
| 22 | { |
| 23 | m_Info.Filename(pBuffer: m_aOutputFilename, BufferLength: sizeof(m_aOutputFilename), pSuffix: "-got.json" ); |
| 24 | IOHANDLE File = io_open(filename: m_aOutputFilename, flags: IOFLAG_WRITE); |
| 25 | EXPECT_TRUE(File); |
| 26 | m_pJson = new CJsonFileWriter(File); |
| 27 | } |
| 28 | |
| 29 | void Expect(const char *pExpected) |
| 30 | { |
| 31 | ASSERT_TRUE(m_pJson); |
| 32 | delete m_pJson; |
| 33 | m_pJson = nullptr; |
| 34 | |
| 35 | IOHANDLE GotFile = io_open(filename: m_aOutputFilename, flags: IOFLAG_READ); |
| 36 | ASSERT_TRUE(GotFile); |
| 37 | char *pOutput = io_read_all_str(io: GotFile); |
| 38 | io_close(io: GotFile); |
| 39 | ASSERT_TRUE(pOutput); |
| 40 | EXPECT_STREQ(pOutput, pExpected); |
| 41 | bool Correct = str_comp(a: pOutput, b: pExpected) == 0; |
| 42 | free(ptr: pOutput); |
| 43 | |
| 44 | if(!Correct) |
| 45 | { |
| 46 | char aFilename[IO_MAX_PATH_LENGTH]; |
| 47 | m_Info.Filename(pBuffer: aFilename, BufferLength: sizeof(aFilename), pSuffix: "-expected.json" ); |
| 48 | IOHANDLE ExpectedFile = io_open(filename: aFilename, flags: IOFLAG_WRITE); |
| 49 | ASSERT_TRUE(ExpectedFile); |
| 50 | io_write(io: ExpectedFile, buffer: pExpected, size: str_length(str: pExpected)); |
| 51 | io_close(io: ExpectedFile); |
| 52 | } |
| 53 | else |
| 54 | { |
| 55 | fs_remove(filename: m_aOutputFilename); |
| 56 | } |
| 57 | } |
| 58 | }; |
| 59 | |
| 60 | class JsonStringWriter |
| 61 | { |
| 62 | public: |
| 63 | CJsonStringWriter *m_pJson; |
| 64 | |
| 65 | JsonStringWriter() : |
| 66 | m_pJson(nullptr) |
| 67 | { |
| 68 | m_pJson = new CJsonStringWriter(); |
| 69 | } |
| 70 | |
| 71 | void Expect(const char *pExpected) |
| 72 | { |
| 73 | ASSERT_TRUE(m_pJson); |
| 74 | const std::string OutputString = m_pJson->GetOutputString(); |
| 75 | EXPECT_STREQ(OutputString.c_str(), pExpected); |
| 76 | delete m_pJson; |
| 77 | m_pJson = nullptr; |
| 78 | } |
| 79 | }; |
| 80 | |
| 81 | template<typename T> |
| 82 | class JsonWriters : public testing::Test |
| 83 | { |
| 84 | public: |
| 85 | T Impl; |
| 86 | }; |
| 87 | |
| 88 | using JsonWriterTestFixures = ::testing::Types<JsonFileWriter, JsonStringWriter>; |
| 89 | TYPED_TEST_SUITE(JsonWriters, JsonWriterTestFixures); |
| 90 | |
| 91 | TYPED_TEST(JsonWriters, Empty) |
| 92 | { |
| 93 | this->Impl.Expect("\n" ); |
| 94 | } |
| 95 | |
| 96 | TYPED_TEST(JsonWriters, EmptyObject) |
| 97 | { |
| 98 | this->Impl.m_pJson->BeginObject(); |
| 99 | this->Impl.m_pJson->EndObject(); |
| 100 | this->Impl.Expect("{\n}\n" ); |
| 101 | } |
| 102 | |
| 103 | TYPED_TEST(JsonWriters, EmptyArray) |
| 104 | { |
| 105 | this->Impl.m_pJson->BeginArray(); |
| 106 | this->Impl.m_pJson->EndArray(); |
| 107 | this->Impl.Expect("[\n]\n" ); |
| 108 | } |
| 109 | |
| 110 | TYPED_TEST(JsonWriters, SpecialCharacters) |
| 111 | { |
| 112 | this->Impl.m_pJson->BeginObject(); |
| 113 | this->Impl.m_pJson->WriteAttribute("\x01\"'\r\n\t" ); |
| 114 | this->Impl.m_pJson->BeginArray(); |
| 115 | this->Impl.m_pJson->WriteStrValue(" \"'abc\x01\n" ); |
| 116 | this->Impl.m_pJson->EndArray(); |
| 117 | this->Impl.m_pJson->EndObject(); |
| 118 | this->Impl.Expect( |
| 119 | "{\n" |
| 120 | "\t\"\\u0001\\\"'\\r\\n\\t\": [\n" |
| 121 | "\t\t\" \\\"'abc\\u0001\\n\"\n" |
| 122 | "\t]\n" |
| 123 | "}\n" ); |
| 124 | } |
| 125 | |
| 126 | TYPED_TEST(JsonWriters, HelloWorld) |
| 127 | { |
| 128 | this->Impl.m_pJson->WriteStrValue("hello world" ); |
| 129 | this->Impl.Expect("\"hello world\"\n" ); |
| 130 | } |
| 131 | |
| 132 | TYPED_TEST(JsonWriters, Unicode) |
| 133 | { |
| 134 | this->Impl.m_pJson->WriteStrValue("Heizölrückstoßabdämpfung" ); |
| 135 | this->Impl.Expect("\"Heizölrückstoßabdämpfung\"\n" ); |
| 136 | } |
| 137 | |
| 138 | TYPED_TEST(JsonWriters, True) |
| 139 | { |
| 140 | this->Impl.m_pJson->WriteBoolValue(true); |
| 141 | this->Impl.Expect("true\n" ); |
| 142 | } |
| 143 | |
| 144 | TYPED_TEST(JsonWriters, False) |
| 145 | { |
| 146 | this->Impl.m_pJson->WriteBoolValue(false); |
| 147 | this->Impl.Expect("false\n" ); |
| 148 | } |
| 149 | |
| 150 | TYPED_TEST(JsonWriters, Null) |
| 151 | { |
| 152 | this->Impl.m_pJson->WriteNullValue(); |
| 153 | this->Impl.Expect("null\n" ); |
| 154 | } |
| 155 | |
| 156 | TYPED_TEST(JsonWriters, EmptyString) |
| 157 | { |
| 158 | this->Impl.m_pJson->WriteStrValue("" ); |
| 159 | this->Impl.Expect("\"\"\n" ); |
| 160 | } |
| 161 | |
| 162 | TYPED_TEST(JsonWriters, EscapeNewline) |
| 163 | { |
| 164 | this->Impl.m_pJson->WriteStrValue("\n" ); |
| 165 | this->Impl.Expect("\"\\n\"\n" ); |
| 166 | } |
| 167 | |
| 168 | TYPED_TEST(JsonWriters, EscapeBackslash) |
| 169 | { |
| 170 | this->Impl.m_pJson->WriteStrValue("\\" ); |
| 171 | this->Impl.Expect("\"\\\\\"\n" ); // https://www.xkcd.com/1638/ |
| 172 | } |
| 173 | |
| 174 | TYPED_TEST(JsonWriters, EscapeControl) |
| 175 | { |
| 176 | this->Impl.m_pJson->WriteStrValue("\x1b" ); |
| 177 | this->Impl.Expect("\"\\u001b\"\n" ); |
| 178 | } |
| 179 | |
| 180 | TYPED_TEST(JsonWriters, EscapeUnicode) |
| 181 | { |
| 182 | this->Impl.m_pJson->WriteStrValue("愛😂" ); |
| 183 | this->Impl.Expect("\"愛😂\"\n" ); |
| 184 | } |
| 185 | |
| 186 | TYPED_TEST(JsonWriters, Zero) |
| 187 | { |
| 188 | this->Impl.m_pJson->WriteIntValue(0); |
| 189 | this->Impl.Expect("0\n" ); |
| 190 | } |
| 191 | |
| 192 | TYPED_TEST(JsonWriters, One) |
| 193 | { |
| 194 | this->Impl.m_pJson->WriteIntValue(1); |
| 195 | this->Impl.Expect("1\n" ); |
| 196 | } |
| 197 | |
| 198 | TYPED_TEST(JsonWriters, MinusOne) |
| 199 | { |
| 200 | this->Impl.m_pJson->WriteIntValue(-1); |
| 201 | this->Impl.Expect("-1\n" ); |
| 202 | } |
| 203 | |
| 204 | TYPED_TEST(JsonWriters, Large) |
| 205 | { |
| 206 | this->Impl.m_pJson->WriteIntValue(std::numeric_limits<int>::max()); |
| 207 | this->Impl.Expect("2147483647\n" ); |
| 208 | } |
| 209 | |
| 210 | TYPED_TEST(JsonWriters, Small) |
| 211 | { |
| 212 | this->Impl.m_pJson->WriteIntValue(std::numeric_limits<int>::min()); |
| 213 | this->Impl.Expect("-2147483648\n" ); |
| 214 | } |
| 215 | |