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