1 /***************************************************************************
2                          testqgsrangewidget.cpp
3                          ---------------------------
4     begin                : Jan 2018
5     copyright            : (C) 2018 by Alessandro Pasotti
6     email                : elpaso at itopen dot it
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 #include "qgstest.h"
19 
20 #include "qgsrangewidgetwrapper.h"
21 #include "qgsrangeconfigdlg.h"
22 #include "qgsdoublespinbox.h"
23 #include "qgsspinbox.h"
24 #include "qgsapplication.h"
25 #include "qgslogger.h"
26 #include "qgsvectorlayer.h"
27 #include "qgsdataprovider.h"
28 #include "qgsfilterlineedit.h"
29 
30 #include <QLineEdit>
31 #include <QObject>
32 #include <QtTest/QSignalSpy>
33 
34 #include <memory>
35 
36 #define SPECIAL_TEXT_WHEN_EMPTY QString( QChar( 0x2063 ) )
37 
38 /**
39  * @ingroup UnitTests
40  * This is a unit test for the range widget
41  *
42  * \see QgsRangeWidgetWrapper
43  */
44 class TestQgsRangeWidgetWrapper : public QObject
45 {
46     Q_OBJECT
47   private slots:
48     void initTestCase();// will be called before the first testfunction is executed.
49     void cleanupTestCase();// will be called after the last testfunction was executed.
50     void init();// will be called before each testfunction is executed.
51     void cleanup();// will be called after every testfunction.
52     void test_setDoubleRange();
53     void test_setDoubleSmallerRange();
54     void test_setDoubleLimits();
55     void test_nulls();
56     void test_negativeIntegers(); // see GH issue #32149
57     void test_focus();
58     void testLongLong();
59 
60   private:
61     std::unique_ptr<QgsRangeWidgetWrapper> widget0; // For field 0
62     std::unique_ptr<QgsRangeWidgetWrapper> widget1; // For field 1
63     std::unique_ptr<QgsRangeWidgetWrapper> widget2; // For field 2
64     std::unique_ptr<QgsRangeWidgetWrapper> widget3; // For field 3
65     std::unique_ptr<QgsVectorLayer> vl;
66 };
67 
initTestCase()68 void TestQgsRangeWidgetWrapper::initTestCase()
69 {
70   // Set up the QgsSettings environment
71   QCoreApplication::setOrganizationName( QStringLiteral( "QGIS" ) );
72   QCoreApplication::setOrganizationDomain( QStringLiteral( "qgis.org" ) );
73   QCoreApplication::setApplicationName( QStringLiteral( "QGIS-TEST-RANGE-WIDGET" ) );
74 
75   QgsApplication::init();
76   QgsApplication::initQgis();
77 }
78 
cleanupTestCase()79 void TestQgsRangeWidgetWrapper::cleanupTestCase()
80 {
81   QgsApplication::exitQgis();
82 }
83 
init()84 void TestQgsRangeWidgetWrapper::init()
85 {
86   vl = std::make_unique<QgsVectorLayer>( QStringLiteral( "Point?crs=epsg:4326" ),
87                                          QStringLiteral( "myvl" ),
88                                          QLatin1String( "memory" ) );
89 
90   // add fields
91   QList<QgsField> fields;
92   fields.append( QgsField( "id", QVariant::Int ) );
93   // precision = 9
94   QgsField dfield( "number",  QVariant::Double );
95   dfield.setPrecision( 9 );
96   fields.append( dfield );
97   // default precision = 0
98   const QgsField dfield2( "number_def",  QVariant::Double );
99   fields.append( dfield2 );
100   // simple int
101   fields.append( QgsField( "simplenumber", QVariant::Int ) );
102   fields.append( QgsField( "longlong", QVariant::LongLong ) );
103   vl->dataProvider()->addAttributes( fields );
104   vl->updateFields();
105   QVERIFY( vl.get() );
106   QVERIFY( vl->isValid() );
107   // Add feature 1:1:123.123456789:123.123456789:NULL:POINT( 1 1 )
108   QgsFeature feat1( vl->fields(),  1 );
109   feat1.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "POINT( 1 1 )" ) ) );
110   feat1.setAttribute( QStringLiteral( "id" ), 1 );
111   feat1.setAttribute( QStringLiteral( "number" ), 123.123456789 );
112   feat1.setAttribute( QStringLiteral( "number_def" ), 123.123456789 );
113   vl->dataProvider()->addFeature( feat1 );
114   // Add feature 2:2:NULL:NULL:NULL:POINT( 2 2 )
115   QgsFeature feat2( vl->fields(),  2 );
116   feat2.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "POINT( 2 2 )" ) ) );
117   feat2.setAttribute( QStringLiteral( "id" ), 2 );
118   vl->dataProvider()->addFeature( feat2 );
119   // Add feature 3:3:-123.123456789:-123.123456789:NULL:POINT( 3 3 )
120   QgsFeature feat3( vl->fields(),  3 );
121   feat3.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "POINT( 3 3 )" ) ) );
122   feat3.setAttribute( QStringLiteral( "number" ), -123.123456789 );
123   feat3.setAttribute( QStringLiteral( "number_def" ), -123.123456789 );
124   feat3.setAttribute( QStringLiteral( "id" ), 3 );
125   vl->dataProvider()->addFeature( feat3 );
126   // Verify feat 1 was added
127   QCOMPARE( vl->featureCount( ), ( long )3 );
128   const QgsFeature _feat1( vl->getFeature( 1 ) );
129   QCOMPARE( _feat1, feat1 );
130   widget0 = std::make_unique<QgsRangeWidgetWrapper>( vl.get(), 0, nullptr, nullptr );
131   widget1 = std::make_unique<QgsRangeWidgetWrapper>( vl.get(), 1, nullptr, nullptr );
132   widget2 = std::make_unique<QgsRangeWidgetWrapper>( vl.get(), 2, nullptr, nullptr );
133   widget3 = std::make_unique<QgsRangeWidgetWrapper>( vl.get(), 3, nullptr, nullptr );
134   QVERIFY( widget1.get() );
135 }
136 
cleanup()137 void TestQgsRangeWidgetWrapper::cleanup()
138 {
139 }
140 
test_setDoubleRange()141 void TestQgsRangeWidgetWrapper::test_setDoubleRange()
142 {
143   // Test setting scale range with doubles and NULL values, default range
144   // See https://github.com/qgis/QGIS/issues/25773
145   // QGIS 3 Vector Layer Fields Garbled when Clicking the Toggle Editing Icon
146 
147   QgsDoubleSpinBox *editor = qobject_cast<QgsDoubleSpinBox *>( widget1->createWidget( nullptr ) );
148   QVERIFY( editor );
149   widget1->initWidget( editor );
150   QgsDoubleSpinBox *editor2 = qobject_cast<QgsDoubleSpinBox *>( widget2->createWidget( nullptr ) );
151   QVERIFY( editor2 );
152   widget2->initWidget( editor2 );
153 
154   const QgsFeature feat( vl->getFeature( 1 ) );
155   QVERIFY( feat.isValid() );
156   QCOMPARE( feat.attribute( 1 ).toDouble(), 123.123456789 );
157   widget1->setFeature( vl->getFeature( 1 ) );
158   widget2->setFeature( vl->getFeature( 1 ) );
159   QCOMPARE( vl->fields().at( 1 ).precision(), 9 );
160   // Default is 0 !!! for double, really ?
161   QCOMPARE( vl->fields().at( 2 ).precision(), 0 );
162   QCOMPARE( editor->decimals(), vl->fields().at( 1 ).precision() );
163   QCOMPARE( editor->decimals(), 9 );
164   QCOMPARE( editor2->decimals(), vl->fields().at( 2 ).precision() );
165   QCOMPARE( editor->valueFromText( feat.attribute( 1 ).toString() ),  123.123456789 );
166   QCOMPARE( feat.attribute( 1 ).toString(), QStringLiteral( "123.123456789" ) );
167   QCOMPARE( editor2->valueFromText( feat.attribute( 1 ).toString() ), 123.123456789 );
168   QCOMPARE( editor->value( ), 123.123456789 );
169   QCOMPARE( editor2->value( ), 123.0 );
170   QCOMPARE( editor->minimum( ), std::numeric_limits<double>::lowest() );
171   QCOMPARE( editor2->minimum( ), std::numeric_limits<double>::lowest() );
172   QCOMPARE( editor->maximum( ), std::numeric_limits<double>::max() );
173   QCOMPARE( editor2->maximum( ), std::numeric_limits<double>::max() );
174 
175   widget1->setFeature( vl->getFeature( 2 ) );
176   widget2->setFeature( vl->getFeature( 2 ) );
177   QCOMPARE( editor->value( ), editor->minimum() );
178   QCOMPARE( editor2->value( ), editor->minimum() );
179 
180   widget1->setFeature( vl->getFeature( 3 ) );
181   widget2->setFeature( vl->getFeature( 3 ) );
182   QCOMPARE( editor->value( ), -123.123456789 );
183   QCOMPARE( editor2->value( ), -123.0 );
184 }
185 
test_setDoubleSmallerRange()186 void TestQgsRangeWidgetWrapper::test_setDoubleSmallerRange()
187 {
188   // Same test but we set a smaller validity range for the widget
189   QVariantMap cfg;
190   cfg.insert( QStringLiteral( "Min" ), -100.0 );
191   cfg.insert( QStringLiteral( "Max" ), 100.0 );
192   cfg.insert( QStringLiteral( "Step" ), 1 );
193   widget1->setConfig( cfg );
194   QgsDoubleSpinBox *editor = qobject_cast<QgsDoubleSpinBox *>( widget1->createWidget( nullptr ) );
195   QVERIFY( editor );
196   widget1->initWidget( editor );
197 
198   widget2->setConfig( cfg );
199   QgsDoubleSpinBox *editor2 = qobject_cast<QgsDoubleSpinBox *>( widget2->createWidget( nullptr ) );
200   QVERIFY( editor2 );
201   widget2->initWidget( editor2 );
202 
203   const QgsFeature feat( vl->getFeature( 1 ) );
204   QVERIFY( feat.isValid() );
205   QCOMPARE( feat.attribute( 1 ).toDouble(), 123.123456789 );
206   widget1->setFeature( vl->getFeature( 1 ) );
207   widget2->setFeature( vl->getFeature( 1 ) );
208 
209   QCOMPARE( vl->fields().at( 1 ).precision(), 9 );
210   // Default is 0 !!! for double, really ?
211   QCOMPARE( vl->fields().at( 2 ).precision(), 0 );
212   QCOMPARE( editor->decimals(), vl->fields().at( 1 ).precision() );
213   QCOMPARE( editor2->decimals(), vl->fields().at( 2 ).precision() );
214   // value was changed to the maximum (not NULL) accepted value
215   QCOMPARE( editor->value( ), 100.0 );
216   // value was changed to the maximum (not NULL) accepted value
217   QCOMPARE( editor2->value( ), 100.0 );
218   // minimum was lowered by the precision (10e-9)
219   QCOMPARE( editor->minimum( ), -100.000000001 );
220   // minimum was lowered by step (1)
221   QCOMPARE( editor2->minimum( ), ( double ) - 101 );
222   QCOMPARE( editor->maximum( ), ( double )100 );
223   QCOMPARE( editor2->maximum( ), ( double )100 );
224 
225   // NULL, NULL
226   widget1->setFeature( vl->getFeature( 2 ) );
227   widget2->setFeature( vl->getFeature( 2 ) );
228   QCOMPARE( editor->value( ), editor->minimum() );
229   QCOMPARE( editor2->value( ), editor2->minimum() );
230 
231   // negative, negative
232   widget1->setFeature( vl->getFeature( 3 ) );
233   widget2->setFeature( vl->getFeature( 3 ) );
234   // value was changed to the minimum
235   QCOMPARE( editor->value( ), editor->minimum() );
236   QCOMPARE( editor2->value( ), editor2->minimum() );
237 
238 }
239 
test_setDoubleLimits()240 void TestQgsRangeWidgetWrapper::test_setDoubleLimits()
241 {
242   // Same test but check double numeric limits
243   QVariantMap cfg;
244   cfg.insert( QStringLiteral( "Min" ), std::numeric_limits<double>::lowest() );
245   cfg.insert( QStringLiteral( "Max" ), std::numeric_limits<double>::max() );
246   cfg.insert( QStringLiteral( "Step" ), 1 );
247   widget1->setConfig( cfg );
248   QgsDoubleSpinBox *editor = qobject_cast<QgsDoubleSpinBox *>( widget1->createWidget( nullptr ) );
249   QVERIFY( editor );
250   widget1->initWidget( editor );
251 
252   widget2->setConfig( cfg );
253   QgsDoubleSpinBox *editor2 = qobject_cast<QgsDoubleSpinBox *>( widget2->createWidget( nullptr ) );
254   QVERIFY( editor2 );
255   widget2->initWidget( editor2 );
256 
257   QCOMPARE( editor->minimum( ), std::numeric_limits<double>::lowest() );
258   QCOMPARE( editor2->minimum( ), std::numeric_limits<double>::lowest() );
259   QCOMPARE( editor->maximum( ), std::numeric_limits<double>::max() );
260   QCOMPARE( editor2->maximum( ), std::numeric_limits<double>::max() );
261 
262   const QgsFeature feat( vl->getFeature( 1 ) );
263   QVERIFY( feat.isValid() );
264   QCOMPARE( feat.attribute( 1 ).toDouble(), 123.123456789 );
265   widget1->setFeature( vl->getFeature( 1 ) );
266   widget2->setFeature( vl->getFeature( 1 ) );
267 
268   QCOMPARE( vl->fields().at( 1 ).precision(), 9 );
269   // Default is 0 !!! for double, really ?
270   QCOMPARE( vl->fields().at( 2 ).precision(), 0 );
271   QCOMPARE( editor->decimals(), vl->fields().at( 1 ).precision() );
272   QCOMPARE( editor2->decimals(), vl->fields().at( 2 ).precision() );
273   QCOMPARE( editor->value( ), 123.123456789 );
274   QCOMPARE( editor2->value( ), 123.0 );
275 
276   // NULL, NULL
277   widget1->setFeature( vl->getFeature( 2 ) );
278   widget2->setFeature( vl->getFeature( 2 ) );
279   QCOMPARE( editor->value( ), editor->minimum() );
280   QCOMPARE( editor2->value( ), editor2->minimum() );
281 
282   // negative, negative
283   widget1->setFeature( vl->getFeature( 3 ) );
284   widget2->setFeature( vl->getFeature( 3 ) );
285   // value was changed to the minimum
286   QCOMPARE( editor->value( ), -123.123456789 );
287   QCOMPARE( editor2->value( ), -123.0 );
288 
289 }
290 
test_nulls()291 void TestQgsRangeWidgetWrapper::test_nulls()
292 {
293   QgsApplication::setNullRepresentation( QString( "" ) );
294 
295   QVariantMap cfg;
296   cfg.insert( QStringLiteral( "Min" ), 100.00 );
297   cfg.insert( QStringLiteral( "Max" ), 200.00 );
298   cfg.insert( QStringLiteral( "Step" ), 1 );
299   cfg.insert( QStringLiteral( "Precision" ), 0 );
300   widget1->setConfig( cfg );
301   QgsDoubleSpinBox *editor1 = qobject_cast<QgsDoubleSpinBox *>( widget1->createWidget( nullptr ) );
302   QVERIFY( editor1 );
303   widget1->initWidget( editor1 );
304   // Out of range
305   widget1->setFeature( vl->getFeature( 3 ) );
306   QCOMPARE( editor1->value( ), editor1->minimum() );
307   QCOMPARE( widget1->value( ), QVariant( QVariant::Double ) );
308   widget1->setFeature( QgsFeature( vl->fields() ) );
309   // Null
310   QCOMPARE( editor1->value( ), editor1->minimum() );
311   QCOMPARE( widget1->value( ), QVariant( QVariant::Double ) );
312   QCOMPARE( editor1->mLineEdit->text(), SPECIAL_TEXT_WHEN_EMPTY );
313   editor1->mLineEdit->setText( QString( "151%1" ).arg( SPECIAL_TEXT_WHEN_EMPTY ) );
314   QCOMPARE( widget1->value( ).toInt(), 151 );
315   editor1->mLineEdit->setText( QString( SPECIAL_TEXT_WHEN_EMPTY ).append( QStringLiteral( "161" ) ) );
316   QCOMPARE( widget1->value( ).toInt(), 161 );
317 
318 
319   QgsSpinBox *editor0 = qobject_cast<QgsSpinBox *>( widget0->createWidget( nullptr ) );
320   QVERIFY( editor0 );
321   widget0->setConfig( cfg );
322   widget0->initWidget( editor0 );
323   // Out of range
324   widget0->setFeature( vl->getFeature( 3 ) );
325   QCOMPARE( editor0->value( ), editor0->minimum() );
326   QCOMPARE( widget0->value( ), QVariant( QVariant::Int ) );
327   widget0->setFeature( QgsFeature( vl->fields() ) );
328   // Null
329   QCOMPARE( editor0->value( ), editor0->minimum() );
330   QCOMPARE( widget0->value( ), QVariant( QVariant::Int ) );
331   QCOMPARE( editor0->mLineEdit->text(), SPECIAL_TEXT_WHEN_EMPTY );
332 
333   editor0->mLineEdit->setText( QString( "150%1" ).arg( SPECIAL_TEXT_WHEN_EMPTY ) );
334   QCOMPARE( widget0->value( ).toInt(), 150 );
335   editor0->mLineEdit->setText( QString( SPECIAL_TEXT_WHEN_EMPTY ).append( QStringLiteral( "160" ) ) );
336   QCOMPARE( widget0->value( ).toInt(), 160 );
337 
338 }
339 
test_negativeIntegers()340 void TestQgsRangeWidgetWrapper::test_negativeIntegers()
341 {
342   QgsApplication::setNullRepresentation( QString( "" ) );
343 
344   QVariantMap cfg;
345   widget3->setConfig( cfg );
346 
347   QgsSpinBox *editor3 = qobject_cast<QgsSpinBox *>( widget3->createWidget( nullptr ) );
348   QVERIFY( editor3 );
349   widget3->initWidget( editor3 );
350 
351   QgsFeature feature { vl->getFeature( 3 ) };
352   feature.setAttribute( 3, -12345 );
353 
354   widget3->setFeature( feature );
355   QCOMPARE( widget3->value( ).toInt(), -12345 );
356 
357   cfg.insert( QStringLiteral( "Min" ), 10 );
358   widget3->setConfig( cfg );
359   widget3->initWidget( editor3 );
360   widget3->setFeature( feature );
361   QVERIFY( widget3->value().isNull() );
362   QCOMPARE( widget3->value( ).toInt(), 0 );
363 
364   cfg.clear();
365   cfg.insert( QStringLiteral( "Min" ), -12346 );
366   widget3->setConfig( cfg );
367   widget3->initWidget( editor3 );
368   widget3->setFeature( feature );
369   QCOMPARE( widget3->value( ).toInt(), -12345 );
370 
371 }
372 
test_focus()373 void TestQgsRangeWidgetWrapper::test_focus()
374 {
375   QgsApplication::setNullRepresentation( QString( "nope" ) );
376 
377   QWidget *w = new QWidget(); //required for focus events
378   QApplication::setActiveWindow( w );
379 
380   QVariantMap cfg;
381   cfg.insert( QStringLiteral( "AllowNull" ), true );
382 
383   //QgsDoubleSpinBox
384   widget1->setConfig( cfg );
385   QgsDoubleSpinBox *editor1 = qobject_cast<QgsDoubleSpinBox *>( widget1->createWidget( w ) );
386   QVERIFY( editor1 );
387   widget1->initWidget( editor1 );
388   widget1->setValue( QVariant( QVariant::Double ) );
389 
390   //QgsDoubleSpinBox
391   widget2->setConfig( cfg );
392   QgsDoubleSpinBox *editor2 = qobject_cast<QgsDoubleSpinBox *>( widget2->createWidget( w ) );
393   QVERIFY( editor2 );
394   widget2->initWidget( editor2 );
395   widget2->setValue( QVariant( QVariant::Double ) );
396 
397   //QgsSpinBox
398   widget3->setConfig( cfg );
399   QgsSpinBox *editor3 = qobject_cast<QgsSpinBox *>( widget3->createWidget( w ) );
400   QVERIFY( editor3 );
401   widget3->initWidget( editor3 );
402   widget3->setValue( QVariant( QVariant::Int ) );
403 
404   QVERIFY( widget1->value().isNull() );
405   QVERIFY( widget2->value().isNull() );
406   QVERIFY( widget3->value().isNull() );
407   QVERIFY( !editor1->mLineEdit->hasFocus() );
408   QVERIFY( !editor2->mLineEdit->hasFocus() );
409   QVERIFY( !editor3->mLineEdit->hasFocus() );
410   QCOMPARE( editor1->mLineEdit->text(), QStringLiteral( "nope" ) );
411   QCOMPARE( editor2->mLineEdit->text(), QStringLiteral( "nope" ) );
412   QCOMPARE( editor3->mLineEdit->text(), QStringLiteral( "nope" ) );
413 
414   editor1->mLineEdit->setFocus();
415   QVERIFY( widget1->value().isNull() );
416   QVERIFY( widget2->value().isNull() );
417   QVERIFY( widget3->value().isNull() );
418   QVERIFY( editor1->mLineEdit->hasFocus() );
419   QVERIFY( !editor2->mLineEdit->hasFocus() );
420   QVERIFY( !editor3->mLineEdit->hasFocus() );
421   QCOMPARE( editor1->mLineEdit->text(), QString() );
422   QCOMPARE( editor2->mLineEdit->text(), QStringLiteral( "nope" ) );
423   QCOMPARE( editor3->mLineEdit->text(), QStringLiteral( "nope" ) );
424 
425   editor2->mLineEdit->setFocus();
426   QVERIFY( widget1->value().isNull() );
427   QVERIFY( widget2->value().isNull() );
428   QVERIFY( widget3->value().isNull() );
429   QVERIFY( !editor1->mLineEdit->hasFocus() );
430   QVERIFY( editor2->mLineEdit->hasFocus() );
431   QVERIFY( !editor3->mLineEdit->hasFocus() );
432   QCOMPARE( editor1->mLineEdit->text(), QStringLiteral( "nope" ) );
433   QCOMPARE( editor2->mLineEdit->text(), QString() );
434   QCOMPARE( editor3->mLineEdit->text(), QStringLiteral( "nope" ) );
435 
436   editor3->mLineEdit->setFocus();
437   QVERIFY( widget1->value().isNull() );
438   QVERIFY( widget2->value().isNull() );
439   QVERIFY( widget3->value().isNull() );
440   QVERIFY( !editor1->mLineEdit->hasFocus() );
441   QVERIFY( !editor2->mLineEdit->hasFocus() );
442   QVERIFY( editor3->mLineEdit->hasFocus() );
443   QCOMPARE( editor1->mLineEdit->text(), QStringLiteral( "nope" ) );
444   QCOMPARE( editor2->mLineEdit->text(), QStringLiteral( "nope" ) );
445   QCOMPARE( editor3->mLineEdit->text(), QStringLiteral( "" ) );
446 
447   editor1->mLineEdit->setFocus();
448   editor1->mLineEdit->setText( QString( "151.000000000" ) );
449   QVERIFY( !widget1->value().isNull() );
450   QVERIFY( widget2->value().isNull() );
451   QVERIFY( widget3->value().isNull() );
452   QVERIFY( editor1->mLineEdit->hasFocus() );
453   QVERIFY( !editor2->mLineEdit->hasFocus() );
454   QVERIFY( !editor3->mLineEdit->hasFocus() );
455   QCOMPARE( editor1->mLineEdit->text(), QStringLiteral( "151.000000000" ) );
456   QCOMPARE( editor2->mLineEdit->text(), QStringLiteral( "nope" ) );
457   QCOMPARE( editor3->mLineEdit->text(), QStringLiteral( "nope" ) );
458 
459   editor2->mLineEdit->setFocus();
460   QVERIFY( widget0->value().isNull() );
461   QVERIFY( !widget1->value().isNull() );
462   QVERIFY( widget2->value().isNull() );
463   QVERIFY( !editor1->mLineEdit->hasFocus() );
464   QVERIFY( editor2->mLineEdit->hasFocus() );
465   QVERIFY( !editor3->mLineEdit->hasFocus() );
466   QCOMPARE( editor1->mLineEdit->text(), QStringLiteral( "151.000000000" ) );
467   QCOMPARE( editor2->mLineEdit->text(), QString() );
468   QCOMPARE( editor3->mLineEdit->text(), QStringLiteral( "nope" ) );
469 
470 }
471 
testLongLong()472 void TestQgsRangeWidgetWrapper::testLongLong()
473 {
474   // test range widget with a long long field type
475   std::unique_ptr< QgsRangeWidgetWrapper >wrapper = std::make_unique<QgsRangeWidgetWrapper>( vl.get(), 4, nullptr, nullptr );
476 
477   // should use a double spin box, as a integer spin box does not have sufficient range
478   QgsDoubleSpinBox *editor = qobject_cast<QgsDoubleSpinBox *>( wrapper->createWidget( nullptr ) );
479   QVERIFY( editor );
480   wrapper->initWidget( editor );
481   // no decimals, it's for long long value editing!
482   QCOMPARE( editor->decimals(), 0 );
483   QCOMPARE( editor->minimum( ), std::numeric_limits<double>::lowest() );
484   QCOMPARE( editor->maximum( ), std::numeric_limits<double>::max() );
485 
486   wrapper->setValue( 1234567890123LL );
487 
488   // double spin box value should be lossless
489   QCOMPARE( editor->value(), 1234567890123.0 );
490 
491   // wrapper value must be a long long type, not double
492   QCOMPARE( wrapper->value(), 1234567890123LL );
493 }
494 
495 QGSTEST_MAIN( TestQgsRangeWidgetWrapper )
496 #include "testqgsrangewidgetwrapper.moc"
497