OSDN Git Service

40390dd36f82d1cbdd7a5e2cc33fdbde7dd7a1dc
[mutilities/MUtilities.git] / test / src / GlobalTest.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // MuldeR's Utilities for Qt
3 // Copyright (C) 2004-2016 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 99991
55 #define TEST_RANDOM(X,Y) do \
56 { \
57         MUtils::seed_rand(); \
58         QSet<X> test; \
59         int attempts = 0; \
60         while(test.count() != TEST_RANDOM_MAX) \
61         { \
62                 if(++attempts <= 64) \
63                 { \
64                         if(attempts > 1) \
65                         { \
66                                 MUtils::OS::sleep_ms(1); \
67                         } \
68                         test.clear(); \
69                         for (size_t i = 0; i < TEST_RANDOM_MAX; ++i)  \
70                         {  \
71                                 test.insert(MUtils::next_rand_##Y()); \
72                         } \
73                 } \
74                 else \
75                 { \
76                         FAIL(); /*too many attempts!*/ \
77                 } \
78         } \
79 } \
80 while(0)
81
82 TEST_F(GlobalTest, RandomU32)
83 {
84         TEST_RANDOM(quint32, u32);
85 }
86
87 TEST_F(GlobalTest, RandomU64)
88 {
89         TEST_RANDOM(quint64, u64);
90 }
91
92 TEST_F(GlobalTest, RandomStr)
93 {
94         TEST_RANDOM(QString, str);
95 }
96
97 #undef TEST_RANDOM
98 #undef RND_LIMIT
99
100 //-----------------------------------------------------------------
101 // Trim String
102 //-----------------------------------------------------------------
103
104 #define TEST_TRIM_STR(X,Y,Z) do \
105 { \
106         { \
107                 QString test((Y)); \
108                 MUtils::trim_##X(test); \
109                 ASSERT_QSTR(test, (Z)); \
110         } \
111         { \
112                 const QString test((Y)); \
113                 ASSERT_QSTR(MUtils::trim_##X(test), (Z)); \
114         } \
115 } \
116 while(0)
117
118 TEST_F(GlobalTest, TrimStringLeft)
119 {
120         TEST_TRIM_STR(left, "", "");
121         TEST_TRIM_STR(left, "   ", "");
122         TEST_TRIM_STR(left, "!   test   !", "!   test   !");
123         TEST_TRIM_STR(left, "   test   ", "test   ");
124         TEST_TRIM_STR(left, "   !   test   !   ", "!   test   !   ");
125 }
126
127 TEST_F(GlobalTest, TrimStringRight)
128 {
129         TEST_TRIM_STR(right, "", "");
130         TEST_TRIM_STR(right, "   ", "");
131         TEST_TRIM_STR(right, "!   test   !", "!   test   !");
132         TEST_TRIM_STR(right, "   test   ", "   test");
133         TEST_TRIM_STR(right, "   !   test   !   ", "   !   test   !");
134 }
135
136 #undef TEST_TRIM_STR
137
138 //-----------------------------------------------------------------
139 // Clean File Path
140 //-----------------------------------------------------------------
141
142 #define TEST_CLEAN_FILE(X,Y,Z) do \
143 { \
144         ASSERT_QSTR(MUtils::clean_file_##X((Y)), (Z)); \
145 } \
146 while(0)
147
148 static const char *const VALID_FILENAME_CHARS = "!#$%&'()+,-.0123456789;=@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{}~";
149
150 TEST_F(GlobalTest, CleanFileName)
151 {
152         TEST_CLEAN_FILE(name, "", "");
153         TEST_CLEAN_FILE(name, VALID_FILENAME_CHARS, VALID_FILENAME_CHARS);
154         TEST_CLEAN_FILE(name, "example.txt", "example.txt");
155         TEST_CLEAN_FILE(name, " example.txt", " example.txt");
156         TEST_CLEAN_FILE(name, "example.txt ", "example.txt");
157         TEST_CLEAN_FILE(name, ".example.txt", ".example.txt");
158         TEST_CLEAN_FILE(name, "example.txt.", "example.txt");
159         TEST_CLEAN_FILE(name, "foo<>:\"/\\|?*\t\r\nbar", "foo____________bar");
160         TEST_CLEAN_FILE(name, "NUL", "___");
161         TEST_CLEAN_FILE(name, "xNUL", "xNUL");
162         TEST_CLEAN_FILE(name, "NULx", "NULx");
163         TEST_CLEAN_FILE(name, "NUL.txt", "___.txt");
164         TEST_CLEAN_FILE(name, "NULx.txt", "NULx.txt");
165         TEST_CLEAN_FILE(name, "xNUL.txt", "xNUL.txt");
166 }
167
168 TEST_F(GlobalTest, CleanFilePath)
169 {
170         TEST_CLEAN_FILE(path, "", "");
171         TEST_CLEAN_FILE(path, VALID_FILENAME_CHARS, VALID_FILENAME_CHARS);
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, "foo\\bar\\example.txt", "foo/bar/example.txt");
175         TEST_CLEAN_FILE(path, "\\foo\\bar\\example.txt", "/foo/bar/example.txt");
176         TEST_CLEAN_FILE(path, "\\\\hostname\\share\\example.txt", "//hostname/share/example.txt");
177         TEST_CLEAN_FILE(path, "\\\\?\\c:\\very long path", "//?/c:/very long path");
178         TEST_CLEAN_FILE(path, "c:\\foo<>:\"|?*\t\r\nbar\\example.txt", "c:/foo__________bar/example.txt");
179         TEST_CLEAN_FILE(path, "c:\\example\\foo<>:\"|?*\t\r\nbar.txt", "c:/example/foo__________bar.txt");
180         TEST_CLEAN_FILE(path, "c:\\ foo\\ bar\\ example.txt", "c:/ foo/ bar/ example.txt");
181         TEST_CLEAN_FILE(path, "c:\\foo \\bar \\example.txt ", "c:/foo/bar/example.txt");
182         TEST_CLEAN_FILE(path, "c:\\foo   bar\\exa   mple.txt", "c:/foo   bar/exa   mple.txt");
183         TEST_CLEAN_FILE(path, "c:\\example\\NUL", "c:/example/___");
184         TEST_CLEAN_FILE(path, "c:\\example\\xNUL", "c:/example/xNUL");
185         TEST_CLEAN_FILE(path, "c:\\example\\NULx", "c:/example/NULx");
186         TEST_CLEAN_FILE(path, "c:\\example\\NUL.txt", "c:/example/___.txt");
187         TEST_CLEAN_FILE(path, "c:\\example\\xNUL.txt", "c:/example/xNUL.txt");
188         TEST_CLEAN_FILE(path, "c:\\example\\NULx.txt", "c:/example/NULx.txt");
189 }
190
191 //-----------------------------------------------------------------
192 // File Names
193 //-----------------------------------------------------------------
194
195 #define TEST_FILE_NAME(X, Y, ...) \
196 { \
197         const QString workDir = makeTempFolder(__FUNCTION__); \
198         ASSERT_FALSE(workDir.isEmpty()); \
199         QSet<QString> test; \
200         const QRegExp pattern((Y)); \
201         for (int i = 0; i < 997; ++i) \
202         { \
203                 const QString name = MUtils::make_##X##_file(workDir, __VA_ARGS__); \
204                 ASSERT_FALSE(name.isEmpty()); \
205                 ASSERT_FALSE(test.contains(name)); \
206                 ASSERT_GE(pattern.indexIn(name), 0); \
207                 test.insert(name); \
208                 QFile file(name); \
209                 ASSERT_TRUE(file.open(QIODevice::ReadWrite)); \
210                 ASSERT_GE(file.write(TEST_STRING), strlen(TEST_STRING)); \
211                 file.close(); \
212         } \
213         for (QSet<QString>::const_iterator iter = test.constBegin(); iter != test.constEnd(); iter++) \
214         { \
215                 ASSERT_TRUE(QFile::exists(*iter)); \
216                 QFile::remove(*iter); \
217         } \
218 }
219
220 TEST_F(GlobalTest, TempFileName)
221 {
222         TEST_FILE_NAME(temp, "/\\w+\\.txt$", "txt", true);
223 }
224
225 TEST_F(GlobalTest, UniqFileName)
226 {
227         TEST_FILE_NAME(unique, "/example.\\w+\\.txt$", "example", "txt");
228 }
229
230 #undef TEST_FILE_NAME
231
232 //-----------------------------------------------------------------
233 // Parity
234 //-----------------------------------------------------------------
235
236 TEST_F(GlobalTest, Parity)
237 {
238         ASSERT_EQ(MUtils::parity(0x00000000), false);
239         ASSERT_EQ(MUtils::parity(0x11111111), false);
240         ASSERT_EQ(MUtils::parity(0xFFFFFFFF), false);
241         ASSERT_EQ(MUtils::parity(0x00000001), true );
242         ASSERT_EQ(MUtils::parity(0x00000010), true );
243         ASSERT_EQ(MUtils::parity(0x00000100), true );
244         ASSERT_EQ(MUtils::parity(0x00001000), true );
245         ASSERT_EQ(MUtils::parity(0x00010000), true );
246         ASSERT_EQ(MUtils::parity(0x00100000), true );
247         ASSERT_EQ(MUtils::parity(0x01000000), true );
248         ASSERT_EQ(MUtils::parity(0x10000000), true );
249         ASSERT_EQ(MUtils::parity(0xEFFFFFFF), true );
250         ASSERT_EQ(MUtils::parity(0xFEFFFFFF), true );
251         ASSERT_EQ(MUtils::parity(0xFFEFFFFF), true );
252         ASSERT_EQ(MUtils::parity(0xFFFEFFFF), true );
253         ASSERT_EQ(MUtils::parity(0xFFFFEFFF), true );
254         ASSERT_EQ(MUtils::parity(0xFFFFFEFF), true );
255         ASSERT_EQ(MUtils::parity(0xFFFFFFEF), true );
256         ASSERT_EQ(MUtils::parity(0xFFFFFFFE), true );
257         ASSERT_EQ(MUtils::parity(0x10101010), false);
258         ASSERT_EQ(MUtils::parity(0x01010101), false);
259         ASSERT_EQ(MUtils::parity(0xC8A2CC96), false);
260         ASSERT_EQ(MUtils::parity(0x504928DD), true );
261         ASSERT_EQ(MUtils::parity(0x38BFB9EC), false);
262         ASSERT_EQ(MUtils::parity(0x73F42695), true );
263         ASSERT_EQ(MUtils::parity(0x9161E326), false);
264         ASSERT_EQ(MUtils::parity(0xB1C93AC2), true );
265         ASSERT_EQ(MUtils::parity(0xCA4B1193), false);
266 }
267
268 //-----------------------------------------------------------------
269 // Remove File/Dirrectory
270 //-----------------------------------------------------------------
271
272 #define MAKE_TEST_FILE(X) do \
273 { \
274         ASSERT_TRUE((X).open(QIODevice::ReadWrite)); \
275         ASSERT_GE((X).write(TEST_STRING), strlen(TEST_STRING)); \
276         (X).setPermissions(QFile::ReadOwner|QFile::ExeOwner|QFile::ReadGroup|QFile::ExeGroup|QFile::ReadOther|QFile::ExeOther); \
277 } \
278 while(0)
279
280 #define MAKE_SUB_DIR(X,Y) do \
281 { \
282         ASSERT_TRUE((X).mkpath((Y))); \
283         ASSERT_TRUE((X).cd((Y))); \
284 } \
285 while (0)
286
287 TEST_F(GlobalTest, RemoveFile)
288 {
289         const QString workDir = makeTempFolder(__FUNCTION__);
290         ASSERT_FALSE(workDir.isEmpty());
291         const QString fileName = QString("%1/example.txt").arg(workDir);
292         QFile test(fileName);
293         MAKE_TEST_FILE(test);
294         ASSERT_FALSE(MUtils::remove_file(fileName));
295         test.close();
296         ASSERT_TRUE(QFileInfo(fileName).exists());
297         ASSERT_TRUE(MUtils::remove_file(fileName));
298         ASSERT_FALSE(QFileInfo(fileName).exists());
299 }
300
301 TEST_F(GlobalTest, Directory)
302 {
303         const QString workDir = makeTempFolder(__FUNCTION__);
304         ASSERT_FALSE(workDir.isEmpty());
305         static const char *const DIR_NAMES[] = { "foo", "bar", NULL };
306         for (size_t i = 0; DIR_NAMES[i]; i++)
307         {
308                 QDir dir(workDir);
309                 MAKE_SUB_DIR(dir, QLatin1String(DIR_NAMES[i]));
310                 for (size_t j = 0; DIR_NAMES[j]; j++)
311                 {
312                         QDir subdir(dir);
313                         MAKE_SUB_DIR(subdir, QLatin1String(DIR_NAMES[j]));
314                         QFile test(subdir.filePath("example.txt"));
315                         MAKE_TEST_FILE(test);
316                         test.close();
317                 }
318         }
319         for (size_t i = 0; DIR_NAMES[i]; i++)
320         {
321                 QDir dir(QString("%1/%2").arg(workDir, QLatin1String(DIR_NAMES[i])));
322                 ASSERT_TRUE(dir.exists());
323                 ASSERT_FALSE(MUtils::remove_directory(dir.absolutePath(), false));
324                 dir.refresh();
325                 ASSERT_TRUE(dir.exists());
326                 ASSERT_TRUE(MUtils::remove_directory(dir.absolutePath(), true));
327                 dir.refresh();
328                 ASSERT_FALSE(dir.exists());
329         }
330 }
331
332 #undef MAKE_TEST_FILE
333 #undef MAKE_SUB_DIR
334
335 //-----------------------------------------------------------------
336 // Natural String Sort
337 //-----------------------------------------------------------------
338
339 TEST_F(GlobalTest, NaturalStrSort)
340 {
341         static const char *const TEST[] =
342         {
343                 "z0.txt",   "z1.txt",   "z2.txt",   "z3.txt",   "z4.txt",   "z5.txt",   "z6.txt",   "z7.txt",   "z8.txt",   "z9.txt",
344                 "z10.txt",  "z11.txt",  "z12.txt",  "z13.txt",  "z14.txt",  "z15.txt",  "z16.txt",  "z17.txt",  "z18.txt",  "z19.txt",
345                 "z100.txt", "z101.txt", "z102.txt", "z103.txt", "z104.txt", "z105.txt", "z106.txt", "z107.txt", "z108.txt", "z109.txt",
346                 NULL
347         };
348
349         QStringList test;
350         for (size_t i = 0; TEST[i]; i++)
351         {
352                 test << QLatin1String(TEST[i]);
353         }
354
355         qsrand(time(NULL));
356         for (size_t q = 0; q < 97; q++)
357         {
358                 for (size_t k = 0; k < 997; k++)
359                 {
360                         const size_t len = size_t(test.count());
361                         for (size_t i = 0; i < len; i++)
362                         {
363                                 test.swap(i, qrand() % len);
364                         }
365                 }
366                 MUtils::natural_string_sort(test, true);
367                 for (size_t i = 0; TEST[i]; i++)
368                 {
369                         ASSERT_QSTR(test[i], TEST[i]);
370                 }
371         }
372 }
373
374 //-----------------------------------------------------------------
375 // RegExp Parser
376 //-----------------------------------------------------------------
377
378 #define TEST_REGEX_U32(X,Y,Z,...) do \
379 { \
380         const QRegExp test(QLatin1String((X))); \
381         ASSERT_GE(test.indexIn(QLatin1String((Y))), 0); \
382         quint32 result[(Z)]; \
383         ASSERT_TRUE(MUtils::regexp_parse_uint32(test, result, (Z))); \
384         const quint32 expected[] = { __VA_ARGS__ }; \
385         for(size_t i = 0; i < (Z); i++) \
386         { \
387                 ASSERT_EQ(result[i], expected[i]); \
388         } \
389 } \
390 while(0)
391
392 TEST_F(GlobalTest, ParseRegExp)
393 {
394         TEST_REGEX_U32("(\\d+)", "42", 1, 42);
395         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);
396         TEST_REGEX_U32("x264\\s+(\\d+)\\.(\\d+)\\.(\\d+)\\s+\\w+", "x264 0.148.2744 b97ae06", 3, 0, 148, 2744);
397         TEST_REGEX_U32("HEVC\\s+encoder\\s+version\\s+(\\d+)\\.(\\d+)\\+(\\d+)-\\w+", "HEVC encoder version 2.1+70-78e1e1354a25", 3, 2, 1, 70);
398 }
399
400 #undef TEST_REGEX_U32