]> git.lizzy.rs Git - minetest.git/blob - src/unittest/test_utilities.cpp
Add an activeobject manager to hold active objects (#7939)
[minetest.git] / src / unittest / test_utilities.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
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.
9
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.
14
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.
18 */
19
20 #include "test.h"
21
22 #include <cmath>
23 #include "util/numeric.h"
24 #include "util/string.h"
25
26 class TestUtilities : public TestBase {
27 public:
28         TestUtilities() { TestManager::registerTestModule(this); }
29         const char *getName() { return "TestUtilities"; }
30
31         void runTests(IGameDef *gamedef);
32
33         void testAngleWrapAround();
34         void testWrapDegrees_0_360_v3f();
35         void testLowercase();
36         void testTrim();
37         void testIsYes();
38         void testRemoveStringEnd();
39         void testUrlEncode();
40         void testUrlDecode();
41         void testPadString();
42         void testStartsWith();
43         void testStrEqual();
44         void testStringTrim();
45         void testStrToIntConversion();
46         void testStringReplace();
47         void testStringAllowed();
48         void testAsciiPrintableHelper();
49         void testUTF8();
50         void testRemoveEscapes();
51         void testWrapRows();
52         void testIsNumber();
53         void testIsPowerOfTwo();
54         void testMyround();
55         void testStringJoin();
56 };
57
58 static TestUtilities g_test_instance;
59
60 void TestUtilities::runTests(IGameDef *gamedef)
61 {
62         TEST(testAngleWrapAround);
63         TEST(testWrapDegrees_0_360_v3f);
64         TEST(testLowercase);
65         TEST(testTrim);
66         TEST(testIsYes);
67         TEST(testRemoveStringEnd);
68         TEST(testUrlEncode);
69         TEST(testUrlDecode);
70         TEST(testPadString);
71         TEST(testStartsWith);
72         TEST(testStrEqual);
73         TEST(testStringTrim);
74         TEST(testStrToIntConversion);
75         TEST(testStringReplace);
76         TEST(testStringAllowed);
77         TEST(testAsciiPrintableHelper);
78         TEST(testUTF8);
79         TEST(testRemoveEscapes);
80         TEST(testWrapRows);
81         TEST(testIsNumber);
82         TEST(testIsPowerOfTwo);
83         TEST(testMyround);
84         TEST(testStringJoin);
85 }
86
87 ////////////////////////////////////////////////////////////////////////////////
88
89 inline float ref_WrapDegrees180(float f)
90 {
91         // This is a slower alternative to the wrapDegrees_180() function;
92         // used as a reference for testing
93         float value = fmodf(f + 180, 360);
94         if (value < 0)
95                 value += 360;
96         return value - 180;
97 }
98
99
100 inline float ref_WrapDegrees_0_360(float f)
101 {
102         // This is a slower alternative to the wrapDegrees_0_360() function;
103         // used as a reference for testing
104         float value = fmodf(f, 360);
105         if (value < 0)
106                 value += 360;
107         return value < 0 ? value + 360 : value;
108 }
109
110
111 void TestUtilities::testAngleWrapAround() {
112     UASSERT(fabs(modulo360f(100.0) - 100.0) < 0.001);
113     UASSERT(fabs(modulo360f(720.5) - 0.5) < 0.001);
114     UASSERT(fabs(modulo360f(-0.5) - (-0.5)) < 0.001);
115     UASSERT(fabs(modulo360f(-365.5) - (-5.5)) < 0.001);
116
117     for (float f = -720; f <= -360; f += 0.25) {
118         UASSERT(std::fabs(modulo360f(f) - modulo360f(f + 360)) < 0.001);
119     }
120
121     for (float f = -1440; f <= 1440; f += 0.25) {
122         UASSERT(std::fabs(modulo360f(f) - fmodf(f, 360)) < 0.001);
123         UASSERT(std::fabs(wrapDegrees_180(f) - ref_WrapDegrees180(f)) < 0.001);
124         UASSERT(std::fabs(wrapDegrees_0_360(f) - ref_WrapDegrees_0_360(f)) < 0.001);
125         UASSERT(wrapDegrees_0_360(
126                 std::fabs(wrapDegrees_180(f) - wrapDegrees_0_360(f))) < 0.001);
127     }
128
129 }
130
131 void TestUtilities::testWrapDegrees_0_360_v3f()
132 {
133     // only x test with little step
134         for (float x = -720.f; x <= 720; x += 0.05) {
135         v3f r = wrapDegrees_0_360_v3f(v3f(x, 0, 0));
136         UASSERT(r.X >= 0.0f && r.X < 360.0f)
137         UASSERT(r.Y == 0.0f)
138         UASSERT(r.Z == 0.0f)
139     }
140
141     // only y test with little step
142     for (float y = -720.f; y <= 720; y += 0.05) {
143         v3f r = wrapDegrees_0_360_v3f(v3f(0, y, 0));
144         UASSERT(r.X == 0.0f)
145         UASSERT(r.Y >= 0.0f && r.Y < 360.0f)
146         UASSERT(r.Z == 0.0f)
147     }
148
149     // only z test with little step
150     for (float z = -720.f; z <= 720; z += 0.05) {
151         v3f r = wrapDegrees_0_360_v3f(v3f(0, 0, z));
152         UASSERT(r.X == 0.0f)
153         UASSERT(r.Y == 0.0f)
154         UASSERT(r.Z >= 0.0f && r.Z < 360.0f)
155         }
156
157     // test the whole coordinate translation
158     for (float x = -720.f; x <= 720; x += 2.5) {
159         for (float y = -720.f; y <= 720; y += 2.5) {
160             for (float z = -720.f; z <= 720; z += 2.5) {
161                 v3f r = wrapDegrees_0_360_v3f(v3f(x, y, z));
162                 UASSERT(r.X >= 0.0f && r.X < 360.0f)
163                 UASSERT(r.Y >= 0.0f && r.Y < 360.0f)
164                 UASSERT(r.Z >= 0.0f && r.Z < 360.0f)
165             }
166         }
167     }
168 }
169
170
171 void TestUtilities::testLowercase()
172 {
173         UASSERT(lowercase("Foo bAR") == "foo bar");
174         UASSERT(lowercase("eeeeeeaaaaaaaaaaaààààà") == "eeeeeeaaaaaaaaaaaààààà");
175         UASSERT(lowercase("MINETEST-powa") == "minetest-powa");
176 }
177
178
179 void TestUtilities::testTrim()
180 {
181         UASSERT(trim("") == "");
182         UASSERT(trim("dirt_with_grass") == "dirt_with_grass");
183         UASSERT(trim("\n \t\r  Foo bAR  \r\n\t\t  ") == "Foo bAR");
184         UASSERT(trim("\n \t\r    \r\n\t\t  ") == "");
185 }
186
187
188 void TestUtilities::testIsYes()
189 {
190         UASSERT(is_yes("YeS") == true);
191         UASSERT(is_yes("") == false);
192         UASSERT(is_yes("FAlse") == false);
193         UASSERT(is_yes("-1") == true);
194         UASSERT(is_yes("0") == false);
195         UASSERT(is_yes("1") == true);
196         UASSERT(is_yes("2") == true);
197 }
198
199
200 void TestUtilities::testRemoveStringEnd()
201 {
202         const char *ends[] = {"abc", "c", "bc", "", NULL};
203         UASSERT(removeStringEnd("abc", ends) == "");
204         UASSERT(removeStringEnd("bc", ends) == "b");
205         UASSERT(removeStringEnd("12c", ends) == "12");
206         UASSERT(removeStringEnd("foo", ends) == "");
207 }
208
209
210 void TestUtilities::testUrlEncode()
211 {
212         UASSERT(urlencode("\"Aardvarks lurk, OK?\"")
213                         == "%22Aardvarks%20lurk%2C%20OK%3F%22");
214 }
215
216
217 void TestUtilities::testUrlDecode()
218 {
219         UASSERT(urldecode("%22Aardvarks%20lurk%2C%20OK%3F%22")
220                         == "\"Aardvarks lurk, OK?\"");
221 }
222
223
224 void TestUtilities::testPadString()
225 {
226         UASSERT(padStringRight("hello", 8) == "hello   ");
227 }
228
229 void TestUtilities::testStartsWith()
230 {
231         UASSERT(str_starts_with(std::string(), std::string()) == true);
232         UASSERT(str_starts_with(std::string("the sharp pickaxe"),
233                 std::string()) == true);
234         UASSERT(str_starts_with(std::string("the sharp pickaxe"),
235                 std::string("the")) == true);
236         UASSERT(str_starts_with(std::string("the sharp pickaxe"),
237                 std::string("The")) == false);
238         UASSERT(str_starts_with(std::string("the sharp pickaxe"),
239                 std::string("The"), true) == true);
240         UASSERT(str_starts_with(std::string("T"), std::string("The")) == false);
241 }
242
243 void TestUtilities::testStrEqual()
244 {
245         UASSERT(str_equal(narrow_to_wide("abc"), narrow_to_wide("abc")));
246         UASSERT(str_equal(narrow_to_wide("ABC"), narrow_to_wide("abc"), true));
247 }
248
249
250 void TestUtilities::testStringTrim()
251 {
252         UASSERT(trim("  a") == "a");
253         UASSERT(trim("   a  ") == "a");
254         UASSERT(trim("a   ") == "a");
255         UASSERT(trim("") == "");
256 }
257
258
259 void TestUtilities::testStrToIntConversion()
260 {
261         UASSERT(mystoi("123", 0, 1000) == 123);
262         UASSERT(mystoi("123", 0, 10) == 10);
263 }
264
265
266 void TestUtilities::testStringReplace()
267 {
268         std::string test_str;
269         test_str = "Hello there";
270         str_replace(test_str, "there", "world");
271         UASSERT(test_str == "Hello world");
272         test_str = "ThisAisAaAtest";
273         str_replace(test_str, 'A', ' ');
274         UASSERT(test_str == "This is a test");
275 }
276
277
278 void TestUtilities::testStringAllowed()
279 {
280         UASSERT(string_allowed("hello", "abcdefghijklmno") == true);
281         UASSERT(string_allowed("123", "abcdefghijklmno") == false);
282         UASSERT(string_allowed_blacklist("hello", "123") == true);
283         UASSERT(string_allowed_blacklist("hello123", "123") == false);
284 }
285
286 void TestUtilities::testAsciiPrintableHelper()
287 {
288         UASSERT(IS_ASCII_PRINTABLE_CHAR('e') == true);
289         UASSERT(IS_ASCII_PRINTABLE_CHAR('\0') == false);
290
291         // Ensures that there is no cutting off going on...
292         // If there were, 331 would be cut to 75 in this example
293         // and 73 is a valid ASCII char.
294         int ch = 331;
295         UASSERT(IS_ASCII_PRINTABLE_CHAR(ch) == false);
296 }
297
298 void TestUtilities::testUTF8()
299 {
300         UASSERT(wide_to_utf8(utf8_to_wide("")) == "");
301         UASSERT(wide_to_utf8(utf8_to_wide("the shovel dug a crumbly node!"))
302                 == "the shovel dug a crumbly node!");
303 }
304
305 void TestUtilities::testRemoveEscapes()
306 {
307         UASSERT(unescape_enriched<wchar_t>(
308                 L"abc\x1bXdef") == L"abcdef");
309         UASSERT(unescape_enriched<wchar_t>(
310                 L"abc\x1b(escaped)def") == L"abcdef");
311         UASSERT(unescape_enriched<wchar_t>(
312                 L"abc\x1b((escaped with parenthesis\\))def") == L"abcdef");
313         UASSERT(unescape_enriched<wchar_t>(
314                 L"abc\x1b(incomplete") == L"abc");
315         UASSERT(unescape_enriched<wchar_t>(
316                 L"escape at the end\x1b") == L"escape at the end");
317         // Nested escapes not supported
318         UASSERT(unescape_enriched<wchar_t>(
319                 L"abc\x1b(outer \x1b(inner escape)escape)def") == L"abcescape)def");
320 }
321
322 void TestUtilities::testWrapRows()
323 {
324         UASSERT(wrap_rows("12345678",4) == "1234\n5678");
325         // test that wrap_rows doesn't wrap inside multibyte sequences
326         {
327                 const unsigned char s[] = {
328                         0x2f, 0x68, 0x6f, 0x6d, 0x65, 0x2f, 0x72, 0x61, 0x70, 0x74, 0x6f,
329                         0x72, 0x2f, 0xd1, 0x82, 0xd0, 0xb5, 0xd1, 0x81, 0xd1, 0x82, 0x2f,
330                         0x6d, 0x69, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x74, 0x2f, 0x62, 0x69,
331                         0x6e, 0x2f, 0x2e, 0x2e, 0};
332                 std::string str((char *)s);
333                 UASSERT(utf8_to_wide(wrap_rows(str, 20)) != L"<invalid UTF-8 string>");
334         };
335         {
336                 const unsigned char s[] = {
337                         0x74, 0x65, 0x73, 0x74, 0x20, 0xd1, 0x82, 0xd0, 0xb5, 0xd1, 0x81,
338                         0xd1, 0x82, 0x20, 0xd1, 0x82, 0xd0, 0xb5, 0xd1, 0x81, 0xd1, 0x82,
339                         0x20, 0xd1, 0x82, 0xd0, 0xb5, 0xd1, 0x81, 0xd1, 0x82, 0};
340                 std::string str((char *)s);
341                 UASSERT(utf8_to_wide(wrap_rows(str, 8)) != L"<invalid UTF-8 string>");
342         }
343 }
344
345
346 void TestUtilities::testIsNumber()
347 {
348         UASSERT(is_number("123") == true);
349         UASSERT(is_number("") == false);
350         UASSERT(is_number("123a") == false);
351 }
352
353
354 void TestUtilities::testIsPowerOfTwo()
355 {
356         UASSERT(is_power_of_two(0) == false);
357         UASSERT(is_power_of_two(1) == true);
358         UASSERT(is_power_of_two(2) == true);
359         UASSERT(is_power_of_two(3) == false);
360         for (int exponent = 2; exponent <= 31; ++exponent) {
361                 UASSERT(is_power_of_two((1 << exponent) - 1) == false);
362                 UASSERT(is_power_of_two((1 << exponent)) == true);
363                 UASSERT(is_power_of_two((1 << exponent) + 1) == false);
364         }
365         UASSERT(is_power_of_two(U32_MAX) == false);
366 }
367
368 void TestUtilities::testMyround()
369 {
370         UASSERT(myround(4.6f) == 5);
371         UASSERT(myround(1.2f) == 1);
372         UASSERT(myround(-3.1f) == -3);
373         UASSERT(myround(-6.5f) == -7);
374 }
375
376 void TestUtilities::testStringJoin()
377 {
378         std::vector<std::string> input;
379         UASSERT(str_join(input, ",") == "");
380
381         input.emplace_back("one");
382         UASSERT(str_join(input, ",") == "one");
383
384         input.emplace_back("two");
385         UASSERT(str_join(input, ",") == "one,two");
386
387         input.emplace_back("three");
388         UASSERT(str_join(input, ",") == "one,two,three");
389
390         input[1] = "";
391         UASSERT(str_join(input, ",") == "one,,three");
392
393         input[1] = "two";
394         UASSERT(str_join(input, " and ") == "one and two and three");
395 }
396