1 /***************************************************************************
2   testqgsogrprovidergui.cpp - TestQgsOgrProviderGui
3 
4  ---------------------
5  begin                : 10.11.2017
6  copyright            : (C) 2017 by Alessandro Pasotti
7  email                : apasotti at boundlessgeo dot com
8  ***************************************************************************
9  *                                                                         *
10  *   This program is free software; you can redistribute it and/or modify  *
11  *   it under the terms of the GNU General Public License as published by  *
12  *   the Free Software Foundation; either version 2 of the License, or     *
13  *   (at your option) any later version.                                   *
14  *                                                                         *
15  ***************************************************************************/
16 
17 #include "qgstest.h"
18 #include <QSignalSpy>
19 #include <QTemporaryFile>
20 
21 #include "qgsdataitemguiprovider.h"
22 #include "qgsdataitemguiproviderregistry.h"
23 #include "qgsgeopackagedataitems.h"
24 #include "qgsgui.h"
25 #include "qgsvectorlayer.h"
26 
27 /**
28  * \ingroup UnitTests
29  * This is a unit test for the ogr provider GUI
30  */
31 class TestQgsOgrProviderGui : public QObject
32 {
33     Q_OBJECT
34 
35   private slots:
36     void initTestCase();// will be called before the first testfunction is executed.
37     void cleanupTestCase();// will be called after the last testfunction was executed.
init()38     void init() {}// will be called before each testfunction is executed.
cleanup()39     void cleanup() {}// will be called after every testfunction.
40 
41     void providersRegistered();
42     //! Test GPKG data items rename
43     void testGpkgDataItemRename();
44 
45   private:
46     QString mTestDataDir;
47 };
48 
49 
50 //runs before all tests
initTestCase()51 void TestQgsOgrProviderGui::initTestCase()
52 {
53   // init QGIS's paths - true means that all path will be inited from prefix
54   QgsApplication::init();
55   QgsApplication::initQgis();
56 
57   mTestDataDir = QStringLiteral( TEST_DATA_DIR ) + '/'; //defined in CmakeLists.txt
58 }
59 
providersRegistered()60 void TestQgsOgrProviderGui::providersRegistered()
61 {
62   const QList<QgsDataItemGuiProvider *> providers = QgsGui::dataItemGuiProviderRegistry()->providers();
63   bool hasOgrProvider = false;
64   bool hasGpkgProvider = false;
65   for ( QgsDataItemGuiProvider *provider : providers )
66   {
67     if ( provider->name() == QLatin1String( "ogr_items" ) )
68       hasOgrProvider = true;
69     if ( provider->name() == QLatin1String( "geopackage_items" ) )
70       hasGpkgProvider = true;
71   }
72   QVERIFY( hasOgrProvider );
73   QVERIFY( hasGpkgProvider );
74 }
75 
76 //runs after all tests
cleanupTestCase()77 void TestQgsOgrProviderGui::cleanupTestCase()
78 {
79   QgsApplication::exitQgis();
80 }
81 
testGpkgDataItemRename()82 void TestQgsOgrProviderGui::testGpkgDataItemRename()
83 {
84   QTemporaryFile f( QStringLiteral( "qgis-XXXXXX.gpkg" ) );
85   f.open();
86   f.close();
87   const QString fileName { f.fileName( ) };
88   f.remove();
89   QVERIFY( QFile::copy( QStringLiteral( "%1/provider/bug_21227-rename-styles.gpkg" ).arg( mTestDataDir ),  fileName ) );
90 
91   // create geopackage item and populate it with layers
92   QgsGeoPackageCollectionItem gpkgItem( nullptr, QStringLiteral( "test gpkg" ), QStringLiteral( "gpkg:/%1" ).arg( fileName ) );
93   gpkgItem.populate( true );
94   const QVector<QgsDataItem *> items = gpkgItem.children();
95   QgsDataItem *itemLayer1 = nullptr;
96   for ( QgsDataItem *item : items )
97   {
98     if ( item->name() == QLatin1String( "layer 1" ) )
99       itemLayer1 = item;
100   }
101   QVERIFY( itemLayer1 );
102 
103   QSignalSpy spyDataChanged( &gpkgItem, &QgsDataItem::dataChanged );
104 
105   // try to rename
106   const QList<QgsDataItemGuiProvider *> providers = QgsGui::dataItemGuiProviderRegistry()->providers();
107   bool success = false;
108   for ( QgsDataItemGuiProvider *provider : providers )
109   {
110     if ( provider->rename( itemLayer1, QStringLiteral( "layer 3" ), QgsDataItemGuiContext() ) )
111     {
112       success = true;
113       // also check it was the correct provider
114       QCOMPARE( provider->name(), QStringLiteral( "geopackage_items" ) );
115     }
116   }
117   QVERIFY( success );
118 
119   // gpkg item gets refreshed in the background and there will be multiple dataChanged signals
120   // emitted unfortunately, so let's just wait until no more data changes signals are coming.
121   // Animation of "loading" icon also triggers dataChanged() signals, making even the number
122   // of signals unpredictable...
123   while ( spyDataChanged.wait( 500 ) )
124     ;
125 
126   // Check that the style is still available
127   const QgsVectorLayer metadataLayer( QStringLiteral( "/%1|layername=layer_styles" ).arg( fileName ) );
128   QVERIFY( metadataLayer.isValid() );
129   QgsFeature feature;
130   QgsFeatureIterator it = metadataLayer.getFeatures( QgsFeatureRequest( QgsExpression( QStringLiteral( "\"f_table_name\" = 'layer 3'" ) ) ) );
131   QVERIFY( it.nextFeature( feature ) );
132   QVERIFY( feature.isValid() );
133   QCOMPARE( feature.attribute( QStringLiteral( "styleName" ) ).toString(), QString( "style for layer 1" ) );
134   it = metadataLayer.getFeatures( QgsFeatureRequest( QgsExpression( QStringLiteral( "\"f_table_name\" = 'layer 1' " ) ) ) );
135   QVERIFY( !it.nextFeature( feature ) );
136   it = metadataLayer.getFeatures( QgsFeatureRequest( QgsExpression( QStringLiteral( "\"f_table_name\" = 'layer 2' " ) ) ) );
137   QVERIFY( it.nextFeature( feature ) );
138   QVERIFY( feature.isValid() );
139   QCOMPARE( feature.attribute( QStringLiteral( "styleName" ) ).toString(), QString( "style for layer 2" ) );
140 }
141 
142 
143 QGSTEST_MAIN( TestQgsOgrProviderGui )
144 #include "testqgsogrprovidergui.moc"
145