1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2015 The Qt Company Ltd. |
4 | ** Contact: http://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the test suite of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL21$ |
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 http://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at http://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 2.1 or version 3 as published by the Free |
20 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and |
21 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the |
22 | ** following information to ensure the GNU Lesser General Public License |
23 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and |
24 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
25 | ** |
26 | ** As a special exception, The Qt Company gives you certain additional |
27 | ** rights. These rights are described in The Qt Company LGPL Exception |
28 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
29 | ** |
30 | ** $QT_END_LICENSE$ |
31 | ** |
32 | ****************************************************************************/ |
33 | |
34 | //TESTED_COMPONENT=src/versit |
35 | |
36 | #include "tst_qversitwriter.h" |
37 | #include <QtVersit/qversitwriter.h> |
38 | #include <QtVersit/qversitdocument.h> |
39 | #include <QtVersit/qversitproperty.h> |
40 | #include <QtTest/QtTest> |
41 | #include <QByteArray> |
42 | |
43 | QTVERSIT_USE_NAMESPACE |
44 | |
45 | void tst_QVersitWriter::init() |
46 | { |
47 | mOutputDevice = new QBuffer; |
48 | mWriter = new QVersitWriter; |
49 | mSignalCatcher = new SignalCatcher; |
50 | connect(sender: mWriter, SIGNAL(stateChanged(QVersitWriter::State)), |
51 | receiver: mSignalCatcher, SLOT(stateChanged(QVersitWriter::State))); |
52 | } |
53 | |
54 | void tst_QVersitWriter::cleanup() |
55 | { |
56 | delete mWriter; |
57 | delete mOutputDevice; |
58 | delete mSignalCatcher; |
59 | } |
60 | |
61 | void tst_QVersitWriter::testDevice() |
62 | { |
63 | // No device |
64 | QVERIFY(mWriter->device() == NULL); |
65 | |
66 | // Device has been set |
67 | mWriter->setDevice(mOutputDevice); |
68 | QVERIFY(mWriter->device() == mOutputDevice); |
69 | } |
70 | |
71 | void tst_QVersitWriter::testDefaultCodec() |
72 | { |
73 | QVERIFY(mWriter->defaultCodec() == 0); |
74 | mWriter->setDefaultCodec(QTextCodec::codecForName(name: "UTF-16BE" )); |
75 | QVERIFY(mWriter->defaultCodec() == QTextCodec::codecForName("UTF-16BE" )); |
76 | } |
77 | |
78 | void tst_QVersitWriter::testWritingVersions() |
79 | { |
80 | mWriter->setDevice(mOutputDevice); |
81 | mOutputDevice->open(openMode: QBuffer::ReadWrite); |
82 | |
83 | QVersitDocument document; |
84 | QVersitProperty property; |
85 | property.setName(QString(QString::fromLatin1(str: "FN" ))); |
86 | property.setValue(QString::fromLatin1(str: "John" )); |
87 | document.addProperty(property); |
88 | |
89 | QByteArray vCard30( |
90 | "BEGIN:VCARD\r\n" |
91 | "VERSION:3.0\r\n" |
92 | "FN:John\r\n" |
93 | "END:VCARD\r\n" ); |
94 | QByteArray vCard21( |
95 | "BEGIN:VCARD\r\n" |
96 | "VERSION:2.1\r\n" |
97 | "FN:John\r\n" |
98 | "END:VCARD\r\n" ); |
99 | |
100 | // Given no type or componentType, it should be vCard 3.0 |
101 | QVERIFY(mWriter->startWriting(document)); |
102 | mWriter->waitForFinished(); |
103 | QCOMPARE(mOutputDevice->buffer(), vCard30); |
104 | |
105 | // document type should override the guess |
106 | document.setType(QVersitDocument::VCard21Type); |
107 | mOutputDevice->buffer().clear(); |
108 | mOutputDevice->seek(off: 0); |
109 | QVERIFY(mWriter->startWriting(document)); |
110 | mWriter->waitForFinished(); |
111 | QCOMPARE(mOutputDevice->buffer(), vCard21); |
112 | |
113 | // param to startWriting should override document type |
114 | mOutputDevice->buffer().clear(); |
115 | mOutputDevice->seek(off: 0); |
116 | QVERIFY(mWriter->startWriting(document, QVersitDocument::VCard30Type)); |
117 | mWriter->waitForFinished(); |
118 | QCOMPARE(mOutputDevice->buffer(), vCard30); |
119 | } |
120 | |
121 | void tst_QVersitWriter::testWriting21() |
122 | { |
123 | // vCard 2.1 |
124 | QByteArray vCard21( |
125 | "BEGIN:VCARD\r\n\ |
126 | VERSION:2.1\r\n\ |
127 | FN:John\r\n\ |
128 | END:VCARD\r\n" ); |
129 | QVersitDocument document; |
130 | document.setComponentType(QStringLiteral("VCARD" )); |
131 | QVersitProperty property; |
132 | property.setName(QString(QStringLiteral("FN" ))); |
133 | property.setValue(QStringLiteral("John" )); |
134 | document.addProperty(property); |
135 | document.setType(QVersitDocument::VCard21Type); |
136 | QList<QVersitDocument> list; |
137 | list.append(t: document); |
138 | |
139 | // Device not set |
140 | QCOMPARE(mWriter->state(), QVersitWriter::InactiveState); |
141 | QCOMPARE(mWriter->error(), QVersitWriter::NoError); |
142 | QVERIFY(!mWriter->startWriting(list)); |
143 | QCOMPARE(mWriter->state(), QVersitWriter::InactiveState); |
144 | QCOMPARE(mWriter->error(), QVersitWriter::IOError); |
145 | QVERIFY(!mWriter->waitForFinished()); |
146 | |
147 | // Device not opened |
148 | mWriter->setDevice(mOutputDevice); |
149 | QVERIFY(!mWriter->startWriting(list)); |
150 | QCOMPARE(mWriter->state(), QVersitWriter::InactiveState); |
151 | QCOMPARE(mWriter->error(), QVersitWriter::IOError); |
152 | |
153 | // Now open the device and it should work. |
154 | mOutputDevice->open(openMode: QBuffer::ReadWrite); |
155 | QVERIFY2(mWriter->startWriting(list), QString::number(mWriter->error()).toLatin1().data()); |
156 | QVERIFY2(mWriter->waitForFinished(), QString::number(mWriter->error()).toLatin1().data()); |
157 | QCOMPARE(mWriter->state(), QVersitWriter::FinishedState); |
158 | QCOMPARE(mWriter->error(), QVersitWriter::NoError); |
159 | mOutputDevice->seek(off: 0); |
160 | QByteArray result(mOutputDevice->readAll()); |
161 | QCOMPARE(result, vCard21); |
162 | |
163 | // Try some other codec |
164 | delete mOutputDevice; |
165 | mOutputDevice = new QBuffer; |
166 | mOutputDevice->open(openMode: QBuffer::ReadWrite); |
167 | mWriter->setDevice(mOutputDevice); |
168 | QTextCodec* utf16(QTextCodec::codecForName(name: "UTF-16" )); |
169 | mWriter->setDefaultCodec(utf16); |
170 | QVERIFY2(mWriter->startWriting(list), QString::number(mWriter->error()).toLatin1().data()); |
171 | QVERIFY2(mWriter->waitForFinished(), QString::number(mWriter->error()).toLatin1().data()); |
172 | QCOMPARE(mWriter->state(), QVersitWriter::FinishedState); |
173 | QCOMPARE(mWriter->error(), QVersitWriter::NoError); |
174 | mOutputDevice->seek(off: 0); |
175 | result = mOutputDevice->readAll(); |
176 | QByteArray expected(utf16->fromUnicode(uc: QLatin1String(vCard21.data()))); |
177 | QCOMPARE(result, expected); |
178 | } |
179 | |
180 | void tst_QVersitWriter::testWriting30() |
181 | { |
182 | // vCard 3.0 |
183 | QByteArray vCard30( |
184 | "BEGIN:VCARD\r\n\ |
185 | VERSION:3.0\r\n\ |
186 | FN:John\r\n\ |
187 | END:VCARD\r\n" ); |
188 | |
189 | QVersitDocument document; |
190 | document.setComponentType(QStringLiteral("VCARD" )); |
191 | QVersitProperty property; |
192 | property.setName(QString(QStringLiteral("FN" ))); |
193 | property.setValue(QStringLiteral("John" )); |
194 | document.addProperty(property); |
195 | document.setType(QVersitDocument::VCard30Type); |
196 | QList<QVersitDocument> list; |
197 | list.append(t: document); |
198 | |
199 | // Basic 3.0 test |
200 | mOutputDevice->open(openMode: QBuffer::ReadWrite); |
201 | mWriter->setDevice(mOutputDevice); |
202 | QVERIFY2(mWriter->startWriting(list), QString::number(mWriter->error()).toLatin1().data()); |
203 | QVERIFY2(mWriter->waitForFinished(), QString::number(mWriter->error()).toLatin1().data()); |
204 | QCOMPARE(mWriter->state(), QVersitWriter::FinishedState); |
205 | QCOMPARE(mWriter->error(), QVersitWriter::NoError); |
206 | mOutputDevice->seek(off: 0); |
207 | QByteArray result(mOutputDevice->readAll()); |
208 | QCOMPARE(result, vCard30); |
209 | |
210 | qApp->processEvents(); // clean up before we start sniffing signals |
211 | |
212 | // Asynchronous writing |
213 | mOutputDevice->reset(); |
214 | mSignalCatcher->mReceived.clear(); |
215 | QVERIFY2(mWriter->startWriting(list), QString::number(mWriter->error()).toLatin1().data()); |
216 | QTRY_VERIFY(mSignalCatcher->mReceived.count() >= 2); |
217 | QCOMPARE(mSignalCatcher->mReceived.at(0), QVersitWriter::ActiveState); |
218 | QCOMPARE(mSignalCatcher->mReceived.at(1), QVersitWriter::FinishedState); |
219 | |
220 | // Cancelling |
221 | delete mOutputDevice; |
222 | mOutputDevice = new QBuffer; |
223 | mOutputDevice->open(openMode: QBuffer::ReadWrite); |
224 | mSignalCatcher->mReceived.clear(); |
225 | mWriter->setDevice(mOutputDevice); |
226 | mWriter->startWriting(input: list); |
227 | mWriter->cancel(); |
228 | mWriter->waitForFinished(); |
229 | QTRY_VERIFY(mSignalCatcher->mReceived.count() >= 2); |
230 | QCOMPARE(mSignalCatcher->mReceived.at(0), QVersitWriter::ActiveState); |
231 | QVersitWriter::State state(mSignalCatcher->mReceived.at(i: 1)); |
232 | // It's possible that it finishes before it cancels. |
233 | QVERIFY(state == QVersitWriter::CanceledState |
234 | || state == QVersitWriter::FinishedState); |
235 | } |
236 | |
237 | void tst_QVersitWriter::testByteArrayOutput() |
238 | { |
239 | const QByteArray vCard30( |
240 | "BEGIN:VCARD\r\n" |
241 | "VERSION:3.0\r\n" |
242 | "FN:John\r\n" |
243 | "END:VCARD\r\n" ); |
244 | |
245 | delete mWriter; // we don't want the init()ed writer. |
246 | |
247 | QByteArray output; |
248 | mWriter = new QVersitWriter(&output); |
249 | |
250 | QVERIFY(mWriter->device() == 0); |
251 | |
252 | QVersitDocument document(QVersitDocument::VCard30Type); |
253 | document.setComponentType(QStringLiteral("VCARD" )); |
254 | QVersitProperty property; |
255 | property.setName(QString(QStringLiteral("FN" ))); |
256 | property.setValue(QStringLiteral("John" )); |
257 | document.addProperty(property); |
258 | QVERIFY2(mWriter->startWriting(document), QString::number(mWriter->error()).toLatin1().data()); |
259 | QVERIFY2(mWriter->waitForFinished(), QString::number(mWriter->error()).toLatin1().data()); |
260 | QCOMPARE(output, vCard30); |
261 | } |
262 | |
263 | void tst_QVersitWriter::testWritingDocument() |
264 | { |
265 | QFETCH(QVersitDocument, document); |
266 | QFETCH(QByteArray, expected); |
267 | |
268 | mOutputDevice->open(openMode: QBuffer::ReadWrite); |
269 | mWriter->setDevice(mOutputDevice); |
270 | QVERIFY2(mWriter->startWriting(document), QString::number(mWriter->error()).toLatin1().data()); |
271 | QVERIFY2(mWriter->waitForFinished(), QString::number(mWriter->error()).toLatin1().data()); |
272 | mOutputDevice->seek(off: 0); |
273 | QByteArray result(mOutputDevice->readAll()); |
274 | if (result!=expected) qDebug() << result << expected; |
275 | QCOMPARE(result, expected); |
276 | |
277 | // try it again in another codec |
278 | QTextCodec* utf16(QTextCodec::codecForName(name: "UTF-16" )); |
279 | mWriter->setDefaultCodec(utf16); |
280 | mOutputDevice->buffer().clear(); |
281 | mOutputDevice->seek(off: 0); |
282 | QVERIFY2(mWriter->startWriting(document), QString::number(mWriter->error()).toLatin1().data()); |
283 | QVERIFY2(mWriter->waitForFinished(), QString::number(mWriter->error()).toLatin1().data()); |
284 | mOutputDevice->seek(off: 0); |
285 | result = mOutputDevice->readAll(); |
286 | expected = utf16->fromUnicode(uc: QString::fromLatin1(str: expected)); |
287 | if (result!=expected) qDebug() << result << expected; |
288 | QCOMPARE(result, expected); |
289 | } |
290 | |
291 | void tst_QVersitWriter::testWritingDocument_data() |
292 | { |
293 | QTest::addColumn<QVersitDocument>(name: "document" ); |
294 | QTest::addColumn<QByteArray>(name: "expected" ); |
295 | |
296 | QVersitDocument document(QVersitDocument::VCard21Type); |
297 | document.setComponentType(QStringLiteral("VCARD" )); |
298 | QVersitProperty property; |
299 | property.setName(QStringLiteral("FN" )); |
300 | property.setValue(QStringLiteral("Bob" )); |
301 | document.addProperty(property); |
302 | QTest::newRow(dataTag: "basic vCard 2.1" ) << document << QByteArray( |
303 | "BEGIN:VCARD\r\n" |
304 | "VERSION:2.1\r\n" |
305 | "FN:Bob\r\n" |
306 | "END:VCARD\r\n" |
307 | ); |
308 | |
309 | document.setComponentType(QStringLiteral("VCARD" )); |
310 | document.setType(QVersitDocument::VCard30Type); |
311 | QTest::newRow(dataTag: "basic vCard 3.0" ) << document << QByteArray( |
312 | "BEGIN:VCARD\r\n" |
313 | "VERSION:3.0\r\n" |
314 | "FN:Bob\r\n" |
315 | "END:VCARD\r\n" |
316 | ); |
317 | |
318 | document.setComponentType(QStringLiteral("VCARD" )); |
319 | document.setType(QVersitDocument::VCard40Type); |
320 | QTest::newRow(dataTag: "basic vCard 4.0" ) << document << QByteArray( |
321 | "BEGIN:VCARD\r\n" |
322 | "VERSION:4.0\r\n" |
323 | "FN:Bob\r\n" |
324 | "END:VCARD\r\n" |
325 | ); |
326 | |
327 | { |
328 | QVersitDocument document(QVersitDocument::ICalendar20Type); |
329 | document.setComponentType(QStringLiteral("VCALENDAR" )); |
330 | QVersitDocument subdocument(QVersitDocument::ICalendar20Type); |
331 | subdocument.setComponentType(QStringLiteral("VEVENT" )); |
332 | property.setValueType(QVersitProperty::PreformattedType); |
333 | property.setName(QStringLiteral("RRULE" )); |
334 | property.setValue(QStringLiteral("FREQ=MONTHLY;BYMONTHDAY=1,3" )); |
335 | subdocument.addProperty(property); |
336 | document.addSubDocument(subdocument); |
337 | QTest::newRow(dataTag: "basic iCalendar 2.0" ) << document << QByteArray( |
338 | "BEGIN:VCALENDAR\r\n" |
339 | "VERSION:2.0\r\n" |
340 | "BEGIN:VEVENT\r\n" |
341 | "RRULE:FREQ=MONTHLY;BYMONTHDAY=1,3\r\n" |
342 | "END:VEVENT\r\n" |
343 | "END:VCALENDAR\r\n" ); |
344 | } |
345 | |
346 | { |
347 | QVersitDocument document(QVersitDocument::ICalendar20Type); |
348 | document.setComponentType(QStringLiteral("VCALENDAR" )); |
349 | QVersitProperty property; |
350 | property.setName(QStringLiteral("PRODID" )); |
351 | property.setValue(QStringLiteral("-//hacksw/handcal//NONSGML v1.0//EN" )); |
352 | document.addProperty(property); |
353 | QVersitDocument nested(QVersitDocument::ICalendar20Type); |
354 | nested.setComponentType(QStringLiteral("VEVENT" )); |
355 | property.setName(QStringLiteral("DTSTART" )); |
356 | property.setValue(QStringLiteral("19970714T170000Z" )); |
357 | nested.addProperty(property); |
358 | property.setName(QStringLiteral("DTEND" )); |
359 | property.setValue(QStringLiteral("19970715T035959Z" )); |
360 | nested.addProperty(property); |
361 | property.setName(QStringLiteral("SUMMARY" )); |
362 | property.setValue(QStringLiteral("Bastille Day Party" )); |
363 | nested.addProperty(property); |
364 | document.addSubDocument(subdocument: nested); |
365 | QTest::newRow(dataTag: "iCalendar 2.0 from spec" ) << document << QByteArray( |
366 | "BEGIN:VCALENDAR\r\n" |
367 | "VERSION:2.0\r\n" |
368 | "PRODID:-//hacksw/handcal//NONSGML v1.0//EN\r\n" |
369 | "BEGIN:VEVENT\r\n" |
370 | "DTSTART:19970714T170000Z\r\n" |
371 | "DTEND:19970715T035959Z\r\n" |
372 | "SUMMARY:Bastille Day Party\r\n" |
373 | "END:VEVENT\r\n" |
374 | "END:VCALENDAR\r\n" ); |
375 | } |
376 | |
377 | { |
378 | QString longString(QLatin1String( |
379 | "4567890123456789012345678901234567890123456789012345678901234567890123456" |
380 | "234567890123456789012345678901234567890123456789012345678901234567890123456" |
381 | "234567890123456789012" )); |
382 | QVersitDocument document(QVersitDocument::VCard21Type); |
383 | document.setComponentType(QStringLiteral("VCARD" )); |
384 | QVersitProperty property; |
385 | property.setName(QStringLiteral("FN" )); |
386 | property.setValue(longString); |
387 | document.addProperty(property); |
388 | QByteArray expected21( |
389 | "BEGIN:VCARD\r\n" |
390 | "VERSION:2.1\r\n" |
391 | "FN:4567890123456789012345678901234567890123456789012345678901234567890123456\r\n" |
392 | " 234567890123456789012345678901234567890123456789012345678901234567890123456\r\n" |
393 | " 234567890123456789012\r\n" |
394 | "END:VCARD\r\n" ); |
395 | QTest::newRow(dataTag: "folding 2.1" ) << document << expected21; |
396 | |
397 | document.setType(QVersitDocument::VCard30Type); |
398 | QByteArray expected30( |
399 | "BEGIN:VCARD\r\n" |
400 | "VERSION:3.0\r\n" |
401 | "FN:4567890123456789012345678901234567890123456789012345678901234567890123456\r\n" |
402 | " 234567890123456789012345678901234567890123456789012345678901234567890123456\r\n" |
403 | " 234567890123456789012\r\n" |
404 | "END:VCARD\r\n" ); |
405 | QTest::newRow(dataTag: "folding 3.0" ) << document << expected30; |
406 | |
407 | document.setType(QVersitDocument::VCard21Type); |
408 | property.setValue(longString.toLatin1()); |
409 | property.setValueType(QVersitProperty::BinaryType); |
410 | document.removeProperties(name: "FN" ); |
411 | document.addProperty(property); |
412 | QByteArray expected21b( |
413 | "BEGIN:VCARD\r\n" |
414 | "VERSION:2.1\r\n" |
415 | "FN;ENCODING=BASE64:\r\n" |
416 | " NDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODk\r\n" |
417 | " wMTIzNDU2Nzg5MDEyMzQ1NjIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MD\r\n" |
418 | " EyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1NjIzNDU2Nzg5MDEyMzQ1Njc4OTAxM\r\n" |
419 | " g==\r\n" |
420 | "\r\n" |
421 | "END:VCARD\r\n" ); |
422 | QTest::newRow(dataTag: "folding 2.1" ) << document << expected21b; |
423 | |
424 | document.setType(QVersitDocument::VCard30Type); |
425 | QByteArray expected30b( |
426 | "BEGIN:VCARD\r\n" |
427 | "VERSION:3.0\r\n" |
428 | "FN;ENCODING=b:NDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OT\r\n" |
429 | " AxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1NjIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwM\r\n" |
430 | " TIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1NjIzNDU2Nzg5MDEy\r\n" |
431 | " MzQ1Njc4OTAxMg==\r\n" |
432 | "END:VCARD\r\n" ); |
433 | QTest::newRow(dataTag: "folding 3.0" ) << document << expected30b; |
434 | } |
435 | } |
436 | |
437 | QTEST_MAIN(tst_QVersitWriter) |
438 | |