1 /***************************************************************************
2     testqgslistwidget.cpp
3      --------------------------------------
4     Date                 : 08 09 2016
5     Copyright            : (C) 2016 Patrick Valsecchi
6     Email                : patrick dot valsecchi at camptocamp 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 <editorwidgets/qgslistwidgetfactory.h>
20 #include <qgslistwidget.h>
21 #include <editorwidgets/core/qgseditorwidgetwrapper.h>
22 #include <qgsapplication.h>
23 #include <qgsvectorlayer.h>
24 #include <editorwidgets/qgslistwidgetwrapper.h>
25 #include <QSignalSpy>
26 
27 class TestQgsListWidget : public QObject
28 {
29     Q_OBJECT
30   private:
31     QString dbConn;
32   private slots:
initTestCase()33     void initTestCase() // will be called before the first testfunction is executed.
34     {
35       QgsApplication::init();
36       QgsApplication::initQgis();
37       dbConn = getenv( "QGIS_PGTEST_DB" );
38       if ( dbConn.isEmpty() )
39       {
40         dbConn = "service=\"qgis_test\"";
41       }
42     }
43 
cleanupTestCase()44     void cleanupTestCase() // will be called after the last testfunction was executed.
45     {
46       // delete new features in db from postgres test
47       QgsVectorLayer *vl_array_int = new QgsVectorLayer( QStringLiteral( "%1 sslmode=disable key=\"pk\" table=\"qgis_test\".\"array_tbl\" sql=" ).arg( dbConn ), QStringLiteral( "json" ), QStringLiteral( "postgres" ) );
48       vl_array_int->startEditing( );
49       const QgsFeatureIds delete_ids = QSet<QgsFeatureId>() << Q_INT64_C( 997 ) << Q_INT64_C( 998 ) << Q_INT64_C( 999 );
50       vl_array_int->deleteFeatures( delete_ids );
51       vl_array_int->commitChanges( false );
52       QgsVectorLayer *vl_array_str = new QgsVectorLayer( QStringLiteral( "%1 sslmode=disable key=\"pk\" table=\"qgis_test\".\"string_array\" sql=" ).arg( dbConn ), QStringLiteral( "json" ), QStringLiteral( "postgres" ) );
53       vl_array_str->startEditing( );
54       vl_array_str->deleteFeatures( delete_ids );
55       vl_array_str->commitChanges( false );
56       QgsApplication::exitQgis();
57     }
58 
testStringUpdate()59     void testStringUpdate()
60     {
61       const QgsListWidgetFactory factory( QStringLiteral( "testList" ) );
62       QgsVectorLayer vl( QStringLiteral( "Point?field=fld:string[]" ), QStringLiteral( "test" ), QStringLiteral( "memory" ) );
63       QgsEditorWidgetWrapper *wrapper = factory.create( &vl, 0, nullptr, nullptr );
64       QVERIFY( wrapper );
65       const QSignalSpy spy( wrapper, SIGNAL( valueChanged( const QVariant & ) ) );
66 
67       QgsListWidget *widget = qobject_cast< QgsListWidget * >( wrapper->widget() );
68       QVERIFY( widget );
69 
70       QStringList initial;
71       initial << QStringLiteral( "one" ) << QStringLiteral( "two" );
72       wrapper->setValues( initial, QVariantList() );
73 
74       const QVariant value = wrapper->value();
75       QCOMPARE( int( value.type() ), int( QVariant::StringList ) );
76       QCOMPARE( value.toStringList(), initial );
77       QCOMPARE( spy.count(), 0 );
78 
79       QAbstractItemModel *model = widget->tableView->model();
80       model->setData( model->index( 0, 0 ), "hello" );
81       QCOMPARE( spy.count(), 1 );
82       QVERIFY( widget->valid() );
83 
84       QStringList expected = initial;
85       expected[0] = QStringLiteral( "hello" );
86       const QVariant eventValue = spy.at( 0 ).at( 0 ).value<QVariant>();
87       QCOMPARE( int( eventValue.type() ), int( QVariant::StringList ) );
88       QCOMPARE( eventValue.toStringList(), expected );
89       QCOMPARE( wrapper->value().toStringList(), expected );
90       QCOMPARE( spy.count(), 1 );
91       QVERIFY( widget->valid() );
92     }
93 
testIntUpdate()94     void testIntUpdate()
95     {
96       const QgsListWidgetFactory factory( QStringLiteral( "testList" ) );
97       QgsVectorLayer vl( QStringLiteral( "Point?field=fld:int[]" ), QStringLiteral( "test" ), QStringLiteral( "memory" ) );
98       QgsEditorWidgetWrapper *wrapper = factory.create( &vl, 0, nullptr, nullptr );
99       QVERIFY( wrapper );
100       QSignalSpy spy( wrapper, SIGNAL( valueChanged( const QVariant & ) ) );
101 
102       QgsListWidget *widget = qobject_cast< QgsListWidget * >( wrapper->widget() );
103       QVERIFY( widget );
104 
105       QVariantList initial;
106       initial << 1 << -2;
107       wrapper->setValues( initial, QVariantList() );
108 
109       const QVariant value = wrapper->value();
110       QCOMPARE( int( value.type() ), int( QVariant::List ) );
111       QCOMPARE( value.toList(), initial );
112       QCOMPARE( spy.count(), 0 );
113 
114       QAbstractItemModel *model = widget->tableView->model();
115       model->setData( model->index( 0, 0 ), 3 );
116       QCOMPARE( spy.count(), 1 );
117 
118       QVariantList expected = initial;
119       expected[0] = 3;
120       QCOMPARE( spy.count(), 1 );
121       QVariant eventValue = spy.at( 0 ).at( 0 ).value<QVariant>();
122       QCOMPARE( int( eventValue.type() ), int( QVariant::List ) );
123       QCOMPARE( eventValue.toList(), expected );
124       QCOMPARE( wrapper->value().toList(), expected );
125       QVERIFY( widget->valid() );
126 
127       model->setData( model->index( 0, 0 ), "a" );
128       expected = initial;
129       expected.removeAt( 0 );
130       QVERIFY( !widget->valid() );
131       QCOMPARE( wrapper->value().toList(), expected );
132 
133       spy.clear();
134       model->setData( model->index( 0, 0 ), 56 );
135       expected = initial;
136       expected[0] = 56;
137       QCOMPARE( spy.count(), 1 );
138       eventValue = spy.at( 0 ).at( 0 ).value<QVariant>();
139       QCOMPARE( eventValue.toList(), expected );
140       QCOMPARE( wrapper->value().toList(), expected );
141       QVERIFY( widget->valid() );
142     }
143 
testPostgres()144     void testPostgres()
145     {
146       //create pg layers
147       QgsVectorLayer *vl_array_int = new QgsVectorLayer( QStringLiteral( "%1 sslmode=disable key=\"pk\" table=\"qgis_test\".\"array_tbl\" sql=" ).arg( dbConn ), QStringLiteral( "json" ), QStringLiteral( "postgres" ) );
148       QVERIFY( vl_array_int->isValid( ) );
149 
150       QgsListWidgetWrapper w_array_int( vl_array_int, vl_array_int->fields().indexOf( QLatin1String( "location" ) ), nullptr, nullptr );
151       QgsListWidget *widget = qobject_cast< QgsListWidget * >( w_array_int.widget( ) );
152 
153       vl_array_int->startEditing( );
154       QVariantList newList;
155       newList.append( QStringLiteral( "100" ) );
156       widget->setList( QList<QVariant>() << 100 );
157       QVERIFY( w_array_int.value( ).isValid( ) );
158       QCOMPARE( widget->list( ), QList<QVariant>( ) << 100 );
159       // save value and check it is saved properly in postges
160       QgsFeature new_rec_997 {vl_array_int->fields(), 997};
161       new_rec_997.setAttribute( 0, QVariant( 997 ) );
162       vl_array_int->addFeature( new_rec_997, QgsFeatureSink::RollBackOnErrors );
163       vl_array_int->commitChanges( false );
164       bool success = vl_array_int->changeAttributeValue( 997, 1, w_array_int.value(), QVariant(), false );
165       QVERIFY( success );
166       success = vl_array_int->commitChanges( false );
167       QVERIFY( success );
168 
169       w_array_int.setFeature( vl_array_int->getFeature( 997 ) );
170       QCOMPARE( widget->list( ), QList<QVariant>( ) << 100 );
171 
172       // alter two values at a time which triggered old bug (#38784)
173       widget->setList( QList<QVariant>() << 4 << 5 << 6 );
174       QgsFeature new_rec_998 {vl_array_int->fields(), 998};
175       new_rec_998.setAttribute( 0, QVariant( 998 ) );
176       new_rec_998.setAttribute( 1, w_array_int.value() );
177       vl_array_int->addFeature( new_rec_998, QgsFeatureSink::RollBackOnErrors );
178 
179       widget->setList( QList<QVariant>() << 10 << 11 << 12 );
180       QgsFeature new_rec_999 {vl_array_int->fields(), 999};
181       new_rec_999.setAttribute( 0, QVariant( 999 ) );
182       new_rec_999.setAttribute( 1, w_array_int.value() );
183       vl_array_int->addFeature( new_rec_999, QgsFeatureSink::RollBackOnErrors );
184       vl_array_int->commitChanges( false );
185 
186       w_array_int.setFeature( vl_array_int->getFeature( 998 ) );
187       QCOMPARE( widget->list( ), QList<QVariant>( ) << 4 << 5 << 6 );
188 
189       w_array_int.setFeature( vl_array_int->getFeature( 999 ) );
190       QCOMPARE( widget->list( ), QList<QVariant>() << 10 << 11 << 12 );
191 
192       // do similar for array of strings
193       QgsVectorLayer *vl_array_str = new QgsVectorLayer( QStringLiteral( "%1 sslmode=disable key=\"pk\" table=\"qgis_test\".\"string_array\" sql=" ).arg( dbConn ), QStringLiteral( "json" ), QStringLiteral( "postgres" ) );
194       QVERIFY( vl_array_str->isValid() );
195 
196       QgsListWidgetWrapper w_array_str( vl_array_str, vl_array_str->fields().indexOf( QLatin1String( "value" ) ), nullptr, nullptr );
197       widget = qobject_cast< QgsListWidget * >( w_array_str.widget( ) );
198       vl_array_str->startEditing( );
199       QVariantList newListStr;
200 
201       // test quotes
202       newListStr.append( QStringLiteral( "10\"0" ) );
203       widget->setList( newListStr );
204       QVERIFY( w_array_str.value().isValid() );
205       QCOMPARE( widget->list( ), QList<QVariant>( ) << QStringLiteral( "10\"0" ) );
206       // save value and check it is saved properly in postges
207       QgsFeature new_rec_997_str {vl_array_str->fields(), 997};
208       new_rec_997_str.setAttribute( 0, QVariant( 997 ) );
209       vl_array_str->addFeature( new_rec_997_str, QgsFeatureSink::RollBackOnErrors );
210       vl_array_str->commitChanges( false );
211       success = vl_array_str->changeAttributeValue( 997, 1, w_array_str.value(), QVariant(), false );
212       QVERIFY( success );
213       success = vl_array_str->commitChanges( false );
214       QVERIFY( success );
215 
216       w_array_str.setFeature( vl_array_str->getFeature( 997 ) );
217       QCOMPARE( widget->list( ), QList<QVariant>( ) << QStringLiteral( "10\"0" ) );
218 
219       // alter two values at a time which triggered old bug (#38784)
220       widget->setList( QList<QVariant>() << QStringLiteral( "four" ) << QStringLiteral( "five" ) << QStringLiteral( "six" ) );
221       QgsFeature new_rec_998_str {vl_array_str->fields(), 998};
222       new_rec_998_str.setAttribute( 0, QVariant( 998 ) );
223       new_rec_998_str.setAttribute( 1, w_array_str.value() );
224       vl_array_str->addFeature( new_rec_998_str, QgsFeatureSink::RollBackOnErrors );
225 
226       widget->setList( QList<QVariant>() << QStringLiteral( "ten" ) << QStringLiteral( "eleven" ) << QStringLiteral( "twelve" ) );
227       QgsFeature new_rec_999_str {vl_array_str->fields(), 999};
228       new_rec_999_str.setAttribute( 0, QVariant( 999 ) );
229       new_rec_999_str.setAttribute( 1, w_array_str.value() );
230       vl_array_str->addFeature( new_rec_999_str, QgsFeatureSink::RollBackOnErrors );
231       vl_array_str->commitChanges( false );
232 
233       w_array_str.setFeature( vl_array_str->getFeature( 998 ) );
234       QCOMPARE( widget->list( ), QList<QVariant>() << QStringLiteral( "four" ) << QStringLiteral( "five" ) << QStringLiteral( "six" ) );
235 
236       w_array_str.setFeature( vl_array_str->getFeature( 999 ) );
237       QCOMPARE( widget->list( ), QList<QVariant>() << QStringLiteral( "ten" ) << QStringLiteral( "eleven" ) << QStringLiteral( "twelve" ) );
238     }
239 };
240 
241 QGSTEST_MAIN( TestQgsListWidget )
242 #include "testqgslistwidget.moc"
243