1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Copyright (C) 2016 Intel Corporation. |
5 | ** Contact: https://www.qt.io/licensing/ |
6 | ** |
7 | ** This file is part of the test suite of the Qt Toolkit. |
8 | ** |
9 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
10 | ** Commercial License Usage |
11 | ** Licensees holding valid commercial Qt licenses may use this file in |
12 | ** accordance with the commercial license agreement provided with the |
13 | ** Software or, alternatively, in accordance with the terms contained in |
14 | ** a written agreement between you and The Qt Company. For licensing terms |
15 | ** and conditions see https://www.qt.io/terms-conditions. For further |
16 | ** information use the contact form at https://www.qt.io/contact-us. |
17 | ** |
18 | ** GNU General Public License Usage |
19 | ** Alternatively, this file may be used under the terms of the GNU |
20 | ** General Public License version 3 as published by the Free Software |
21 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
22 | ** included in the packaging of this file. Please review the following |
23 | ** information to ensure the GNU General Public License requirements will |
24 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
25 | ** |
26 | ** $QT_END_LICENSE$ |
27 | ** |
28 | ****************************************************************************/ |
29 | |
30 | #include <QtCore/QUrl> |
31 | #include <QtTest/QtTest> |
32 | |
33 | #include "private/qtldurl_p.h" |
34 | #include "private/qurl_p.h" |
35 | |
36 | // For testsuites |
37 | #define IDNA_ACE_PREFIX "xn--" |
38 | #define IDNA_SUCCESS 1 |
39 | #define STRINGPREP_NO_UNASSIGNED 1 |
40 | #define STRINGPREP_CONTAINS_UNASSIGNED 2 |
41 | #define STRINGPREP_CONTAINS_PROHIBITED 3 |
42 | #define STRINGPREP_BIDI_BOTH_L_AND_RAL 4 |
43 | #define STRINGPREP_BIDI_LEADTRAIL_NOT_RAL 5 |
44 | |
45 | struct ushortarray { |
46 | ushortarray() {} |
47 | template <size_t N> |
48 | ushortarray(unsigned short (&array)[N]) |
49 | { |
50 | memcpy(points, array, N*sizeof(unsigned short)); |
51 | } |
52 | |
53 | unsigned short points[100]; |
54 | }; |
55 | |
56 | Q_DECLARE_METATYPE(ushortarray) |
57 | Q_DECLARE_METATYPE(QUrl::FormattingOptions) |
58 | Q_DECLARE_METATYPE(QUrl::ComponentFormattingOptions) |
59 | |
60 | class tst_QUrlInternal : public QObject |
61 | { |
62 | Q_OBJECT |
63 | |
64 | private Q_SLOTS: |
65 | // IDNA internals |
66 | #ifdef QT_BUILD_INTERNAL |
67 | void idna_testsuite_data(); |
68 | void idna_testsuite(); |
69 | void nameprep_testsuite_data(); |
70 | void nameprep_testsuite(); |
71 | void nameprep_highcodes_data(); |
72 | void nameprep_highcodes(); |
73 | #endif |
74 | void ace_testsuite_data(); |
75 | void ace_testsuite(); |
76 | void std3violations_data(); |
77 | void std3violations(); |
78 | void std3deviations_data(); |
79 | void std3deviations(); |
80 | |
81 | // percent-encoding internals |
82 | void correctEncodedMistakes_data(); |
83 | void correctEncodedMistakes(); |
84 | void encodingRecode_data(); |
85 | void encodingRecode(); |
86 | void encodingRecodeInvalidUtf8_data(); |
87 | void encodingRecodeInvalidUtf8(); |
88 | void recodeByteArray_data(); |
89 | void recodeByteArray(); |
90 | }; |
91 | #include "tst_qurlinternal.moc" |
92 | |
93 | #ifdef QT_BUILD_INTERNAL |
94 | void tst_QUrlInternal::idna_testsuite_data() |
95 | { |
96 | QTest::addColumn<int>("numchars" ); |
97 | QTest::addColumn<ushortarray>("unicode" ); |
98 | QTest::addColumn<QByteArray>("punycode" ); |
99 | QTest::addColumn<int>("allowunassigned" ); |
100 | QTest::addColumn<int>("usestd3asciirules" ); |
101 | QTest::addColumn<int>("toasciirc" ); |
102 | QTest::addColumn<int>("tounicoderc" ); |
103 | |
104 | unsigned short d1[] = { 0x0644, 0x064A, 0x0647, 0x0645, 0x0627, 0x0628, 0x062A, 0x0643, |
105 | 0x0644, 0x0645, 0x0648, 0x0634, 0x0639, 0x0631, 0x0628, 0x064A, |
106 | 0x061F }; |
107 | QTest::newRow(dataTag: "Arabic (Egyptian)" ) << 17 << ushortarray(d1) |
108 | << QByteArray(IDNA_ACE_PREFIX "egbpdaj6bu4bxfgehfvwxn" ) |
109 | << 0 << 0 << IDNA_SUCCESS << IDNA_SUCCESS; |
110 | |
111 | unsigned short d2[] = { 0x4ED6, 0x4EEC, 0x4E3A, 0x4EC0, 0x4E48, 0x4E0D, 0x8BF4, 0x4E2D, |
112 | 0x6587 }; |
113 | QTest::newRow(dataTag: "Chinese (simplified)" ) << 9 << ushortarray(d2) |
114 | << QByteArray(IDNA_ACE_PREFIX "ihqwcrb4cv8a8dqg056pqjye" ) |
115 | << 0 << 0 << IDNA_SUCCESS << IDNA_SUCCESS; |
116 | |
117 | unsigned short d3[] = { 0x4ED6, 0x5011, 0x7232, 0x4EC0, 0x9EBD, 0x4E0D, 0x8AAA, 0x4E2D, |
118 | 0x6587 }; |
119 | QTest::newRow(dataTag: "Chinese (traditional)" ) << 9 << ushortarray(d3) |
120 | << QByteArray(IDNA_ACE_PREFIX "ihqwctvzc91f659drss3x8bo0yb" ) |
121 | << 0 << 0 << IDNA_SUCCESS << IDNA_SUCCESS; |
122 | |
123 | unsigned short d4[] = { 0x0050, 0x0072, 0x006F, 0x010D, 0x0070, 0x0072, 0x006F, 0x0073, |
124 | 0x0074, 0x011B, 0x006E, 0x0065, 0x006D, 0x006C, 0x0075, 0x0076, |
125 | 0x00ED, 0x010D, 0x0065, 0x0073, 0x006B, 0x0079 }; |
126 | QTest::newRow(dataTag: "Czech" ) << 22 << ushortarray(d4) |
127 | << QByteArray(IDNA_ACE_PREFIX "Proprostnemluvesky-uyb24dma41a" ) |
128 | << 0 << 0 << IDNA_SUCCESS << IDNA_SUCCESS; |
129 | |
130 | unsigned short d5[] = { 0x05DC, 0x05DE, 0x05D4, 0x05D4, 0x05DD, 0x05E4, 0x05E9, 0x05D5, |
131 | 0x05D8, 0x05DC, 0x05D0, 0x05DE, 0x05D3, 0x05D1, 0x05E8, 0x05D9, |
132 | 0x05DD, 0x05E2, 0x05D1, 0x05E8, 0x05D9, 0x05EA }; |
133 | QTest::newRow(dataTag: "Hebrew" ) << 22 << ushortarray(d5) |
134 | << QByteArray(IDNA_ACE_PREFIX "4dbcagdahymbxekheh6e0a7fei0b" ) |
135 | << 0 << 0 << IDNA_SUCCESS << IDNA_SUCCESS; |
136 | |
137 | unsigned short d6[] = { 0x092F, 0x0939, 0x0932, 0x094B, 0x0917, 0x0939, 0x093F, 0x0928, |
138 | 0x094D, 0x0926, 0x0940, 0x0915, 0x094D, 0x092F, 0x094B, 0x0902, |
139 | 0x0928, 0x0939, 0x0940, 0x0902, 0x092C, 0x094B, 0x0932, 0x0938, |
140 | 0x0915, 0x0924, 0x0947, 0x0939, 0x0948, 0x0902 }; |
141 | QTest::newRow(dataTag: "Hindi (Devanagari)" ) << 30 << ushortarray(d6) |
142 | << QByteArray(IDNA_ACE_PREFIX "i1baa7eci9glrd9b2ae1bj0hfcgg6iyaf8o0a1dig0cd" ) |
143 | << 0 << 0 << IDNA_SUCCESS; |
144 | |
145 | unsigned short d7[] = { 0x306A, 0x305C, 0x307F, 0x3093, 0x306A, 0x65E5, 0x672C, 0x8A9E, |
146 | 0x3092, 0x8A71, 0x3057, 0x3066, 0x304F, 0x308C, 0x306A, 0x3044, |
147 | 0x306E, 0x304B }; |
148 | QTest::newRow(dataTag: "Japanese (kanji and hiragana)" ) << 18 << ushortarray(d7) |
149 | << QByteArray(IDNA_ACE_PREFIX "n8jok5ay5dzabd5bym9f0cm5685rrjetr6pdxa" ) |
150 | << 0 << 0 << IDNA_SUCCESS; |
151 | |
152 | unsigned short d8[] = { 0x043F, 0x043E, 0x0447, 0x0435, 0x043C, 0x0443, 0x0436, 0x0435, |
153 | 0x043E, 0x043D, 0x0438, 0x043D, 0x0435, 0x0433, 0x043E, 0x0432, |
154 | 0x043E, 0x0440, 0x044F, 0x0442, 0x043F, 0x043E, 0x0440, 0x0443, |
155 | 0x0441, 0x0441, 0x043A, 0x0438 }; |
156 | QTest::newRow(dataTag: "Russian (Cyrillic)" ) << 28 << ushortarray(d8) |
157 | << QByteArray(IDNA_ACE_PREFIX "b1abfaaepdrnnbgefbadotcwatmq2g4l" ) |
158 | << 0 << 0 << IDNA_SUCCESS << IDNA_SUCCESS; |
159 | |
160 | unsigned short d9[] = { 0x0050, 0x006F, 0x0072, 0x0071, 0x0075, 0x00E9, 0x006E, 0x006F, |
161 | 0x0070, 0x0075, 0x0065, 0x0064, 0x0065, 0x006E, 0x0073, 0x0069, |
162 | 0x006D, 0x0070, 0x006C, 0x0065, 0x006D, 0x0065, 0x006E, 0x0074, |
163 | 0x0065, 0x0068, 0x0061, 0x0062, 0x006C, 0x0061, 0x0072, 0x0065, |
164 | 0x006E, 0x0045, 0x0073, 0x0070, 0x0061, 0x00F1, 0x006F, 0x006C }; |
165 | QTest::newRow(dataTag: "Spanish" ) << 40 << ushortarray(d9) |
166 | << QByteArray(IDNA_ACE_PREFIX "PorqunopuedensimplementehablarenEspaol-fmd56a" ) |
167 | << 0 << 0 << IDNA_SUCCESS; |
168 | |
169 | unsigned short d10[] = { 0x0054, 0x1EA1, 0x0069, 0x0073, 0x0061, 0x006F, 0x0068, 0x1ECD, |
170 | 0x006B, 0x0068, 0x00F4, 0x006E, 0x0067, 0x0074, 0x0068, 0x1EC3, |
171 | 0x0063, 0x0068, 0x1EC9, 0x006E, 0x00F3, 0x0069, 0x0074, 0x0069, |
172 | 0x1EBF, 0x006E, 0x0067, 0x0056, 0x0069, 0x1EC7, 0x0074 }; |
173 | QTest::newRow(dataTag: "Vietnamese" ) << 31 << ushortarray(d10) |
174 | << QByteArray(IDNA_ACE_PREFIX "TisaohkhngthchnitingVit-kjcr8268qyxafd2f1b9g" ) |
175 | << 0 << 0 << IDNA_SUCCESS; |
176 | |
177 | unsigned short d11[] = { 0x0033, 0x5E74, 0x0042, 0x7D44, 0x91D1, 0x516B, 0x5148, 0x751F }; |
178 | QTest::newRow(dataTag: "Japanese" ) << 8 << ushortarray(d11) |
179 | << QByteArray(IDNA_ACE_PREFIX "3B-ww4c5e180e575a65lsy2b" ) |
180 | << 0 << 0 << IDNA_SUCCESS << IDNA_SUCCESS; |
181 | |
182 | // this test does NOT include nameprepping, so the capitals will remain |
183 | unsigned short d12[] = { 0x5B89, 0x5BA4, 0x5948, 0x7F8E, 0x6075, 0x002D, 0x0077, 0x0069, |
184 | 0x0074, 0x0068, 0x002D, 0x0053, 0x0055, 0x0050, 0x0045, 0x0052, |
185 | 0x002D, 0x004D, 0x004F, 0x004E, 0x004B, 0x0045, 0x0059, 0x0053 }; |
186 | QTest::newRow(dataTag: "Japanese2" ) << 24 << ushortarray(d12) |
187 | << QByteArray(IDNA_ACE_PREFIX "-with-SUPER-MONKEYS-pc58ag80a8qai00g7n9n" ) |
188 | << 0 << 0 << IDNA_SUCCESS; |
189 | |
190 | unsigned short d13[] = { 0x0048, 0x0065, 0x006C, 0x006C, 0x006F, 0x002D, 0x0041, 0x006E, |
191 | 0x006F, 0x0074, 0x0068, 0x0065, 0x0072, 0x002D, 0x0057, 0x0061, |
192 | 0x0079, 0x002D, 0x305D, 0x308C, 0x305E, 0x308C, 0x306E, 0x5834, |
193 | 0x6240 }; |
194 | QTest::newRow(dataTag: "Japanese3" ) << 25 << ushortarray(d13) |
195 | << QByteArray(IDNA_ACE_PREFIX "Hello-Another-Way--fc4qua05auwb3674vfr0b" ) |
196 | << 0 << 0 << IDNA_SUCCESS; |
197 | |
198 | unsigned short d14[] = { 0x3072, 0x3068, 0x3064, 0x5C4B, 0x6839, 0x306E, 0x4E0B, 0x0032 }; |
199 | QTest::newRow(dataTag: "Japanese4" ) << 8 << ushortarray(d14) |
200 | << QByteArray(IDNA_ACE_PREFIX "2-u9tlzr9756bt3uc0v" ) |
201 | << 0 << 0 << IDNA_SUCCESS << IDNA_SUCCESS; |
202 | |
203 | unsigned short d15[] = { 0x004D, 0x0061, 0x006A, 0x0069, 0x3067, 0x004B, 0x006F, 0x0069, |
204 | 0x3059, 0x308B, 0x0035, 0x79D2, 0x524D }; |
205 | QTest::newRow(dataTag: "Japanese5" ) << 13 << ushortarray(d15) |
206 | << QByteArray(IDNA_ACE_PREFIX "MajiKoi5-783gue6qz075azm5e" ) |
207 | << 0 << 0 << IDNA_SUCCESS << IDNA_SUCCESS; |
208 | |
209 | unsigned short d16[] = { 0x30D1, 0x30D5, 0x30A3, 0x30FC, 0x0064, 0x0065, 0x30EB, 0x30F3, 0x30D0 }; |
210 | QTest::newRow(dataTag: "Japanese6" ) << 9 << ushortarray(d16) |
211 | << QByteArray(IDNA_ACE_PREFIX "de-jg4avhby1noc0d" ) |
212 | << 0 << 0 << IDNA_SUCCESS << IDNA_SUCCESS; |
213 | |
214 | unsigned short d17[] = { 0x305D, 0x306E, 0x30B9, 0x30D4, 0x30FC, 0x30C9, 0x3067 }; |
215 | QTest::newRow(dataTag: "Japanese7" ) << 7 << ushortarray(d17) |
216 | << QByteArray(IDNA_ACE_PREFIX "d9juau41awczczp" ) |
217 | << 0 << 0 << IDNA_SUCCESS << IDNA_SUCCESS; |
218 | |
219 | unsigned short d18[] = { 0x03b5, 0x03bb, 0x03bb, 0x03b7, 0x03bd, 0x03b9, 0x03ba, 0x03ac }; |
220 | QTest::newRow(dataTag: "Greek" ) << 8 << ushortarray(d18) |
221 | << QByteArray(IDNA_ACE_PREFIX "hxargifdar" ) |
222 | << 0 << 0 << IDNA_SUCCESS << IDNA_SUCCESS; |
223 | |
224 | unsigned short d19[] = { 0x0062, 0x006f, 0x006e, 0x0121, 0x0075, 0x0073, 0x0061, 0x0127, |
225 | 0x0127, 0x0061 }; |
226 | QTest::newRow(dataTag: "Maltese (Malti)" ) << 10 << ushortarray(d19) |
227 | << QByteArray(IDNA_ACE_PREFIX "bonusaa-5bb1da" ) |
228 | << 0 << 0 << IDNA_SUCCESS << IDNA_SUCCESS; |
229 | |
230 | unsigned short d20[] = {0x043f, 0x043e, 0x0447, 0x0435, 0x043c, 0x0443, 0x0436, 0x0435, |
231 | 0x043e, 0x043d, 0x0438, 0x043d, 0x0435, 0x0433, 0x043e, 0x0432, |
232 | 0x043e, 0x0440, 0x044f, 0x0442, 0x043f, 0x043e, 0x0440, 0x0443, |
233 | 0x0441, 0x0441, 0x043a, 0x0438 }; |
234 | QTest::newRow(dataTag: "Russian (Cyrillic)" ) << 28 << ushortarray(d20) |
235 | << QByteArray(IDNA_ACE_PREFIX "b1abfaaepdrnnbgefbadotcwatmq2g4l" ) |
236 | << 0 << 0 << IDNA_SUCCESS << IDNA_SUCCESS; |
237 | } |
238 | #endif |
239 | |
240 | #ifdef QT_BUILD_INTERNAL |
241 | void tst_QUrlInternal::idna_testsuite() |
242 | { |
243 | QFETCH(int, numchars); |
244 | QFETCH(ushortarray, unicode); |
245 | QFETCH(QByteArray, punycode); |
246 | |
247 | QString result; |
248 | qt_punycodeEncoder(s: (QChar*)unicode.points, ucLength: numchars, output: &result); |
249 | QCOMPARE(result.toLatin1(), punycode); |
250 | QCOMPARE(qt_punycodeDecoder(result), QString::fromUtf16(unicode.points, numchars)); |
251 | } |
252 | #endif |
253 | |
254 | #ifdef QT_BUILD_INTERNAL |
255 | void tst_QUrlInternal::nameprep_testsuite_data() |
256 | { |
257 | QTest::addColumn<QString>(name: "in" ); |
258 | QTest::addColumn<QString>(name: "out" ); |
259 | QTest::addColumn<QString>(name: "profile" ); |
260 | QTest::addColumn<int>(name: "flags" ); |
261 | QTest::addColumn<int>(name: "rc" ); |
262 | |
263 | QTest::newRow(dataTag: "Map to nothing" ) |
264 | << QString::fromUtf8(str: "foo\xC2\xAD\xCD\x8F\xE1\xA0\x86\xE1\xA0\x8B" |
265 | "bar" "\xE2\x80\x8B\xE2\x81\xA0" "baz\xEF\xB8\x80\xEF\xB8\x88" |
266 | "\xEF\xB8\x8F\xEF\xBB\xBF" ) |
267 | << QString::fromUtf8(str: "foobarbaz" ) |
268 | << QString() << 0 << 0; |
269 | |
270 | QTest::newRow(dataTag: "Case folding ASCII U+0043 U+0041 U+0046 U+0045" ) |
271 | << QString::fromUtf8(str: "CAFE" ) |
272 | << QString::fromUtf8(str: "cafe" ) |
273 | << QString() << 0 << 0; |
274 | |
275 | QTest::newRow(dataTag: "Case folding 8bit U+00DF (german sharp s)" ) |
276 | << QString::fromUtf8(str: "\xC3\x9F" ) |
277 | << QString("ss" ) |
278 | << QString() << 0 << 0; |
279 | |
280 | QTest::newRow(dataTag: "Case folding U+0130 (turkish capital I with dot)" ) |
281 | << QString::fromUtf8(str: "\xC4\xB0" ) |
282 | << QString::fromUtf8(str: "i\xcc\x87" ) |
283 | << QString() << 0 << 0; |
284 | |
285 | QTest::newRow(dataTag: "Case folding multibyte U+0143 U+037A" ) |
286 | << QString::fromUtf8(str: "\xC5\x83\xCD\xBA" ) |
287 | << QString::fromUtf8(str: "\xC5\x84 \xCE\xB9" ) |
288 | << QString() << 0 << 0; |
289 | |
290 | QTest::newRow(dataTag: "Case folding U+2121 U+33C6 U+1D7BB" ) |
291 | << QString::fromUtf8(str: "\xE2\x84\xA1\xE3\x8F\x86\xF0\x9D\x9E\xBB" ) |
292 | << QString::fromUtf8(str: "telc\xE2\x88\x95" "kg\xCF\x83" ) |
293 | << QString() << 0 << 0; |
294 | |
295 | QTest::newRow(dataTag: "Normalization of U+006a U+030c U+00A0 U+00AA" ) |
296 | << QString::fromUtf8(str: "\x6A\xCC\x8C\xC2\xA0\xC2\xAA" ) |
297 | << QString::fromUtf8(str: "\xC7\xB0 a" ) |
298 | << QString() << 0 << 0; |
299 | |
300 | QTest::newRow(dataTag: "Case folding U+1FB7 and normalization" ) |
301 | << QString::fromUtf8(str: "\xE1\xBE\xB7" ) |
302 | << QString::fromUtf8(str: "\xE1\xBE\xB6\xCE\xB9" ) |
303 | << QString() << 0 << 0; |
304 | |
305 | QTest::newRow(dataTag: "Self-reverting case folding U+01F0 and normalization" ) |
306 | // << QString::fromUtf8("\xC7\xF0") ### typo in the original testsuite |
307 | << QString::fromUtf8(str: "\xC7\xB0" ) |
308 | << QString::fromUtf8(str: "\xC7\xB0" ) |
309 | << QString() << 0 << 0; |
310 | |
311 | QTest::newRow(dataTag: "Self-reverting case folding U+0390 and normalization" ) |
312 | << QString::fromUtf8(str: "\xCE\x90" ) |
313 | << QString::fromUtf8(str: "\xCE\x90" ) |
314 | << QString() << 0 << 0; |
315 | |
316 | QTest::newRow(dataTag: "Self-reverting case folding U+03B0 and normalization" ) |
317 | << QString::fromUtf8(str: "\xCE\xB0" ) |
318 | << QString::fromUtf8(str: "\xCE\xB0" ) |
319 | << QString() << 0 << 0; |
320 | |
321 | QTest::newRow(dataTag: "Self-reverting case folding U+1E96 and normalization" ) |
322 | << QString::fromUtf8(str: "\xE1\xBA\x96" ) |
323 | << QString::fromUtf8(str: "\xE1\xBA\x96" ) |
324 | << QString() << 0 << 0; |
325 | |
326 | QTest::newRow(dataTag: "Self-reverting case folding U+1F56 and normalization" ) |
327 | << QString::fromUtf8(str: "\xE1\xBD\x96" ) |
328 | << QString::fromUtf8(str: "\xE1\xBD\x96" ) |
329 | << QString() << 0 << 0; |
330 | |
331 | QTest::newRow(dataTag: "ASCII space character U+0020" ) |
332 | << QString::fromUtf8(str: "\x20" ) |
333 | << QString::fromUtf8(str: "\x20" ) |
334 | << QString() << 0 << 0; |
335 | |
336 | QTest::newRow(dataTag: "Non-ASCII 8bit space character U+00A0" ) |
337 | << QString::fromUtf8(str: "\xC2\xA0" ) |
338 | << QString::fromUtf8(str: "\x20" ) |
339 | << QString() << 0 << 0; |
340 | |
341 | QTest::newRow(dataTag: "Non-ASCII multibyte space character U+1680" ) |
342 | << QString::fromUtf8(str: "x\xE1\x9A\x80x" ) |
343 | << QString() |
344 | << QString("Nameprep" ) << 0 << STRINGPREP_CONTAINS_PROHIBITED; |
345 | |
346 | QTest::newRow(dataTag: "Non-ASCII multibyte space character U+2000" ) |
347 | << QString::fromUtf8(str: "\xE2\x80\x80" ) |
348 | << QString::fromUtf8(str: "\x20" ) |
349 | << QString() << 0 << 0; |
350 | |
351 | QTest::newRow(dataTag: "Zero Width Space U+200b" ) |
352 | << QString::fromUtf8(str: "\xE2\x80\x8b" ) |
353 | << QString() |
354 | << QString() << 0 << 0; |
355 | |
356 | QTest::newRow(dataTag: "Non-ASCII multibyte space character U+3000" ) |
357 | << QString::fromUtf8(str: "\xE3\x80\x80" ) |
358 | << QString::fromUtf8(str: "\x20" ) |
359 | << QString() << 0 << 0; |
360 | |
361 | QTest::newRow(dataTag: "ASCII control characters U+0010 U+007F" ) |
362 | << QString::fromUtf8(str: "\x10\x7F" ) |
363 | << QString::fromUtf8(str: "\x10\x7F" ) |
364 | << QString() << 0 << 0; |
365 | |
366 | QTest::newRow(dataTag: "Non-ASCII 8bit control character U+0080" ) |
367 | << QString::fromUtf8(str: "x\xC2\x80x" ) |
368 | << QString() |
369 | << QString("Nameprep" ) << 0 << STRINGPREP_CONTAINS_PROHIBITED; |
370 | |
371 | QTest::newRow(dataTag: "Non-ASCII 8bit control character U+0085" ) |
372 | << QString::fromUtf8(str: "x\xC2\x85x" ) |
373 | << QString() |
374 | << QString("Nameprep" ) << 0 << STRINGPREP_CONTAINS_PROHIBITED; |
375 | |
376 | QTest::newRow(dataTag: "Non-ASCII multibyte control character U+180E" ) |
377 | << QString::fromUtf8(str: "x\xE1\xA0\x8Ex" ) |
378 | << QString() |
379 | << QString("Nameprep" ) << 0 << STRINGPREP_CONTAINS_PROHIBITED; |
380 | |
381 | QTest::newRow(dataTag: "Zero Width No-Break Space U+FEFF" ) |
382 | << QString::fromUtf8(str: "\xEF\xBB\xBF" ) |
383 | << QString() |
384 | << QString() << 0 << 0; |
385 | |
386 | QTest::newRow(dataTag: "Non-ASCII control character U+1D175" ) |
387 | << QString::fromUtf8(str: "x\xF0\x9D\x85\xB5x" ) |
388 | << QString() |
389 | << QString("Nameprep" ) << 0 << STRINGPREP_CONTAINS_PROHIBITED; |
390 | |
391 | QTest::newRow(dataTag: "Plane 0 private use character U+F123" ) |
392 | << QString::fromUtf8(str: "x\xEF\x84\xA3x" ) |
393 | << QString() |
394 | << QString("Nameprep" ) << 0 << STRINGPREP_CONTAINS_PROHIBITED; |
395 | |
396 | QTest::newRow(dataTag: "Plane 15 private use character U+F1234" ) |
397 | << QString::fromUtf8(str: "x\xF3\xB1\x88\xB4x" ) |
398 | << QString() |
399 | << QString("Nameprep" ) << 0 << STRINGPREP_CONTAINS_PROHIBITED; |
400 | |
401 | QTest::newRow(dataTag: "Plane 16 private use character U+10F234" ) |
402 | << QString::fromUtf8(str: "x\xF4\x8F\x88\xB4x" ) |
403 | << QString() |
404 | << QString("Nameprep" ) << 0 << STRINGPREP_CONTAINS_PROHIBITED; |
405 | |
406 | QTest::newRow(dataTag: "Non-character code point U+8FFFE" ) |
407 | << QString::fromUtf8(str: "x\xF2\x8F\xBF\xBEx" ) |
408 | << QString() |
409 | << QString("Nameprep" ) << 0 << STRINGPREP_CONTAINS_PROHIBITED; |
410 | |
411 | QTest::newRow(dataTag: "Non-character code point U+10FFFF" ) |
412 | << QString::fromUtf8(str: "x\xF4\x8F\xBF\xBFx" ) |
413 | << QString() |
414 | << QString("Nameprep" ) << 0 << STRINGPREP_CONTAINS_PROHIBITED; |
415 | |
416 | QTest::newRow(dataTag: "Surrogate code U+DF42" ) |
417 | << QString::fromUtf8(str: "x\xED\xBD\x82x" ) |
418 | << QString() |
419 | << QString("Nameprep" ) << 0 << STRINGPREP_CONTAINS_PROHIBITED; |
420 | |
421 | QTest::newRow(dataTag: "Non-plain text character U+FFFD" ) |
422 | << QString::fromUtf8(str: "x\xEF\xBF\xBDx" ) |
423 | << QString() |
424 | << QString("Nameprep" ) << 0 << STRINGPREP_CONTAINS_PROHIBITED; |
425 | |
426 | QTest::newRow(dataTag: "Ideographic description character U+2FF5" ) |
427 | << QString::fromUtf8(str: "x\xE2\xBF\xB5x" ) |
428 | << QString() |
429 | << QString("Nameprep" ) << 0 << STRINGPREP_CONTAINS_PROHIBITED; |
430 | |
431 | QTest::newRow(dataTag: "Display property character U+0341" ) |
432 | << QString::fromUtf8(str: "\xCD\x81" ) |
433 | << QString::fromUtf8(str: "\xCC\x81" ) |
434 | << QString() << 0 << 0; |
435 | |
436 | QTest::newRow(dataTag: "Left-to-right mark U+200E" ) |
437 | << QString::fromUtf8(str: "x\xE2\x80\x8Ex" ) |
438 | << QString() |
439 | << QString("Nameprep" ) << 0 << STRINGPREP_CONTAINS_PROHIBITED; |
440 | |
441 | QTest::newRow(dataTag: "Deprecated U+202A" ) |
442 | << QString::fromUtf8(str: "x\xE2\x80\xAA" ) |
443 | << QString() |
444 | << QString("Nameprep" ) << 0 << STRINGPREP_CONTAINS_PROHIBITED; |
445 | |
446 | QTest::newRow(dataTag: "Language tagging character U+E0001" ) |
447 | << QString::fromUtf8(str: "x\xF3\xA0\x80\x81x" ) |
448 | << QString() |
449 | << QString("Nameprep" ) << 0 << STRINGPREP_CONTAINS_PROHIBITED; |
450 | |
451 | QTest::newRow(dataTag: "Language tagging character U+E0042" ) |
452 | << QString::fromUtf8(str: "x\xF3\xA0\x81\x82x" ) |
453 | << QString() |
454 | << QString("Nameprep" ) << 0 << STRINGPREP_CONTAINS_PROHIBITED; |
455 | |
456 | QTest::newRow(dataTag: "Bidi: RandALCat character U+05BE and LCat characters" ) |
457 | << QString::fromUtf8(str: "foo\xD6\xBE" "bar" ) |
458 | << QString() |
459 | << QString("Nameprep" ) << 0 << STRINGPREP_BIDI_BOTH_L_AND_RAL; |
460 | |
461 | QTest::newRow(dataTag: "Bidi: RandALCat character U+FD50 and LCat characters" ) |
462 | << QString::fromUtf8(str: "foo\xEF\xB5\x90" "bar" ) |
463 | << QString() |
464 | << QString("Nameprep" ) << 0 << STRINGPREP_BIDI_BOTH_L_AND_RAL; |
465 | |
466 | QTest::newRow(dataTag: "Bidi: RandALCat character U+FB38 and LCat characters" ) |
467 | << QString::fromUtf8(str: "foo\xEF\xB9\xB6" "bar" ) |
468 | << QString::fromUtf8(str: "foo \xd9\x8e" "bar" ) |
469 | << QString() << 0 << 0; |
470 | |
471 | QTest::newRow(dataTag: "Bidi: RandALCat without trailing RandALCat U+0627 U+0031" ) |
472 | << QString::fromUtf8(str: "\xD8\xA7\x31" ) |
473 | << QString() |
474 | << QString("Nameprep" ) << 0 << STRINGPREP_BIDI_LEADTRAIL_NOT_RAL; |
475 | |
476 | QTest::newRow(dataTag: "Bidi: RandALCat character U+0627 U+0031 U+0628" ) |
477 | << QString::fromUtf8(str: "\xD8\xA7\x31\xD8\xA8" ) |
478 | << QString::fromUtf8(str: "\xD8\xA7\x31\xD8\xA8" ) |
479 | << QString() << 0 << 0; |
480 | |
481 | QTest::newRow(dataTag: "Unassigned code point U+E0002" ) |
482 | << QString::fromUtf8(str: "\xF3\xA0\x80\x82" ) |
483 | << QString() |
484 | << QString("Nameprep" ) << STRINGPREP_NO_UNASSIGNED << STRINGPREP_CONTAINS_UNASSIGNED; |
485 | |
486 | QTest::newRow(dataTag: "Larger test (shrinking)" ) |
487 | << QString::fromUtf8(str: "X\xC2\xAD\xC3\x9F\xC4\xB0\xE2\x84\xA1\x6a\xcc\x8c\xc2\xa0\xc2" |
488 | "\xaa\xce\xb0\xe2\x80\x80" ) |
489 | << QString::fromUtf8(str: "xssi\xcc\x87" "tel\xc7\xb0 a\xce\xb0 " ) |
490 | << QString("Nameprep" ) << 0 << 0; |
491 | |
492 | QTest::newRow(dataTag: "Larger test (expanding)" ) |
493 | << QString::fromUtf8(str: "X\xC3\x9F\xe3\x8c\x96\xC4\xB0\xE2\x84\xA1\xE2\x92\x9F\xE3\x8c\x80" ) |
494 | << QString::fromUtf8(str: "xss\xe3\x82\xad\xe3\x83\xad\xe3\x83\xa1\xe3\x83\xbc\xe3\x83\x88" |
495 | "\xe3\x83\xab" "i\xcc\x87" "tel\x28" "d\x29\xe3\x82\xa2\xe3\x83\x91" |
496 | "\xe3\x83\xbc\xe3\x83\x88" ) |
497 | << QString() << 0 << 0; |
498 | } |
499 | #endif |
500 | |
501 | #ifdef QT_BUILD_INTERNAL |
502 | void tst_QUrlInternal::nameprep_testsuite() |
503 | { |
504 | QFETCH(QString, in); |
505 | QFETCH(QString, out); |
506 | QFETCH(QString, profile); |
507 | |
508 | qt_nameprep(source: &in, from: 0); |
509 | QCOMPARE(in, out); |
510 | } |
511 | #endif |
512 | |
513 | #ifdef QT_BUILD_INTERNAL |
514 | void tst_QUrlInternal::nameprep_highcodes_data() |
515 | { |
516 | QTest::addColumn<QString>(name: "in" ); |
517 | QTest::addColumn<QString>(name: "out" ); |
518 | QTest::addColumn<QString>(name: "profile" ); |
519 | QTest::addColumn<int>(name: "flags" ); |
520 | QTest::addColumn<int>(name: "rc" ); |
521 | |
522 | { |
523 | QChar st[] = { '-', 0xd801, 0xdc1d, 'a' }; |
524 | QChar se[] = { '-', 0xd801, 0xdc45, 'a' }; |
525 | QTest::newRow(dataTag: "highcodes (U+1041D)" ) |
526 | << QString(st, sizeof(st)/sizeof(st[0])) |
527 | << QString(se, sizeof(se)/sizeof(se[0])) |
528 | << QString() << 0 << 0; |
529 | } |
530 | { |
531 | QChar st[] = { 0x011C, 0xd835, 0xdf6e, 0x0110 }; |
532 | QChar se[] = { 0x011D, 0x03C9, 0x0111 }; |
533 | QTest::newRow(dataTag: "highcodes (U+1D76E)" ) |
534 | << QString(st, sizeof(st)/sizeof(st[0])) |
535 | << QString(se, sizeof(se)/sizeof(se[0])) |
536 | << QString() << 0 << 0; |
537 | } |
538 | { |
539 | QChar st[] = { 'D', 'o', '\'', 0x2060, 'h' }; |
540 | QChar se[] = { 'd', 'o', '\'', 'h' }; |
541 | QTest::newRow(dataTag: "highcodes (D, o, ', U+2060, h)" ) |
542 | << QString(st, sizeof(st)/sizeof(st[0])) |
543 | << QString(se, sizeof(se)/sizeof(se[0])) |
544 | << QString() << 0 << 0; |
545 | } |
546 | } |
547 | #endif |
548 | |
549 | #ifdef QT_BUILD_INTERNAL |
550 | void tst_QUrlInternal::nameprep_highcodes() |
551 | { |
552 | QFETCH(QString, in); |
553 | QFETCH(QString, out); |
554 | QFETCH(QString, profile); |
555 | |
556 | qt_nameprep(source: &in, from: 0); |
557 | QCOMPARE(in, out); |
558 | } |
559 | #endif |
560 | |
561 | void tst_QUrlInternal::ace_testsuite_data() |
562 | { |
563 | QTest::addColumn<QString>(name: "in" ); |
564 | QTest::addColumn<QString>(name: "toace" ); |
565 | QTest::addColumn<QString>(name: "fromace" ); |
566 | QTest::addColumn<QString>(name: "unicode" ); |
567 | |
568 | QTest::newRow(dataTag: "ascii-lower" ) << "fluke" << "fluke" << "fluke" << "fluke" ; |
569 | QTest::newRow(dataTag: "ascii-mixed" ) << "FLuke" << "fluke" << "fluke" << "fluke" ; |
570 | QTest::newRow(dataTag: "ascii-upper" ) << "FLUKE" << "fluke" << "fluke" << "fluke" ; |
571 | |
572 | QTest::newRow(dataTag: "asciifolded" ) << QString::fromLatin1(str: "stra\337e" ) << "strasse" << "." << "strasse" ; |
573 | QTest::newRow(dataTag: "asciifolded-dotcom" ) << QString::fromLatin1(str: "stra\337e.example.com" ) << "strasse.example.com" << "." << "strasse.example.com" ; |
574 | QTest::newRow(dataTag: "greek-mu" ) << QString::fromLatin1(str: "\265V" ) |
575 | <<"xn--v-lmb" |
576 | << "." |
577 | << QString::fromUtf8(str: "\316\274v" ); |
578 | |
579 | QTest::newRow(dataTag: "non-ascii-lower" ) << QString::fromLatin1(str: "alqualond\353" ) |
580 | << "xn--alqualond-34a" |
581 | << "." |
582 | << QString::fromLatin1(str: "alqualond\353" ); |
583 | QTest::newRow(dataTag: "non-ascii-mixed" ) << QString::fromLatin1(str: "Alqualond\353" ) |
584 | << "xn--alqualond-34a" |
585 | << "." |
586 | << QString::fromLatin1(str: "alqualond\353" ); |
587 | QTest::newRow(dataTag: "non-ascii-upper" ) << QString::fromLatin1(str: "ALQUALOND\313" ) |
588 | << "xn--alqualond-34a" |
589 | << "." |
590 | << QString::fromLatin1(str: "alqualond\353" ); |
591 | |
592 | QTest::newRow(dataTag: "idn-lower" ) << "xn--alqualond-34a" << "xn--alqualond-34a" |
593 | << QString::fromLatin1(str: "alqualond\353" ) |
594 | << QString::fromLatin1(str: "alqualond\353" ); |
595 | QTest::newRow(dataTag: "idn-mixed" ) << "Xn--alqualond-34a" << "xn--alqualond-34a" |
596 | << QString::fromLatin1(str: "alqualond\353" ) |
597 | << QString::fromLatin1(str: "alqualond\353" ); |
598 | QTest::newRow(dataTag: "idn-mixed2" ) << "XN--alqualond-34a" << "xn--alqualond-34a" |
599 | << QString::fromLatin1(str: "alqualond\353" ) |
600 | << QString::fromLatin1(str: "alqualond\353" ); |
601 | QTest::newRow(dataTag: "idn-mixed3" ) << "xn--ALQUALOND-34a" << "xn--alqualond-34a" |
602 | << QString::fromLatin1(str: "alqualond\353" ) |
603 | << QString::fromLatin1(str: "alqualond\353" ); |
604 | QTest::newRow(dataTag: "idn-mixed4" ) << "xn--alqualond-34A" << "xn--alqualond-34a" |
605 | << QString::fromLatin1(str: "alqualond\353" ) |
606 | << QString::fromLatin1(str: "alqualond\353" ); |
607 | QTest::newRow(dataTag: "idn-upper" ) << "XN--ALQUALOND-34A" << "xn--alqualond-34a" |
608 | << QString::fromLatin1(str: "alqualond\353" ) |
609 | << QString::fromLatin1(str: "alqualond\353" ); |
610 | |
611 | QTest::newRow(dataTag: "separator-3002" ) << QString::fromUtf8(str: "example\343\200\202com" ) |
612 | << "example.com" << "." << "example.com" ; |
613 | |
614 | QString egyptianIDN = |
615 | QString::fromUtf8(str: "\331\210\330\262\330\247\330\261\330\251\055\330\247\331\204\330" |
616 | "\243\330\252\330\265\330\247\331\204\330\247\330\252.\331\205" |
617 | "\330\265\330\261" ); |
618 | QTest::newRow(dataTag: "egyptian-tld-ace" ) |
619 | << "xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c" |
620 | << "xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c" |
621 | << "." |
622 | << egyptianIDN; |
623 | QTest::newRow(dataTag: "egyptian-tld-unicode" ) |
624 | << egyptianIDN |
625 | << "xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c" |
626 | << "." |
627 | << egyptianIDN; |
628 | QTest::newRow(dataTag: "egyptian-tld-mix1" ) |
629 | << QString::fromUtf8(str: "\331\210\330\262\330\247\330\261\330\251\055\330\247\331\204\330" |
630 | "\243\330\252\330\265\330\247\331\204\330\247\330\252.xn--wgbh1c" ) |
631 | << "xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c" |
632 | << "." |
633 | << egyptianIDN; |
634 | QTest::newRow(dataTag: "egyptian-tld-mix2" ) |
635 | << QString::fromUtf8(str: "xn----rmckbbajlc6dj7bxne2c.\331\205\330\265\330\261" ) |
636 | << "xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c" |
637 | << "." |
638 | << egyptianIDN; |
639 | |
640 | QString russianIDN = QString::fromUtf8(str: "\321\217\320\275\320\264\320\265\320\272\321\201.\321\200\321\204" ); |
641 | QTest::newRow(dataTag: "russian-tld-ace" ) |
642 | << "xn--d1acpjx3f.xn--p1ai" |
643 | << "xn--d1acpjx3f.xn--p1ai" |
644 | << "." |
645 | << russianIDN; |
646 | |
647 | QString taiwaneseIDN = QString::fromUtf8(str: "\345\217\260\345\214\227\346\214\211\346\221\251.\345\217\260\347\201\243" ); |
648 | QTest::newRow(dataTag: "taiwanese-tld-ace" ) |
649 | << "xn--djrptm67aikb.xn--kpry57d" |
650 | << "xn--djrptm67aikb.xn--kpry57d" |
651 | << "." |
652 | << taiwaneseIDN; |
653 | |
654 | // violations / invalids |
655 | QTest::newRow(dataTag: "invalid-punycode" ) << "xn--z" << "xn--z" << "xn--z" << "xn--z" ; |
656 | |
657 | // U+00A0 NO-BREAK SPACE encodes to Punycode "6a" |
658 | // but it is prohibited and should have caused encoding failure |
659 | QTest::newRow(dataTag: "invalid-nameprep-prohibited" ) << "xn--6a" << "xn--6a" << "xn--6a" << "xn--6a" ; |
660 | |
661 | // U+00AD SOFT HYPHEN between "a" and "b" encodes to Punycode "ab-5da" |
662 | // but it should have been removed in the nameprep stage |
663 | QTest::newRow(dataTag: "invalid-nameprep-maptonothing" ) << "xn-ab-5da" << "xn-ab-5da" << "xn-ab-5da" << "xn-ab-5da" ; |
664 | |
665 | // U+00C1 LATIN CAPITAL LETTER A WITH ACUTE encodes to Punycode "4ba" |
666 | // but it should have nameprepped to lowercase first |
667 | QTest::newRow(dataTag: "invalid-nameprep-uppercase" ) << "xn--4ba" << "xn--4ba" << "xn--4ba" << "xn--4ba" ; |
668 | |
669 | // U+00B5 MICRO SIGN encodes to Punycode "sba" |
670 | // but is should have nameprepped to NFKC U+03BC GREEK SMALL LETTER MU |
671 | QTest::newRow(dataTag: "invalid-nameprep-nonnfkc" ) << "xn--sba" << "xn--sba" << "xn--sba" << "xn--sba" ; |
672 | |
673 | // U+04CF CYRILLIC SMALL LETTER PALOCHKA encodes to "s5a" |
674 | // but it's not in RFC 3454's allowed character list (Unicode 3.2) |
675 | QTest::newRow(dataTag: "invalid-nameprep-unassigned" ) << "xn--s5a" << "xn--s5a" << "xn--s5a" << "xn--s5a" ; |
676 | // same character, see QTBUG-60364 |
677 | QTest::newRow(dataTag: "invalid-nameprep-unassigned2" ) << "xn--80ak6aa92e" << "xn--80ak6aa92e" << "xn--80ak6aa92e" << "xn--80ak6aa92e" ; |
678 | } |
679 | |
680 | void tst_QUrlInternal::ace_testsuite() |
681 | { |
682 | static const char canonsuffix[] = ".troll.no" ; |
683 | QFETCH(QString, in); |
684 | QFETCH(QString, toace); |
685 | QFETCH(QString, fromace); |
686 | QFETCH(QString, unicode); |
687 | |
688 | const char *suffix = canonsuffix; |
689 | if (toace.contains(c: '.')) |
690 | suffix = 0; |
691 | |
692 | QString domain = in + suffix; |
693 | QCOMPARE(QString::fromLatin1(QUrl::toAce(domain)), toace + suffix); |
694 | if (fromace != "." ) |
695 | QCOMPARE(QUrl::fromAce(domain.toLatin1()), fromace + suffix); |
696 | QCOMPARE(QUrl::fromAce(QUrl::toAce(domain)), unicode + suffix); |
697 | |
698 | QUrl u; |
699 | u.setHost(host: domain); |
700 | QVERIFY(u.isValid()); |
701 | QCOMPARE(u.host(), unicode + suffix); |
702 | QCOMPARE(u.host(QUrl::EncodeUnicode), toace + suffix); |
703 | QCOMPARE(u.toEncoded(), "//" + toace.toLatin1() + suffix); |
704 | QCOMPARE(u.toDisplayString(), "//" + unicode + suffix); |
705 | |
706 | domain = in + (suffix ? ".troll.No" : "" ); |
707 | QCOMPARE(QString::fromLatin1(QUrl::toAce(domain)), toace + suffix); |
708 | if (fromace != "." ) |
709 | QCOMPARE(QUrl::fromAce(domain.toLatin1()), fromace + suffix); |
710 | QCOMPARE(QUrl::fromAce(QUrl::toAce(domain)), unicode + suffix); |
711 | |
712 | domain = in + (suffix ? ".troll.NO" : "" ); |
713 | QCOMPARE(QString::fromLatin1(QUrl::toAce(domain)), toace + suffix); |
714 | if (fromace != "." ) |
715 | QCOMPARE(QUrl::fromAce(domain.toLatin1()), fromace + suffix); |
716 | QCOMPARE(QUrl::fromAce(QUrl::toAce(domain)), unicode + suffix); |
717 | } |
718 | |
719 | void tst_QUrlInternal::std3violations_data() |
720 | { |
721 | QTest::addColumn<QString>(name: "source" ); |
722 | QTest::addColumn<bool>(name: "validUrl" ); |
723 | |
724 | QTest::newRow(dataTag: "too-long" ) << "this-domain-is-far-too-long-for-its-own-good-and-should-have-been-limited-to-63-chars" << false; |
725 | QTest::newRow(dataTag: "dash-begin" ) << "-x-foo" << false; |
726 | QTest::newRow(dataTag: "dash-end" ) << "x-foo-" << false; |
727 | QTest::newRow(dataTag: "dash-begin-end" ) << "-foo-" << false; |
728 | |
729 | QTest::newRow(dataTag: "control" ) << "\033foo" << false; |
730 | QTest::newRow(dataTag: "bang" ) << "foo!" << false; |
731 | QTest::newRow(dataTag: "plus" ) << "foo+bar" << false; |
732 | QTest::newRow(dataTag: "dot" ) << "foo.bar" ; |
733 | QTest::newRow(dataTag: "startingdot" ) << ".bar" << false; |
734 | QTest::newRow(dataTag: "startingdot2" ) << ".example.com" << false; |
735 | QTest::newRow(dataTag: "slash" ) << "foo/bar" << true; |
736 | QTest::newRow(dataTag: "colon" ) << "foo:80" << true; |
737 | QTest::newRow(dataTag: "question" ) << "foo?bar" << true; |
738 | QTest::newRow(dataTag: "at" ) << "foo@bar" << true; |
739 | QTest::newRow(dataTag: "backslash" ) << "foo\\bar" << false; |
740 | |
741 | // these characters are transformed by NFKC to non-LDH characters |
742 | QTest::newRow(dataTag: "dot-like" ) << QString::fromUtf8(str: "foo\342\200\244bar" ) << false; // U+2024 ONE DOT LEADER |
743 | QTest::newRow(dataTag: "slash-like" ) << QString::fromUtf8(str: "foo\357\274\217bar" ) << false; // U+FF0F FULLWIDTH SOLIDUS |
744 | |
745 | // The following should be invalid but isn't |
746 | // the DIVISON SLASH doesn't case-fold to a slash |
747 | // is this a problem with RFC 3490? |
748 | //QTest::newRow("slash-like2") << QString::fromUtf8("foo\342\210\225bar") << false; // U+2215 DIVISION SLASH |
749 | } |
750 | |
751 | void tst_QUrlInternal::std3violations() |
752 | { |
753 | QFETCH(QString, source); |
754 | |
755 | #ifdef QT_BUILD_INTERNAL |
756 | { |
757 | QString prepped = source; |
758 | qt_nameprep(source: &prepped, from: 0); |
759 | QVERIFY(!qt_check_std3rules(prepped.constData(), prepped.length())); |
760 | } |
761 | #endif |
762 | |
763 | if (source.contains(c: '.')) |
764 | return; // this test ends here |
765 | |
766 | QUrl url; |
767 | url.setHost(host: source); |
768 | QVERIFY(url.host().isEmpty()); |
769 | |
770 | QFETCH(bool, validUrl); |
771 | if (validUrl) |
772 | return; // test ends here for these cases |
773 | |
774 | url = QUrl("http://" + source + "/some/path" ); |
775 | QVERIFY(!url.isValid()); |
776 | } |
777 | |
778 | void tst_QUrlInternal::std3deviations_data() |
779 | { |
780 | QTest::addColumn<QString>(name: "source" ); |
781 | |
782 | QTest::newRow(dataTag: "ending-dot" ) << "example.com." ; |
783 | QTest::newRow(dataTag: "ending-dot3002" ) << QString("example.com" ) + QChar(0x3002); |
784 | QTest::newRow(dataTag: "underline" ) << "foo_bar" ; //QTBUG-7434 |
785 | } |
786 | |
787 | void tst_QUrlInternal::std3deviations() |
788 | { |
789 | QFETCH(QString, source); |
790 | QVERIFY(!QUrl::toAce(source).isEmpty()); |
791 | |
792 | QUrl url; |
793 | url.setHost(host: source); |
794 | QVERIFY(!url.host().isEmpty()); |
795 | } |
796 | |
797 | void tst_QUrlInternal::correctEncodedMistakes_data() |
798 | { |
799 | QTest::addColumn<QString>(name: "input" ); |
800 | QTest::addColumn<QString>(name: "expected" ); |
801 | |
802 | QTest::newRow(dataTag: "empty" ) << "" << "" ; |
803 | |
804 | // these contain one invalid percent |
805 | QTest::newRow(dataTag: "%" ) << QString("%" ) << QString("%25" ); |
806 | QTest::newRow(dataTag: "3%" ) << QString("3%" ) << QString("3%25" ); |
807 | QTest::newRow(dataTag: "13%" ) << QString("13%" ) << QString("13%25" ); |
808 | QTest::newRow(dataTag: "13%!" ) << QString("13%!" ) << QString("13%25!" ); |
809 | QTest::newRow(dataTag: "13%!!" ) << QString("13%!!" ) << QString("13%25!!" ); |
810 | QTest::newRow(dataTag: "13%a" ) << QString("13%a" ) << QString("13%25a" ); |
811 | QTest::newRow(dataTag: "13%az" ) << QString("13%az" ) << QString("13%25az" ); |
812 | |
813 | // two invalid percents |
814 | QTest::newRow(dataTag: "13%%" ) << "13%%" << "13%25%25" ; |
815 | QTest::newRow(dataTag: "13%a%a" ) << "13%a%a" << "13%25a%25a" ; |
816 | QTest::newRow(dataTag: "13%az%az" ) << "13%az%az" << "13%25az%25az" ; |
817 | |
818 | // these are correct (idempotent) |
819 | QTest::newRow(dataTag: "13%25" ) << QString("13%25" ) << QString("13%25" ); |
820 | QTest::newRow(dataTag: "13%25%25" ) << QString("13%25%25" ) << QString("13%25%25" ); |
821 | |
822 | // these contain one invalid and one valid |
823 | // the code assumes they are all invalid |
824 | QTest::newRow(dataTag: "13%13..%" ) << "13%13..%" << "13%2513..%25" ; |
825 | QTest::newRow(dataTag: "13%..%13" ) << "13%..%13" << "13%25..%2513" ; |
826 | |
827 | // three percents, one invalid |
828 | QTest::newRow(dataTag: "%01%02%3" ) << "%01%02%3" << "%2501%2502%253" ; |
829 | |
830 | // now mix bad percents with Unicode decoding |
831 | QTest::newRow(dataTag: "%C2%" ) << "%C2%" << "%25C2%25" ; |
832 | QTest::newRow(dataTag: "%C2%A" ) << "%C2%A" << "%25C2%25A" ; |
833 | QTest::newRow(dataTag: "%C2%Az" ) << "%C2%Az" << "%25C2%25Az" ; |
834 | QTest::newRow(dataTag: "%E2%A0%" ) << "%E2%A0%" << "%25E2%25A0%25" ; |
835 | QTest::newRow(dataTag: "%E2%A0%A" ) << "%E2%A0%A" << "%25E2%25A0%25A" ; |
836 | QTest::newRow(dataTag: "%E2%A0%Az" ) << "%E2%A0%Az" << "%25E2%25A0%25Az" ; |
837 | QTest::newRow(dataTag: "%F2%A0%A0%" ) << "%F2%A0%A0%" << "%25F2%25A0%25A0%25" ; |
838 | QTest::newRow(dataTag: "%F2%A0%A0%A" ) << "%F2%A0%A0%A" << "%25F2%25A0%25A0%25A" ; |
839 | QTest::newRow(dataTag: "%F2%A0%A0%Az" ) << "%F2%A0%A0%Az" << "%25F2%25A0%25A0%25Az" ; |
840 | } |
841 | |
842 | void tst_QUrlInternal::correctEncodedMistakes() |
843 | { |
844 | QFETCH(QString, input); |
845 | QFETCH(QString, expected); |
846 | |
847 | // prepend some data to be sure that it remains there |
848 | QString dataTag = QTest::currentDataTag(); |
849 | QString output = dataTag; |
850 | |
851 | if (!qt_urlRecode(appendTo&: output, begin: input.constData(), end: input.constData() + input.length(), encoding: { })) |
852 | output += input; |
853 | QCOMPARE(output, dataTag + expected); |
854 | |
855 | // now try the full decode mode |
856 | output = dataTag; |
857 | QString expected2 = QUrl::fromPercentEncoding(expected.toLatin1()); |
858 | |
859 | if (!qt_urlRecode(appendTo&: output, begin: input.constData(), end: input.constData() + input.length(), encoding: QUrl::FullyDecoded)) |
860 | output += input; |
861 | QCOMPARE(output, dataTag + expected2); |
862 | } |
863 | |
864 | static void addUtf8Data(const char *name, const char *data) |
865 | { |
866 | QString encoded = QByteArray(data).toPercentEncoding(); |
867 | QString decoded = QString::fromUtf8(str: data); |
868 | |
869 | // this data contains invaild UTF-8 sequences, so FullyDecoded doesn't work (by design) |
870 | // use PrettyDecoded instead |
871 | QTest::newRow(dataTag: QByteArray("decode-" ) + name) << encoded << QUrl::ComponentFormattingOptions(QUrl::PrettyDecoded) << decoded; |
872 | QTest::newRow(dataTag: QByteArray("encode-" ) + name) << decoded << QUrl::ComponentFormattingOptions(QUrl::FullyEncoded) << encoded; |
873 | } |
874 | |
875 | void tst_QUrlInternal::encodingRecode_data() |
876 | { |
877 | typedef QUrl::ComponentFormattingOptions F; |
878 | QTest::addColumn<QString>(name: "input" ); |
879 | QTest::addColumn<F>(name: "encodingMode" ); |
880 | QTest::addColumn<QString>(name: "expected" ); |
881 | |
882 | // -- idempotent tests -- |
883 | static int modes[] = { QUrl::PrettyDecoded, |
884 | QUrl::EncodeSpaces, |
885 | QUrl::EncodeSpaces | QUrl::EncodeUnicode, |
886 | QUrl::EncodeSpaces | QUrl::EncodeUnicode | QUrl::EncodeDelimiters, |
887 | QUrl::EncodeSpaces | QUrl::EncodeUnicode | QUrl::EncodeDelimiters | QUrl::EncodeReserved, |
888 | QUrl::EncodeSpaces | QUrl::EncodeUnicode | QUrl::EncodeDelimiters | QUrl::DecodeReserved, |
889 | QUrl::EncodeSpaces | QUrl::EncodeUnicode | QUrl::EncodeReserved, |
890 | QUrl::EncodeSpaces | QUrl::EncodeUnicode | QUrl::DecodeReserved, |
891 | QUrl::EncodeSpaces | QUrl::EncodeDelimiters, |
892 | QUrl::EncodeSpaces | QUrl::EncodeDelimiters | QUrl::EncodeReserved, |
893 | QUrl::EncodeSpaces | QUrl::EncodeDelimiters | QUrl::DecodeReserved, |
894 | QUrl::EncodeSpaces | QUrl::EncodeReserved, |
895 | QUrl::EncodeSpaces | QUrl::DecodeReserved, |
896 | |
897 | QUrl::EncodeUnicode, |
898 | QUrl::EncodeUnicode | QUrl::EncodeDelimiters, |
899 | QUrl::EncodeUnicode | QUrl::EncodeDelimiters | QUrl::EncodeReserved, |
900 | QUrl::EncodeUnicode | QUrl::EncodeDelimiters | QUrl::DecodeReserved, |
901 | QUrl::EncodeUnicode | QUrl::EncodeReserved, |
902 | |
903 | QUrl::EncodeDelimiters, |
904 | QUrl::EncodeDelimiters | QUrl::EncodeReserved, |
905 | QUrl::EncodeDelimiters | QUrl::DecodeReserved, |
906 | QUrl::EncodeReserved, |
907 | QUrl::DecodeReserved }; |
908 | for (uint i = 0; i < sizeof(modes)/sizeof(modes[0]); ++i) { |
909 | QByteArray code = QByteArray::number(modes[i], base: 16); |
910 | F mode = QUrl::ComponentFormattingOption(modes[i]); |
911 | |
912 | QTest::newRow(dataTag: "null-0x" + code) << QString() << mode << QString(); |
913 | QTest::newRow(dataTag: "empty-0x" + code) << "" << mode << "" ; |
914 | |
915 | // unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" |
916 | // Unreserved characters are never encoded |
917 | QTest::newRow(dataTag: "alpha-0x" + code) << "abcABCZZzz" << mode << "abcABCZZzz" ; |
918 | QTest::newRow(dataTag: "digits-0x" + code) << "01234567890" << mode << "01234567890" ; |
919 | QTest::newRow(dataTag: "otherunreserved-0x" + code) << "-._~" << mode << "-._~" ; |
920 | |
921 | // Control characters are always encoded |
922 | // Use uppercase because the output is also uppercased |
923 | QTest::newRow(dataTag: "control-nul-0x" + code) << "%00" << mode << "%00" ; |
924 | QTest::newRow(dataTag: "control-0x" + code) << "%0D%0A%1F%1A%7F" << mode << "%0D%0A%1F%1A%7F" ; |
925 | |
926 | // The percent is always encoded |
927 | QTest::newRow(dataTag: "percent-0x" + code) << "25%2525" << mode << "25%2525" ; |
928 | |
929 | // mixed control and unreserved |
930 | QTest::newRow(dataTag: "control-unreserved-0x" + code) << "Foo%00Bar%0D%0Abksp%7F" << mode << "Foo%00Bar%0D%0Abksp%7F" ; |
931 | } |
932 | |
933 | // however, control characters and the percent *are* decoded in FullyDecoded mode |
934 | // this is the only exception |
935 | QTest::newRow(dataTag: "control-nul-fullydecoded" ) << "%00" << F(QUrl::FullyDecoded) << QStringLiteral("\0" ); |
936 | QTest::newRow(dataTag: "control-fullydecoded" ) << "%0D%0A%1F%1A%7F" << F(QUrl::FullyDecoded) << "\r\n\x1f\x1a\x7f" ; |
937 | QTest::newRow(dataTag: "percent-fullydecoded" ) << "25%2525" << F(QUrl::FullyDecoded) << "25%25" ; |
938 | QTest::newRow(dataTag: "control-unreserved-fullydecoded" ) << "Foo%00Bar%0D%0Abksp%7F" << F(QUrl::FullyDecoded) |
939 | << QStringLiteral("Foo\0Bar\r\nbksp\x7F" ); |
940 | |
941 | // gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" |
942 | // sub-delims = "!" / "$" / "&" / "'" / "(" / ")" |
943 | // / "*" / "+" / "," / ";" / "=" |
944 | // in the default operation, delimiters don't get encoded or decoded |
945 | static const char delimiters[] = ":/?#[]@" "!$&'()*+,;=" ; |
946 | for (const char *c = delimiters; *c; ++c) { |
947 | QByteArray code = QByteArray::number(*c, base: 16); |
948 | QString encoded = QString("abc%" ) + code.toUpper() + "def" ; |
949 | QString decoded = QString("abc" ) + *c + "def" ; |
950 | QTest::newRow(dataTag: "delimiter-encoded-" + code) << encoded << F(QUrl::FullyEncoded) << encoded; |
951 | QTest::newRow(dataTag: "delimiter-decoded-" + code) << decoded << F(QUrl::FullyEncoded) << decoded; |
952 | } |
953 | |
954 | // encode control characters |
955 | QTest::newRow(dataTag: "encode-control" ) << "\1abc\2\033esc" << F(QUrl::PrettyDecoded) << "%01abc%02%1Besc" ; |
956 | QTest::newRow(dataTag: "encode-nul" ) << QString::fromLatin1(str: "abc\0def" , size: 7) << F(QUrl::PrettyDecoded) << "abc%00def" ; |
957 | |
958 | // space |
959 | QTest::newRow(dataTag: "space-leave-decoded" ) << "Hello World " << F(QUrl::PrettyDecoded) << "Hello World " ; |
960 | QTest::newRow(dataTag: "space-leave-encoded" ) << "Hello%20World%20" << F(QUrl::FullyEncoded) << "Hello%20World%20" ; |
961 | QTest::newRow(dataTag: "space-encode" ) << "Hello World " << F(QUrl::FullyEncoded) << "Hello%20World%20" ; |
962 | QTest::newRow(dataTag: "space-decode" ) << "Hello%20World%20" << F(QUrl::PrettyDecoded) << "Hello World " ; |
963 | |
964 | // decode unreserved |
965 | QTest::newRow(dataTag: "unreserved-decode" ) << "%66%6f%6f%42a%72" << F(QUrl::FullyEncoded) << "fooBar" ; |
966 | |
967 | // mix encoding with decoding |
968 | QTest::newRow(dataTag: "encode-control-decode-space" ) << "\1\2%200" << F(QUrl::PrettyDecoded) << "%01%02 0" ; |
969 | QTest::newRow(dataTag: "decode-space-encode-control" ) << "%20\1\2" << F(QUrl::PrettyDecoded) << " %01%02" ; |
970 | |
971 | // decode and encode valid UTF-8 data |
972 | // invalid is tested in encodingRecodeInvalidUtf8 |
973 | addUtf8Data(name: "utf8-2char-1" , data: "\xC2\x80" ); // U+0080 |
974 | addUtf8Data(name: "utf8-2char-2" , data: "\xDF\xBF" ); // U+07FF |
975 | addUtf8Data(name: "utf8-3char-1" , data: "\xE0\xA0\x80" ); // U+0800 |
976 | addUtf8Data(name: "utf8-3char-2" , data: "\xED\x9F\xBF" ); // U+D7FF |
977 | addUtf8Data(name: "utf8-3char-3" , data: "\xEE\x80\x80" ); // U+E000 |
978 | addUtf8Data(name: "utf8-3char-4" , data: "\xEF\xBF\xBD" ); // U+FFFD |
979 | addUtf8Data(name: "utf8-4char-1" , data: "\xF0\x90\x80\x80" ); // U+10000 |
980 | addUtf8Data(name: "utf8-4char-2" , data: "\xF4\x8F\xBF\xBD" ); // U+10FFFD |
981 | |
982 | // longer UTF-8 sequences, mixed with unreserved |
983 | addUtf8Data(name: "utf8-string-1" , data: "R\xc3\xa9sum\xc3\xa9" ); |
984 | addUtf8Data(name: "utf8-string-2" , data: "\xDF\xBF\xE0\xA0\x80" "A" ); |
985 | addUtf8Data(name: "utf8-string-3" , data: "\xE0\xA0\x80\xDF\xBF..." ); |
986 | |
987 | QTest::newRow(dataTag: "encode-unicode-noncharacter" ) << QString(QChar(0xffff)) << F(QUrl::FullyEncoded) << "%EF%BF%BF" ; |
988 | QTest::newRow(dataTag: "decode-unicode-noncharacter" ) << QString(QChar(0xffff)) << F(QUrl::PrettyDecoded) << QString::fromUtf8(str: "\xEF\xBF\xBF" ); |
989 | |
990 | // special cases: stuff we can encode, but not decode |
991 | QTest::newRow(dataTag: "unicode-lo-surrogate" ) << QString(QChar(0xD800)) << F(QUrl::FullyEncoded) << "%ED%A0%80" ; |
992 | QTest::newRow(dataTag: "unicode-hi-surrogate" ) << QString(QChar(0xDC00)) << F(QUrl::FullyEncoded) << "%ED%B0%80" ; |
993 | |
994 | // a couple of Unicode strings with leading spaces |
995 | QTest::newRow(dataTag: "space-unicode" ) << QString::fromUtf8(str: " \xc2\xa0" ) << F(QUrl::FullyEncoded) << "%20%C2%A0" ; |
996 | QTest::newRow(dataTag: "space-space-unicode" ) << QString::fromUtf8(str: " \xc2\xa0" ) << F(QUrl::FullyEncoded) << "%20%20%C2%A0" ; |
997 | QTest::newRow(dataTag: "space-space-space-unicode" ) << QString::fromUtf8(str: " \xc2\xa0" ) << F(QUrl::FullyEncoded) << "%20%20%20%C2%A0" ; |
998 | |
999 | // hex case testing |
1000 | QTest::newRow(dataTag: "FF" ) << "%FF" << F(QUrl::FullyEncoded) << "%FF" ; |
1001 | QTest::newRow(dataTag: "Ff" ) << "%Ff" << F(QUrl::FullyEncoded) << "%FF" ; |
1002 | QTest::newRow(dataTag: "fF" ) << "%fF" << F(QUrl::FullyEncoded) << "%FF" ; |
1003 | QTest::newRow(dataTag: "ff" ) << "%ff" << F(QUrl::FullyEncoded) << "%FF" ; |
1004 | |
1005 | // decode UTF-8 mixed with non-UTF-8 and unreserved |
1006 | QTest::newRow(dataTag: "utf8-mix-1" ) << "%80%C2%80" << F(QUrl::PrettyDecoded) << QString::fromUtf8(str: "%80\xC2\x80" ); |
1007 | QTest::newRow(dataTag: "utf8-mix-2" ) << "%C2%C2%80" << F(QUrl::PrettyDecoded) << QString::fromUtf8(str: "%C2\xC2\x80" ); |
1008 | QTest::newRow(dataTag: "utf8-mix-3" ) << "%E0%C2%80" << F(QUrl::PrettyDecoded) << QString::fromUtf8(str: "%E0\xC2\x80" ); |
1009 | QTest::newRow(dataTag: "utf8-mix-3" ) << "A%C2%80" << F(QUrl::PrettyDecoded) << QString::fromUtf8(str: "A\xC2\x80" ); |
1010 | QTest::newRow(dataTag: "utf8-mix-3" ) << "%C2%80A" << F(QUrl::PrettyDecoded) << QString::fromUtf8(str: "\xC2\x80" "A" ); |
1011 | } |
1012 | |
1013 | void tst_QUrlInternal::encodingRecode() |
1014 | { |
1015 | QFETCH(QString, input); |
1016 | QFETCH(QString, expected); |
1017 | QFETCH(QUrl::ComponentFormattingOptions, encodingMode); |
1018 | |
1019 | // prepend some data to be sure that it remains there |
1020 | QString output = QTest::currentDataTag(); |
1021 | expected.prepend(s: output); |
1022 | |
1023 | if (!qt_urlRecode(appendTo&: output, begin: input.constData(), end: input.constData() + input.length(), encoding: encodingMode)) |
1024 | output += input; |
1025 | QCOMPARE(output, expected); |
1026 | } |
1027 | |
1028 | void tst_QUrlInternal::encodingRecodeInvalidUtf8_data() |
1029 | { |
1030 | QTest::addColumn<QByteArray>(name: "utf8" ); |
1031 | QTest::addColumn<QString>(name: "utf16" ); |
1032 | |
1033 | extern void loadInvalidUtf8Rows(); |
1034 | extern void loadNonCharactersRows(); |
1035 | loadInvalidUtf8Rows(); |
1036 | loadNonCharactersRows(); |
1037 | |
1038 | QTest::newRow(dataTag: "utf8-mix-4" ) << QByteArray("\xE0.A2\x80" ); |
1039 | QTest::newRow(dataTag: "utf8-mix-5" ) << QByteArray("\xE0\xA2.80" ); |
1040 | QTest::newRow(dataTag: "utf8-mix-6" ) << QByteArray("\xE0\xA2\x33" ); |
1041 | } |
1042 | |
1043 | void tst_QUrlInternal::encodingRecodeInvalidUtf8() |
1044 | { |
1045 | QFETCH(QByteArray, utf8); |
1046 | QString input = utf8.toPercentEncoding(); |
1047 | |
1048 | // prepend some data to be sure that it remains there |
1049 | QString output = QTest::currentDataTag(); |
1050 | |
1051 | if (!qt_urlRecode(appendTo&: output, begin: input.constData(), end: input.constData() + input.length(), encoding: QUrl::PrettyDecoded)) |
1052 | output += input; |
1053 | QCOMPARE(output, QTest::currentDataTag() + input); |
1054 | |
1055 | // this is just control |
1056 | output = QTest::currentDataTag(); |
1057 | if (!qt_urlRecode(appendTo&: output, begin: input.constData(), end: input.constData() + input.length(), encoding: QUrl::FullyEncoded)) |
1058 | output += input; |
1059 | QCOMPARE(output, QTest::currentDataTag() + input); |
1060 | |
1061 | // verify for security reasons that all bad UTF-8 data got replaced by QChar::ReplacementCharacter |
1062 | output = QTest::currentDataTag(); |
1063 | if (!qt_urlRecode(appendTo&: output, begin: input.constData(), end: input.constData() + input.length(), encoding: QUrl::FullyEncoded)) |
1064 | output += input; |
1065 | for (int i = int(strlen(s: QTest::currentDataTag())); i < output.length(); ++i) { |
1066 | QVERIFY2(output.at(i).unicode() < 0x80 || output.at(i) == QChar::ReplacementCharacter, |
1067 | qPrintable(QString("Character at i == %1 was U+%2" ).arg(i).arg(output.at(i).unicode(), 4, 16, QLatin1Char('0')))); |
1068 | } |
1069 | } |
1070 | |
1071 | void tst_QUrlInternal::recodeByteArray_data() |
1072 | { |
1073 | QTest::addColumn<QByteArray>(name: "input" ); |
1074 | QTest::addColumn<QString>(name: "expected" ); |
1075 | |
1076 | QTest::newRow(dataTag: "null" ) << QByteArray() << QString(); |
1077 | QTest::newRow(dataTag: "empty" ) << QByteArray("" ) << QString("" ); |
1078 | QTest::newRow(dataTag: "normal" ) << QByteArray("Hello" ) << "Hello" ; |
1079 | QTest::newRow(dataTag: "valid-utf8" ) << QByteArray("\xc3\xa9" ) << "%C3%A9" ; |
1080 | QTest::newRow(dataTag: "percent-encoded" ) << QByteArray("%C3%A9%00%C0%80" ) << "%C3%A9%00%C0%80" ; |
1081 | QTest::newRow(dataTag: "invalid-utf8-1" ) << QByteArray("\xc3\xc3" ) << "%C3%C3" ; |
1082 | QTest::newRow(dataTag: "invalid-utf8-2" ) << QByteArray("\xc0\x80" ) << "%C0%80" ; |
1083 | |
1084 | // note: percent-encoding the control characters ("\0" -> "%00") would also |
1085 | // be correct, but it's unnecessary for this function |
1086 | QTest::newRow(dataTag: "binary" ) << QByteArray("\0\x1f" , 2) << QString::fromLatin1(str: "\0\x1f" , size: 2);; |
1087 | QTest::newRow(dataTag: "binary+percent-encoded" ) << QByteArray("\0%25" , 4) << QString::fromLatin1(str: "\0%25" , size: 4); |
1088 | } |
1089 | |
1090 | void tst_QUrlInternal::recodeByteArray() |
1091 | { |
1092 | QFETCH(QByteArray, input); |
1093 | QFETCH(QString, expected); |
1094 | QString output = qt_urlRecodeByteArray(ba: input); |
1095 | |
1096 | QCOMPARE(output.isNull(), input.isNull()); |
1097 | QCOMPARE(output.isEmpty(), input.isEmpty()); |
1098 | QCOMPARE(output, expected); |
1099 | } |
1100 | |
1101 | QTEST_APPLESS_MAIN(tst_QUrlInternal) |
1102 | |