24
24
25
25
#include < qgsapplication.h>
26
26
#include < qgscoordinatereferencesystem.h>
27
- #include < qgsgrass.h>
28
- #include < qgsgrassimport.h>
27
+ #include < qgsgeometry.h>
28
+ #include < qgslinestringv2.h>
29
+ #include < qgspointv2.h>
30
+ #include < qgspolygonv2.h>
29
31
#include < qgsproviderregistry.h>
30
32
#include < qgsrasterbandstats.h>
31
33
#include < qgsrasterlayer.h>
32
34
#include < qgsvectordataprovider.h>
35
+ #include < qgsvectorlayer.h>
36
+
37
+ #include < qgsgrass.h>
38
+ #include < qgsgrassimport.h>
39
+ #include < qgsgrassprovider.h>
33
40
34
41
extern " C"
35
42
{
@@ -62,6 +69,7 @@ class TestQgsGrassProvider: public QObject
62
69
void info ();
63
70
void rasterImport ();
64
71
void vectorImport ();
72
+ void edit ();
65
73
private:
66
74
void reportRow ( const QString& message );
67
75
void reportHeader ( const QString& message );
@@ -78,6 +86,10 @@ class TestQgsGrassProvider: public QObject
78
86
bool removeRecursively ( const QString &filePath, QString *error = 0 );
79
87
bool copyLocation ( QString& tmpGisdbase );
80
88
bool createTmpLocation ( QString& tmpGisdbase, QString& tmpLocation, QString& tmpMapset );
89
+ bool equal ( QgsFeature feature, QgsFeature expectedFeatures );
90
+ bool compare ( QList<QgsFeature> features, QList<QgsFeature> expectedFeatures, bool & ok );
91
+ bool compare ( QString uri, QgsGrassObject mapObject, QgsVectorLayer *expectedLayer, bool & ok );
92
+ QList<QgsFeature> getFeatures ( QgsVectorLayer *layer );
81
93
QString mGisdbase ;
82
94
QString mLocation ;
83
95
QString mReport ;
@@ -105,7 +117,7 @@ void TestQgsGrassProvider::initTestCase()
105
117
// in version different form which we are testing here and it would also load GRASS libs in different version
106
118
// and result in segfault when __do_global_dtors_aux() is called.
107
119
// => we must set QGIS_PROVIDER_FILE before QgsApplication::initQgis() to avoid loading GRASS provider in different version
108
- QgsGrass::putEnv ( " QGIS_PROVIDER_FILE" , " gdal|ogr" );
120
+ QgsGrass::putEnv ( " QGIS_PROVIDER_FILE" , QString ( " gdal|ogr|memoryprovider|grassprovider%1 " ). arg ( GRASS_BUILD_VERSION ) );
109
121
QgsApplication::initQgis ();
110
122
QString mySettings = QgsApplication::showSettings ();
111
123
mySettings = mySettings.replace ( " \n " , " <br />\n " );
@@ -599,6 +611,7 @@ bool TestQgsGrassProvider::createTmpLocation( QString& tmpGisdbase, QString& tmp
599
611
tmpFile->open ();
600
612
tmpGisdbase = tmpFile->fileName ();
601
613
delete tmpFile;
614
+ // tmpGisdbase = QDir::tempPath() + "/qgis-grass-test/test"; // debug
602
615
reportRow ( " tmpGisdbase: " + tmpGisdbase );
603
616
tmpLocation = " test" ;
604
617
tmpMapset = " PERMANENT" ;
@@ -754,5 +767,309 @@ void TestQgsGrassProvider::vectorImport()
754
767
GVERIFY ( ok );
755
768
}
756
769
770
+ class TestQgsGrassCommand
771
+ {
772
+ public:
773
+ enum Command
774
+ {
775
+ AddFeature
776
+ };
777
+
778
+ TestQgsGrassCommand ( Command c, QgsFeature f, int t ) : command( c ), feature( f ), type( t ) {}
779
+
780
+ QString toString ();
781
+ Command command;
782
+ QgsFeature feature;
783
+ int type; // GRASS type
784
+ };
785
+
786
+ QString TestQgsGrassCommand::toString ()
787
+ {
788
+ QString string;
789
+ if ( command == AddFeature )
790
+ {
791
+ string += " AddFeature " ;
792
+ string += feature.geometry ()->exportToWkt ( 1 );
793
+ }
794
+ return string;
795
+ }
796
+
797
+ void TestQgsGrassProvider::edit ()
798
+ {
799
+ reportHeader ( " TestQgsGrassProvider::edit" );
800
+ bool ok = true ;
801
+
802
+ QString tmpGisdbase;
803
+ QString tmpLocation;
804
+ QString tmpMapset;
805
+
806
+ if ( !createTmpLocation ( tmpGisdbase, tmpLocation, tmpMapset ) )
807
+ {
808
+ reportRow ( " cannot create temporary location" );
809
+ GVERIFY ( false );
810
+ return ;
811
+ }
812
+
813
+ QList<QList<TestQgsGrassCommand>> commandGroups;
814
+
815
+ QList<TestQgsGrassCommand> commands;
816
+ QgsFeature feature;
817
+ feature.setGeometry ( new QgsGeometry ( new QgsPointV2 ( QgsWKBTypes::Point, 10 , 10 , 0 ) ) );
818
+ commands << TestQgsGrassCommand ( TestQgsGrassCommand::AddFeature, feature, GV_POINT );
819
+ commandGroups << commands;
820
+
821
+ for ( int i = 0 ; i < commandGroups.size (); i++ )
822
+ {
823
+ commands = commandGroups[i];
824
+
825
+ // Create GRASS vector
826
+ QString name = QString ( " edit_%1" ).arg ( i );
827
+ QgsGrassObject mapObject = QgsGrassObject ( tmpGisdbase, tmpLocation, tmpMapset, name, QgsGrassObject::Vector );
828
+ reportRow ( " create new map: " + mapObject.toString () );
829
+ QString error;
830
+ QgsGrass::createVectorMap ( mapObject, error );
831
+ if ( !error.isEmpty () )
832
+ {
833
+ reportRow ( error );
834
+ ok = false ;
835
+ break ;
836
+ }
837
+
838
+ QString uri = mapObject.mapsetPath () + " /" + name + " /1_point" ;
839
+ reportRow ( " uri: " + uri );
840
+ QgsVectorLayer *layer = new QgsVectorLayer ( uri, name, " grass" );
841
+ if ( !layer->isValid () )
842
+ {
843
+ reportRow ( " layer is not valid" );
844
+ ok = false ;
845
+ break ;
846
+ }
847
+ QgsGrassProvider *provider = qobject_cast<QgsGrassProvider *>( layer->dataProvider () );
848
+ if ( !provider )
849
+ {
850
+ reportRow ( " cannot get provider" );
851
+ ok = false ;
852
+ break ;
853
+ }
854
+
855
+ // Create memory vector for verification, it has no fields until added
856
+ QgsVectorLayer *expectedLayer = new QgsVectorLayer ( " Point" , " test" , " memory" );
857
+ if ( !expectedLayer->isValid () )
858
+ {
859
+ reportRow ( " verification layer is not valid" );
860
+ ok = false ;
861
+ break ;
862
+ }
863
+
864
+ layer->startEditing ();
865
+ provider->startEditing ( layer );
866
+
867
+ expectedLayer->startEditing ();
868
+
869
+ for ( int j = 0 ; j < commands.size (); j++ )
870
+ {
871
+ TestQgsGrassCommand command = commands[j];
872
+ if ( command.command == TestQgsGrassCommand::AddFeature )
873
+ {
874
+ reportRow ( " command: " + command.toString () );
875
+ provider->setNewFeatureType ( command.type );
876
+
877
+ QgsFeature feature = command.feature ;
878
+ feature.initAttributes ( layer->fields ().size () ); // attributes must match layer fields
879
+ layer->addFeature ( feature );
880
+
881
+ QgsFeature expectedFeature = command.feature ;
882
+ expectedFeature.initAttributes ( expectedLayer->fields ().size () );
883
+ // expectedFeature.setGeometry( new QgsGeometry( new QgsPointV2( QgsWKBTypes::Point, 10, 20, 0 ) ) ); // debug
884
+ expectedLayer->addFeature ( expectedFeature );
885
+ }
886
+ if ( !compare ( uri, mapObject, expectedLayer, ok ) )
887
+ {
888
+ reportRow ( " command failed" );
889
+ break ;
890
+ }
891
+ else
892
+ {
893
+ reportRow ( " command ok" );
894
+ }
895
+ }
896
+
897
+ layer->commitChanges ();
898
+ delete layer;
899
+ delete expectedLayer;
900
+ }
901
+
902
+ removeRecursively ( tmpGisdbase );
903
+ GVERIFY ( ok );
904
+ }
905
+
906
+ QList<QgsFeature> TestQgsGrassProvider::getFeatures ( QgsVectorLayer *layer )
907
+ {
908
+ QgsFeatureIterator iterator = layer->getFeatures ( QgsFeatureRequest () );
909
+ QgsFeature feature;
910
+ QList<QgsFeature> features;
911
+ while ( iterator.nextFeature ( feature ) )
912
+ {
913
+ features << feature;
914
+ }
915
+ iterator.close ();
916
+ return features;
917
+ }
918
+
919
+ bool TestQgsGrassProvider::equal ( QgsFeature feature, QgsFeature expectedFeature )
920
+ {
921
+ if ( !feature.geometry ()->equals ( expectedFeature.geometry () ) )
922
+ {
923
+ return false ;
924
+ }
925
+ // GRASS feature has always additional cat field
926
+ QSet<int > indexes;
927
+ for ( int i = 0 ; i < feature.fields ()->size (); i++ )
928
+ {
929
+ QString name = feature.fields ()->at ( i ).name ();
930
+ if ( name == " cat" ) // skip cat
931
+ {
932
+ continue ;
933
+ }
934
+ indexes << i;
935
+ }
936
+ for ( int i = 0 ; i < expectedFeature.fields ()->size (); i++ )
937
+ {
938
+ QString name = expectedFeature.fields ()->at ( i ).name ();
939
+ int index = feature.fields ()->indexFromName ( name );
940
+ if ( index < 0 )
941
+ {
942
+ // not found
943
+ return false ;
944
+ }
945
+ indexes.remove ( index );
946
+ if ( feature.attribute ( index ) != expectedFeature.attribute ( i ) )
947
+ {
948
+ return false ;
949
+ }
950
+ }
951
+ if ( indexes.size () > 0 )
952
+ {
953
+ // unexpected attribute in feature
954
+ QStringList names;
955
+ Q_FOREACH ( int i, indexes )
956
+ {
957
+ names << feature.fields ()->at ( i ).name ();
958
+ }
959
+ reportRow ( QString ( " feature has %1 unexpected attributes: %2" ).arg ( indexes.size () ).arg ( names.join ( " ," ) ) );
960
+ return false ;
961
+ }
962
+ return true ;
963
+ }
964
+
965
+ bool TestQgsGrassProvider::compare ( QList<QgsFeature> features, QList<QgsFeature> expectedFeatures, bool & ok )
966
+ {
967
+ bool localOk = true ;
968
+ if ( features.size () != expectedFeatures.size () )
969
+ {
970
+ reportRow ( QString ( " different number of features (%1) and expected features (%2)" ).arg ( features.size () ).arg ( expectedFeatures.size () ) );
971
+ ok = false ;
972
+ return false ;
973
+ }
974
+ // Check if each expected feature exists in features
975
+ Q_FOREACH ( const QgsFeature& expectedFeature, expectedFeatures )
976
+ {
977
+ bool found = false ;
978
+ Q_FOREACH ( const QgsFeature& feature, features )
979
+ {
980
+ if ( equal ( feature, expectedFeature ) )
981
+ {
982
+ found = true ;
983
+ break ;
984
+ }
985
+ }
986
+ if ( !found )
987
+ {
988
+ reportRow ( QString ( " expected feature fid = %1 not found in features" ).arg ( expectedFeature.id () ) );
989
+ ok = false ;
990
+ localOk = false ;
991
+ }
992
+ }
993
+ return localOk;
994
+ }
995
+
996
+ bool TestQgsGrassProvider::compare ( QString uri, QgsGrassObject mapObject, QgsVectorLayer *expectedLayer, bool & ok )
997
+ {
998
+ QList<QgsFeature> expectedFeatures = getFeatures ( expectedLayer );
999
+
1000
+ // read the map using another layer/provider
1001
+ QgsVectorLayer *layer = new QgsVectorLayer ( uri, " test" , " grass" );
1002
+ if ( !layer->isValid () )
1003
+ {
1004
+ reportRow ( " shared layer is not valid" );
1005
+ ok = false ;
1006
+ return false ;
1007
+ }
1008
+ QList<QgsFeature> features = getFeatures ( layer );
1009
+ delete layer;
1010
+ layer = 0 ;
1011
+
1012
+ bool sharedOk = compare ( features, expectedFeatures, ok );
1013
+ if ( sharedOk )
1014
+ {
1015
+ reportRow ( " comparison with shared layer ok" );
1016
+ }
1017
+ else
1018
+ {
1019
+ reportRow ( " comparison with shared layer failed" );
1020
+ }
1021
+
1022
+ // Open an independent layer which does not share data with edited one
1023
+ // build topology
1024
+ G_TRY
1025
+ {
1026
+ struct Map_info *map = QgsGrass::vectNewMapStruct ();
1027
+ QgsGrass::setMapset ( mapObject );
1028
+ Vect_open_old ( map, mapObject.name ().toUtf8 ().data (), mapObject.mapset ().toUtf8 ().data () );
1029
+
1030
+ #if ( GRASS_VERSION_MAJOR == 6 && GRASS_VERSION_MINOR >= 4 ) || GRASS_VERSION_MAJOR > 6
1031
+ Vect_build ( map );
1032
+ #else
1033
+ Vect_build ( map, stderr );
1034
+ #endif
1035
+ Vect_set_release_support ( map );
1036
+ Vect_close ( map );
1037
+ QgsGrass::vectDestroyMapStruct ( map );
1038
+ }
1039
+ G_CATCH ( QgsGrass::Exception &e )
1040
+ {
1041
+ reportRow ( " Cannot build topology: " + QString ( e.what () ) );
1042
+ ok = false ;
1043
+ return false ;
1044
+ }
1045
+
1046
+ QgsGrassVectorMapStore * mapStore = new QgsGrassVectorMapStore ();
1047
+ QgsGrassVectorMapStore::setStore ( mapStore );
1048
+
1049
+ layer = new QgsVectorLayer ( uri, " test" , " grass" );
1050
+ if ( !layer->isValid () )
1051
+ {
1052
+ reportRow ( " independent layer is not valid" );
1053
+ ok = false ;
1054
+ return false ;
1055
+ }
1056
+ features = getFeatures ( layer );
1057
+ delete layer;
1058
+ QgsGrassVectorMapStore::setStore ( 0 );
1059
+ delete mapStore;
1060
+
1061
+ bool independentOk = compare ( features, expectedFeatures, ok );
1062
+ if ( independentOk )
1063
+ {
1064
+ reportRow ( " comparison with independent layer ok" );
1065
+ }
1066
+ else
1067
+ {
1068
+ reportRow ( " comparison with independent layer failed" );
1069
+ }
1070
+
1071
+ return sharedOk && independentOk;
1072
+ }
1073
+
757
1074
QTEST_MAIN ( TestQgsGrassProvider )
758
1075
#include " testqgsgrassprovider.moc"
0 commit comments