| 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 | |