aboutsummaryrefslogtreecommitdiffstats
path: root/tests/test_busyindicator.cpp
blob: 3f267c7359e90702e9b823c83a2acf314688bb01 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
 * qtmaildir - a Qt6 mail client for notmuch-indexed Maildirs
 * Copyright (C) 2026 Danilo M. <danix@danix.xyz>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <QtTest>

#include "busyindicator.h"

class TestBusyIndicator : public QObject
{
    Q_OBJECT

private slots:
    void itStartsIndeterminateAndHidden();
    void itStaysHiddenInsideAShownParent();
    void setProgressShowsARealFraction();
    void aTotalOfZeroFallsBackToBusyRatherThanAnEmptyBar();
    void itSwitchesBackFromDeterminateToIndeterminate();
    void aValueOutsideTheRangeIsClamped();
};

void TestBusyIndicator::itStartsIndeterminateAndHidden()
{
    BusyIndicator indicator;

    // setRange(0, 0) is what Qt reads as indeterminate, and it is the state
    // the status bar's sync indicator lives in.
    QCOMPARE(indicator.minimum(), 0);
    QCOMPARE(indicator.maximum(), 0);
    QVERIFY(!indicator.isDeterminate());
}

void TestBusyIndicator::itStaysHiddenInsideAShownParent()
{
    // The hidden-on-construction property needs a SHOWN PARENT to be
    // observable at all, and both obvious probes measure nothing without one.
    // Measured against a standalone Qt program: a parentless widget reports
    // isVisible() false and isHidden() true whether or not hide() was ever
    // called, so a mutation deleting the constructor's hide() survives both
    // assertions. What differs is WA_WState_ExplicitShowHide, and the
    // behaviour it produces appears only once a parent is shown, which is how
    // MainWindow's status bar holds this widget.
    QWidget parent;
    BusyIndicator *indicator = new BusyIndicator(&parent);
    parent.show();

    QVERIFY2(!indicator->isBusy(),
             "the indicator showed itself as soon as its parent appeared");

    indicator->setBusy(true);
    QVERIFY(indicator->isBusy());
}

void TestBusyIndicator::setProgressShowsARealFraction()
{
    BusyIndicator indicator;
    indicator.setProgress(3, 10);

    QVERIFY2(indicator.isDeterminate(),
             "a bar given a total stayed in the indeterminate range");
    QCOMPARE(indicator.maximum(), 10);
    QCOMPARE(indicator.value(), 3);

    // Showing a fraction means being visible. A caller that set progress and
    // got a hidden widget would have to remember a second call.
    QVERIFY(indicator.isBusy());
}

void TestBusyIndicator::aTotalOfZeroFallsBackToBusyRatherThanAnEmptyBar()
{
    // The trap this guards: setRange(0, 0) IS the indeterminate range, so a
    // total of zero passed straight through would hand the caller an
    // animating bar while it believed it had drawn an empty fraction. Making
    // it explicitly busy is the honest reading of "no total known".
    BusyIndicator indicator;
    indicator.setProgress(0, 0);

    QVERIFY(!indicator.isDeterminate());
    QVERIFY2(indicator.isBusy(),
             "a total of zero left the indicator hidden and silent");

    indicator.setProgress(5, -1);
    QVERIFY(!indicator.isDeterminate());
    QVERIFY(indicator.isBusy());
}

void TestBusyIndicator::itSwitchesBackFromDeterminateToIndeterminate()
{
    // The send popup's whole reason for one widget rather than two: it drains
    // a determinate bar through the undo countdown, then switches THE SAME
    // widget to indeterminate when send_command starts and the duration stops
    // being knowable. A setBusy() that left a stale range would keep drawing
    // the countdown's last fraction.
    BusyIndicator indicator;
    indicator.setProgress(9, 10);
    QVERIFY(indicator.isDeterminate());

    indicator.setBusy(true);
    QVERIFY2(!indicator.isDeterminate(),
             "the bar kept the countdown's range after switching to busy");
    QCOMPARE(indicator.maximum(), 0);
    QVERIFY(indicator.isBusy());

    indicator.setBusy(false);
    QVERIFY(!indicator.isBusy());
}

void TestBusyIndicator::aValueOutsideTheRangeIsClamped()
{
    // A countdown driven by a timer can overshoot its own total by a tick.
    // Qt leaves an out-of-range value unset rather than clamping, which shows
    // the PREVIOUS fraction, so the bar would appear to stall near the end.
    BusyIndicator indicator;
    indicator.setProgress(50, 10);
    QCOMPARE(indicator.value(), 10);

    indicator.setProgress(-5, 10);
    QCOMPARE(indicator.value(), 0);
}

QTEST_MAIN(TestBusyIndicator)
#include "test_busyindicator.moc"