test_layerobserver.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /***************************************************************************
  2. test_layerobserver.h
  3. --------------------
  4. begin : Apr 2020
  5. copyright : (C) 2020 by Ivan Ivanov
  6. email : ivan@opengis.ch
  7. ***************************************************************************/
  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. #define QFIELDTEST_MAIN
  17. #include "layerobserver.h"
  18. #include "utils/qfieldcloudutils.h"
  19. #include "catch2.h"
  20. QStringList getDeltaOperations( QString fileName )
  21. {
  22. QStringList operations;
  23. QFile deltaFile( fileName );
  24. if ( !deltaFile.open( QIODevice::ReadOnly ) )
  25. return operations;
  26. QJsonDocument doc = QJsonDocument::fromJson( deltaFile.readAll() );
  27. if ( doc.isNull() )
  28. return operations;
  29. QJsonArray deltasJsonArray = doc.object().value( QStringLiteral( "deltas" ) ).toArray();
  30. for ( const QJsonValue &v : std::as_const( deltasJsonArray ) )
  31. operations.append( v.toObject().value( QStringLiteral( "method" ) ).toString() );
  32. return operations;
  33. }
  34. QString getId( QString fileName )
  35. {
  36. QFile deltaFile( fileName );
  37. if ( !deltaFile.open( QIODevice::ReadOnly ) )
  38. return QString();
  39. QJsonDocument doc = QJsonDocument::fromJson( deltaFile.readAll() );
  40. if ( doc.isNull() )
  41. return QString();
  42. return doc.object().value( QStringLiteral( "id" ) ).toString();
  43. }
  44. TEST_CASE( "TestLayerObserver" )
  45. {
  46. QTemporaryDir settingsDir;
  47. REQUIRE( settingsDir.isValid() );
  48. REQUIRE( QDir( settingsDir.path() ).mkpath( QStringLiteral( "cloud_projects/TEST_PROJECT_ID" ) ) );
  49. QDir projectDir( QStringLiteral( "%1/cloud_projects/TEST_PROJECT_ID" ).arg( settingsDir.path() ) );
  50. QFieldCloudUtils::setLocalCloudDirectory( settingsDir.path() );
  51. QFile projectFile( QStringLiteral( "%1/%2" ).arg( projectDir.path(), QStringLiteral( "project.qgs" ) ) );
  52. QFile attachmentFile( QStringLiteral( "%1/%2" ).arg( projectDir.path(), QStringLiteral( "attachment.jpg" ) ) );
  53. REQUIRE( projectFile.open( QIODevice::WriteOnly ) );
  54. REQUIRE( projectFile.flush() );
  55. QgsProject::instance()->setFileName( projectFile.fileName() );
  56. std::unique_ptr<QgsVectorLayer> mLayer = std::make_unique<QgsVectorLayer>( QStringLiteral( "Point?crs=EPSG:3857&field=fid:integer&field=str:string" ), QStringLiteral( "Test Layer" ), QStringLiteral( "memory" ) );
  57. mLayer->setCustomProperty( QStringLiteral( "QFieldSync/action" ), QStringLiteral( "CLOUD" ) );
  58. mLayer->setCustomProperty( QStringLiteral( "QFieldSync/sourceDataPrimaryKeys" ), QStringLiteral( "fid" ) );
  59. REQUIRE( mLayer->isValid() );
  60. QgsFeature f1( mLayer->fields() );
  61. f1.setAttribute( QStringLiteral( "fid" ), 1 );
  62. f1.setAttribute( QStringLiteral( "str" ), "string1" );
  63. f1.setGeometry( QgsGeometry( new QgsPoint( 25.9657, 43.8356 ) ) );
  64. QgsFeature f2( mLayer->fields() );
  65. f2.setAttribute( QStringLiteral( "fid" ), 2 );
  66. f2.setAttribute( QStringLiteral( "str" ), "string2" );
  67. f2.setGeometry( QgsGeometry( new QgsPoint( 23.398819, 41.7672147 ) ) );
  68. QgsFeature f3( mLayer->fields() );
  69. f3.setAttribute( QStringLiteral( "fid" ), 3 );
  70. f3.setAttribute( QStringLiteral( "str" ), "string3" );
  71. REQUIRE( mLayer->startEditing() );
  72. REQUIRE( mLayer->addFeature( f1 ) );
  73. REQUIRE( mLayer->addFeature( f2 ) );
  74. REQUIRE( mLayer->addFeature( f3 ) );
  75. REQUIRE( mLayer->commitChanges() );
  76. std::unique_ptr<LayerObserver> mLayerObserver = std::make_unique<LayerObserver>( QgsProject::instance() );
  77. REQUIRE( QgsProject::instance()->addMapLayer( mLayer.get(), false, false ) );
  78. REQUIRE( !mLayerObserver->deltaFileWrapper()->hasError() );
  79. #if 0
  80. SECTION( "HasError" )
  81. {
  82. // ? how I can test such thing?
  83. QSKIP( "decide how we test errors" );
  84. REQUIRE( mLayerObserver->deltaFileWrapper()->hasError() == false );
  85. REQUIRE( QFile::exists( mLayerObserver->deltaFileWrapper()->fileName() ) );
  86. }
  87. #endif
  88. SECTION( "Clear" )
  89. {
  90. QgsFeature f1( mLayer->fields() );
  91. f1.setAttribute( QStringLiteral( "fid" ), 1000 );
  92. f1.setAttribute( QStringLiteral( "str" ), "new_string1" );
  93. f1.setGeometry( QgsGeometry( new QgsPoint( 25.9657, 43.8356 ) ) );
  94. REQUIRE( mLayer->startEditing() );
  95. REQUIRE( mLayer->addFeature( f1 ) );
  96. REQUIRE( mLayer->commitChanges() );
  97. REQUIRE( getDeltaOperations( mLayerObserver->deltaFileWrapper()->fileName() ).size() == 1 );
  98. QgsFeature f2( mLayer->fields() );
  99. f2.setAttribute( QStringLiteral( "fid" ), 1001 );
  100. f2.setAttribute( QStringLiteral( "str" ), "new_string2" );
  101. f2.setGeometry( QgsGeometry( new QgsPoint( 25.9657, 43.8356 ) ) );
  102. REQUIRE( mLayer->startEditing() );
  103. REQUIRE( mLayer->addFeature( f1 ) );
  104. REQUIRE( mLayer->commitChanges() );
  105. REQUIRE( getDeltaOperations( mLayerObserver->deltaFileWrapper()->fileName() ).size() == 2 );
  106. mLayerObserver->reset();
  107. REQUIRE( mLayer->startEditing() );
  108. REQUIRE( mLayer->commitChanges() );
  109. REQUIRE( getDeltaOperations( mLayerObserver->deltaFileWrapper()->fileName() ).size() == 0 );
  110. }
  111. SECTION( "ObservesEditingStopped" )
  112. {
  113. QgsFeature f1( mLayer->fields() );
  114. f1.setAttribute( QStringLiteral( "fid" ), 1002 );
  115. f1.setAttribute( QStringLiteral( "str" ), "new_string" );
  116. f1.setGeometry( QgsGeometry( new QgsPoint( 25.9657, 43.8356 ) ) );
  117. REQUIRE( mLayer->startEditing() );
  118. REQUIRE( mLayer->addFeature( f1 ) );
  119. // the changes are not written on the disk yet
  120. REQUIRE( getDeltaOperations( mLayerObserver->deltaFileWrapper()->fileName() ) == QStringList() );
  121. // when we stop editing, all changes are written
  122. REQUIRE( mLayer->commitChanges() );
  123. REQUIRE( getDeltaOperations( mLayerObserver->deltaFileWrapper()->fileName() ) == QStringList( { "create" } ) );
  124. }
  125. SECTION( "ObservesAdded" )
  126. {
  127. QgsFeature f1( mLayer->fields() );
  128. f1.setAttribute( QStringLiteral( "fid" ), 1003 );
  129. f1.setAttribute( QStringLiteral( "str" ), "new_string" );
  130. f1.setGeometry( QgsGeometry( new QgsPoint( 25.9657, 43.8356 ) ) );
  131. REQUIRE( mLayer->startEditing() );
  132. REQUIRE( mLayer->addFeature( f1 ) );
  133. REQUIRE( mLayer->commitChanges() );
  134. REQUIRE( getDeltaOperations( mLayerObserver->deltaFileWrapper()->fileName() ) == QStringList( { "create" } ) );
  135. }
  136. SECTION( "ObservesRemoved" )
  137. {
  138. REQUIRE( mLayer->startEditing() );
  139. REQUIRE( mLayer->deleteFeature( 1 ) );
  140. REQUIRE( mLayer->commitChanges() );
  141. REQUIRE( getDeltaOperations( mLayerObserver->deltaFileWrapper()->fileName() ) == QStringList( { "delete" } ) );
  142. }
  143. SECTION( "ObservesAttributeValueChanges" )
  144. {
  145. QgsFeature f1 = mLayer->getFeature( 2 );
  146. f1.setAttribute( QStringLiteral( "str" ), f1.attribute( QStringLiteral( "str" ) ).toString() + "_new" );
  147. QgsFeature f2 = mLayer->getFeature( 3 );
  148. f2.setAttribute( QStringLiteral( "str" ), f2.attribute( QStringLiteral( "str" ) ).toString() + "_new" );
  149. f2.setGeometry( QgsGeometry( new QgsPoint( 88.7695313, 51.0897229 ) ) );
  150. REQUIRE( mLayer->startEditing() );
  151. REQUIRE( mLayer->updateFeature( f1 ) );
  152. REQUIRE( mLayer->updateFeature( f2 ) );
  153. REQUIRE( mLayer->commitChanges() );
  154. REQUIRE( getDeltaOperations( mLayerObserver->deltaFileWrapper()->fileName() ) == QStringList( { "patch", "patch" } ) );
  155. }
  156. SECTION( "ObservesGeometryChanges" )
  157. {
  158. REQUIRE( mLayer->startEditing() );
  159. QgsFeature f1 = mLayer->getFeature( 2 );
  160. f1.setGeometry( QgsGeometry( new QgsPoint( 13.0545044, 47.8094654 ) ) );
  161. QgsFeature f2 = mLayer->getFeature( 3 );
  162. f2.setAttribute( QStringLiteral( "str" ), f2.attribute( QStringLiteral( "str" ) ).toString() + "_new" );
  163. f2.setGeometry( QgsGeometry( new QgsPoint( 13.0545044, 47.8094654 ) ) );
  164. REQUIRE( mLayer->updateFeature( f1 ) );
  165. REQUIRE( mLayer->updateFeature( f2 ) );
  166. REQUIRE( mLayer->commitChanges() );
  167. REQUIRE( getDeltaOperations( mLayerObserver->deltaFileWrapper()->fileName() ) == QStringList( { "patch", "patch" } ) );
  168. }
  169. }