Add server side ncurses terminal
[oweals/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 "util/numeric.h"
23 #include "util/string.h"
24
25 class TestUtilities : public TestBase {
26 public:
27         TestUtilities() { TestManager::registerTestModule(this); }
28         const char *getName() { return "TestUtilities"; }
29
30         void runTests(IGameDef *gamedef);
31
32         void testAngleWrapAround();
33         void testLowercase();
34         void testTrim();
35         void testIsYes();
36         void testRemoveStringEnd();
37         void testUrlEncode();
38         void testUrlDecode();
39         void testPadString();
40         void testStartsWith();
41         void testStrEqual();
42         void testStringTrim();
43         void testStrToIntConversion();
44         void testStringReplace();
45         void testStringAllowed();
46         void testAsciiPrintableHelper();
47         void testUTF8();
48         void testWrapRows();
49         void testIsNumber();
50         void testIsPowerOfTwo();
51         void testMyround();
52 };
53
54 static TestUtilities g_test_instance;
55
56 void TestUtilities::runTests(IGameDef *gamedef)
57 {
58         TEST(testAngleWrapAround);
59         TEST(testLowercase);
60         TEST(testTrim);
61         TEST(testIsYes);
62         TEST(testRemoveStringEnd);
63         TEST(testUrlEncode);
64         TEST(testUrlDecode);
65         TEST(testPadString);
66         TEST(testStartsWith);
67         TEST(testStrEqual);
68         TEST(testStringTrim);
69         TEST(testStrToIntConversion);
70         TEST(testStringReplace);
71         TEST(testStringAllowed);
72         TEST(testAsciiPrintableHelper);
73         TEST(testUTF8);
74         TEST(testWrapRows);
75         TEST(testIsNumber);
76         TEST(testIsPowerOfTwo);
77         TEST(testMyround);
78 }
79
80 ////////////////////////////////////////////////////////////////////////////////
81
82 inline float ref_WrapDegrees180(float f)
83 {
84         // This is a slower alternative to the wrapDegrees_180() function;
85         // used as a reference for testing
86         float value = fmodf(f + 180, 360);
87         if (value < 0)
88                 value += 360;
89         return value - 180;
90 }
91
92
93 inline float ref_WrapDegrees_0_360(float f)
94 {
95         // This is a slower alternative to the wrapDegrees_0_360() function;
96         // used as a reference for testing
97         float value = fmodf(f, 360);
98         if (value < 0)
99                 value += 360;
100         return value < 0 ? value + 360 : value;
101 }
102
103
104 void TestUtilities::testAngleWrapAround()
105 {
106         UASSERT(fabs(modulo360f(100.0) - 100.0) < 0.001);
107         UASSERT(fabs(modulo360f(720.5) - 0.5) < 0.001);
108         UASSERT(fabs(modulo360f(-0.5) - (-0.5)) < 0.001);
109         UASSERT(fabs(modulo360f(-365.5) - (-5.5)) < 0.001);
110
111         for (float f = -720; f <= -360; f += 0.25) {
112                 UASSERT(fabs(modulo360f(f) - modulo360f(f + 360)) < 0.001);
113         }
114
115         for (float f = -1440; f <= 1440; f += 0.25) {
116                 UASSERT(fabs(modulo360f(f) - fmodf(f, 360)) < 0.001);
117                 UASSERT(fabs(wrapDegrees_180(f) - ref_WrapDegrees180(f)) < 0.001);
118                 UASSERT(fabs(wrapDegrees_0_360(f) - ref_WrapDegrees_0_360(f)) < 0.001);
119                 UASSERT(wrapDegrees_0_360(fabs(wrapDegrees_180(f) - wrapDegrees_0_360(f))) < 0.001);
120         }
121 }
122
123
124 void TestUtilities::testLowercase()
125 {
126         UASSERT(lowercase("Foo bAR") == "foo bar");
127 }
128
129
130 void TestUtilities::testTrim()
131 {
132         UASSERT(trim("") == "");
133         UASSERT(trim("dirt_with_grass") == "dirt_with_grass");
134         UASSERT(trim("\n \t\r  Foo bAR  \r\n\t\t  ") == "Foo bAR");
135         UASSERT(trim("\n \t\r    \r\n\t\t  ") == "");
136 }
137
138
139 void TestUtilities::testIsYes()
140 {
141         UASSERT(is_yes("YeS") == true);
142         UASSERT(is_yes("") == false);
143         UASSERT(is_yes("FAlse") == false);
144         UASSERT(is_yes("-1") == true);
145         UASSERT(is_yes("0") == false);
146         UASSERT(is_yes("1") == true);
147         UASSERT(is_yes("2") == true);
148 }
149
150
151 void TestUtilities::testRemoveStringEnd()
152 {
153         const char *ends[] = {"abc", "c", "bc", "", NULL};
154         UASSERT(removeStringEnd("abc", ends) == "");
155         UASSERT(removeStringEnd("bc", ends) == "b");
156         UASSERT(removeStringEnd("12c", ends) == "12");
157         UASSERT(removeStringEnd("foo", ends) == "");
158 }
159
160
161 void TestUtilities::testUrlEncode()
162 {
163         UASSERT(urlencode("\"Aardvarks lurk, OK?\"")
164                         == "%22Aardvarks%20lurk%2C%20OK%3F%22");
165 }
166
167
168 void TestUtilities::testUrlDecode()
169 {
170         UASSERT(urldecode("%22Aardvarks%20lurk%2C%20OK%3F%22")
171                         == "\"Aardvarks lurk, OK?\"");
172 }
173
174
175 void TestUtilities::testPadString()
176 {
177         UASSERT(padStringRight("hello", 8) == "hello   ");
178 }
179
180 void TestUtilities::testStartsWith()
181 {
182         UASSERT(str_starts_with(std::string(), std::string()) == true);
183         UASSERT(str_starts_with(std::string("the sharp pickaxe"),
184                 std::string()) == true);
185         UASSERT(str_starts_with(std::string("the sharp pickaxe"),
186                 std::string("the")) == true);
187         UASSERT(str_starts_with(std::string("the sharp pickaxe"),
188                 std::string("The")) == false);
189         UASSERT(str_starts_with(std::string("the sharp pickaxe"),
190                 std::string("The"), true) == true);
191         UASSERT(str_starts_with(std::string("T"), std::string("The")) == false);
192 }
193
194 void TestUtilities::testStrEqual()
195 {
196         UASSERT(str_equal(narrow_to_wide("abc"), narrow_to_wide("abc")));
197         UASSERT(str_equal(narrow_to_wide("ABC"), narrow_to_wide("abc"), true));
198 }
199
200
201 void TestUtilities::testStringTrim()
202 {
203         UASSERT(trim("  a") == "a");
204         UASSERT(trim("   a  ") == "a");
205         UASSERT(trim("a   ") == "a");
206         UASSERT(trim("") == "");
207 }
208
209
210 void TestUtilities::testStrToIntConversion()
211 {
212         UASSERT(mystoi("123", 0, 1000) == 123);
213         UASSERT(mystoi("123", 0, 10) == 10);
214 }
215
216
217 void TestUtilities::testStringReplace()
218 {
219         std::string test_str;
220         test_str = "Hello there";
221         str_replace(test_str, "there", "world");
222         UASSERT(test_str == "Hello world");
223         test_str = "ThisAisAaAtest";
224         str_replace(test_str, 'A', ' ');
225         UASSERT(test_str == "This is a test");
226 }
227
228
229 void TestUtilities::testStringAllowed()
230 {
231         UASSERT(string_allowed("hello", "abcdefghijklmno") == true);
232         UASSERT(string_allowed("123", "abcdefghijklmno") == false);
233         UASSERT(string_allowed_blacklist("hello", "123") == true);
234         UASSERT(string_allowed_blacklist("hello123", "123") == false);
235 }
236
237 void TestUtilities::testAsciiPrintableHelper()
238 {
239         UASSERT(IS_ASCII_PRINTABLE_CHAR('e') == true);
240         UASSERT(IS_ASCII_PRINTABLE_CHAR('\0') == false);
241
242         // Ensures that there is no cutting off going on...
243         // If there were, 331 would be cut to 75 in this example
244         // and 73 is a valid ASCII char.
245         int ch = 331;
246         UASSERT(IS_ASCII_PRINTABLE_CHAR(ch) == false);
247 }
248
249 void TestUtilities::testUTF8()
250 {
251         UASSERT(wide_to_utf8(utf8_to_wide("")) == "");
252         UASSERT(wide_to_utf8(utf8_to_wide("the shovel dug a crumbly node!"))
253                 == "the shovel dug a crumbly node!");
254 }
255
256 void TestUtilities::testWrapRows()
257 {
258         UASSERT(wrap_rows("12345678",4) == "1234\n5678");
259         // test that wrap_rows doesn't wrap inside multibyte sequences
260         {
261                 const unsigned char s[] = {
262                         0x2f, 0x68, 0x6f, 0x6d, 0x65, 0x2f, 0x72, 0x61, 0x70, 0x74, 0x6f,
263                         0x72, 0x2f, 0xd1, 0x82, 0xd0, 0xb5, 0xd1, 0x81, 0xd1, 0x82, 0x2f,
264                         0x6d, 0x69, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x74, 0x2f, 0x62, 0x69,
265                         0x6e, 0x2f, 0x2e, 0x2e, 0};
266                 std::string str((char *)s);
267                 UASSERT(utf8_to_wide(wrap_rows(str, 20)) != L"<invalid UTF-8 string>");
268         };
269         {
270                 const unsigned char s[] = {
271                         0x74, 0x65, 0x73, 0x74, 0x20, 0xd1, 0x82, 0xd0, 0xb5, 0xd1, 0x81,
272                         0xd1, 0x82, 0x20, 0xd1, 0x82, 0xd0, 0xb5, 0xd1, 0x81, 0xd1, 0x82,
273                         0x20, 0xd1, 0x82, 0xd0, 0xb5, 0xd1, 0x81, 0xd1, 0x82, 0};
274                 std::string str((char *)s);
275                 UASSERT(utf8_to_wide(wrap_rows(str, 8)) != L"<invalid UTF-8 string>");
276         }
277 }
278
279
280 void TestUtilities::testIsNumber()
281 {
282         UASSERT(is_number("123") == true);
283         UASSERT(is_number("") == false);
284         UASSERT(is_number("123a") == false);
285 }
286
287
288 void TestUtilities::testIsPowerOfTwo()
289 {
290         UASSERT(is_power_of_two(0) == false);
291         UASSERT(is_power_of_two(1) == true);
292         UASSERT(is_power_of_two(2) == true);
293         UASSERT(is_power_of_two(3) == false);
294         for (int exponent = 2; exponent <= 31; ++exponent) {
295                 UASSERT(is_power_of_two((1 << exponent) - 1) == false);
296                 UASSERT(is_power_of_two((1 << exponent)) == true);
297                 UASSERT(is_power_of_two((1 << exponent) + 1) == false);
298         }
299         UASSERT(is_power_of_two(U32_MAX) == false);
300 }
301
302 void TestUtilities::testMyround()
303 {
304         UASSERT(myround(4.6f) == 5);
305         UASSERT(myround(1.2f) == 1);
306         UASSERT(myround(-3.1f) == -3);
307         UASSERT(myround(-6.5f) == -7);
308 }
309