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 | |
30 | #include <QtCore/QCoreApplication> |
31 | #include <QtCore/QStringList> |
32 | #include <QtTest/QtTest> |
33 | #include <private/qmetaobjectbuilder_p.h> |
34 | |
35 | /* |
36 | This test makes a testlog containing lots of characters which have a special meaning in |
37 | XML, with the purpose of exposing bugs in testlib's XML output code. |
38 | */ |
39 | class tst_BadXml : public QObject |
40 | { |
41 | Q_OBJECT |
42 | |
43 | private slots: |
44 | void badDataTag() const; |
45 | void badDataTag_data() const; |
46 | |
47 | void badMessage() const; |
48 | void badMessage_data() const; |
49 | |
50 | void failWithNoFile() const; |
51 | |
52 | void encoding(); |
53 | |
54 | public: |
55 | static QList<QByteArray> const& badStrings(); |
56 | }; |
57 | |
58 | /* |
59 | Custom metaobject to make it possible to change class name at runtime. |
60 | */ |
61 | class EmptyClass : public tst_BadXml |
62 | { Q_OBJECT }; |
63 | |
64 | class tst_BadXmlSub : public tst_BadXml |
65 | { |
66 | public: |
67 | tst_BadXmlSub() |
68 | : className("tst_BadXml" ), mo(0) {} |
69 | ~tst_BadXmlSub() { free(ptr: mo); } |
70 | |
71 | const QMetaObject* metaObject() const; |
72 | |
73 | QByteArray className; |
74 | private: |
75 | QMetaObject *mo; |
76 | }; |
77 | |
78 | const QMetaObject* tst_BadXmlSub::metaObject() const |
79 | { |
80 | if (!mo || (mo->className() != className)) { |
81 | free(ptr: mo); |
82 | QMetaObjectBuilder builder(&EmptyClass::staticMetaObject); |
83 | builder.setClassName(className); |
84 | const_cast<tst_BadXmlSub *>(this)->mo = builder.toMetaObject(); |
85 | } |
86 | return mo; |
87 | } |
88 | |
89 | /* |
90 | Outputs incidents and benchmark results with the current data tag set to a bad string. |
91 | */ |
92 | void tst_BadXml::badDataTag() const |
93 | { |
94 | qDebug(msg: "a message" ); |
95 | |
96 | QBENCHMARK { |
97 | } |
98 | |
99 | QFETCH(bool, shouldFail); |
100 | if (shouldFail) |
101 | QFAIL("a failure" ); |
102 | } |
103 | |
104 | void tst_BadXml::badDataTag_data() const |
105 | { |
106 | QTest::addColumn<bool>(name: "shouldFail" ); |
107 | |
108 | foreach (char const* str, badStrings()) { |
109 | QTest::newRow(qPrintable(QString("fail %1" ).arg(str))) << true; |
110 | QTest::newRow(qPrintable(QString("pass %1" ).arg(str))) << false; |
111 | } |
112 | } |
113 | |
114 | void tst_BadXml::failWithNoFile() const |
115 | { |
116 | QTest::qFail(statementStr: "failure message" , file: 0, line: 0); |
117 | } |
118 | |
119 | // QTBUG-35743, test whether XML is using correct UTF-8 encoding |
120 | // on platforms where the console encoding differs. |
121 | void tst_BadXml::encoding() |
122 | { |
123 | QStringList arguments = QCoreApplication::arguments(); |
124 | arguments.pop_front(); // Prevent match on binary "badxml" |
125 | if (arguments.filter(QStringLiteral("xml" )).isEmpty()) |
126 | QSKIP("Skipped for text due to unpredictable console encoding." ); |
127 | QString string; |
128 | string += QChar(ushort(0xDC)); // German umlaut Ue |
129 | string += QStringLiteral("lrich " ); |
130 | string += QChar(ushort(0xDC)); // German umlaut Ue |
131 | string += QStringLiteral("ml" ); |
132 | string += QChar(ushort(0xE4)); // German umlaut ae |
133 | string += QStringLiteral("ut" ); |
134 | qDebug() << string; |
135 | } |
136 | |
137 | /* |
138 | Outputs a message containing a bad string. |
139 | */ |
140 | void tst_BadXml::badMessage() const |
141 | { |
142 | QFETCH(QByteArray, message); |
143 | qDebug(msg: "%s" , message.constData()); |
144 | } |
145 | |
146 | void tst_BadXml::badMessage_data() const |
147 | { |
148 | QTest::addColumn<QByteArray>(name: "message" ); |
149 | |
150 | int i = 0; |
151 | foreach (QByteArray const& str, badStrings()) { |
152 | QTest::newRow(qPrintable(QString::fromLatin1("string %1" ).arg(i++))) << str; |
153 | } |
154 | } |
155 | |
156 | /* |
157 | Returns a list of strings likely to expose bugs in XML output code. |
158 | */ |
159 | QList<QByteArray> const& tst_BadXml::badStrings() |
160 | { |
161 | static QList<QByteArray> out; |
162 | if (out.isEmpty()) { |
163 | out << "end cdata ]]> text ]]> more text" ; |
164 | out << "quotes \" text\" more text" ; |
165 | out << "xml close > open < tags < text" ; |
166 | out << "all > \" mixed ]]> up > \" in < the ]]> hopes < of triggering \"< ]]> bugs" ; |
167 | } |
168 | return out; |
169 | } |
170 | |
171 | int main(int argc, char** argv) |
172 | { |
173 | QCoreApplication app(argc, argv); |
174 | |
175 | /* |
176 | tst_selftests can't handle multiple XML documents in a single testrun, so we'll |
177 | decide before we begin which of our "bad strings" we want to use for our testcase |
178 | name. |
179 | */ |
180 | int badstring = -1; |
181 | QVector<char const*> args; |
182 | for (int i = 0; i < argc; ++i) { |
183 | if (!strcmp(s1: argv[i], s2: "-badstring" )) { |
184 | bool ok = false; |
185 | if (i < argc-1) { |
186 | badstring = QByteArray(argv[i+1]).toInt(ok: &ok); |
187 | ++i; |
188 | } |
189 | if (!ok) { |
190 | qFatal(msg: "Bad `-badstring' option" ); |
191 | } |
192 | } |
193 | else { |
194 | args << argv[i]; |
195 | } |
196 | } |
197 | |
198 | args << "-eventcounter" ; |
199 | |
200 | /* |
201 | We just want testlib to output a benchmark result, we don't actually care about the value, |
202 | so just do one iteration to save time. |
203 | */ |
204 | args << "-iterations" << "1" ; |
205 | |
206 | if (badstring == -1) { |
207 | tst_BadXml test; |
208 | return QTest::qExec(testObject: &test, argc: args.count(), argv: const_cast<char**>(args.data())); |
209 | } |
210 | |
211 | QList<QByteArray> badstrings = tst_BadXml::badStrings(); |
212 | if (badstring >= badstrings.count()) |
213 | qFatal(msg: "`-badstring %d' is out of range" , badstring); |
214 | |
215 | tst_BadXmlSub test; |
216 | test.className = badstrings[badstring].constData(); |
217 | return QTest::qExec(testObject: &test, argc: args.count(), argv: const_cast<char**>(args.data())); |
218 | } |
219 | |
220 | #include "tst_badxml.moc" |
221 | |