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 <QtTest/QtTest>
31#include "qprogressbar.h"
32#include <qlocale.h>
33#include <qapplication.h>
34#include <qstyleoption.h>
35#include <qdebug.h>
36#include <qtimer.h>
37#include <QStyleFactory>
38
39class tst_QProgressBar : public QObject
40{
41Q_OBJECT
42private slots:
43 void getSetCheck();
44 void minMaxSameValue();
45 void destroyIndeterminate();
46 void text();
47 void format();
48 void setValueRepaint_data();
49 void setValueRepaint();
50#ifndef Q_OS_MAC
51 void setMinMaxRepaint();
52#endif
53 void sizeHint();
54 void formatedText_data();
55 void formatedText();
56 void localizedFormattedText();
57
58 void task245201_testChangeStyleAndDelete_data();
59 void task245201_testChangeStyleAndDelete();
60};
61
62// Testing get/set functions
63void tst_QProgressBar::getSetCheck()
64{
65 QProgressBar obj1;
66 // bool QProgressBar::invertedAppearance()
67 // void QProgressBar::setInvertedAppearance(bool)
68 obj1.setInvertedAppearance(false);
69 QCOMPARE(false, obj1.invertedAppearance());
70 obj1.setInvertedAppearance(true);
71 QCOMPARE(true, obj1.invertedAppearance());
72
73 // int QProgressBar::minimum()
74 // void QProgressBar::setMinimum(int)
75 obj1.setMinimum(0);
76 QCOMPARE(0, obj1.minimum());
77 obj1.setMinimum(INT_MAX);
78 QCOMPARE(INT_MAX, obj1.minimum());
79 obj1.setMinimum(INT_MIN);
80 QCOMPARE(INT_MIN, obj1.minimum());
81
82 // int QProgressBar::maximum()
83 // void QProgressBar::setMaximum(int)
84 obj1.setMaximum(0);
85 QCOMPARE(0, obj1.maximum());
86 obj1.setMaximum(INT_MIN);
87 QCOMPARE(INT_MIN, obj1.maximum());
88 obj1.setMaximum(INT_MAX);
89 QCOMPARE(INT_MAX, obj1.maximum());
90
91 // int QProgressBar::value()
92 // void QProgressBar::setValue(int)
93 obj1.setValue(0);
94 QCOMPARE(0, obj1.value());
95 obj1.setValue(INT_MIN);
96 QCOMPARE(INT_MIN, obj1.value());
97 obj1.setValue(INT_MAX);
98 QCOMPARE(INT_MAX, obj1.value());
99}
100
101void tst_QProgressBar::minMaxSameValue()
102{
103 QProgressBar bar;
104 bar.setRange(minimum: 10, maximum: 10);
105 bar.setValue(10);
106 bar.move(ax: 300, ay: 300);
107 bar.show();
108 QVERIFY(QTest::qWaitForWindowExposed(&bar));
109}
110
111void tst_QProgressBar::destroyIndeterminate()
112{
113 // This test crashes on styles that animate indeterminate / busy
114 // progressbars, and forget to remove the bars from internal logics when
115 // it's deleted.
116 QPointer<QProgressBar> bar = new QProgressBar;
117 bar->setMaximum(0);
118 bar->move(ax: 300, ay: 300);
119 bar->show();
120 QVERIFY(QTest::qWaitForWindowExposed(bar.data()));
121
122 QEventLoop loop;
123 QTimer::singleShot(msec: 500, receiver: bar, SLOT(deleteLater()));
124 QTimer::singleShot(msec: 3000, receiver: &loop, SLOT(quit()));
125 loop.exec();
126
127 QVERIFY(!bar);
128}
129
130void tst_QProgressBar::text()
131{
132 QProgressBar bar;
133 bar.setRange(minimum: 10, maximum: 10);
134 bar.setValue(10);
135 QCOMPARE(bar.text(), QString("100%"));
136 bar.setRange(minimum: 0, maximum: 10);
137 QCOMPARE(bar.text(), QString("100%"));
138 bar.setValue(5);
139 QCOMPARE(bar.text(), QString("50%"));
140 bar.setRange(minimum: 0, maximum: 5);
141 bar.setValue(0);
142 bar.setRange(minimum: 5, maximum: 5);
143 QCOMPARE(bar.text(), QString());
144}
145
146class ProgressBar : public QProgressBar
147{
148 void paintEvent(QPaintEvent *event)
149 {
150 repainted = true;
151 QProgressBar::paintEvent(event);
152 }
153public:
154 bool repainted;
155 using QProgressBar::initStyleOption;
156};
157
158void tst_QProgressBar::format()
159{
160 ProgressBar bar;
161 bar.setRange(minimum: 0, maximum: 10);
162 bar.setValue(1);
163 bar.move(ax: 300, ay: 300);
164 bar.show();
165 QVERIFY(QTest::qWaitForWindowExposed(&bar));
166
167 bar.repainted = false;
168 bar.setFormat("%v of %m (%p%)");
169 QTRY_VERIFY(bar.repainted);
170 bar.repainted = false;
171 bar.setFormat("%v of %m (%p%)");
172 qApp->processEvents();
173
174#if !defined(Q_OS_MACOS) && !defined(Q_OS_WIN)
175 // Animated scroll bars get paint events all the time
176 QVERIFY(!bar.repainted);
177#endif
178
179 QCOMPARE(bar.text(), QString("1 of 10 (10%)"));
180 bar.setRange(minimum: 5, maximum: 5);
181 bar.setValue(5);
182 QCOMPARE(bar.text(), QString("5 of 0 (100%)"));
183 bar.setRange(minimum: 0, maximum: 5);
184 bar.setValue(0);
185 bar.setRange(minimum: 5, maximum: 5);
186 QCOMPARE(bar.text(), QString());
187}
188
189void tst_QProgressBar::setValueRepaint_data()
190{
191 QTest::addColumn<int>(name: "min");
192 QTest::addColumn<int>(name: "max");
193 QTest::addColumn<int>(name: "increment");
194
195 auto add = [](int min, int max, int increment) {
196 QTest::addRow(format: "%d-%d@%d", min, max, increment) << min << max << increment;
197 };
198
199 add(0, 10, 1);
200
201 auto add_set = [=](int min, int max, int increment) {
202 // check corner cases, and adjacent values (to circumvent explicit checks for corner cases)
203 add(min, max, increment);
204 add(min + 1, max, increment);
205 add(min, max - 1, increment);
206 add(min + 1, max - 1, increment);
207 };
208
209 add_set(INT_MIN, INT_MAX, INT_MAX / 50 + 1);
210 add_set(0, INT_MAX, INT_MAX / 100 + 1);
211 add_set(INT_MIN, 0, INT_MAX / 100 + 1);
212}
213
214void tst_QProgressBar::setValueRepaint()
215{
216 QFETCH(int, min);
217 QFETCH(int, max);
218 QFETCH(int, increment);
219
220 ProgressBar pbar;
221 pbar.setMinimum(min);
222 pbar.setMaximum(max);
223 pbar.setFormat("%v");
224 pbar.move(ax: 300, ay: 300);
225 pbar.show();
226 QVERIFY(QTest::qWaitForWindowExposed(&pbar));
227
228 QApplication::processEvents();
229 for (qint64 i = min; i < max; i += increment) {
230 pbar.repainted = false;
231 pbar.setValue(int(i));
232 QTRY_VERIFY(pbar.repainted);
233 }
234}
235
236// This test is invalid on Mac, since progressbars
237// are animated there
238
239#ifndef Q_OS_MAC
240void tst_QProgressBar::setMinMaxRepaint()
241{
242 if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland"), cs: Qt::CaseInsensitive))
243 QSKIP("Wayland: This fails. Figure out why.");
244
245 ProgressBar pbar;
246 pbar.setMinimum(0);
247 pbar.setMaximum(10);
248 pbar.setFormat("%v");
249 pbar.move(ax: 300, ay: 300);
250 pbar.show();
251 qApp->setActiveWindow(&pbar);
252 QVERIFY(QTest::qWaitForWindowActive(&pbar));
253
254 // No repaint when setting minimum to the current minimum
255 pbar.repainted = false;
256 pbar.setMinimum(0);
257 QTest::qWait(ms: 50);
258#ifdef Q_OS_WINRT
259 QEXPECT_FAIL("", "Broken on WinRT - QTBUG-68297", Abort);
260#endif
261 QTRY_VERIFY(!pbar.repainted);
262
263 // No repaint when setting maximum to the current maximum
264 pbar.repainted = false;
265 pbar.setMaximum(10);
266 QTest::qWait(ms: 50);
267 QTRY_VERIFY(!pbar.repainted);
268
269 // Repaint when setting minimum
270 for (int i = 9; i >= 0; i--) {
271 pbar.repainted = false;
272 pbar.setMinimum(i);
273 QTRY_VERIFY(pbar.repainted);
274 }
275
276 // Repaint when setting maximum
277 for (int i = 0; i < 10; ++i) {
278 pbar.repainted = false;
279 pbar.setMaximum(i);
280 QTRY_VERIFY(pbar.repainted);
281 }
282}
283#endif //Q_OS_MAC
284
285void tst_QProgressBar::sizeHint()
286{
287 ProgressBar bar;
288 bar.setMinimum(0);
289 bar.setMaximum(10);
290 bar.setValue(5);
291
292 //test if the sizeHint is big enough
293 QFontMetrics fm = bar.fontMetrics();
294 QStyleOptionProgressBar opt;
295 bar.initStyleOption(option: &opt);
296 QSize size = QSize(9 * 7 + fm.horizontalAdvance(QLatin1Char('0')) * 4, fm.height() + 8);
297 size= bar.style()->sizeFromContents(ct: QStyle::CT_ProgressBar, opt: &opt, contentsSize: size, w: &bar);
298 QSize barSize = bar.sizeHint();
299 QVERIFY(barSize.width() >= size.width());
300 QCOMPARE(barSize.height(), size.height());
301}
302
303void tst_QProgressBar::formatedText_data()
304{
305 QTest::addColumn<int>(name: "minimum");
306 QTest::addColumn<int>(name: "maximum");
307 QTest::addColumn<int>(name: "value");
308 QTest::addColumn<QString>(name: "format");
309 QTest::addColumn<QString>(name: "text");
310
311 QTest::newRow(dataTag: "1") << -100 << 100 << 0 << QString::fromLatin1(str: " %p - %v - %m ") << QString::fromLatin1(str: " 50 - 0 - 200 ");
312 QTest::newRow(dataTag: "2") << -100 << 0 << -25 << QString::fromLatin1(str: " %p - %v - %m ") << QString::fromLatin1(str: " 75 - -25 - 100 ");
313 QTest::newRow(dataTag: "3") << 10 << 10 << 10 << QString::fromLatin1(str: " %p - %v - %m ") << QString::fromLatin1(str: " 100 - 10 - 0 ");
314 QTest::newRow(dataTag: "task152227") << INT_MIN << INT_MAX << 42 << QString::fromLatin1(str: " %p - %v - %m ") << QString::fromLatin1(str: " 50 - 42 - 4294967295 ");
315}
316
317void tst_QProgressBar::formatedText()
318{
319 QFETCH(int, minimum);
320 QFETCH(int, maximum);
321 QFETCH(int, value);
322 QFETCH(QString, format);
323 QFETCH(QString, text);
324 QProgressBar bar;
325 bar.setRange(minimum, maximum);
326 bar.setValue(value);
327 bar.setFormat(format);
328 QCOMPARE(bar.text(), text);
329}
330
331void tst_QProgressBar::localizedFormattedText() // QTBUG-28751
332{
333 QProgressBar bar;
334 const int value = 42;
335 bar.setValue(value);
336 const QString defaultExpectedNumber = QString::number(value);
337 const QString defaultExpectedValue = defaultExpectedNumber + QLatin1Char('%');
338 QCOMPARE(bar.text(), defaultExpectedValue);
339
340 // Temporarily switch to Egyptian, which has a different percent sign and number formatting
341 QLocale egypt(QLocale::Arabic, QLocale::Egypt);
342 bar.setLocale(egypt);
343 const QString egyptianExpectedNumber = egypt.toString(i: value);
344 const QString egyptianExpectedValue = egyptianExpectedNumber + egypt.percent();
345 if (egyptianExpectedValue == defaultExpectedValue)
346 QSKIP("Egyptian locale does not work on this system.");
347 QCOMPARE(bar.text(), egyptianExpectedValue);
348
349 bar.setLocale(QLocale());
350 QCOMPARE(bar.text(), defaultExpectedValue);
351
352 // Set a custom format containing only the number
353 bar.setFormat(QStringLiteral("%p"));
354 QCOMPARE(bar.text(), defaultExpectedNumber);
355 bar.setLocale(egypt);
356 QCOMPARE(bar.text(), egyptianExpectedNumber);
357
358 // Clear the format
359 bar.resetFormat();
360 QCOMPARE(bar.text(), egyptianExpectedValue);
361 bar.setLocale(QLocale());
362 QCOMPARE(bar.text(), defaultExpectedValue);
363}
364
365void tst_QProgressBar::task245201_testChangeStyleAndDelete_data()
366{
367 QTest::addColumn<QString>(name: "style1_str");
368 QTest::addColumn<QString>(name: "style2_str");
369
370 QTest::newRow(dataTag: "fusion-windows") << QString::fromLatin1(str: "fusion") << QString::fromLatin1(str: "windows");
371 QTest::newRow(dataTag: "gtk-fusion") << QString::fromLatin1(str: "gtk") << QString::fromLatin1(str: "fusion");
372}
373
374void tst_QProgressBar::task245201_testChangeStyleAndDelete()
375{
376 QFETCH(QString, style1_str);
377 QFETCH(QString, style2_str);
378
379 QProgressBar *bar = new QProgressBar;
380
381 QStyle *style = QStyleFactory::create(style1_str);
382 bar->setStyle(style);
383 bar->move(ax: 300, ay: 300);
384 bar->show();
385 QVERIFY(QTest::qWaitForWindowExposed(bar));
386 QStyle *style2 = QStyleFactory::create(style2_str);
387 bar->setStyle(style2);
388 QTest::qWait(ms: 10);
389
390 delete bar;
391 QTest::qWait(ms: 100); //should not crash
392 delete style;
393 delete style2;
394}
395
396QTEST_MAIN(tst_QProgressBar)
397#include "tst_qprogressbar.moc"
398

source code of qtbase/tests/auto/widgets/widgets/qprogressbar/tst_qprogressbar.cpp