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 <QtTest/QtTest> |
30 | #include <qsizepolicy.h> |
31 | |
32 | Q_DECLARE_METATYPE(Qt::Orientations) |
33 | Q_DECLARE_METATYPE(QSizePolicy) |
34 | Q_DECLARE_METATYPE(QSizePolicy::Policy) |
35 | Q_DECLARE_METATYPE(QSizePolicy::ControlType) |
36 | |
37 | class tst_QSizePolicy : public QObject |
38 | { |
39 | Q_OBJECT |
40 | |
41 | private Q_SLOTS: |
42 | void cleanup() { QVERIFY(QApplication::topLevelWidgets().isEmpty()); } |
43 | void qtest(); |
44 | void constExpr(); |
45 | void defaultValues(); |
46 | void getSetCheck_data() { data(); } |
47 | void getSetCheck(); |
48 | void transposed_data() { data(); } |
49 | void transposed(); |
50 | void dataStream(); |
51 | void horizontalStretch(); |
52 | void verticalStretch(); |
53 | void qhash_data() { data(); } |
54 | void qhash(); |
55 | private: |
56 | void data() const; |
57 | }; |
58 | |
59 | |
60 | struct PrettyPrint { |
61 | const char *m_s; |
62 | template <typename T> |
63 | explicit PrettyPrint(const T &t) : m_s(nullptr) |
64 | { |
65 | using QT_PREPEND_NAMESPACE(QTest)::toString; |
66 | m_s = toString(t); |
67 | } |
68 | ~PrettyPrint() { delete[] m_s; } |
69 | const char* s() const { return m_s ? m_s : "<null>" ; } |
70 | }; |
71 | |
72 | void tst_QSizePolicy::qtest() |
73 | { |
74 | #define CHECK(x) QCOMPARE(PrettyPrint(QSizePolicy::x).s(), #x) |
75 | // Policy: |
76 | CHECK(Fixed); |
77 | CHECK(Minimum); |
78 | CHECK(Ignored); |
79 | CHECK(MinimumExpanding); |
80 | CHECK(Expanding); |
81 | CHECK(Maximum); |
82 | CHECK(Preferred); |
83 | // ControlType: |
84 | CHECK(ButtonBox); |
85 | CHECK(CheckBox); |
86 | CHECK(ComboBox); |
87 | CHECK(Frame); |
88 | CHECK(GroupBox); |
89 | CHECK(Label); |
90 | CHECK(Line); |
91 | CHECK(LineEdit); |
92 | CHECK(PushButton); |
93 | CHECK(RadioButton); |
94 | CHECK(Slider); |
95 | CHECK(SpinBox); |
96 | CHECK(TabWidget); |
97 | CHECK(ToolButton); |
98 | #undef CHECK |
99 | #define CHECK2(x, y) QCOMPARE(PrettyPrint(QSizePolicy::x|QSizePolicy::y).s(), \ |
100 | QSizePolicy::x < QSizePolicy::y ? #x "|" #y : #y "|" #x) |
101 | // ControlTypes (sample) |
102 | CHECK2(ButtonBox, CheckBox); |
103 | CHECK2(CheckBox, ButtonBox); |
104 | CHECK2(ToolButton, Slider); |
105 | #undef CHECK2 |
106 | } |
107 | |
108 | void tst_QSizePolicy::constExpr() |
109 | { |
110 | /* gcc < 4.8.0 has problems with init'ing variant members in constexpr ctors */ |
111 | /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54922 */ |
112 | #if !defined(Q_CC_GNU) || defined(Q_CC_INTEL) || defined(Q_CC_CLANG) || Q_CC_GNU >= 408 |
113 | // check that certain ctors are constexpr (compile-only): |
114 | { Q_CONSTEXPR QSizePolicy sp; Q_UNUSED(sp); } |
115 | { Q_CONSTEXPR QSizePolicy sp = QSizePolicy(); Q_UNUSED(sp); } |
116 | { Q_CONSTEXPR QSizePolicy sp = QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); Q_UNUSED(sp); } |
117 | { Q_CONSTEXPR QSizePolicy sp = QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding, QSizePolicy::DefaultType); |
118 | Q_CONSTEXPR QSizePolicy tp = sp.transposed(); Q_UNUSED(tp); } |
119 | { |
120 | // QTBUG-69983: For ControlType != QSizePolicy::DefaultType, qCountTrailingZeroBits() |
121 | // is used, which MSVC 15.8.1 does not consider constexpr due to built-ins |
122 | # if defined(QT_HAS_CONSTEXPR_BUILTINS) && (!defined(Q_CC_MSVC) || _MSC_VER < 1915) |
123 | Q_RELAXED_CONSTEXPR auto sp = QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed, QSizePolicy::CheckBox); |
124 | # else |
125 | Q_CONSTEXPR auto sp = QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding, QSizePolicy::DefaultType); |
126 | # endif |
127 | Q_RELAXED_CONSTEXPR auto tp = sp.transposed(); Q_UNUSED(tp); |
128 | } |
129 | #else |
130 | QSKIP("QSizePolicy cannot be constexpr with this version of the compiler." ); |
131 | #endif |
132 | } |
133 | |
134 | void tst_QSizePolicy::defaultValues() |
135 | { |
136 | { |
137 | // check values of a default-constructed QSizePolicy |
138 | QSizePolicy sp; |
139 | QCOMPARE(sp.horizontalPolicy(), QSizePolicy::Fixed); |
140 | QCOMPARE(sp.verticalPolicy(), QSizePolicy::Fixed); |
141 | QCOMPARE(sp.horizontalStretch(), 0); |
142 | QCOMPARE(sp.verticalStretch(), 0); |
143 | QCOMPARE(sp.verticalStretch(), 0); |
144 | QCOMPARE(sp.controlType(), QSizePolicy::DefaultType); |
145 | QCOMPARE(sp.hasHeightForWidth(), false); |
146 | QCOMPARE(sp.hasWidthForHeight(), false); |
147 | } |
148 | } |
149 | |
150 | #define FETCH_TEST_DATA \ |
151 | QFETCH(QSizePolicy, sp); \ |
152 | QFETCH(QSizePolicy::Policy, hp); \ |
153 | QFETCH(QSizePolicy::Policy, vp); \ |
154 | QFETCH(int, hst); \ |
155 | QFETCH(int, vst); \ |
156 | QFETCH(QSizePolicy::ControlType, ct); \ |
157 | QFETCH(bool, hfw); \ |
158 | QFETCH(bool, wfh); \ |
159 | QFETCH(Qt::Orientations, ed) |
160 | |
161 | |
162 | // Testing get/set functions |
163 | void tst_QSizePolicy::getSetCheck() |
164 | { |
165 | FETCH_TEST_DATA; |
166 | |
167 | QCOMPARE(QPixmap(), QPixmap()); |
168 | |
169 | QCOMPARE(sp.horizontalPolicy(), hp); |
170 | QCOMPARE(sp.verticalPolicy(), vp); |
171 | QCOMPARE(sp.horizontalStretch(), hst); |
172 | QCOMPARE(sp.verticalStretch(), vst); |
173 | QCOMPARE(sp.controlType(), ct); |
174 | QCOMPARE(sp.hasHeightForWidth(), hfw); |
175 | QCOMPARE(sp.hasWidthForHeight(), wfh); |
176 | QCOMPARE(sp.expandingDirections(), ed); |
177 | } |
178 | |
179 | void tst_QSizePolicy::transposed() |
180 | { |
181 | FETCH_TEST_DATA; |
182 | |
183 | const QSizePolicy tr = sp.transposed(); |
184 | |
185 | QCOMPARE(tr.horizontalPolicy(), vp); // swapped |
186 | QCOMPARE(tr.verticalPolicy(), hp); // swapped |
187 | QCOMPARE(tr.horizontalStretch(), vst); // swapped |
188 | QCOMPARE(tr.verticalStretch(), hst); // swapped |
189 | QCOMPARE(tr.controlType(), ct); // not swapped |
190 | QCOMPARE(tr.hasHeightForWidth(), hfw); // not swapped (historic behavior) |
191 | QCOMPARE(tr.hasWidthForHeight(), wfh); // not swapped (historic behavior) |
192 | QCOMPARE(tr.expandingDirections(), ed); // swapped |
193 | |
194 | // destructive test - keep last: |
195 | sp.transpose(); |
196 | QCOMPARE(sp, tr); |
197 | } |
198 | |
199 | static void makeRow(QSizePolicy sp, QSizePolicy::Policy hp, QSizePolicy::Policy vp, |
200 | int hst, int vst, QSizePolicy::ControlType ct, bool hfw, bool wfh, |
201 | Qt::Orientations orients) |
202 | { |
203 | QTest::addRow(format: "%s-%s-%d-%d-%s-%s-%s" , |
204 | PrettyPrint(hp).s(), PrettyPrint(vp).s(), hst, vst, |
205 | PrettyPrint(ct).s(), |
206 | hfw ? "true" : "false" , wfh ? "true" : "false" ) |
207 | << sp << hp << vp << hst << vst << ct << hfw << wfh << orients; |
208 | } |
209 | |
210 | void tst_QSizePolicy::data() const |
211 | { |
212 | QTest::addColumn<QSizePolicy>(name: "sp" ); |
213 | QTest::addColumn<QSizePolicy::Policy>(name: "hp" ); |
214 | QTest::addColumn<QSizePolicy::Policy>(name: "vp" ); |
215 | QTest::addColumn<int>(name: "hst" ); |
216 | QTest::addColumn<int>(name: "vst" ); |
217 | QTest::addColumn<QSizePolicy::ControlType>(name: "ct" ); |
218 | QTest::addColumn<bool>(name: "hfw" ); |
219 | QTest::addColumn<bool>(name: "wfh" ); |
220 | QTest::addColumn<Qt::Orientations>(name: "ed" ); |
221 | |
222 | { |
223 | static const QSizePolicy::Policy policies[3] = { |
224 | QSizePolicy::Fixed, |
225 | QSizePolicy::Minimum, |
226 | QSizePolicy::Ignored |
227 | }; |
228 | static const QSizePolicy::ControlType controlTypes[4] = { |
229 | QSizePolicy::DefaultType, |
230 | QSizePolicy::ButtonBox, |
231 | QSizePolicy::CheckBox, |
232 | QSizePolicy::ToolButton |
233 | }; |
234 | |
235 | #define ITEMCOUNT(arr) int(sizeof(arr)/sizeof(arr[0])) |
236 | QSizePolicy sp, oldsp; |
237 | #ifdef GENERATE_BASELINE |
238 | QFile out(QString::fromAscii("qsizepolicy-Qt%1%2.txt" ).arg((QT_VERSION >> 16) & 0xff).arg((QT_VERSION) >> 8 & 0xff)); |
239 | if (out.open(QIODevice::WriteOnly | QIODevice::Truncate)) { |
240 | QDataStream stream(&out); |
241 | #endif |
242 | /* Loop for permutating over the values most likely to trigger a bug: |
243 | - mininumum, maximum values |
244 | - Some values with LSB set, others with MSB unset. (check if shifts are ok) |
245 | |
246 | */ |
247 | // Look specifically for |
248 | for (int ihp = 0; ihp < ITEMCOUNT(policies); ++ihp) { |
249 | QSizePolicy::Policy hp = policies[ihp]; |
250 | for (int ivp = 0; ivp < ITEMCOUNT(policies); ++ivp) { |
251 | QSizePolicy::Policy vp = policies[ivp]; |
252 | for (int ict = 0; ict < ITEMCOUNT(controlTypes); ++ict) { |
253 | QSizePolicy::ControlType ct = controlTypes[ict]; |
254 | for (int hst= 0; hst <= 255; hst+=85) { //[0,85,170,255] |
255 | for (int vst = 0; vst <= 255; vst+=85) { |
256 | for (int j = 0; j < 3; ++j) { |
257 | bool hfw = j & 1; |
258 | bool wfh = j & 2; // cannot set hfw and wfh at the same time |
259 | oldsp = sp; |
260 | for (int i = 0; i < 5; ++i) { |
261 | switch (i) { |
262 | case 0: sp.setHorizontalPolicy(hp); break; |
263 | case 1: sp.setVerticalPolicy(vp); break; |
264 | case 2: sp.setHorizontalStretch(hst); break; |
265 | case 3: sp.setVerticalStretch(vst); break; |
266 | case 4: sp.setControlType(ct); break; |
267 | case 5: sp.setHeightForWidth(hfw); sp.setWidthForHeight(wfh); break; |
268 | default: break; |
269 | } |
270 | |
271 | Qt::Orientations orients; |
272 | if (sp.horizontalPolicy() & QSizePolicy::ExpandFlag) |
273 | orients |= Qt::Horizontal; |
274 | if (sp.verticalPolicy() & QSizePolicy::ExpandFlag) |
275 | orients |= Qt::Vertical; |
276 | |
277 | makeRow(sp, |
278 | hp: i >= 0 ? hp : oldsp.horizontalPolicy(), |
279 | vp: i >= 1 ? vp : oldsp.verticalPolicy(), |
280 | hst: i >= 2 ? hst : oldsp.horizontalStretch(), |
281 | vst: i >= 3 ? vst : oldsp.verticalStretch(), |
282 | ct: i >= 4 ? ct : oldsp.controlType(), |
283 | hfw: i >= 5 ? hfw : oldsp.hasHeightForWidth(), |
284 | wfh: i >= 5 ? wfh : oldsp.hasWidthForHeight(), |
285 | orients); |
286 | #ifdef GENERATE_BASELINE |
287 | stream << sp; |
288 | #endif |
289 | } |
290 | } |
291 | } |
292 | } |
293 | } |
294 | } |
295 | } |
296 | #ifdef GENERATE_BASELINE |
297 | out.close(); |
298 | } |
299 | #endif |
300 | #undef ITEMCOUNT |
301 | } |
302 | } |
303 | |
304 | void tst_QSizePolicy::dataStream() |
305 | { |
306 | QByteArray data; |
307 | QSizePolicy sp(QSizePolicy::Minimum, QSizePolicy::Expanding); |
308 | { |
309 | QDataStream stream(&data, QIODevice::ReadWrite); |
310 | sp.setHorizontalStretch(42); |
311 | sp.setVerticalStretch(10); |
312 | sp.setControlType(QSizePolicy::CheckBox); |
313 | sp.setHeightForWidth(true); |
314 | |
315 | stream << sp; // big endian |
316 | /* |
317 | | BYTE 0 | BYTE 1 | |
318 | | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | |
319 | +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ |
320 | | Horizontal stretch | Vertical stretch | |
321 | +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ |
322 | |
323 | | BYTE 2 | BYTE 3 | |
324 | | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | |
325 | +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ |
326 | | pad | wfh | Control Type | hfw | Vertical policy | Horizontal policy | |
327 | +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ |
328 | */ |
329 | QCOMPARE((char)data[0], char(42)); // h stretch |
330 | QCOMPARE((char)data[1], char(10)); // v stretch |
331 | QCOMPARE((char)data[2], char(1 | (2 << 1))); // (hfw + CheckBox) |
332 | QCOMPARE((char)data[3], char(QSizePolicy::Minimum | (QSizePolicy::Expanding << 4))); |
333 | } |
334 | |
335 | { |
336 | QSizePolicy readSP; |
337 | QDataStream stream(data); |
338 | stream >> readSP; |
339 | QCOMPARE(sp, readSP); |
340 | } |
341 | } |
342 | |
343 | |
344 | void tst_QSizePolicy::horizontalStretch() |
345 | { |
346 | QSizePolicy sp; |
347 | sp.setHorizontalStretch(257); |
348 | QCOMPARE(sp.horizontalStretch(), 255); |
349 | sp.setHorizontalStretch(-2); |
350 | QCOMPARE(sp.horizontalStretch(), 0); |
351 | } |
352 | |
353 | void tst_QSizePolicy::verticalStretch() |
354 | { |
355 | QSizePolicy sp; |
356 | sp.setVerticalStretch(-2); |
357 | QCOMPARE(sp.verticalStretch(), 0); |
358 | sp.setVerticalStretch(257); |
359 | QCOMPARE(sp.verticalStretch(), 255); |
360 | } |
361 | |
362 | void tst_QSizePolicy::qhash() |
363 | { |
364 | FETCH_TEST_DATA; |
365 | Q_UNUSED(ed); |
366 | |
367 | QSizePolicy sp2(hp, vp, ct); |
368 | sp2.setVerticalStretch(vst); |
369 | sp2.setHorizontalStretch(hst); |
370 | if (hfw) sp2.setHeightForWidth(true); |
371 | if (wfh) sp2.setWidthForHeight(true); |
372 | QCOMPARE(sp, sp2); |
373 | QCOMPARE(qHash(sp), qHash(sp2)); |
374 | } |
375 | |
376 | #undef FETCH_TEST_DATA |
377 | |
378 | QTEST_MAIN(tst_QSizePolicy) |
379 | #include "tst_qsizepolicy.moc" |
380 | |