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