1 /***************************************************************************
2     testqgsdatetimeedit.cpp
3      --------------------------------------
4     Date                 : September 2019
5     Copyright            : (C) 2019 Etienne Trimaille
6     Email                : etienne dot trimaille 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 #include "qdatetime.h"
19 
20 #include <qgsdatetimeedit.h>
21 #include <qgsdatetimeeditwrapper.h>
22 #include <qgsdatetimefieldformatter.h>
23 
24 class TestQgsDateTimeEdit: public QObject
25 {
26     Q_OBJECT
27   private slots:
28     void initTestCase(); // will be called before the first testfunction is executed.
29     void cleanupTestCase(); // will be called after the last testfunction was executed.
30     void init(); // will be called before each testfunction is executed.
31     void cleanup(); // will be called after every testfunction.
32 
33     void nullValues();
34     void focus();
35     void testDateTime();
36 
37   private:
38     std::unique_ptr<QgsDateTimeEditWrapper> widget1; // For field 0
39     std::unique_ptr<QgsDateTimeEditWrapper> widget2; // For field 1
40     std::unique_ptr<QgsDateTimeEditWrapper> widget3; // For field 2
41     std::unique_ptr<QgsDateTimeEditWrapper> widget4; // For field 3
42     std::unique_ptr<QgsDateTimeEditWrapper> widget5; // For field 4
43     std::unique_ptr<QgsDateTimeEditWrapper> widget6; // For field 5
44     std::unique_ptr<QgsDateTimeEditWrapper> widget7; // For field 6
45     std::unique_ptr<QgsVectorLayer> vl;
46 
47 };
48 
initTestCase()49 void TestQgsDateTimeEdit::initTestCase()
50 {
51 }
52 
cleanupTestCase()53 void TestQgsDateTimeEdit::cleanupTestCase()
54 {
55 }
56 
init()57 void TestQgsDateTimeEdit::init()
58 {
59 
60   vl = std::make_unique<QgsVectorLayer>( QStringLiteral( "Point?crs=epsg:4326" ),
61                                          QStringLiteral( "myvl" ),
62                                          QLatin1String( "memory" ) );
63 
64   // add fields
65   QList<QgsField> fields;
66   fields.append( QgsField( "date1", QVariant::Date ) );
67   fields.append( QgsField( "date2", QVariant::Date ) );
68   fields.append( QgsField( "date3", QVariant::Date ) );
69   fields.append( QgsField( "time", QVariant::Time ) );
70   fields.append( QgsField( "datetime1", QVariant::DateTime ) );
71   fields.append( QgsField( "datetime2", QVariant::DateTime ) );
72   fields.append( QgsField( "text", QVariant::String ) );
73   vl->dataProvider()->addAttributes( fields );
74   vl->updateFields();
75   QVERIFY( vl.get() );
76   QVERIFY( vl->isValid() );
77 
78   widget1 = std::make_unique<QgsDateTimeEditWrapper>( vl.get(), 0, nullptr, nullptr );
79   widget2 = std::make_unique<QgsDateTimeEditWrapper>( vl.get(), 1, nullptr, nullptr );
80   widget3 = std::make_unique<QgsDateTimeEditWrapper>( vl.get(), 2, nullptr, nullptr );
81   widget4 = std::make_unique<QgsDateTimeEditWrapper>( vl.get(), 3, nullptr, nullptr );
82   widget5 = std::make_unique<QgsDateTimeEditWrapper>( vl.get(), 4, nullptr, nullptr );
83   widget6 = std::make_unique<QgsDateTimeEditWrapper>( vl.get(), 5, nullptr, nullptr );
84   widget7 = std::make_unique<QgsDateTimeEditWrapper>( vl.get(), 6, nullptr, nullptr );
85   QVERIFY( widget1.get() );
86   QVERIFY( widget2.get() );
87   QVERIFY( widget3.get() );
88   QVERIFY( widget4.get() );
89   QVERIFY( widget5.get() );
90   QVERIFY( widget6.get() );
91   QVERIFY( widget7.get() );
92 }
93 
cleanup()94 void TestQgsDateTimeEdit::cleanup()
95 {
96 }
97 
nullValues()98 void TestQgsDateTimeEdit::nullValues()
99 {
100   QgsDateTimeEdit *timeEdit = new QgsDateTimeEdit();
101 
102   // Allow null with a null datetime
103   QVERIFY( timeEdit->allowNull() );
104   timeEdit->setDateTime( QDateTime() );
105   QCOMPARE( timeEdit->dateTime(), QDateTime() );
106   QCOMPARE( timeEdit->time(), QTime() );
107   QCOMPARE( timeEdit->date(), QDate() );
108 
109   // Not null with not null datetime
110   const QDateTime date( QDate( 2019, 7, 6 ), QTime( 8, 30, 0 ) );
111   timeEdit->setAllowNull( false );
112   QVERIFY( !timeEdit->allowNull() );
113   timeEdit->setDateTime( date );
114   QCOMPARE( timeEdit->dateTime(), date );
115   QCOMPARE( timeEdit->time(), date.time() );
116   QCOMPARE( timeEdit->date(), date.date() );
117 
118   // Not null with null date
119   timeEdit->setAllowNull( false );
120   QVERIFY( !timeEdit->allowNull() );
121   timeEdit->setDateTime( QDateTime() );
122   QCOMPARE( timeEdit->dateTime(), date );
123   QCOMPARE( timeEdit->time(), date.time() );
124   QCOMPARE( timeEdit->date(), date.date() );
125 
126   delete timeEdit;
127 
128   // QgsDateEdit
129 
130   QgsDateEdit *dateEdit = new QgsDateEdit();
131 
132   // Allow null with a null datetime
133   QVERIFY( dateEdit->allowNull() );
134   dateEdit->setDate( QDate() );
135   QCOMPARE( dateEdit->date(), QDate() );
136 
137   // Not null with not null datetime
138   const QDate dt( 2019, 7, 6 );
139   dateEdit->setAllowNull( false );
140   QVERIFY( !dateEdit->allowNull() );
141   dateEdit->setDate( dt );
142   QCOMPARE( dateEdit->date(), dt );
143 
144   // Not null with null date
145   dateEdit->setAllowNull( false );
146   QVERIFY( !dateEdit->allowNull() );
147   dateEdit->setDate( QDate() );
148   QCOMPARE( dateEdit->date(), dt );
149 
150   delete dateEdit;
151 
152   // QgsTimeEdit
153 
154   QgsTimeEdit *tEdit = new QgsTimeEdit();
155 
156   // Allow null with a null datetime
157   QVERIFY( tEdit->allowNull() );
158   tEdit->setTime( QTime() );
159   QCOMPARE( tEdit->time(), QTime() );
160 
161   // Not null with not null datetime
162   const QTime t( 8, 30, 0 );
163   tEdit->setAllowNull( false );
164   QVERIFY( !tEdit->allowNull() );
165   tEdit->setTime( t );
166   QCOMPARE( tEdit->time(), t );
167 
168   // Not null with null date
169   tEdit->setAllowNull( false );
170   QVERIFY( !tEdit->allowNull() );
171   tEdit->setTime( QTime() );
172   QCOMPARE( tEdit->time(), t );
173 
174   delete tEdit;
175 }
176 
focus()177 void TestQgsDateTimeEdit::focus()
178 {
179   QgsApplication::setNullRepresentation( QString( "nope" ) );
180   QWidget w; //required for focus events
181   QApplication::setActiveWindow( &w );
182 
183   QVariantMap cfg;
184   cfg.insert( QStringLiteral( "AllowNull" ), true );
185 
186   widget1->setConfig( cfg );
187   QgsDateTimeEdit *dateedit1 = qobject_cast<QgsDateTimeEdit *>( widget1->createWidget( &w ) );
188   QVERIFY( dateedit1 );
189   widget1->initWidget( dateedit1 );
190   widget1->setValue( QVariant::Date );
191 
192   widget2->setConfig( cfg );
193   QgsDateTimeEdit *dateedit2 = qobject_cast<QgsDateTimeEdit *>( widget2->createWidget( &w ) );
194   QVERIFY( dateedit2 );
195   widget2->initWidget( dateedit2 );
196   widget2->setValue( QVariant::Date );
197 
198   widget3->setConfig( cfg );
199   QgsDateTimeEdit *dateedit3 = qobject_cast<QgsDateTimeEdit *>( widget3->createWidget( &w ) );
200   QVERIFY( dateedit3 );
201   widget3->initWidget( dateedit3 );
202   widget3->setValue( QVariant::Date );
203 
204   QVERIFY( widget1->value().isNull() );
205   QVERIFY( widget2->value().isNull() );
206   QVERIFY( widget3->value().isNull() );
207   QVERIFY( !dateedit1->hasFocus() );
208   QVERIFY( !dateedit2->hasFocus() );
209   QVERIFY( !dateedit3->hasFocus() );
210   QCOMPARE( dateedit1->text(), QStringLiteral( "nope" ) );
211   QCOMPARE( dateedit2->text(), QStringLiteral( "nope" ) );
212   QCOMPARE( dateedit3->text(), QStringLiteral( "nope" ) );
213 
214   dateedit1->setFocus();
215   QVERIFY( widget1->value().isNull() );
216   QVERIFY( widget2->value().isNull() );
217   QVERIFY( widget3->value().isNull() );
218   QVERIFY( dateedit1->hasFocus() );
219   QVERIFY( !dateedit2->hasFocus() );
220   QVERIFY( !dateedit3->hasFocus() );
221   QCOMPARE( dateedit1->text(), QDateTime::currentDateTime().toString( QgsDateTimeFieldFormatter::DATE_FORMAT ) );
222   QCOMPARE( dateedit2->text(), QStringLiteral( "nope" ) );
223   QCOMPARE( dateedit3->text(), QStringLiteral( "nope" ) );
224 
225   dateedit2->setFocus();
226   QVERIFY( widget1->value().isNull() );
227   QVERIFY( widget2->value().isNull() );
228   QVERIFY( widget3->value().isNull() );
229   QVERIFY( !dateedit1->hasFocus() );
230   QVERIFY( dateedit2->hasFocus() );
231   QVERIFY( !dateedit3->hasFocus() );
232   QCOMPARE( dateedit1->text(), QStringLiteral( "nope" ) );
233   QCOMPARE( dateedit2->text(), QDateTime::currentDateTime().toString( QgsDateTimeFieldFormatter::DATE_FORMAT ) );
234   QCOMPARE( dateedit3->text(), QStringLiteral( "nope" ) );
235 
236   dateedit3->setFocus();
237   QVERIFY( widget1->value().isNull() );
238   QVERIFY( widget2->value().isNull() );
239   QVERIFY( widget3->value().isNull() );
240   QVERIFY( !dateedit1->hasFocus() );
241   QVERIFY( !dateedit2->hasFocus() );
242   QVERIFY( dateedit3->hasFocus() );
243   QCOMPARE( dateedit1->text(), QStringLiteral( "nope" ) );
244   QCOMPARE( dateedit2->text(), QStringLiteral( "nope" ) );
245   QCOMPARE( dateedit3->text(), QDateTime::currentDateTime().toString( QgsDateTimeFieldFormatter::DATE_FORMAT ) );
246 
247   dateedit1->setFocus();
248   dateedit1->setDateTime( QDateTime::fromString( QStringLiteral( "1955-11-12" ), QgsDateTimeFieldFormatter::DATE_FORMAT ) );
249   QVERIFY( !widget1->value().isNull() );
250   QVERIFY( widget2->value().isNull() );
251   QVERIFY( widget3->value().isNull() );
252   QVERIFY( dateedit1->hasFocus() );
253   QVERIFY( !dateedit2->hasFocus() );
254   QVERIFY( !dateedit3->hasFocus() );
255   QCOMPARE( dateedit1->text(), QStringLiteral( "1955-11-12" ) );
256   QCOMPARE( dateedit2->text(), QStringLiteral( "nope" ) );
257   QCOMPARE( dateedit3->text(), QStringLiteral( "nope" ) );
258 
259   dateedit2->setFocus();
260   QVERIFY( !widget1->value().isNull() );
261   QVERIFY( widget2->value().isNull() );
262   QVERIFY( widget3->value().isNull() );
263   QVERIFY( !dateedit1->hasFocus() );
264   QVERIFY( dateedit2->hasFocus() );
265   QVERIFY( !dateedit3->hasFocus() );
266   QCOMPARE( dateedit1->text(), QStringLiteral( "1955-11-12" ) );
267   QCOMPARE( dateedit2->text(), QDateTime::currentDateTime().toString( QgsDateTimeFieldFormatter::DATE_FORMAT ) );
268   QCOMPARE( dateedit3->text(), QStringLiteral( "nope" ) );
269 
270   dateedit1->setFocus();
271   dateedit1->clear();
272   QVERIFY( widget1->value().isNull() );
273   QVERIFY( widget2->value().isNull() );
274   QVERIFY( widget3->value().isNull() );
275   QVERIFY( dateedit1->hasFocus() );
276   QVERIFY( !dateedit2->hasFocus() );
277   QVERIFY( !dateedit3->hasFocus() );
278   QCOMPARE( dateedit1->text(), QDateTime::currentDateTime().toString( QgsDateTimeFieldFormatter::DATE_FORMAT ) );
279   QCOMPARE( dateedit2->text(), QStringLiteral( "nope" ) );
280   QCOMPARE( dateedit3->text(), QStringLiteral( "nope" ) );
281 
282   dateedit2->setFocus();
283   QVERIFY( widget1->value().isNull() );
284   QVERIFY( widget2->value().isNull() );
285   QVERIFY( widget3->value().isNull() );
286   QVERIFY( !dateedit1->hasFocus() );
287   QVERIFY( dateedit2->hasFocus() );
288   QVERIFY( !dateedit3->hasFocus() );
289   QCOMPARE( dateedit1->text(), QStringLiteral( "nope" ) );
290   QCOMPARE( dateedit2->text(), QDateTime::currentDateTime().toString( QgsDateTimeFieldFormatter::DATE_FORMAT ) );
291   QCOMPARE( dateedit3->text(), QStringLiteral( "nope" ) );
292 }
293 
testDateTime()294 void TestQgsDateTimeEdit::testDateTime()
295 {
296   QgsApplication::setNullRepresentation( QString( "nope" ) );
297   QWidget w;
298   QApplication::setActiveWindow( &w );
299 
300   QVariantMap cfg;
301   cfg.insert( QStringLiteral( "AllowNull" ), true );
302 
303   widget4->setConfig( cfg );
304   QgsDateTimeEdit *dateedit4 = qobject_cast<QgsDateTimeEdit *>( widget4->createWidget( &w ) );
305   QVERIFY( dateedit4 );
306   widget4->initWidget( dateedit4 );
307   widget4->setValue( QTime( 23, 10, 57 ) );
308   const QTime value { widget4->value().toTime() };
309   QCOMPARE( value, QTime( 23, 10, 57 ) );
310 
311   widget5->setConfig( cfg );
312   QgsDateTimeEdit *dateedit5 = qobject_cast<QgsDateTimeEdit *>( widget5->createWidget( &w ) );
313   QVERIFY( dateedit5 );
314   widget5->initWidget( dateedit5 );
315   widget5->setValue( QDate( 1966, 11, 25 ) );
316   const QDate value5 { widget5->value().toDate() };
317   QCOMPARE( value5, QDate( 1966, 11, 25 ) );
318 
319   widget6->setConfig( cfg );
320   QgsDateTimeEdit *dateedit6 = qobject_cast<QgsDateTimeEdit *>( widget6->createWidget( &w ) );
321   QVERIFY( dateedit6 );
322   widget6->initWidget( dateedit6 );
323   widget6->setValue( QDate( 1, 1, 1 ) );
324   const QDate value6 { widget6->value().toDate() };
325   QCOMPARE( value6, QDate( 1, 1, 1 ) );
326 
327   // Test for issue GH #46542
328   widget7->setConfig( cfg );
329   QgsDateTimeEdit *dateedit7 = qobject_cast<QgsDateTimeEdit *>( widget7->createWidget( &w ) );
330   QVERIFY( dateedit7 );
331   widget7->initWidget( dateedit7 );
332   QgsFeature f { vl->fields() };
333   f.setAttribute( QStringLiteral( "text" ), QgsExpression{ QStringLiteral( "now()" ) }.evaluate() );
334   widget7->setFeature( f );
335   const QDate value7 { widget7->value().toDate() };
336   QCOMPARE( value7, QDate::currentDate() );
337 
338 }
339 
340 QGSTEST_MAIN( TestQgsDateTimeEdit )
341 #include "testqgsdatetimeedit.moc"
342