]> git.lizzy.rs Git - minetest.git/blob - src/unittest/test_utilities.cpp
112b53f0b111f23a17132f8466e229ba6684dff4
[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 }
175
176
177 void TestUtilities::testTrim()
178 {
179         UASSERT(trim("") == "");
180         UASSERT(trim("dirt_with_grass") == "dirt_with_grass");
181         UASSERT(trim("\n \t\r  Foo bAR  \r\n\t\t  ") == "Foo bAR");
182         UASSERT(trim("\n \t\r    \r\n\t\t  ") == "");
183 }
184
185
186 void TestUtilities::testIsYes()
187 {
188         UASSERT(is_yes("YeS") == true);
189         UASSERT(is_yes("") == false);
190         UASSERT(is_yes("FAlse") == false);
191         UASSERT(is_yes("-1") == true);
192         UASSERT(is_yes("0") == false);
193         UASSERT(is_yes("1") == true);
194         UASSERT(is_yes("2") == true);
195 }
196
197
198 void TestUtilities::testRemoveStringEnd()
199 {
200         const char *ends[] = {"abc", "c", "bc", "", NULL};
201         UASSERT(removeStringEnd("abc", ends) == "");
202         UASSERT(removeStringEnd("bc", ends) == "b");
203         UASSERT(removeStringEnd("12c", ends) == "12");
204         UASSERT(removeStringEnd("foo", ends) == "");
205 }
206
207
208 void TestUtilities::testUrlEncode()
209 {
210         UASSERT(urlencode("\"Aardvarks lurk, OK?\"")
211                         == "%22Aardvarks%20lurk%2C%20OK%3F%22");
212 }
213
214
215 void TestUtilities::testUrlDecode()
216 {
217         UASSERT(urldecode("%22Aardvarks%20lurk%2C%20OK%3F%22")
218                         == "\"Aardvarks lurk, OK?\"");
219 }
220
221
222 void TestUtilities::testPadString()
223 {
224         UASSERT(padStringRight("hello", 8) == "hello   ");
225 }
226
227 void TestUtilities::testStartsWith()
228 {
229         UASSERT(str_starts_with(std::string(), std::string()) == true);
230         UASSERT(str_starts_with(std::string("the sharp pickaxe"),
231                 std::string()) == true);
232         UASSERT(str_starts_with(std::string("the sharp pickaxe"),
233                 std::string("the")) == true);
234         UASSERT(str_starts_with(std::string("the sharp pickaxe"),
235                 std::string("The")) == false);
236         UASSERT(str_starts_with(std::string("the sharp pickaxe"),
237                 std::string("The"), true) == true);
238         UASSERT(str_starts_with(std::string("T"), std::string("The")) == false);
239 }
240
241 void TestUtilities::testStrEqual()
242 {
243         UASSERT(str_equal(narrow_to_wide("abc"), narrow_to_wide("abc")));
244         UASSERT(str_equal(narrow_to_wide("ABC"), narrow_to_wide("abc"), true));
245 }
246
247
248 void TestUtilities::testStringTrim()
249 {
250         UASSERT(trim("  a") == "a");
251         UASSERT(trim("   a  ") == "a");
252         UASSERT(trim("a   ") == "a");
253         UASSERT(trim("") == "");
254 }
255
256
257 void TestUtilities::testStrToIntConversion()
258 {
259         UASSERT(mystoi("123", 0, 1000) == 123);
260         UASSERT(mystoi("123", 0, 10) == 10);
261 }
262
263
264 void TestUtilities::testStringReplace()
265 {
266         std::string test_str;
267         test_str = "Hello there";
268         str_replace(test_str, "there", "world");
269         UASSERT(test_str == "Hello world");
270         test_str = "ThisAisAaAtest";
271         str_replace(test_str, 'A', ' ');
272         UASSERT(test_str == "This is a test");
273 }
274
275
276 void TestUtilities::testStringAllowed()
277 {
278         UASSERT(string_allowed("hello", "abcdefghijklmno") == true);
279         UASSERT(string_allowed("123", "abcdefghijklmno") == false);
280         UASSERT(string_allowed_blacklist("hello", "123") == true);
281         UASSERT(string_allowed_blacklist("hello123", "123") == false);
282 }
283
284 void TestUtilities::testAsciiPrintableHelper()
285 {
286         UASSERT(IS_ASCII_PRINTABLE_CHAR('e') == true);
287         UASSERT(IS_ASCII_PRINTABLE_CHAR('\0') == false);
288
289         // Ensures that there is no cutting off going on...
290         // If there were, 331 would be cut to 75 in this example
291         // and 73 is a valid ASCII char.
292         int ch = 331;
293         UASSERT(IS_ASCII_PRINTABLE_CHAR(ch) == false);
294 }
295
296 void TestUtilities::testUTF8()
297 {
298         UASSERT(wide_to_utf8(utf8_to_wide("")) == "");
299         UASSERT(wide_to_utf8(utf8_to_wide("the shovel dug a crumbly node!"))
300                 == "the shovel dug a crumbly node!");
301 }
302
303 void TestUtilities::testRemoveEscapes()
304 {
305         UASSERT(unescape_enriched<wchar_t>(
306                 L"abc\x1bXdef") == L"abcdef");
307         UASSERT(unescape_enriched<wchar_t>(
308                 L"abc\x1b(escaped)def") == L"abcdef");
309         UASSERT(unescape_enriched<wchar_t>(
310                 L"abc\x1b((escaped with parenthesis\\))def") == L"abcdef");
311         UASSERT(unescape_enriched<wchar_t>(
312                 L"abc\x1b(incomplete") == L"abc");
313         UASSERT(unescape_enriched<wchar_t>(
314                 L"escape at the end\x1b") == L"escape at the end");
315         // Nested escapes not supported
316         UASSERT(unescape_enriched<wchar_t>(
317                 L"abc\x1b(outer \x1b(inner escape)escape)def") == L"abcescape)def");
318 }
319
320 void TestUtilities::testWrapRows()
321 {
322         UASSERT(wrap_rows("12345678",4) == "1234\n5678");
323         // test that wrap_rows doesn't wrap inside multibyte sequences
324         {
325                 const unsigned char s[] = {
326                         0x2f, 0x68, 0x6f, 0x6d, 0x65, 0x2f, 0x72, 0x61, 0x70, 0x74, 0x6f,
327                         0x72, 0x2f, 0xd1, 0x82, 0xd0, 0xb5, 0xd1, 0x81, 0xd1, 0x82, 0x2f,
328                         0x6d, 0x69, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x74, 0x2f, 0x62, 0x69,
329                         0x6e, 0x2f, 0x2e, 0x2e, 0};
330                 std::string str((char *)s);
331                 UASSERT(utf8_to_wide(wrap_rows(str, 20)) != L"<invalid UTF-8 string>");
332         };
333         {
334                 const unsigned char s[] = {
335                         0x74, 0x65, 0x73, 0x74, 0x20, 0xd1, 0x82, 0xd0, 0xb5, 0xd1, 0x81,
336                         0xd1, 0x82, 0x20, 0xd1, 0x82, 0xd0, 0xb5, 0xd1, 0x81, 0xd1, 0x82,
337                         0x20, 0xd1, 0x82, 0xd0, 0xb5, 0xd1, 0x81, 0xd1, 0x82, 0};
338                 std::string str((char *)s);
339                 UASSERT(utf8_to_wide(wrap_rows(str, 8)) != L"<invalid UTF-8 string>");
340         }
341 }
342
343
344 void TestUtilities::testIsNumber()
345 {
346         UASSERT(is_number("123") == true);
347         UASSERT(is_number("") == false);
348         UASSERT(is_number("123a") == false);
349 }
350
351
352 void TestUtilities::testIsPowerOfTwo()
353 {
354         UASSERT(is_power_of_two(0) == false);
355         UASSERT(is_power_of_two(1) == true);
356         UASSERT(is_power_of_two(2) == true);
357         UASSERT(is_power_of_two(3) == false);
358         for (int exponent = 2; exponent <= 31; ++exponent) {
359                 UASSERT(is_power_of_two((1 << exponent) - 1) == false);
360                 UASSERT(is_power_of_two((1 << exponent)) == true);
361                 UASSERT(is_power_of_two((1 << exponent) + 1) == false);
362         }
363         UASSERT(is_power_of_two(U32_MAX) == false);
364 }
365
366 void TestUtilities::testMyround()
367 {
368         UASSERT(myround(4.6f) == 5);
369         UASSERT(myround(1.2f) == 1);
370         UASSERT(myround(-3.1f) == -3);
371         UASSERT(myround(-6.5f) == -7);
372 }
373
374 void TestUtilities::testStringJoin()
375 {
376         std::vector<std::string> input;
377         UASSERT(str_join(input, ",") == "");
378
379         input.emplace_back("one");
380         UASSERT(str_join(input, ",") == "one");
381
382         input.emplace_back("two");
383         UASSERT(str_join(input, ",") == "one,two");
384
385         input.emplace_back("three");
386         UASSERT(str_join(input, ",") == "one,two,three");
387
388         input[1] = "";
389         UASSERT(str_join(input, ",") == "one,,three");
390
391         input[1] = "two";
392         UASSERT(str_join(input, " and ") == "one and two and three");
393 }
394