1 /***************************************************************************
2     testqgsmessagebar.cpp
3      --------------------------------------
4     Date                 : October 2018
5     Copyright            : (C) 2018 Nyall Dawson
6     Email                : nyall dot dawson at gmail dot com
7  ***************************************************************************
8  *                                                                         *
9  *   This program is free software; you can redistribute it and/or modify  *
10  *   it under the terms of the GNU General Public License as published by  *
11  *   the Free Software Foundation; either version 2 of the License, or     *
12  *   (at your option) any later version.                                   *
13  *                                                                         *
14  ***************************************************************************/
15 
16 
17 #include "qgstest.h"
18 
19 #include "qgsmessagebar.h"
20 #include "qgsmessagebaritem.h"
21 #include <memory>
22 
23 class TestQgsMessageBar: public QObject
24 {
25     Q_OBJECT
26   private slots:
27     void initTestCase(); // will be called before the first testfunction is executed.
28     void cleanupTestCase(); // will be called after the last testfunction was executed.
29     void init(); // will be called before each testfunction is executed.
30     void cleanup(); // will be called after every testfunction.
31     void dismiss();
32     void pushPop();
33     void autoDelete();
34 
35 };
36 
initTestCase()37 void TestQgsMessageBar::initTestCase()
38 {
39 
40 }
41 
cleanupTestCase()42 void TestQgsMessageBar::cleanupTestCase()
43 {
44 }
45 
init()46 void TestQgsMessageBar::init()
47 {
48 }
49 
cleanup()50 void TestQgsMessageBar::cleanup()
51 {
52 }
53 
dismiss()54 void TestQgsMessageBar::dismiss()
55 {
56   QgsMessageBar bar;
57   bar.show();
58   QVERIFY( !bar.currentItem() );
59 
60   QgsMessageBarItem *item = new QgsMessageBarItem( QStringLiteral( "test" ) );
61   const QPointer< QgsMessageBarItem > pItem( item );
62   item->dismiss(); // should do nothing, not in a bar yet
63   QgsApplication::sendPostedEvents( nullptr, QEvent::DeferredDelete );
64   for ( int i = 1; i < 100; ++i )
65   {
66     QApplication::processEvents();
67   }
68   QCOMPARE( pItem.data(), item );
69 
70 
71   bar.pushItem( item );
72   QCOMPARE( bar.currentItem(), item );
73 
74   item->dismiss();
75   QgsApplication::sendPostedEvents( nullptr, QEvent::DeferredDelete );
76 
77   for ( int i = 1; i < 100; ++i )
78   {
79     QApplication::processEvents();
80   }
81   QVERIFY( !bar.currentItem() );
82   QVERIFY( !pItem.data() );
83 }
84 
pushPop()85 void TestQgsMessageBar::pushPop()
86 {
87   // test pushing/popping message logic
88   QgsMessageBar bar;
89   QCOMPARE( bar.items().size(), 0 );
90   QVERIFY( !bar.currentItem() );
91   bar.pushMessage( QStringLiteral( "1" ) );
92   QCOMPARE( bar.items().size(), 1 );
93   QCOMPARE( bar.items().at( 0 )->text(), QStringLiteral( "1" ) );
94   QCOMPARE( bar.currentItem()->text(), QStringLiteral( "1" ) );
95   const QPointer< QgsMessageBarItem > item1 = bar.currentItem();
96   // make sure correct item is the visible one
97   QCOMPARE( qobject_cast< QgsMessageBarItem * >( qgis::down_cast< QGridLayout * >( bar.layout() )->itemAt( 3 )->widget() )->text(), QStringLiteral( "1" ) );
98 
99   bar.pushMessage( QStringLiteral( "2" ) );
100   QCOMPARE( bar.items().size(), 2 );
101   QCOMPARE( bar.items().at( 0 )->text(), QStringLiteral( "2" ) );
102   QCOMPARE( bar.items().at( 1 )->text(), QStringLiteral( "1" ) );
103   QCOMPARE( bar.currentItem()->text(), QStringLiteral( "2" ) );
104   const QPointer< QgsMessageBarItem > item2 = bar.currentItem();
105   QCOMPARE( qobject_cast< QgsMessageBarItem * >( qgis::down_cast< QGridLayout * >( bar.layout() )->itemAt( 3 )->widget() )->text(), QStringLiteral( "2" ) );
106 
107   bar.pushMessage( QStringLiteral( "3" ) );
108   QCOMPARE( bar.items().size(), 3 );
109   QCOMPARE( bar.items().at( 0 )->text(), QStringLiteral( "3" ) );
110   QCOMPARE( bar.items().at( 1 )->text(), QStringLiteral( "2" ) );
111   QCOMPARE( bar.items().at( 2 )->text(), QStringLiteral( "1" ) );
112   QCOMPARE( bar.currentItem()->text(), QStringLiteral( "3" ) );
113   const QPointer< QgsMessageBarItem > item3 = bar.currentItem();
114   QCOMPARE( qobject_cast< QgsMessageBarItem * >( qgis::down_cast< QGridLayout * >( bar.layout() )->itemAt( 3 )->widget() )->text(), QStringLiteral( "3" ) );
115 
116   const int childCount = bar.children().count();
117   QVERIFY( bar.popWidget() );
118   QCOMPARE( bar.items().size(), 2 );
119   QCOMPARE( bar.items().at( 0 )->text(), QStringLiteral( "2" ) );
120   QCOMPARE( bar.items().at( 1 )->text(), QStringLiteral( "1" ) );
121   QCOMPARE( bar.currentItem()->text(), QStringLiteral( "2" ) );
122   QCOMPARE( qobject_cast< QgsMessageBarItem * >( qgis::down_cast< QGridLayout * >( bar.layout() )->itemAt( 3 )->widget() )->text(), QStringLiteral( "2" ) );
123   QgsApplication::sendPostedEvents( nullptr, QEvent::DeferredDelete );
124   QCOMPARE( bar.children().count(), childCount - 1 );
125   QVERIFY( !item3 );
126 
127   QVERIFY( bar.popWidget() );
128   QCOMPARE( bar.items().size(), 1 );
129   QCOMPARE( bar.items().at( 0 )->text(), QStringLiteral( "1" ) );
130   QCOMPARE( bar.currentItem()->text(), QStringLiteral( "1" ) );
131   QCOMPARE( qobject_cast< QgsMessageBarItem * >( qgis::down_cast< QGridLayout * >( bar.layout() )->itemAt( 3 )->widget() )->text(), QStringLiteral( "1" ) );
132   QgsApplication::sendPostedEvents( nullptr, QEvent::DeferredDelete );
133   QCOMPARE( bar.children().count(), childCount - 2 );
134   QVERIFY( !item2 );
135 
136   QVERIFY( bar.popWidget() );
137   QCOMPARE( bar.items().size(), 0 );
138   QVERIFY( !bar.currentItem() );
139   QgsApplication::sendPostedEvents( nullptr, QEvent::DeferredDelete );
140   QCOMPARE( bar.children().count(), childCount - 3 );
141   QVERIFY( !item1 );
142 
143   QVERIFY( !bar.popWidget() );
144   QCOMPARE( bar.items().size(), 0 );
145   QVERIFY( !bar.currentItem() );
146 }
147 
autoDelete()148 void TestQgsMessageBar::autoDelete()
149 {
150   // ensure that items are automatically deleted when queue grows too large
151   QgsMessageBar bar;
152   for ( int i = 0; i < bar.MAX_ITEMS; ++i )
153   {
154     bar.pushMessage( QString::number( i ), Qgis::MessageLevel::Warning );
155   }
156   QCOMPARE( bar.items().size(), 100 );
157   QCOMPARE( bar.items().at( 0 )->text(), QStringLiteral( "99" ) );
158   QCOMPARE( bar.items().at( 99 )->text(), QStringLiteral( "0" ) );
159   const QPointer< QgsMessageBarItem > oldest = bar.items().at( 99 );
160 
161   // push one more item, oldest one should be auto-removed
162   bar.pushMessage( QStringLiteral( "100" ), Qgis::MessageLevel::Warning );
163   QCOMPARE( bar.items().size(), 100 );
164   QCOMPARE( bar.items().at( 0 )->text(), QStringLiteral( "100" ) );
165   QCOMPARE( bar.items().at( 99 )->text(), QStringLiteral( "1" ) );
166   QgsApplication::sendPostedEvents( nullptr, QEvent::DeferredDelete );
167   QVERIFY( !oldest );
168 
169   // but if we have a lower priority message we can pop, then do that instead
170   bar.pushMessage( QStringLiteral( "101" ), Qgis::MessageLevel::Info );
171   QCOMPARE( bar.items().size(), 100 );
172   QCOMPARE( bar.items().at( 0 )->text(), QStringLiteral( "101" ) );
173   QCOMPARE( bar.items().at( 1 )->text(), QStringLiteral( "100" ) );
174   QCOMPARE( bar.items().at( 99 )->text(), QStringLiteral( "2" ) );
175   bar.pushMessage( QStringLiteral( "102" ), Qgis::MessageLevel::Info );
176   QCOMPARE( bar.items().size(), 100 );
177   QCOMPARE( bar.items().at( 0 )->text(), QStringLiteral( "102" ) );
178   QCOMPARE( bar.items().at( 1 )->text(), QStringLiteral( "100" ) );
179   QCOMPARE( bar.items().at( 99 )->text(), QStringLiteral( "2" ) );
180 }
181 
182 QGSTEST_MAIN( TestQgsMessageBar )
183 #include "testqgsmessagebar.moc"
184