1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the test suite of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | #include "tst_qmakelib.h" |
30 | |
31 | #include <ioutils.h> |
32 | |
33 | using namespace QMakeInternal; |
34 | |
35 | void tst_qmakelib::initTestCase() |
36 | { |
37 | m_indir = QFINDTESTDATA("testdata" ); |
38 | m_outdir = m_indir + QLatin1String("_build" ); |
39 | m_env.insert(QStringLiteral("E1" ), QStringLiteral("env var" )); |
40 | #ifdef Q_OS_WIN |
41 | m_env.insert(QStringLiteral("COMSPEC" ), qgetenv("COMSPEC" )); |
42 | #endif |
43 | m_prop.insert(akey: ProKey("P1" ), avalue: ProString("prop val" )); |
44 | m_prop.insert(akey: ProKey("QT_HOST_DATA/get" ), avalue: ProString(m_indir)); |
45 | m_prop.insert(akey: ProKey("QT_HOST_DATA/src" ), avalue: ProString(m_indir)); |
46 | |
47 | QVERIFY(!m_indir.isEmpty()); |
48 | QVERIFY(QDir(m_outdir).removeRecursively()); |
49 | QVERIFY(QDir().mkpath(m_outdir)); |
50 | } |
51 | |
52 | void tst_qmakelib::cleanupTestCase() |
53 | { |
54 | QVERIFY(QDir(m_outdir).removeRecursively()); |
55 | } |
56 | |
57 | void tst_qmakelib::proString() |
58 | { |
59 | QString qs1(QStringLiteral("this is a string" )); |
60 | |
61 | ProString s1(qs1); |
62 | QCOMPARE(s1.toQString(), QStringLiteral("this is a string" )); |
63 | |
64 | ProString s2(qs1, 5, 8); |
65 | QCOMPARE(s2.toQString(), QStringLiteral("is a str" )); |
66 | |
67 | QCOMPARE(s2.hash(), 0x80000000); |
68 | qHash(str: s2); |
69 | QCOMPARE(s2.hash(), 90404018U); |
70 | |
71 | QCOMPARE(s2.mid(0, 10).toQString(), QStringLiteral("is a str" )); |
72 | QCOMPARE(s2.mid(1, 5).toQString(), QStringLiteral("s a s" )); |
73 | QCOMPARE(s2.mid(10, 3).toQString(), QStringLiteral("" )); |
74 | |
75 | QString qs2(QStringLiteral(" spacy string " )); |
76 | QCOMPARE(ProString(qs2, 3, 13).trimmed().toQString(), QStringLiteral("spacy string" )); |
77 | QCOMPARE(ProString(qs2, 1, 17).trimmed().toQString(), QStringLiteral("spacy string" )); |
78 | |
79 | QVERIFY(s2.toQStringRef().string()->isSharedWith(qs1)); |
80 | s2.prepend(other: ProString("there " )); |
81 | QCOMPARE(s2.toQString(), QStringLiteral("there is a str" )); |
82 | QVERIFY(!s2.toQStringRef().string()->isSharedWith(qs1)); |
83 | |
84 | ProString s3("this is a longish string with bells and whistles" ); |
85 | s3 = s3.mid(off: 18, len: 17); |
86 | // Prepend to detached string with lots of spare space in it. |
87 | s3.prepend(other: ProString("another " )); |
88 | QCOMPARE(s3.toQString(), QStringLiteral("another string with bells" )); |
89 | |
90 | // Note: The string still has plenty of spare space. |
91 | s3.append(other: QLatin1Char('.')); |
92 | QCOMPARE(s3.toQString(), QStringLiteral("another string with bells." )); |
93 | s3.append(other: QLatin1String(" eh?" )); |
94 | QCOMPARE(s3.toQString(), QStringLiteral("another string with bells. eh?" )); |
95 | |
96 | s3.append(other: ProString(" yeah!" )); |
97 | QCOMPARE(s3.toQString(), QStringLiteral("another string with bells. eh? yeah!" )); |
98 | |
99 | bool pending = false; // Not in string, but joining => add space |
100 | s3.append(other: ProString("..." ), pending: &pending); |
101 | QCOMPARE(s3.toQString(), QStringLiteral("another string with bells. eh? yeah! ..." )); |
102 | QVERIFY(pending); |
103 | |
104 | ProStringList sl1; |
105 | sl1 << ProString("" ) << ProString("foo" ) << ProString("barbaz" ); |
106 | ProString s4a("hallo" ); |
107 | s4a.append(other: sl1); |
108 | QCOMPARE(s4a.toQString(), QStringLiteral("hallo foo barbaz" )); |
109 | ProString s4b("hallo" ); |
110 | pending = false; |
111 | s4b.append(other: sl1, pending: &pending); |
112 | QCOMPARE(s4b.toQString(), QStringLiteral("hallo foo barbaz" )); |
113 | ProString s4c; |
114 | pending = false; |
115 | s4c.append(other: sl1, pending: &pending); |
116 | QCOMPARE(s4c.toQString(), QStringLiteral(" foo barbaz" )); |
117 | // bizarreness |
118 | ProString s4d("hallo" ); |
119 | pending = false; |
120 | s4d.append(other: sl1, pending: &pending, skipEmpty1st: true); |
121 | QCOMPARE(s4d.toQString(), QStringLiteral("hallo foo barbaz" )); |
122 | ProString s4e; |
123 | pending = false; |
124 | s4e.append(other: sl1, pending: &pending, skipEmpty1st: true); |
125 | QCOMPARE(s4e.toQString(), QStringLiteral("foo barbaz" )); |
126 | |
127 | ProStringList sl2; |
128 | sl2 << ProString("foo" ); |
129 | ProString s5; |
130 | s5.append(other: sl2); |
131 | QCOMPARE(s5.toQString(), QStringLiteral("foo" )); |
132 | QVERIFY(s5.toQStringRef().string()->isSharedWith(*sl2.first().toQStringRef().string())); |
133 | |
134 | QCOMPARE(ProString("one" ) + ProString(" more" ), QStringLiteral("one more" )); |
135 | } |
136 | |
137 | void tst_qmakelib::proStringList() |
138 | { |
139 | ProStringList sl1; |
140 | sl1 << ProString("qt" ) << ProString(QLatin1String("is" )) |
141 | << ProString(QStringLiteral("uncool" )).mid(off: 2); |
142 | |
143 | QCOMPARE(sl1.toQStringList(), QStringList() << "qt" << "is" << "cool" ); |
144 | QCOMPARE(sl1.join(QStringLiteral("~~" )), QStringLiteral("qt~~is~~cool" )); |
145 | |
146 | ProStringList sl2; |
147 | sl2 << ProString("mostly" ) << ProString("..." ) << ProString("is" ) << ProString("..." ); |
148 | sl1.insertUnique(value: sl2); |
149 | QCOMPARE(sl1.toQStringList(), QStringList() << "qt" << "is" << "cool" << "mostly" << "..." ); |
150 | |
151 | QVERIFY(sl1.contains("cool" )); |
152 | QVERIFY(!sl1.contains("COOL" )); |
153 | QVERIFY(sl1.contains("COOL" , Qt::CaseInsensitive)); |
154 | } |
155 | |
156 | void tst_qmakelib::quoteArgUnix_data() |
157 | { |
158 | QTest::addColumn<QString>(name: "in" ); |
159 | QTest::addColumn<QString>(name: "out" ); |
160 | |
161 | static const struct { |
162 | const char * const in; |
163 | const char * const out; |
164 | } vals[] = { |
165 | { .in: "" , .out: "''" }, |
166 | { .in: "hallo" , .out: "hallo" }, |
167 | { .in: "hallo du" , .out: "'hallo du'" }, |
168 | { .in: "ha'llo" , .out: "'ha'\\''llo'" }, |
169 | }; |
170 | |
171 | for (unsigned i = 0; i < sizeof(vals)/sizeof(vals[0]); i++) |
172 | QTest::newRow(dataTag: vals[i].in) << QString::fromLatin1(str: vals[i].in) |
173 | << QString::fromLatin1(str: vals[i].out); |
174 | } |
175 | |
176 | void tst_qmakelib::quoteArgUnix() |
177 | { |
178 | QFETCH(QString, in); |
179 | QFETCH(QString, out); |
180 | |
181 | QCOMPARE(IoUtils::shellQuoteUnix(in), out); |
182 | } |
183 | |
184 | void tst_qmakelib::quoteArgWin_data() |
185 | { |
186 | QTest::addColumn<QString>(name: "in" ); |
187 | QTest::addColumn<QString>(name: "out" ); |
188 | |
189 | static const struct { |
190 | const char * const in; |
191 | const char * const out; |
192 | } vals[] = { |
193 | { .in: "" , .out: "\"\"" }, |
194 | { .in: "hallo" , .out: "hallo" }, |
195 | { .in: "hallo du" , .out: "\"hallo du\"" }, |
196 | { .in: "hallo\\" , .out: "hallo\\" }, |
197 | { .in: "hallo du\\" , .out: "\"hallo du\\\\\"" }, |
198 | { .in: "ha\"llo" , .out: "\"ha\\\"llo^\"" }, |
199 | { .in: "ha\\\"llo" , .out: "\"ha\\\\\\\"llo^\"" }, |
200 | }; |
201 | |
202 | for (unsigned i = 0; i < sizeof(vals)/sizeof(vals[0]); i++) |
203 | QTest::newRow(dataTag: vals[i].in) << QString::fromLatin1(str: vals[i].in) |
204 | << QString::fromLatin1(str: vals[i].out); |
205 | } |
206 | |
207 | void tst_qmakelib::quoteArgWin() |
208 | { |
209 | QFETCH(QString, in); |
210 | QFETCH(QString, out); |
211 | |
212 | QCOMPARE(IoUtils::shellQuoteWin(in), out); |
213 | } |
214 | |
215 | void tst_qmakelib::pathUtils() |
216 | { |
217 | QString afp = QCoreApplication::applicationFilePath(); |
218 | QVERIFY(IoUtils::exists(afp)); |
219 | QVERIFY(!IoUtils::exists(afp + "-tehfail" )); |
220 | QCOMPARE(IoUtils::fileType(afp), IoUtils::FileIsRegular); |
221 | QString adp = QCoreApplication::applicationDirPath(); |
222 | QCOMPARE(IoUtils::fileType(adp), IoUtils::FileIsDir); |
223 | |
224 | QString fn0 = "file/path" ; |
225 | QVERIFY(IoUtils::isRelativePath(fn0)); |
226 | |
227 | QString fn1 = "/a/unix/file/path" ; |
228 | QCOMPARE(IoUtils::pathName(fn1).toString(), QStringLiteral("/a/unix/file/" )); |
229 | QCOMPARE(IoUtils::fileName(fn1).toString(), QStringLiteral("path" )); |
230 | } |
231 | |
232 | void tst_qmakelib::ioUtilRelativity_data() |
233 | { |
234 | QTest::addColumn<QString>(name: "path" ); |
235 | QTest::addColumn<bool>(name: "relative" ); |
236 | |
237 | static const struct { |
238 | const char *name; |
239 | const char *path; |
240 | bool relative; |
241 | } rows[] = { |
242 | { .name: "resource" , .path: ":/resource" , |
243 | #ifdef QMAKE_BUILTIN_PRFS |
244 | false |
245 | #else |
246 | .relative: true |
247 | #endif |
248 | }, |
249 | #ifdef Q_OS_WIN // all the complications: |
250 | // (except UNC: unsupported) |
251 | { "drive-abs" , "c:/path/to/file" , false }, |
252 | { "drive-abs-bs" , "c:\\path\\to\\file" , false }, |
253 | { "drive-path" , "c:path/to/file.txt" , true }, |
254 | { "drive-path-bs" , "c:path\\to\\file.txt" , true }, |
255 | { "rooted" , "/Users/qt/bin/true" , true }, |
256 | { "rooted-bs" , "\\Users\\qt\\bin\\true" , true }, |
257 | { "drive-rel" , "c:file.txt" , true }, |
258 | { "subdir-bs" , "path\\to\\file" , true }, |
259 | #else |
260 | { .name: "rooted" , .path: "/usr/bin/false" , .relative: false }, |
261 | #endif // Q_OS_WIN |
262 | { .name: "subdir" , .path: "path/to/file" , .relative: true }, |
263 | { .name: "simple" , .path: "file.name" , .relative: true }, |
264 | { .name: "empty" , .path: "" , .relative: true } |
265 | }; |
266 | |
267 | for (unsigned int i = sizeof(rows) / sizeof(rows[0]); i-- > 0; ) |
268 | QTest::newRow(dataTag: rows[i].name) << QString::fromLatin1(str: rows[i].path) |
269 | << rows[i].relative; |
270 | } |
271 | |
272 | void tst_qmakelib::ioUtilRelativity() |
273 | { |
274 | QFETCH(QString, path); |
275 | QFETCH(bool, relative); |
276 | |
277 | QCOMPARE(IoUtils::isRelativePath(path), relative); |
278 | } |
279 | |
280 | void tst_qmakelib::ioUtilResolve_data() |
281 | { |
282 | QTest::addColumn<QString>(name: "base" ); |
283 | QTest::addColumn<QString>(name: "path" ); |
284 | QTest::addColumn<QString>(name: "expect" ); |
285 | |
286 | static const struct { |
287 | const char *name; |
288 | const char *base; |
289 | const char *path; |
290 | const char *expect; |
291 | } data[] = { |
292 | #ifdef Q_OS_WIN // all the complications: |
293 | { "drive-drive" , "a:/ms/dir" , "z:/root/file" , "z:/root/file" }, |
294 | { "drive-drive-bs" , "a:\\ms\\dir" , "z:\\root\\file" , "z:/root/file" }, |
295 | { "drive-root" , "a:/ms/dir" , "/root/file" , "a:/root/file" }, |
296 | { "drive-root-bs" , "a:\\ms\\dir" , "\\root\\file" , "a:/root/file" }, |
297 | { "drive-sub" , "a:/ms/dir" , "sub/file" , "a:/ms/dir/sub/file" }, |
298 | { "drive-sub-bs" , "a:\\ms\\dir" , "sub\\file" , "a:/ms/dir/sub/file" }, |
299 | { "drive-rel" , "a:/ms/dir" , "file.txt" , "a:/ms/dir/file.txt" }, |
300 | { "drive-rel-bs" , "a:\\ms\\dir" , "file.txt" , "a:/ms/dir/file.txt" }, |
301 | #else |
302 | { .name: "abs-abs" , .base: "/a/unix/dir" , .path: "/root/file" , .expect: "/root/file" }, |
303 | { .name: "abs-sub" , .base: "/a/unix/dir" , .path: "sub/file" , .expect: "/a/unix/dir/sub/file" }, |
304 | { .name: "abs-rel" , .base: "/a/unix/dir" , .path: "file.txt" , .expect: "/a/unix/dir/file.txt" }, |
305 | #endif // Q_OS_WIN |
306 | }; |
307 | |
308 | for (unsigned i = sizeof(data) / sizeof(data[0]); i-- > 0; ) |
309 | QTest::newRow(dataTag: data[i].name) << QString::fromLatin1(str: data[i].base) |
310 | << QString::fromLatin1(str: data[i].path) |
311 | << QString::fromLatin1(str: data[i].expect); |
312 | } |
313 | |
314 | void tst_qmakelib::ioUtilResolve() |
315 | { |
316 | QFETCH(QString, base); |
317 | QFETCH(QString, path); |
318 | QFETCH(QString, expect); |
319 | |
320 | QCOMPARE(IoUtils::resolvePath(base, path), expect); |
321 | } |
322 | |
323 | void QMakeTestHandler::print(const QString &fileName, int lineNo, int type, const QString &msg) |
324 | { |
325 | QString pfx = ((type & QMakeParserHandler::CategoryMask) == QMakeParserHandler::WarningMessage) |
326 | ? QString::fromLatin1(str: "WARNING: " ) : QString(); |
327 | if (lineNo) |
328 | doPrint(QStringLiteral("%1%2:%3: %4" ).arg(args&: pfx, args: fileName, args: QString::number(lineNo), args: msg)); |
329 | else |
330 | doPrint(QStringLiteral("%1%2" ).arg(args&: pfx, args: msg)); |
331 | } |
332 | |
333 | void QMakeTestHandler::doPrint(const QString &msg) |
334 | { |
335 | if (!expected.isEmpty() && expected.first() == msg) { |
336 | expected.removeAt(i: 0); |
337 | } else { |
338 | qWarning(msg: "%s" , qPrintable(msg)); |
339 | printed = true; |
340 | } |
341 | } |
342 | |
343 | QTEST_MAIN(tst_qmakelib) |
344 | |