test_referencingfeaturelistmodel.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. #include "qfield_testbase.h"
  2. #include "qgsquickmapsettings.h"
  3. #include "referencingfeaturelistmodel.h"
  4. #include <QtTest>
  5. #include <qgsapplication.h>
  6. #include <qgsproject.h>
  7. #include <qgsrelationmanager.h>
  8. #include <qgsvectorlayer.h>
  9. class TestReferencingFeatureListModel : public QObject
  10. {
  11. Q_OBJECT
  12. private slots:
  13. void initTestCase()
  14. {
  15. /* TEST PROJECT
  16. *
  17. * LAYERS
  18. * land (id, name, king_id)
  19. * - 0 Mordor
  20. * - 1 Gondor
  21. * - 2 Rohan
  22. * - 3 Eriador
  23. * king
  24. * - 0 Frodo (Gondor, Rohan, Eriador)
  25. * - 1 Gollum (Mordor)
  26. * share (id, share, king_id, land_id)
  27. * - Mordor Frodo 20
  28. * - Gondor Frodo 40
  29. * - Rohan Frodo 60
  30. * - EriadorFrodo 100
  31. *
  32. * - Mordor Gollum 80
  33. * - Gondor Gollum 60
  34. * - Rohan Gollum 40
  35. *
  36. * RELATIONS
  37. * A king can rule several lands, but a land can be ruled by only one king
  38. * - landhasoneking (land m--1 king)
  39. * A king can have shares of several lands and a land can be owned by several kings
  40. * - sharehasoneoner (shares m--1 king)
  41. * - shareofoneland (shares m--1 land)
  42. */
  43. //create layers
  44. mL_Land.reset( new QgsVectorLayer( QStringLiteral( "Polygon?crs=EPSG:3857&field=id:int&field=name:string&field=king_id:int" ), QStringLiteral( "land" ), QStringLiteral( "memory" ) ) );
  45. mL_Land->setDisplayExpression( "name" );
  46. QVERIFY( mL_Land->isValid() );
  47. QgsProject::instance()->addMapLayer( mL_Land.get(), false, false );
  48. mL_King.reset( new QgsVectorLayer( QStringLiteral( "Point?crs=EPSG:3857&field=id:int&field=name:string" ), QStringLiteral( "king" ), QStringLiteral( "memory" ) ) );
  49. mL_King->setDisplayExpression( "name" );
  50. QVERIFY( mL_King->isValid() );
  51. QgsProject::instance()->addMapLayer( mL_King.get(), false, false );
  52. mL_Share.reset( new QgsVectorLayer( QStringLiteral( "Point?crs=EPSG:3857&field=id:integer&field=share:int&field=king_id:int&field=land_id:int" ), QStringLiteral( "share" ), QStringLiteral( "memory" ) ) );
  53. mL_Share->setDisplayExpression( "share" );
  54. QVERIFY( mL_Share->isValid() );
  55. QgsProject::instance()->addMapLayer( mL_Share.get(), false, false );
  56. //create relations
  57. mR_Landhasoneking.setId( QStringLiteral( "land.king" ) );
  58. mR_Landhasoneking.setName( QStringLiteral( "land.king" ) );
  59. mR_Landhasoneking.setReferencingLayer( mL_Land->id() );
  60. mR_Landhasoneking.setReferencedLayer( mL_King->id() );
  61. mR_Landhasoneking.addFieldPair( QStringLiteral( "king_id" ), QStringLiteral( "id" ) );
  62. QVERIFY( mR_Landhasoneking.isValid() );
  63. QgsProject::instance()->relationManager()->addRelation( mR_Landhasoneking );
  64. mR_Sharehasoneking.setId( QStringLiteral( "share.king" ) );
  65. mR_Sharehasoneking.setName( QStringLiteral( "share.king" ) );
  66. mR_Sharehasoneking.setReferencingLayer( mL_Share->id() );
  67. mR_Sharehasoneking.setReferencedLayer( mL_King->id() );
  68. mR_Sharehasoneking.addFieldPair( QStringLiteral( "king_id" ), QStringLiteral( "id" ) );
  69. QVERIFY( mR_Sharehasoneking.isValid() );
  70. QgsProject::instance()->relationManager()->addRelation( mR_Sharehasoneking );
  71. mR_Shareofoneland.setId( QStringLiteral( "share.land" ) );
  72. mR_Shareofoneland.setName( QStringLiteral( "share.land" ) );
  73. mR_Shareofoneland.setReferencingLayer( mL_Share->id() );
  74. mR_Shareofoneland.setReferencedLayer( mL_Land->id() );
  75. mR_Shareofoneland.addFieldPair( QStringLiteral( "land_id" ), QStringLiteral( "id" ) );
  76. QVERIFY( mR_Shareofoneland.isValid() );
  77. QgsProject::instance()->relationManager()->addRelation( mR_Shareofoneland );
  78. // add features on land
  79. QgsFeature land_ft0( mL_Land->fields() );
  80. land_ft0.setAttribute( QStringLiteral( "id" ), 0 );
  81. land_ft0.setAttribute( QStringLiteral( "name" ), "Mordor" );
  82. land_ft0.setAttribute( QStringLiteral( "king_id" ), 1 );
  83. QgsFeature land_ft1( mL_Land->fields() );
  84. land_ft1.setAttribute( QStringLiteral( "id" ), 1 );
  85. land_ft1.setAttribute( QStringLiteral( "name" ), "Gondor" );
  86. land_ft1.setAttribute( QStringLiteral( "king_id" ), 0 );
  87. QgsFeature land_ft2( mL_Land->fields() );
  88. land_ft2.setAttribute( QStringLiteral( "id" ), 2 );
  89. land_ft2.setAttribute( QStringLiteral( "name" ), "Rohan" );
  90. land_ft2.setAttribute( QStringLiteral( "king_id" ), 0 );
  91. QgsFeature land_ft3( mL_Land->fields() );
  92. land_ft3.setAttribute( QStringLiteral( "id" ), 3 );
  93. land_ft3.setAttribute( QStringLiteral( "name" ), "Eriador" );
  94. land_ft3.setAttribute( QStringLiteral( "king_id" ), 0 );
  95. mL_Land->startEditing();
  96. mL_Land->addFeature( land_ft0 );
  97. mL_Land->addFeature( land_ft1 );
  98. mL_Land->addFeature( land_ft2 );
  99. mL_Land->addFeature( land_ft3 );
  100. mL_Land->commitChanges();
  101. QCOMPARE( mL_Land->featureCount(), 4L );
  102. // add features on king
  103. QgsFeature king_ft0( mL_King->fields() );
  104. king_ft0.setAttribute( QStringLiteral( "id" ), 0 );
  105. king_ft0.setAttribute( QStringLiteral( "name" ), "Frodo" );
  106. QgsFeature king_ft1( mL_King->fields() );
  107. king_ft1.setAttribute( QStringLiteral( "id" ), 1 );
  108. king_ft1.setAttribute( QStringLiteral( "name" ), "Gollum" );
  109. mL_King->startEditing();
  110. mL_King->addFeature( king_ft0 );
  111. mL_King->addFeature( king_ft1 );
  112. mL_King->commitChanges();
  113. QCOMPARE( mL_King->featureCount(), 2L );
  114. // add features on share
  115. QgsFeature share_ft0( mL_Share->fields() );
  116. share_ft0.setAttribute( QStringLiteral( "id" ), 0 );
  117. share_ft0.setAttribute( QStringLiteral( "king_id" ), 0 );
  118. share_ft0.setAttribute( QStringLiteral( "land_id" ), 0 );
  119. share_ft0.setAttribute( QStringLiteral( "share" ), 20 );
  120. QgsFeature share_ft1( mL_Share->fields() );
  121. share_ft1.setAttribute( QStringLiteral( "id" ), 1 );
  122. share_ft1.setAttribute( QStringLiteral( "king_id" ), 0 );
  123. share_ft1.setAttribute( QStringLiteral( "land_id" ), 1 );
  124. share_ft1.setAttribute( QStringLiteral( "share" ), 40 );
  125. QgsFeature share_ft2( mL_Share->fields() );
  126. share_ft2.setAttribute( QStringLiteral( "id" ), 2 );
  127. share_ft2.setAttribute( QStringLiteral( "king_id" ), 0 );
  128. share_ft2.setAttribute( QStringLiteral( "land_id" ), 2 );
  129. share_ft2.setAttribute( QStringLiteral( "share" ), 60 );
  130. QgsFeature share_ft3( mL_Share->fields() );
  131. share_ft3.setAttribute( QStringLiteral( "id" ), 3 );
  132. share_ft3.setAttribute( QStringLiteral( "king_id" ), 0 );
  133. share_ft3.setAttribute( QStringLiteral( "land_id" ), 3 );
  134. share_ft3.setAttribute( QStringLiteral( "share" ), 100 );
  135. QgsFeature share_ft4( mL_Share->fields() );
  136. share_ft4.setAttribute( QStringLiteral( "id" ), 4 );
  137. share_ft4.setAttribute( QStringLiteral( "king_id" ), 1 );
  138. share_ft4.setAttribute( QStringLiteral( "land_id" ), 0 );
  139. share_ft4.setAttribute( QStringLiteral( "share" ), 80 );
  140. QgsFeature share_ft5( mL_Share->fields() );
  141. share_ft5.setAttribute( QStringLiteral( "id" ), 5 );
  142. share_ft5.setAttribute( QStringLiteral( "king_id" ), 1 );
  143. share_ft5.setAttribute( QStringLiteral( "land_id" ), 1 );
  144. share_ft5.setAttribute( QStringLiteral( "share" ), 60 );
  145. QgsFeature share_ft6( mL_Share->fields() );
  146. share_ft6.setAttribute( QStringLiteral( "id" ), 6 );
  147. share_ft6.setAttribute( QStringLiteral( "king_id" ), 1 );
  148. share_ft6.setAttribute( QStringLiteral( "land_id" ), 2 );
  149. share_ft6.setAttribute( QStringLiteral( "share" ), 40 );
  150. mL_Share->startEditing();
  151. mL_Share->addFeature( share_ft0 );
  152. mL_Share->addFeature( share_ft1 );
  153. mL_Share->addFeature( share_ft2 );
  154. mL_Share->addFeature( share_ft3 );
  155. mL_Share->addFeature( share_ft4 );
  156. mL_Share->addFeature( share_ft5 );
  157. mL_Share->addFeature( share_ft6 );
  158. mL_Share->commitChanges();
  159. QCOMPARE( mL_Share->featureCount(), 7L );
  160. mModel = new ReferencingFeatureListModel();
  161. }
  162. /*
  163. testGetReferencingFeatures
  164. - load project
  165. - create model (set relation, set feature)
  166. - count list / compare list
  167. - change parent feature
  168. - count list / compare list
  169. */
  170. void testGetReferencingFeatures()
  171. {
  172. mModel->setRelation( mR_Landhasoneking );
  173. QSignalSpy( mModel, &ReferencingFeatureListModel::modelUpdated ).wait( 500 );
  174. mModel->setNmRelation( QgsRelation() );
  175. QSignalSpy( mModel, &ReferencingFeatureListModel::modelUpdated ).wait( 500 );
  176. //check out Frodo
  177. mModel->setFeature( mL_King->getFeature( 1 ) );
  178. QVERIFY( QSignalSpy( mModel, &ReferencingFeatureListModel::modelUpdated ).wait( 1000 ) );
  179. //Frodo rules 3 lands (Gondor, Rohan, Eriador)
  180. QCOMPARE( mModel->rowCount(), 3 );
  181. //check out Gollum
  182. mModel->setFeature( mL_King->getFeature( 2 ) );
  183. QVERIFY( QSignalSpy( mModel, &ReferencingFeatureListModel::modelUpdated ).wait( 1000 ) );
  184. //Gollum rules 1 land (Mordor)
  185. QCOMPARE( mModel->rowCount(), 1 );
  186. }
  187. /*
  188. testGetManyToManyReferencedFeatures
  189. - load project
  190. - create model (set relation, set nmrelation, set feature)
  191. - count list / compare list
  192. - change parent feature
  193. - count list / compare list
  194. */
  195. void testGetManyToManyReferencedFeatures()
  196. {
  197. mModel->setRelation( mR_Sharehasoneking );
  198. QSignalSpy( mModel, &ReferencingFeatureListModel::modelUpdated ).wait( 500 );
  199. mModel->setNmRelation( mR_Shareofoneland );
  200. QSignalSpy( mModel, &ReferencingFeatureListModel::modelUpdated ).wait( 500 );
  201. //check out Frodo
  202. mModel->setFeature( mL_King->getFeature( 1 ) );
  203. QVERIFY( QSignalSpy( mModel, &ReferencingFeatureListModel::modelUpdated ).wait( 1000 ) );
  204. //Frodo has shares of 4 lands (Mordor, Gondor, Rohan, Eriador)
  205. QCOMPARE( mModel->rowCount(), 4 );
  206. //check out Gollum
  207. mModel->setFeature( mL_King->getFeature( 2 ) );
  208. QVERIFY( QSignalSpy( mModel, &ReferencingFeatureListModel::modelUpdated ).wait( 1000 ) );
  209. //Gollum has shares of 3 lands (Mordor, Gondor, Rohan)
  210. QCOMPARE( mModel->rowCount(), 3 );
  211. }
  212. /*
  213. testDeleteReferencingFeature
  214. - load project
  215. - create model (set relation, set feature)
  216. - count list / compare list
  217. - delete child features
  218. - count list / compare list
  219. */
  220. void testDeleteReferencingFeature()
  221. {
  222. mModel->setNmRelation( QgsRelation() );
  223. QSignalSpy( mModel, &ReferencingFeatureListModel::modelUpdated ).wait( 500 );
  224. mModel->setRelation( mR_Landhasoneking );
  225. QSignalSpy( mModel, &ReferencingFeatureListModel::modelUpdated ).wait( 500 );
  226. //check out Frodo
  227. mModel->setFeature( mL_King->getFeature( 1 ) );
  228. QVERIFY( QSignalSpy( mModel, &ReferencingFeatureListModel::modelUpdated ).wait( 1000 ) );
  229. //Frodo rules 3 lands (Gondor, Rohan, Eriador)
  230. QCOMPARE( mModel->rowCount(), 3 );
  231. //check display string of rohan
  232. QString displayString = mModel->data( mModel->index( 1, 0 ), ReferencingFeatureListModel::DisplayString ).toString();
  233. QCOMPARE( displayString, QStringLiteral( "Gondor" ) );
  234. //delete Rohan
  235. mModel->deleteFeature( qvariant_cast<QgsFeature>( mModel->data( mModel->index( 1, 0 ), ReferencingFeatureListModel::ReferencingFeature ) ).id() );
  236. QVERIFY( QSignalSpy( mModel, &ReferencingFeatureListModel::modelUpdated ).wait( 1000 ) );
  237. //Frodo rules 2 lands (Gondor, Eriador) no Rohan anymore
  238. QCOMPARE( mModel->rowCount(), 2 );
  239. }
  240. /*
  241. testDdeleteReferenceToManyToManyReferencedFeature
  242. - load project
  243. - create model (set relation, set feature)
  244. - count list / compare list
  245. - delete (unlink) child features
  246. - count list / compare list
  247. */
  248. void testDeleteReferenceToManyToManyReferencedFeature()
  249. {
  250. mModel->setRelation( mR_Sharehasoneking );
  251. QSignalSpy( mModel, &ReferencingFeatureListModel::modelUpdated ).wait( 500 );
  252. mModel->setNmRelation( mR_Shareofoneland );
  253. QSignalSpy( mModel, &ReferencingFeatureListModel::modelUpdated ).wait( 500 );
  254. //check out Frodo
  255. mModel->setFeature( mL_King->getFeature( 1 ) );
  256. QVERIFY( QSignalSpy( mModel, &ReferencingFeatureListModel::modelUpdated ).wait( 1000 ) );
  257. //Frodo has shares of 4 lands (Mordor, Gondor, Eriador, Rohan)
  258. QCOMPARE( mModel->rowCount(), 4 );
  259. //check out Gollum
  260. mModel->setFeature( mL_King->getFeature( 2 ) );
  261. QVERIFY( QSignalSpy( mModel, &ReferencingFeatureListModel::modelUpdated ).wait( 1000 ) );
  262. //Gollum has shares of 3 lands (Mordor, Gondor, Rohan)
  263. QCOMPARE( mModel->rowCount(), 3 );
  264. //check display string of Gollums Mordor share (80)
  265. QString displayString = mModel->data( mModel->index( 0, 0 ), ReferencingFeatureListModel::DisplayString ).toString();
  266. QCOMPARE( displayString, QStringLiteral( "40" ) );
  267. //delete Gollums share on Mordor
  268. mModel->deleteFeature( qvariant_cast<QgsFeature>( mModel->data( mModel->index( 0, 0 ), ReferencingFeatureListModel::ReferencingFeature ) ).id() );
  269. QVERIFY( QSignalSpy( mModel, &ReferencingFeatureListModel::modelUpdated ).wait( 1000 ) );
  270. //Gollum has shares of 2 landd (Gondor, Rohan)
  271. QCOMPARE( mModel->rowCount(), 2 );
  272. //check out Frodo again
  273. mModel->setFeature( mL_King->getFeature( 1 ) );
  274. QVERIFY( QSignalSpy( mModel, &ReferencingFeatureListModel::modelUpdated ).wait( 1000 ) );
  275. //Frodo has still shares of 4 lands (Mordor, Gondor, Eriador, Rohan) because his shares are untouched
  276. QCOMPARE( mModel->rowCount(), 4 );
  277. }
  278. void cleanupTestCase()
  279. {
  280. delete mModel;
  281. QgsProject::instance()->removeMapLayer( mL_Land.get() );
  282. QgsProject::instance()->removeMapLayer( mL_King.get() );
  283. QgsProject::instance()->removeMapLayer( mL_Share.get() );
  284. }
  285. private:
  286. std::unique_ptr<QgsVectorLayer> mL_Land;
  287. std::unique_ptr<QgsVectorLayer> mL_King;
  288. std::unique_ptr<QgsVectorLayer> mL_Share;
  289. QgsRelation mR_Landhasoneking;
  290. QgsRelation mR_Sharehasoneking;
  291. QgsRelation mR_Shareofoneland;
  292. ReferencingFeatureListModel *mModel;
  293. };
  294. QFIELDTEST_MAIN( TestReferencingFeatureListModel )
  295. #include "test_referencingfeaturelistmodel.moc"