OSDN Git Service

fa4fa670f31f709c0bcc577edf1aed14867dcfae
[mutilities/MUtilities.git] / test / src / GlobalTest.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // MuldeR's Utilities for Qt
3 // Copyright (C) 2004-2022 LoRd_MuldeR <MuldeR2@GMX.de>
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library 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 GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 //
19 // http://www.gnu.org/licenses/lgpl-2.1.txt
20 //////////////////////////////////////////////////////////////////////////////////
21
22 #include "MUtilsTest.h"
23
24 //MUtils
25 #include <MUtils/OSSupport.h>
26
27 //Qt
28 #include <QSet>
29
30 //===========================================================================
31 // TESTBED CLASS
32 //===========================================================================
33
34 class GlobalTest : public Testbed
35 {
36 protected:
37         virtual void SetUp()
38         {
39         }
40
41         virtual void TearDown()
42         {
43         }
44 };
45
46 //===========================================================================
47 // TEST METHODS
48 //===========================================================================
49
50 //-----------------------------------------------------------------
51 // Random
52 //-----------------------------------------------------------------
53
54 #define TEST_RANDOM_MAX 29989
55 #define TEST_RANDOM(X,Y) do \
56 { \
57         QSet<X> test; \
58         for (size_t retry = 0; retry < 8; ++retry) \
59         { \
60                 test.clear(); \
61                 for (size_t i = 0; i < TEST_RANDOM_MAX; ++i)  \
62                 {  \
63                         test.insert(MUtils::next_rand_##Y()); \
64                 } \
65                 if(test.count() == TEST_RANDOM_MAX) \
66                 { \
67                         break; \
68                 } \
69         } \
70         ASSERT_EQ(test.count(), TEST_RANDOM_MAX); \
71 } \
72 while(0)
73
74 TEST_F(GlobalTest, RandomU32)
75 {
76         TEST_RANDOM(quint32, u32);
77 }
78
79 TEST_F(GlobalTest, RandomU64)
80 {
81         TEST_RANDOM(quint64, u64);
82 }
83
84 TEST_F(GlobalTest, RandomStr)
85 {
86         TEST_RANDOM(QString, str);
87 }
88
89 #undef TEST_RANDOM
90 #undef RND_LIMIT
91
92 //-----------------------------------------------------------------
93 // Trim String
94 //-----------------------------------------------------------------
95
96 #define TEST_TRIM_STR(X,Y,Z) do \
97 { \
98         { \
99                 QString test((Y)); \
100                 MUtils::trim_##X(test); \
101                 ASSERT_QSTR(test, (Z)); \
102         } \
103         { \
104                 const QString test((Y)); \
105                 ASSERT_QSTR(MUtils::trim_##X(test), (Z)); \
106         } \
107 } \
108 while(0)
109
110 TEST_F(GlobalTest, TrimStringLeft)
111 {
112         TEST_TRIM_STR(left, "", "");
113         TEST_TRIM_STR(left, "   ", "");
114         TEST_TRIM_STR(left, "!   test   !", "!   test   !");
115         TEST_TRIM_STR(left, "   test   ", "test   ");
116         TEST_TRIM_STR(left, "   !   test   !   ", "!   test   !   ");
117 }
118
119 TEST_F(GlobalTest, TrimStringRight)
120 {
121         TEST_TRIM_STR(right, "", "");
122         TEST_TRIM_STR(right, "   ", "");
123         TEST_TRIM_STR(right, "!   test   !", "!   test   !");
124         TEST_TRIM_STR(right, "   test   ", "   test");
125         TEST_TRIM_STR(right, "   !   test   !   ", "   !   test   !");
126 }
127
128 #undef TEST_TRIM_STR
129
130 //-----------------------------------------------------------------
131 // Clean File Path
132 //-----------------------------------------------------------------
133
134 #define TEST_CLEAN_FILE(X,Y,Z) do \
135 { \
136         ASSERT_QSTR(MUtils::clean_file_##X((Y), false), (Z)); \
137 } \
138 while(0)
139
140 static const char *const VALID_FILENAME_CHARS = "!#$%&'()+,-.0123456789;=@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{}~";
141
142 TEST_F(GlobalTest, CleanFileName)
143 {
144         TEST_CLEAN_FILE(name, "", "");
145         TEST_CLEAN_FILE(name, VALID_FILENAME_CHARS, VALID_FILENAME_CHARS);
146         TEST_CLEAN_FILE(name, "example.txt", "example.txt");
147         TEST_CLEAN_FILE(name, " example.txt", " example.txt");
148         TEST_CLEAN_FILE(name, "example.txt ", "example.txt");
149         TEST_CLEAN_FILE(name, ".example.txt", ".example.txt");
150         TEST_CLEAN_FILE(name, "example.txt.", "example.txt");
151         TEST_CLEAN_FILE(name, "foo<>:\"/\\|?*\t\r\nbar", "foo____________bar");
152         TEST_CLEAN_FILE(name, "NUL", "___");
153         TEST_CLEAN_FILE(name, "xNUL", "xNUL");
154         TEST_CLEAN_FILE(name, "NULx", "NULx");
155         TEST_CLEAN_FILE(name, "NUL.txt", "___.txt");
156         TEST_CLEAN_FILE(name, "NULx.txt", "NULx.txt");
157         TEST_CLEAN_FILE(name, "xNUL.txt", "xNUL.txt");
158 }
159
160 TEST_F(GlobalTest, CleanFilePath)
161 {
162         TEST_CLEAN_FILE(path, "", "");
163         TEST_CLEAN_FILE(path, VALID_FILENAME_CHARS, VALID_FILENAME_CHARS);
164         TEST_CLEAN_FILE(path, "c:\\foo\\bar\\example.txt", "c:/foo/bar/example.txt");
165         TEST_CLEAN_FILE(path, "c:/foo/bar/example.txt", "c:/foo/bar/example.txt");
166         TEST_CLEAN_FILE(path, "foo\\bar\\example.txt", "foo/bar/example.txt");
167         TEST_CLEAN_FILE(path, "\\foo\\bar\\example.txt", "/foo/bar/example.txt");
168         TEST_CLEAN_FILE(path, "\\\\hostname\\share\\example.txt", "//hostname/share/example.txt");
169         TEST_CLEAN_FILE(path, "\\\\?\\c:\\very long path", "//?/c:/very long path");
170         TEST_CLEAN_FILE(path, "c:\\foo<>:\"|?*\t\r\nbar\\example.txt", "c:/foo__________bar/example.txt");
171         TEST_CLEAN_FILE(path, "c:\\example\\foo<>:\"|?*\t\r\nbar.txt", "c:/example/foo__________bar.txt");
172         TEST_CLEAN_FILE(path, "c:\\ foo\\ bar\\ example.txt", "c:/ foo/ bar/ example.txt");
173         TEST_CLEAN_FILE(path, "c:\\foo \\bar \\example.txt ", "c:/foo/bar/example.txt");
174         TEST_CLEAN_FILE(path, "c:\\foo   bar\\exa   mple.txt", "c:/foo   bar/exa   mple.txt");
175         TEST_CLEAN_FILE(path, "c:\\example\\NUL", "c:/example/___");
176         TEST_CLEAN_FILE(path, "c:\\example\\xNUL", "c:/example/xNUL");
177         TEST_CLEAN_FILE(path, "c:\\example\\NULx", "c:/example/NULx");
178         TEST_CLEAN_FILE(path, "c:\\example\\NUL.txt", "c:/example/___.txt");
179         TEST_CLEAN_FILE(path, "c:\\example\\xNUL.txt", "c:/example/xNUL.txt");
180         TEST_CLEAN_FILE(path, "c:\\example\\NULx.txt", "c:/example/NULx.txt");
181 }
182
183 //-----------------------------------------------------------------
184 // File Names
185 //-----------------------------------------------------------------
186
187 #define TEST_FILE_NAME(X, Y, ...) \
188 { \
189         const QString workDir = makeTempFolder(__FUNCTION__); \
190         ASSERT_FALSE(workDir.isEmpty()); \
191         QSet<QString> test; \
192         const QRegExp pattern((Y)); \
193         for (int i = 0; i < 997; ++i) \
194         { \
195                 const QString name = MUtils::make_##X##_file(workDir, __VA_ARGS__); \
196                 ASSERT_FALSE(name.isEmpty()); \
197                 ASSERT_FALSE(test.contains(name)); \
198                 ASSERT_GE(pattern.indexIn(name), 0); \
199                 test.insert(name); \
200                 QFile file(name); \
201                 ASSERT_TRUE(file.open(QIODevice::ReadWrite)); \
202                 ASSERT_GE(file.write(TEST_STRING), strlen(TEST_STRING)); \
203                 file.close(); \
204         } \
205         for (QSet<QString>::const_iterator iter = test.constBegin(); iter != test.constEnd(); iter++) \
206         { \
207                 ASSERT_TRUE(QFile::exists(*iter)); \
208                 QFile::remove(*iter); \
209         } \
210 }
211
212 TEST_F(GlobalTest, TempFileName)
213 {
214         TEST_FILE_NAME(temp, "/\\w+\\.txt$", "txt", true);
215 }
216
217 TEST_F(GlobalTest, UniqFileName)
218 {
219         TEST_FILE_NAME(unique, "/example.\\w+\\.txt$", "example", "txt");
220 }
221
222 #undef TEST_FILE_NAME
223
224 //-----------------------------------------------------------------
225 // Parity
226 //-----------------------------------------------------------------
227
228 TEST_F(GlobalTest, Parity)
229 {
230         ASSERT_EQ(MUtils::parity(0x00000000), false);
231         ASSERT_EQ(MUtils::parity(0x11111111), false);
232         ASSERT_EQ(MUtils::parity(0xFFFFFFFF), false);
233         ASSERT_EQ(MUtils::parity(0x00000001), true );
234         ASSERT_EQ(MUtils::parity(0x00000010), true );
235         ASSERT_EQ(MUtils::parity(0x00000100), true );
236         ASSERT_EQ(MUtils::parity(0x00001000), true );
237         ASSERT_EQ(MUtils::parity(0x00010000), true );
238         ASSERT_EQ(MUtils::parity(0x00100000), true );
239         ASSERT_EQ(MUtils::parity(0x01000000), true );
240         ASSERT_EQ(MUtils::parity(0x10000000), true );
241         ASSERT_EQ(MUtils::parity(0xEFFFFFFF), true );
242         ASSERT_EQ(MUtils::parity(0xFEFFFFFF), true );
243         ASSERT_EQ(MUtils::parity(0xFFEFFFFF), true );
244         ASSERT_EQ(MUtils::parity(0xFFFEFFFF), true );
245         ASSERT_EQ(MUtils::parity(0xFFFFEFFF), true );
246         ASSERT_EQ(MUtils::parity(0xFFFFFEFF), true );
247         ASSERT_EQ(MUtils::parity(0xFFFFFFEF), true );
248         ASSERT_EQ(MUtils::parity(0xFFFFFFFE), true );
249         ASSERT_EQ(MUtils::parity(0x10101010), false);
250         ASSERT_EQ(MUtils::parity(0x01010101), false);
251         ASSERT_EQ(MUtils::parity(0xC8A2CC96), false);
252         ASSERT_EQ(MUtils::parity(0x504928DD), true );
253         ASSERT_EQ(MUtils::parity(0x38BFB9EC), false);
254         ASSERT_EQ(MUtils::parity(0x73F42695), true );
255         ASSERT_EQ(MUtils::parity(0x9161E326), false);
256         ASSERT_EQ(MUtils::parity(0xB1C93AC2), true );
257         ASSERT_EQ(MUtils::parity(0xCA4B1193), false);
258 }
259
260 //-----------------------------------------------------------------
261 // Remove File/Dirrectory
262 //-----------------------------------------------------------------
263
264 #define MAKE_TEST_FILE(X) do \
265 { \
266         ASSERT_TRUE((X).open(QIODevice::ReadWrite)); \
267         ASSERT_GE((X).write(TEST_STRING), strlen(TEST_STRING)); \
268         (X).setPermissions(QFile::ReadOwner|QFile::ExeOwner|QFile::ReadGroup|QFile::ExeGroup|QFile::ReadOther|QFile::ExeOther); \
269 } \
270 while(0)
271
272 #define MAKE_SUB_DIR(X,Y) do \
273 { \
274         ASSERT_TRUE((X).mkpath((Y))); \
275         ASSERT_TRUE((X).cd((Y))); \
276 } \
277 while (0)
278
279 TEST_F(GlobalTest, RemoveFile)
280 {
281         const QString workDir = makeTempFolder(__FUNCTION__);
282         ASSERT_FALSE(workDir.isEmpty());
283         const QString fileName = QString("%1/example.txt").arg(workDir);
284         QFile test(fileName);
285         MAKE_TEST_FILE(test);
286         ASSERT_FALSE(MUtils::remove_file(fileName));
287         test.close();
288         ASSERT_TRUE(QFileInfo(fileName).exists());
289         ASSERT_TRUE(MUtils::remove_file(fileName));
290         ASSERT_FALSE(QFileInfo(fileName).exists());
291 }
292
293 TEST_F(GlobalTest, Directory)
294 {
295         const QString workDir = makeTempFolder(__FUNCTION__);
296         ASSERT_FALSE(workDir.isEmpty());
297         static const char *const DIR_NAMES[] = { "foo", "bar", NULL };
298         for (size_t i = 0; DIR_NAMES[i]; i++)
299         {
300                 QDir dir(workDir);
301                 MAKE_SUB_DIR(dir, QLatin1String(DIR_NAMES[i]));
302                 for (size_t j = 0; DIR_NAMES[j]; j++)
303                 {
304                         QDir subdir(dir);
305                         MAKE_SUB_DIR(subdir, QLatin1String(DIR_NAMES[j]));
306                         QFile test(subdir.filePath("example.txt"));
307                         MAKE_TEST_FILE(test);
308                         test.close();
309                 }
310         }
311         for (size_t i = 0; DIR_NAMES[i]; i++)
312         {
313                 QDir dir(QString("%1/%2").arg(workDir, QLatin1String(DIR_NAMES[i])));
314                 ASSERT_TRUE(dir.exists());
315                 ASSERT_FALSE(MUtils::remove_directory(dir.absolutePath(), false));
316                 dir.refresh();
317                 ASSERT_TRUE(dir.exists());
318                 ASSERT_TRUE(MUtils::remove_directory(dir.absolutePath(), true));
319                 dir.refresh();
320                 ASSERT_FALSE(dir.exists());
321         }
322 }
323
324 #undef MAKE_TEST_FILE
325 #undef MAKE_SUB_DIR
326
327 //-----------------------------------------------------------------
328 // Natural String Sort
329 //-----------------------------------------------------------------
330
331 TEST_F(GlobalTest, NaturalStrSort)
332 {
333         static const char *const TEST[] =
334         {
335                 "z0.txt",   "z1.txt",   "z2.txt",   "z3.txt",   "z4.txt",   "z5.txt",   "z6.txt",   "z7.txt",   "z8.txt",   "z9.txt",
336                 "z10.txt",  "z11.txt",  "z12.txt",  "z13.txt",  "z14.txt",  "z15.txt",  "z16.txt",  "z17.txt",  "z18.txt",  "z19.txt",
337                 "z100.txt", "z101.txt", "z102.txt", "z103.txt", "z104.txt", "z105.txt", "z106.txt", "z107.txt", "z108.txt", "z109.txt",
338                 NULL
339         };
340
341         QStringList test;
342         for (size_t i = 0; TEST[i]; i++)
343         {
344                 test << QLatin1String(TEST[i]);
345         }
346
347         qsrand(time(NULL));
348         for (size_t q = 0; q < 97; q++)
349         {
350                 for (size_t k = 0; k < 997; k++)
351                 {
352                         const size_t len = size_t(test.count());
353                         for (size_t i = 0; i < len; i++)
354                         {
355                                 test.swap(i, qrand() % len);
356                         }
357                 }
358                 MUtils::natural_string_sort(test, true);
359                 for (size_t i = 0; TEST[i]; i++)
360                 {
361                         ASSERT_QSTR(test[i], TEST[i]);
362                 }
363         }
364 }
365
366 //-----------------------------------------------------------------
367 // RegExp Parser
368 //-----------------------------------------------------------------
369
370 #define TEST_REGEX_U32(X,Y,Z,...) do \
371 { \
372         const QRegExp test(QLatin1String((X))); \
373         ASSERT_GE(test.indexIn(QLatin1String((Y))), 0); \
374         quint32 result[(Z)]; \
375         ASSERT_TRUE(MUtils::regexp_parse_uint32(test, result, (Z))); \
376         const quint32 expected[] = { __VA_ARGS__ }; \
377         for(size_t i = 0; i < (Z); i++) \
378         { \
379                 ASSERT_EQ(result[i], expected[i]); \
380         } \
381 } \
382 while(0)
383
384 TEST_F(GlobalTest, ParseRegExp)
385 {
386         TEST_REGEX_U32("(\\d+)", "42", 1, 42);
387         TEST_REGEX_U32("(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)", "4 8 15 16 23 42", 6, 4, 8, 15, 16, 23, 42);
388         TEST_REGEX_U32("x264\\s+(\\d+)\\.(\\d+)\\.(\\d+)\\s+\\w+", "x264 0.148.2744 b97ae06", 3, 0, 148, 2744);
389         TEST_REGEX_U32("HEVC\\s+encoder\\s+version\\s+(\\d+)\\.(\\d+)\\+(\\d+)-\\w+", "HEVC encoder version 2.1+70-78e1e1354a25", 3, 2, 1, 70);
390 }
391
392 #undef TEST_REGEX_U32