3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include "util/string.h"
23 #include "util/serialize.h"
26 class TestSerialization : public TestBase {
28 TestSerialization() { TestManager::registerTestModule(this); }
29 const char *getName() { return "TestSerialization"; }
31 void runTests(IGameDef *gamedef);
32 void buildTestStrings();
34 void testSerializeString();
35 void testSerializeLongString();
36 void testSerializeJsonString();
37 void testDeSerializeString();
38 void testDeSerializeLongString();
39 void testStreamRead();
40 void testStreamWrite();
41 void testFloatFormat();
43 std::string teststring2;
44 std::wstring teststring2_w;
45 std::string teststring2_w_encoded;
47 static const u8 test_serialized_data[12 * 11 - 2];
50 static TestSerialization g_test_instance;
52 void TestSerialization::runTests(IGameDef *gamedef)
56 TEST(testSerializeString);
57 TEST(testDeSerializeString);
58 TEST(testSerializeLongString);
59 TEST(testDeSerializeLongString);
60 TEST(testSerializeJsonString);
62 TEST(testStreamWrite);
63 TEST(testFloatFormat);
66 ////////////////////////////////////////////////////////////////////////////////
68 // To be used like this:
69 // mkstr("Some\0string\0with\0embedded\0nuls")
70 // since std::string("...") doesn't work as expected in that case.
71 template<size_t N> std::string mkstr(const char (&s)[N])
73 return std::string(s, N - 1);
76 void TestSerialization::buildTestStrings()
78 std::ostringstream tmp_os;
79 std::wostringstream tmp_os_w;
80 std::ostringstream tmp_os_w_encoded;
81 for (int i = 0; i < 256; i++) {
83 tmp_os_w << (wchar_t)i;
84 tmp_os_w_encoded << (char)0 << (char)i;
86 teststring2 = tmp_os.str();
87 teststring2_w = tmp_os_w.str();
88 teststring2_w_encoded = tmp_os_w_encoded.str();
91 void TestSerialization::testSerializeString()
94 UASSERT(serializeString16("") == mkstr("\0\0"));
97 UASSERT(serializeString16("Hello world!") == mkstr("\0\14Hello world!"));
99 // Test character range
100 UASSERT(serializeString16(teststring2) == mkstr("\1\0") + teststring2);
103 void TestSerialization::testDeSerializeString()
107 std::istringstream is(serializeString16(teststring2), std::ios::binary);
108 UASSERT(deSerializeString16(is) == teststring2);
114 // Test deserialize an incomplete length specifier
116 std::istringstream is(mkstr("\x53"), std::ios::binary);
117 EXCEPTION_CHECK(SerializationError, deSerializeString16(is));
120 // Test deserialize a string with incomplete data
122 std::istringstream is(mkstr("\x00\x55 abcdefg"), std::ios::binary);
123 EXCEPTION_CHECK(SerializationError, deSerializeString16(is));
127 void TestSerialization::testSerializeLongString()
130 UASSERT(serializeString32("") == mkstr("\0\0\0\0"));
133 UASSERT(serializeString32("Hello world!") == mkstr("\0\0\0\14Hello world!"));
135 // Test character range
136 UASSERT(serializeString32(teststring2) == mkstr("\0\0\1\0") + teststring2);
139 void TestSerialization::testDeSerializeLongString()
143 std::istringstream is(serializeString32(teststring2), std::ios::binary);
144 UASSERT(deSerializeString32(is) == teststring2);
150 // Test deserialize an incomplete length specifier
152 std::istringstream is(mkstr("\x53"), std::ios::binary);
153 EXCEPTION_CHECK(SerializationError, deSerializeString32(is));
156 // Test deserialize a string with incomplete data
158 std::istringstream is(mkstr("\x00\x00\x00\x05 abc"), std::ios::binary);
159 EXCEPTION_CHECK(SerializationError, deSerializeString32(is));
162 // Test deserialize a string with a length too large
164 std::istringstream is(mkstr("\xFF\xFF\xFF\xFF blah"), std::ios::binary);
165 EXCEPTION_CHECK(SerializationError, deSerializeString32(is));
170 void TestSerialization::testSerializeJsonString()
173 UASSERT(serializeJsonString("") == "\"\"");
176 UASSERT(serializeJsonString("Hello world!") == "\"Hello world!\"");
178 // MSVC fails when directly using "\\\\"
179 std::string backslash = "\\";
180 UASSERT(serializeJsonString(teststring2) ==
182 "\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007" +
183 "\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f" +
184 "\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017" +
185 "\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f" +
186 " !\\\"" + teststring2.substr(0x23, 0x2f-0x23) +
187 "\\/" + teststring2.substr(0x30, 0x5c-0x30) +
188 backslash + backslash + teststring2.substr(0x5d, 0x7f-0x5d) + "\\u007f" +
189 "\\u0080\\u0081\\u0082\\u0083\\u0084\\u0085\\u0086\\u0087" +
190 "\\u0088\\u0089\\u008a\\u008b\\u008c\\u008d\\u008e\\u008f" +
191 "\\u0090\\u0091\\u0092\\u0093\\u0094\\u0095\\u0096\\u0097" +
192 "\\u0098\\u0099\\u009a\\u009b\\u009c\\u009d\\u009e\\u009f" +
193 "\\u00a0\\u00a1\\u00a2\\u00a3\\u00a4\\u00a5\\u00a6\\u00a7" +
194 "\\u00a8\\u00a9\\u00aa\\u00ab\\u00ac\\u00ad\\u00ae\\u00af" +
195 "\\u00b0\\u00b1\\u00b2\\u00b3\\u00b4\\u00b5\\u00b6\\u00b7" +
196 "\\u00b8\\u00b9\\u00ba\\u00bb\\u00bc\\u00bd\\u00be\\u00bf" +
197 "\\u00c0\\u00c1\\u00c2\\u00c3\\u00c4\\u00c5\\u00c6\\u00c7" +
198 "\\u00c8\\u00c9\\u00ca\\u00cb\\u00cc\\u00cd\\u00ce\\u00cf" +
199 "\\u00d0\\u00d1\\u00d2\\u00d3\\u00d4\\u00d5\\u00d6\\u00d7" +
200 "\\u00d8\\u00d9\\u00da\\u00db\\u00dc\\u00dd\\u00de\\u00df" +
201 "\\u00e0\\u00e1\\u00e2\\u00e3\\u00e4\\u00e5\\u00e6\\u00e7" +
202 "\\u00e8\\u00e9\\u00ea\\u00eb\\u00ec\\u00ed\\u00ee\\u00ef" +
203 "\\u00f0\\u00f1\\u00f2\\u00f3\\u00f4\\u00f5\\u00f6\\u00f7" +
204 "\\u00f8\\u00f9\\u00fa\\u00fb\\u00fc\\u00fd\\u00fe\\u00ff" +
208 std::istringstream is(serializeJsonString(teststring2), std::ios::binary);
209 UASSERT(deSerializeJsonString(is) == teststring2);
216 void TestSerialization::testStreamRead()
219 (const char *)test_serialized_data,
220 sizeof(test_serialized_data));
221 std::istringstream is(datastr, std::ios_base::binary);
223 UASSERT(readU8(is) == 0x11);
224 UASSERT(readU16(is) == 0x2233);
225 UASSERT(readU32(is) == 0x44556677);
226 UASSERT(readU64(is) == 0x8899AABBCCDDEEFFLL);
228 UASSERT(readS8(is) == -128);
229 UASSERT(readS16(is) == 30000);
230 UASSERT(readS32(is) == -6);
231 UASSERT(readS64(is) == -43);
233 UASSERT(readF1000(is) == 53.534f);
234 UASSERT(readF1000(is) == -300000.32f);
235 UASSERT(readF1000(is) == F1000_MIN);
236 UASSERT(readF1000(is) == F1000_MAX);
238 UASSERT(deSerializeString16(is) == "foobar!");
240 UASSERT(readV2S16(is) == v2s16(500, 500));
241 UASSERT(readV3S16(is) == v3s16(4207, 604, -30));
242 UASSERT(readV2S32(is) == v2s32(1920, 1080));
243 UASSERT(readV3S32(is) == v3s32(-400, 6400054, 290549855));
245 UASSERT(readV3F1000(is) == v3f(500, 10024.2f, -192.54f));
246 UASSERT(readARGB8(is) == video::SColor(255, 128, 50, 128));
248 UASSERT(deSerializeString32(is) == "some longer string here");
250 UASSERT(is.rdbuf()->in_avail() == 2);
251 UASSERT(readU16(is) == 0xF00D);
252 UASSERT(is.rdbuf()->in_avail() == 0);
256 void TestSerialization::testStreamWrite()
258 std::ostringstream os(std::ios_base::binary);
262 writeU16(os, 0x2233);
263 writeU32(os, 0x44556677);
264 writeU64(os, 0x8899AABBCCDDEEFFLL);
271 writeF1000(os, 53.53467f);
272 writeF1000(os, -300000.32f);
273 writeF1000(os, F1000_MIN);
274 writeF1000(os, F1000_MAX);
276 os << serializeString16("foobar!");
279 UASSERT(data.size() < sizeof(test_serialized_data));
280 UASSERT(!memcmp(&data[0], test_serialized_data, data.size()));
282 writeV2S16(os, v2s16(500, 500));
283 writeV3S16(os, v3s16(4207, 604, -30));
284 writeV2S32(os, v2s32(1920, 1080));
285 writeV3S32(os, v3s32(-400, 6400054, 290549855));
287 writeV3F1000(os, v3f(500, 10024.2f, -192.54f));
288 writeARGB8(os, video::SColor(255, 128, 50, 128));
290 os << serializeString32("some longer string here");
292 writeU16(os, 0xF00D);
295 UASSERT(data.size() == sizeof(test_serialized_data));
296 UASSERT(!memcmp(&data[0], test_serialized_data, sizeof(test_serialized_data)));
300 void TestSerialization::testFloatFormat()
302 FloatType type = getFloatSerializationType();
306 // Check precision of float calculations on this platform
307 const std::unordered_map<f32, u32> float_results = {
308 { 0.0f, 0x00000000UL },
309 { 1.0f, 0x3F800000UL },
310 { -1.0f, 0xBF800000UL },
311 { 0.1f, 0x3DCCCCCDUL },
312 { -0.1f, 0xBDCCCCCDUL },
313 { 1945329.25f, 0x49ED778AUL },
314 { -23298764.f, 0xCBB1C166UL },
315 { 0.5f, 0x3F000000UL },
316 { -0.5f, 0xBF000000UL }
318 for (const auto &v : float_results) {
319 i = f32Tou32Slow(v.first);
320 if (std::abs((s64)v.second - i) > 32) {
321 printf("Inaccurate float values on %.9g, expected 0x%X, actual 0x%X\n",
322 v.first, v.second, i);
326 fs = u32Tof32Slow(v.second);
327 if (std::fabs(v.first - fs) > std::fabs(v.first * 0.000005f)) {
328 printf("Inaccurate float values on 0x%X, expected %.9g, actual 0x%.9g\n",
329 v.second, v.first, fs);
334 if (type == FLOATTYPE_SLOW) {
335 // conversion using memcpy is not possible
336 // Skip exact float comparison checks below
340 // The code below compares the IEEE conversion functions with a
341 // known good IEC559/IEEE754 implementation. This test neeeds
342 // IEC559 compliance in the compiler.
343 #if defined(__GNUC__) && (!defined(__STDC_IEC_559__) || defined(__FAST_MATH__))
344 // GNU C++ lies about its IEC559 support when -ffast-math is active.
345 // https://gcc.gnu.org/bugzilla//show_bug.cgi?id=84949
346 bool is_iec559 = false;
348 bool is_iec559 = std::numeric_limits<f32>::is_iec559;
353 auto test_single = [&fs, &fm](const u32 &i) -> bool {
355 fs = u32Tof32Slow(i);
357 printf("u32Tof32Slow failed on 0x%X, expected %.9g, actual %.9g\n",
361 if (f32Tou32Slow(fs) != i) {
362 printf("f32Tou32Slow failed on %.9g, expected 0x%X, actual 0x%X\n",
363 fs, i, f32Tou32Slow(fs));
369 // Use step of prime 277 to speed things up from 3 minutes to a few seconds
370 // Test from 0 to 0xFF800000UL (positive)
371 for (i = 0x00000000UL; i <= 0x7F800000UL; i += 277)
372 UASSERT(test_single(i));
374 // Ensure +inf and -inf are tested
375 UASSERT(test_single(0x7F800000UL));
376 UASSERT(test_single(0xFF800000UL));
378 // Test from 0x80000000UL to 0xFF800000UL (negative)
379 for (i = 0x80000000UL; i <= 0xFF800000UL; i += 277)
380 UASSERT(test_single(i));
383 const u8 TestSerialization::test_serialized_data[12 * 11 - 2] = {
384 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc,
385 0xdd, 0xee, 0xff, 0x80, 0x75, 0x30, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff,
386 0xff, 0xff, 0xff, 0xff, 0xff, 0xd5, 0x00, 0x00, 0xd1, 0x1e, 0xee, 0x1e,
387 0x5b, 0xc0, 0x80, 0x00, 0x02, 0x80, 0x7F, 0xFF, 0xFD, 0x80, 0x00, 0x07,
388 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72, 0x21, 0x01, 0xf4, 0x01, 0xf4, 0x10,
389 0x6f, 0x02, 0x5c, 0xff, 0xe2, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x04,
390 0x38, 0xff, 0xff, 0xfe, 0x70, 0x00, 0x61, 0xa8, 0x36, 0x11, 0x51, 0x70,
391 0x5f, 0x00, 0x07, 0xa1, 0x20, 0x00, 0x98, 0xf5, 0x08, 0xff,
392 0xfd, 0x0f, 0xe4, 0xff, 0x80, 0x32, 0x80, 0x00, 0x00, 0x00, 0x17, 0x73,
393 0x6f, 0x6d, 0x65, 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x65, 0x72, 0x20, 0x73,
394 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x68, 0x65, 0x72, 0x65, 0xF0, 0x0D,