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
13class JsonFileWriter
14{
15public:
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
60class JsonStringWriter
61{
62public:
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
81template<typename T>
82class JsonWriters : public testing::Test
83{
84public:
85 T Impl;
86};
87
88using JsonWriterTestFixures = ::testing::Types<JsonFileWriter, JsonStringWriter>;
89TYPED_TEST_SUITE(JsonWriters, JsonWriterTestFixures);
90
91TYPED_TEST(JsonWriters, Empty)
92{
93 this->Impl.Expect("\n");
94}
95
96TYPED_TEST(JsonWriters, EmptyObject)
97{
98 this->Impl.m_pJson->BeginObject();
99 this->Impl.m_pJson->EndObject();
100 this->Impl.Expect("{\n}\n");
101}
102
103TYPED_TEST(JsonWriters, EmptyArray)
104{
105 this->Impl.m_pJson->BeginArray();
106 this->Impl.m_pJson->EndArray();
107 this->Impl.Expect("[\n]\n");
108}
109
110TYPED_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
126TYPED_TEST(JsonWriters, HelloWorld)
127{
128 this->Impl.m_pJson->WriteStrValue("hello world");
129 this->Impl.Expect("\"hello world\"\n");
130}
131
132TYPED_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
138TYPED_TEST(JsonWriters, True)
139{
140 this->Impl.m_pJson->WriteBoolValue(true);
141 this->Impl.Expect("true\n");
142}
143
144TYPED_TEST(JsonWriters, False)
145{
146 this->Impl.m_pJson->WriteBoolValue(false);
147 this->Impl.Expect("false\n");
148}
149
150TYPED_TEST(JsonWriters, Null)
151{
152 this->Impl.m_pJson->WriteNullValue();
153 this->Impl.Expect("null\n");
154}
155
156TYPED_TEST(JsonWriters, EmptyString)
157{
158 this->Impl.m_pJson->WriteStrValue("");
159 this->Impl.Expect("\"\"\n");
160}
161
162TYPED_TEST(JsonWriters, EscapeNewline)
163{
164 this->Impl.m_pJson->WriteStrValue("\n");
165 this->Impl.Expect("\"\\n\"\n");
166}
167
168TYPED_TEST(JsonWriters, EscapeBackslash)
169{
170 this->Impl.m_pJson->WriteStrValue("\\");
171 this->Impl.Expect("\"\\\\\"\n"); // https://www.xkcd.com/1638/
172}
173
174TYPED_TEST(JsonWriters, EscapeControl)
175{
176 this->Impl.m_pJson->WriteStrValue("\x1b");
177 this->Impl.Expect("\"\\u001b\"\n");
178}
179
180TYPED_TEST(JsonWriters, EscapeUnicode)
181{
182 this->Impl.m_pJson->WriteStrValue("愛😂");
183 this->Impl.Expect("\"愛😂\"\n");
184}
185
186TYPED_TEST(JsonWriters, Zero)
187{
188 this->Impl.m_pJson->WriteIntValue(0);
189 this->Impl.Expect("0\n");
190}
191
192TYPED_TEST(JsonWriters, One)
193{
194 this->Impl.m_pJson->WriteIntValue(1);
195 this->Impl.Expect("1\n");
196}
197
198TYPED_TEST(JsonWriters, MinusOne)
199{
200 this->Impl.m_pJson->WriteIntValue(-1);
201 this->Impl.Expect("-1\n");
202}
203
204TYPED_TEST(JsonWriters, Large)
205{
206 this->Impl.m_pJson->WriteIntValue(std::numeric_limits<int>::max());
207 this->Impl.Expect("2147483647\n");
208}
209
210TYPED_TEST(JsonWriters, Small)
211{
212 this->Impl.m_pJson->WriteIntValue(std::numeric_limits<int>::min());
213 this->Impl.Expect("-2147483648\n");
214}
215