1 /* This file is part of the KDE project
2 * Copyright (C) 2004 David Faure <faure@kde.org>
3 * Copyright 2008 Thomas Zander <zander@kde.org>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 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 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20 #include <KoXmlWriter.h>
21
22 #include <QString>
23 #include <QBuffer>
24 #include <QTest>
25 #include <QLoggingCategory>
26
27 class TestXmlWriter : public QObject
28 {
29 Q_OBJECT
30 private Q_SLOTS:
31 void initTestCase();
32 void testDocytype();
33 void testEmtpyElement();
34 void testAttributes();
35 void testIndent();
36 void testTextNode();
37 void testTextSpan();
38 void testTextSpanWithTabCache();
39 void testProcessingInstruction();
40 void testAddManifestEntry();
41 void testEscapingLongString();
42 void testEscalingLongString2();
43 void testConfig();
44
45 void speedTest();
46
47 private:
48 void setup(const char *publicId = 0, const char *systemId = 0);
49 QString content();
50
51 KoXmlWriter *writer;
52 QBuffer *buffer;
53 };
54
initTestCase()55 void TestXmlWriter::initTestCase()
56 {
57 QLoggingCategory::setFilterRules("*.debug=false\n"
58 "calligra.lib.odf=true\ncalligra.lib.store=true");
59 }
60
setup(const char * publicId,const char * systemId)61 void TestXmlWriter::setup(const char *publicId, const char *systemId)
62 {
63 buffer = new QBuffer();
64 buffer->open( QIODevice::WriteOnly );
65
66 writer = new KoXmlWriter( buffer );
67 writer->startDocument( "dummy", publicId, systemId );
68 writer->startElement( "dummy" );
69 }
70
content()71 QString TestXmlWriter::content()
72 {
73 writer->endElement();
74 writer->endDocument();
75 buffer->putChar( '\0' ); /*null-terminate*/
76 buffer->close();
77 QString stringContent = QString::fromUtf8(buffer->data());
78 int index = stringContent.indexOf("<dummy");
79 Q_ASSERT(index);
80 index = stringContent.indexOf('>', index);
81 stringContent = stringContent.mid(index+1, stringContent.length() - index - 11).trimmed();
82 return stringContent;
83 }
84
testDocytype()85 void TestXmlWriter::testDocytype()
86 {
87 setup("foo", "bar");
88 QCOMPARE(content(), QString());
89 QString stringContent = QString::fromUtf8(buffer->data());
90 QCOMPARE(stringContent, QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
91 "<!DOCTYPE dummy PUBLIC \"foo\" \"bar\">\n<dummy/>\n"));
92 }
93
testAttributes()94 void TestXmlWriter::testAttributes()
95 {
96 setup();
97
98 writer->startElement("test");
99 writer->addAttribute("a", "val");
100 writer->addAttribute("b", "<\">");
101 writer->addAttribute("c", -42);
102 writer->addAttribute("d", 1234.56789012345);
103 writer->addAttributePt("e", 1234.56789012345);
104 writer->addAttribute("f", false);
105 writer->addAttribute("g", true);
106 writer->endElement();
107 QCOMPARE(content(), QString("<test a=\"val\" b=\"<">\" c=\"-42\" d=\"1234.56789012345\" e=\"1234.56789012345pt\" f=\"false\" g=\"true\"/>"));
108 }
109
testEmtpyElement()110 void TestXmlWriter::testEmtpyElement()
111 {
112 setup();
113 writer->startElement("m");
114 writer->endElement();
115 QCOMPARE(content(), QString("<m/>"));
116 }
117
testIndent()118 void TestXmlWriter::testIndent()
119 {
120 setup();
121 writer->startElement("a");
122 writer->startElement("b");
123 writer->startElement("c");
124 writer->endElement();
125 writer->endElement();
126 writer->endElement();
127 QCOMPARE(content(), QString("<a>\n <b>\n <c/>\n </b>\n </a>"));
128 }
129
testTextNode()130 void TestXmlWriter::testTextNode()
131 {
132 setup();
133 writer->startElement("a");
134 writer->startElement("b", false /*no indent*/);
135 writer->startElement("c");
136 writer->endElement();
137 writer->addTextNode("te");
138 writer->addTextNode("xt");
139 writer->endElement();
140 writer->endElement();
141 QCOMPARE(content(), QString("<a>\n <b><c/>text</b>\n </a>"));
142 }
143
testTextSpan()144 void TestXmlWriter::testTextSpan()
145 {
146 setup();
147 writer->startElement("p", false /*no indent*/);
148 writer->addTextSpan(QString::fromLatin1(" \t\n foo "));
149 writer->endElement();
150 QCOMPARE(content(), QString("<p><text:s text:c=\"3\"/><text:tab/><text:line-break/> foo<text:s text:c=\"2\"/></p>"));
151 }
152
testTextSpanWithTabCache()153 void TestXmlWriter::testTextSpanWithTabCache()
154 {
155 setup();
156 writer->startElement("p", false /*no indent*/);
157 QMap<int, int> tabCache;
158 tabCache.insert(3, 0);
159 writer->addTextSpan(QString::fromUtf8(" \t\n foö "), tabCache);
160 writer->endElement();
161 QCOMPARE(content(), QString::fromUtf8("<p><text:s text:c=\"3\"/><text:tab text:tab-ref=\"1\"/>"
162 "<text:line-break/> foö<text:s text:c=\"2\"/></p>"));
163 }
164
testProcessingInstruction()165 void TestXmlWriter::testProcessingInstruction()
166 {
167 setup();
168 writer->startElement("p", false /*no indent*/);
169 writer->addProcessingInstruction("opendocument foobar");
170 writer->addTextSpan(QString::fromLatin1("foo"));
171 writer->endElement();
172 QCOMPARE(content(), QString("<p><?opendocument foobar?>foo</p>"));
173 }
174
testAddManifestEntry()175 void TestXmlWriter::testAddManifestEntry()
176 {
177 setup();
178 writer->addManifestEntry(QString::fromLatin1("foo/bar/blah"), QString::fromLatin1("mime/type"));
179 QCOMPARE(content(), QString("<manifest:file-entry manifest:media-type=\"mime/type\" "
180 "manifest:full-path=\"foo/bar/blah\"/>"));
181 }
182
183
testEscapingLongString()184 void TestXmlWriter::testEscapingLongString()
185 {
186 int sz = 15000; // must be more than KoXmlWriter::s_escapeBufferLen
187 QString x(sz);
188 x.fill('x', sz);
189 x += '&';
190 setup();
191
192 writer->startElement("test");
193 writer->addAttribute("a", x);
194 writer->endElement();
195
196 QString expected = "<test a=\"";
197 expected += x + "amp;\"/>";
198 QCOMPARE(content(), QString(expected));
199 }
200
testEscalingLongString2()201 void TestXmlWriter::testEscalingLongString2()
202 {
203 QString longPath;
204 for (uint i = 0 ; i < 1000 ; ++i)
205 longPath += QString::fromLatin1("M10 10L20 20 ");
206 setup();
207 writer->startElement("test");
208 writer->addAttribute("a", longPath);
209 writer->endElement();
210 QString expected = "<test a=\"";
211 expected += longPath.toUtf8() + "\"/>";
212 QCOMPARE(content(), expected);
213
214 }
215
testConfig()216 void TestXmlWriter::testConfig()
217 {
218 setup();
219 const bool val = true;
220 const int num = 1;
221 const qreal numdouble = 5.0;
222 writer->addConfigItem(QString::fromLatin1("TestConfigBool"), val);
223 writer->addConfigItem(QString::fromLatin1("TestConfigInt"), num);
224 writer->addConfigItem(QString::fromLatin1("TestConfigDouble"), numdouble);
225 QCOMPARE(content(), QString("<config:config-item config:name=\"TestConfigBool\""
226 " config:type=\"boolean\">true</config:config-item>\n"
227 " <config:config-item config:name=\"TestConfigInt\" config:type=\"int\">1</config:config-item>\n"
228 " <config:config-item config:name=\"TestConfigDouble\" config:type=\"double\">5</config:config-item>"));
229 }
230
231 static const int NumParagraphs = 30000;
232
speedTest()233 void TestXmlWriter::speedTest()
234 {
235 QTime time;
236 time.start();
237 QString paragText = QString::fromUtf8("This is the text of the paragraph. I'm including a euro sign to test encoding issues: €");
238 QString styleName = "Heading 1";
239
240 QFile out(QString::fromLatin1("out5.xml"));
241 if (out.open(QIODevice::WriteOnly)) {
242 KoXmlWriter writer(&out);
243 writer.startDocument("rootelem");
244 writer.startElement("rootelem");
245 for (int i = 0 ; i < NumParagraphs ; ++i) {
246 writer.startElement("paragraph");
247 writer.addAttribute("text:style-name", styleName);
248 writer.addTextNode(paragText);
249 writer.endElement();
250 }
251 writer.endElement();
252 writer.endDocument();
253 }
254 out.close();
255 out.remove();
256 qInfo()<<"writing"<<NumParagraphs<<"XML elements using KoXmlWriter:"<<time.elapsed()<<"ms";
257 // TODO we might want to convert this into a QBenchmark test
258 }
259
260 QTEST_GUILESS_MAIN(TestXmlWriter)
261 #include <TestXmlWriter.moc>
262
263