1 /***************************************************************************
2 testqgsvectorfilewriter.cpp
3 --------------------------------------
4 Date : Frida Nov 23 2007
5 Copyright : (C) 2007 by Tim Sutton
6 Email : tim@linfiniti.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 #include "qgstest.h"
16
17 #include <QApplication>
18 #include <QObject>
19 #include <QSplashScreen>
20 #include <QString>
21 #include <QStringList>
22
23 #include "qgisapp.h"
24 #include "qgsapplication.h"
25 #include "qgsfeature.h"
26 #include "qgsfeaturestore.h"
27 #include "qgsfield.h"
28 #include "qgsclipboard.h"
29 #include "qgsvectorlayer.h"
30 #include "qgsgeometry.h"
31 #include "qgspoint.h"
32 #include "qgssettings.h"
33
34 /**
35 * \ingroup UnitTests
36 * This is a unit test for the QgisApp clipboard.
37 */
38 class TestQgisAppClipboard : public QObject
39 {
40 Q_OBJECT
41
42 public:
43 TestQgisAppClipboard();
44
45 private slots:
46 void initTestCase();// will be called before the first testfunction is executed.
47 void cleanupTestCase();// will be called after the last testfunction was executed.
init()48 void init() {} // will be called before each testfunction is executed.
cleanup()49 void cleanup() {} // will be called after every testfunction.
50
51 void copyPaste();
52 void copyToText();
53 void pasteWkt();
54 void pasteGeoJson();
55 void retrieveFields();
56 void clipboardLogic(); //test clipboard logic
57
58 private:
59 QgisApp *mQgisApp = nullptr;
60 QString mTestDataDir;
61 };
62
63 TestQgisAppClipboard::TestQgisAppClipboard() = default;
64
65 //runs before all tests
initTestCase()66 void TestQgisAppClipboard::initTestCase()
67 {
68 // Set up the QgsSettings environment
69 QCoreApplication::setOrganizationName( QStringLiteral( "QGIS" ) );
70 QCoreApplication::setOrganizationDomain( QStringLiteral( "qgis.org" ) );
71 QCoreApplication::setApplicationName( QStringLiteral( "QGIS-TEST" ) );
72
73 qDebug() << "TestQgisAppClipboard::initTestCase()";
74 // init QGIS's paths - true means that all path will be inited from prefix
75 QgsApplication::init();
76 QgsApplication::initQgis();
77 mTestDataDir = QStringLiteral( TEST_DATA_DIR ) + '/'; //defined in CmakeLists.txt
78 mQgisApp = new QgisApp();
79 }
80
81 //runs after all tests
cleanupTestCase()82 void TestQgisAppClipboard::cleanupTestCase()
83 {
84 QgsApplication::exitQgis();
85 }
86
copyPaste()87 void TestQgisAppClipboard::copyPaste()
88 {
89 qDebug() << "TestQgisAppClipboard::copyPaste()";
90
91 QMap<QString, int> filesCounts;
92 filesCounts.insert( QStringLiteral( "points.shp" ), 17 );
93 filesCounts.insert( QStringLiteral( "lines.shp" ), 6 );
94 filesCounts.insert( QStringLiteral( "polys.shp" ), 10 );
95
96 Q_FOREACH ( const QString &fileName, filesCounts.keys() )
97 {
98 // add vector layer
99 QString filePath = mTestDataDir + fileName;
100 qDebug() << "add vector layer: " << filePath;
101 QgsVectorLayer *inputLayer = mQgisApp->addVectorLayer( filePath, fileName, QStringLiteral( "ogr" ) );
102 QVERIFY( inputLayer->isValid() );
103
104 // copy all features to clipboard
105 inputLayer->selectAll();
106 mQgisApp->copySelectionToClipboard( inputLayer );
107
108 QgsFeatureList features = mQgisApp->clipboard()->copyOf();
109 qDebug() << features.size() << " features copied to clipboard";
110
111 QVERIFY( features.size() == filesCounts.value( fileName ) );
112
113 QgsVectorLayer *pastedLayer = mQgisApp->pasteAsNewMemoryVector( QStringLiteral( "pasted" ) );
114 QVERIFY( pastedLayer );
115 QVERIFY( pastedLayer->isValid() );
116 qDebug() << pastedLayer->featureCount() << " features in pasted layer";
117 QVERIFY( pastedLayer->featureCount() == filesCounts.value( fileName ) );
118 }
119 }
120
copyToText()121 void TestQgisAppClipboard::copyToText()
122 {
123 //set clipboard to some QgsFeatures
124 QgsFields fields;
125 fields.append( QgsField( QStringLiteral( "int_field" ), QVariant::Int ) );
126 fields.append( QgsField( QStringLiteral( "string_field" ), QVariant::String ) );
127 QgsFeature feat( fields, 5 );
128 feat.setAttribute( QStringLiteral( "int_field" ), 9 );
129 feat.setAttribute( QStringLiteral( "string_field" ), "val" );
130 feat.setGeometry( QgsGeometry( new QgsPoint( 5, 6 ) ) );
131 QgsFeature feat2( fields, 6 );
132 feat2.setAttribute( QStringLiteral( "int_field" ), 19 );
133 feat2.setAttribute( QStringLiteral( "string_field" ), "val2" );
134 feat2.setGeometry( QgsGeometry( new QgsPoint( 7, 8 ) ) );
135 QgsFeatureStore feats;
136 feats.addFeature( feat );
137 feats.addFeature( feat2 );
138 feats.setFields( fields );
139 mQgisApp->clipboard()->replaceWithCopyOf( feats );
140
141 // attributes only
142 QgsSettings settings;
143 settings.setEnumValue( QStringLiteral( "/qgis/copyFeatureFormat" ), QgsClipboard::AttributesOnly );
144 QString result, resultHtml;
145 mQgisApp->clipboard()->generateClipboardText( result, resultHtml );
146 QCOMPARE( result, QString( "int_field\tstring_field\n9\tval\n19\tval2" ) );
147
148 // attributes with WKT
149 settings.setEnumValue( QStringLiteral( "/qgis/copyFeatureFormat" ), QgsClipboard::AttributesWithWKT );
150 mQgisApp->clipboard()->generateClipboardText( result, resultHtml );
151 QCOMPARE( result, QString( "wkt_geom\tint_field\tstring_field\nPoint (5 6)\t9\tval\nPoint (7 8)\t19\tval2" ) );
152
153 // HTML test
154 mQgisApp->clipboard()->replaceWithCopyOf( feats );
155 result = mQgisApp->clipboard()->data( "text/html" );
156 QCOMPARE( result, QString( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"><html><head><meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\"/></head><body><table border=\"1\"><tr><td>wkt_geom</td><td>int_field</td><td>string_field</td></tr><tr><td>Point (5 6)</td><td>9</td><td>val</td></tr><tr><td>Point (7 8)</td><td>19</td><td>val2</td></tr></table></body></html>" ) );
157
158 // GeoJSON
159 settings.setEnumValue( QStringLiteral( "/qgis/copyFeatureFormat" ), QgsClipboard::GeoJSON );
160 mQgisApp->clipboard()->generateClipboardText( result, resultHtml );
161 QString expected = "{\"features\":[{\"geometry\":{\"coordinates\":[5.0,6.0],\"type\":\"Point\"},\"id\":5,"
162 "\"properties\":{\"int_field\":9,\"string_field\":\"val\"},\"type\":\"Feature\"},"
163 "{\"geometry\":{\"coordinates\":[7.0,8.0],\"type\":\"Point\"},\"id\":6,"
164 "\"properties\":{\"int_field\":19,\"string_field\":\"val2\"},\"type\":\"Feature\"}],"
165 "\"type\":\"FeatureCollection\"}";
166 QCOMPARE( result, expected );
167
168 // test CRS is transformed correctly for GeoJSON
169
170 QgsCoordinateReferenceSystem crs( QStringLiteral( "EPSG:3111" ) );
171 feats = QgsFeatureStore();
172 feats.setCrs( crs );
173 feat.setGeometry( QgsGeometry( new QgsPoint( 2502577, 2403869 ) ) );
174 feats.addFeature( feat );
175 feats.setFields( fields );
176 mQgisApp->clipboard()->replaceWithCopyOf( feats );
177
178 mQgisApp->clipboard()->generateClipboardText( result, resultHtml );
179
180 // just test coordinates as integers - that's enough to verify that reprojection has occurred
181 // and helps avoid rounding issues
182 QRegExp regex( "\\[([-\\d.]+),([-\\d.]+)\\]" );
183 ( void )regex.indexIn( result );
184 QStringList list = regex.capturedTexts();
185 QCOMPARE( list.count(), 3 );
186
187 int x = std::round( list.at( 1 ).toDouble() );
188 int y = std::round( list.at( 2 ).toDouble() );
189
190 QCOMPARE( x, 145 );
191 QCOMPARE( y, -38 );
192
193 // test that multiline text fields are quoted to render correctly as csv files in WKT mode
194 QgsFeature feat3( fields, 7 );
195 feat3.setAttribute( QStringLiteral( "string_field" ), "Single line text" );
196 feat3.setAttribute( QStringLiteral( "int_field" ), 1 );
197 feat3.setGeometry( QgsGeometry( new QgsPoint( 5, 6 ) ) );
198 QgsFeature feat4( fields, 8 );
199 feat4.setAttribute( QStringLiteral( "string_field" ), "Unix Multiline \nText" );
200 feat4.setAttribute( QStringLiteral( "int_field" ), 2 );
201 feat4.setGeometry( QgsGeometry( new QgsPoint( 7, 8 ) ) );
202 QgsFeature feat5( fields, 9 );
203 feat5.setAttribute( QStringLiteral( "string_field" ), "Windows Multiline \r\nText" );
204 feat5.setAttribute( QStringLiteral( "int_field" ), 3 );
205 feat5.setGeometry( QgsGeometry( new QgsPoint( 9, 10 ) ) );
206 QgsFeatureStore featsML;
207 featsML.addFeature( feat3 );
208 featsML.addFeature( feat4 );
209 featsML.addFeature( feat5 );
210 featsML.setFields( fields );
211 mQgisApp->clipboard()->replaceWithCopyOf( featsML );
212
213 // attributes only
214 settings.setEnumValue( QStringLiteral( "/qgis/copyFeatureFormat" ), QgsClipboard::AttributesOnly );
215 mQgisApp->clipboard()->generateClipboardText( result, resultHtml );
216 qDebug() << result;
217 QCOMPARE( result, QString( "int_field\tstring_field\n1\tSingle line text\n2\t\"Unix Multiline \nText\"\n3\t\"Windows Multiline \r\nText\"" ) );
218
219 // attributes with WKT
220 settings.setEnumValue( QStringLiteral( "/qgis/copyFeatureFormat" ), QgsClipboard::AttributesWithWKT );
221 mQgisApp->clipboard()->generateClipboardText( result, resultHtml );
222 QCOMPARE( result, QString( "wkt_geom\tint_field\tstring_field\nPoint (5 6)\t1\tSingle line text\nPoint (7 8)\t2\t\"Unix Multiline \nText\"\nPoint (9 10)\t3\t\"Windows Multiline \r\nText\"" ) );
223 }
224
pasteWkt()225 void TestQgisAppClipboard::pasteWkt()
226 {
227 mQgisApp->clipboard()->setText( QStringLiteral( "POINT (125 10)\nPOINT (111 30)" ) );
228
229 QgsFeatureList features = mQgisApp->clipboard()->copyOf();
230 QCOMPARE( features.length(), 2 );
231 QVERIFY( features.at( 0 ).hasGeometry() && !features.at( 0 ).geometry().isNull() );
232 QCOMPARE( features.at( 0 ).geometry().constGet()->wkbType(), QgsWkbTypes::Point );
233 QgsGeometry featureGeom = features.at( 0 ).geometry();
234 const QgsPoint *point = dynamic_cast< const QgsPoint * >( featureGeom.constGet() );
235 QCOMPARE( point->x(), 125.0 );
236 QCOMPARE( point->y(), 10.0 );
237 QVERIFY( features.at( 1 ).hasGeometry() && !features.at( 1 ).geometry().isNull() );
238 QCOMPARE( features.at( 1 ).geometry().constGet()->wkbType(), QgsWkbTypes::Point );
239 point = dynamic_cast< const QgsPoint * >( features.at( 1 ).geometry().constGet() );
240 QCOMPARE( point->x(), 111.0 );
241 QCOMPARE( point->y(), 30.0 );
242
243 // be sure parsing does not consider attached parameters that
244 // can change geometryType as in https://github.com/qgis/QGIS/issues/24769
245 mQgisApp->clipboard()->setText( QStringLiteral( "POINT (111 30)\t GoodFieldValue\nPOINT (125 10)\t(WrongFieldValue)" ) );
246
247 features = mQgisApp->clipboard()->copyOf();
248 QCOMPARE( features.length(), 2 );
249
250 QVERIFY( features.at( 0 ).hasGeometry() && !features.at( 0 ).geometry().isNull() );
251 QCOMPARE( features.at( 0 ).geometry().constGet()->wkbType(), QgsWkbTypes::Point );
252 featureGeom = features.at( 0 ).geometry();
253 point = dynamic_cast< const QgsPoint * >( featureGeom.constGet() );
254 QCOMPARE( point->x(), 111.0 );
255 QCOMPARE( point->y(), 30.0 );
256
257 QVERIFY( features.at( 1 ).hasGeometry() && !features.at( 1 ).geometry().isNull() );
258 QCOMPARE( features.at( 1 ).geometry().constGet()->wkbType(), QgsWkbTypes::Point );
259 point = dynamic_cast< const QgsPoint * >( features.at( 1 ).geometry().constGet() );
260 QCOMPARE( point->x(), 125.0 );
261 QCOMPARE( point->y(), 10.0 );
262
263 //clipboard should support features without geometry
264 mQgisApp->clipboard()->setText( QStringLiteral( "\tMNL\t11\t282\tkm\t\t\t\n\tMNL\t11\t347.80000000000001\tkm\t\t\t" ) );
265 features = mQgisApp->clipboard()->copyOf();
266 QCOMPARE( features.length(), 2 );
267 QVERIFY( !features.at( 0 ).hasGeometry() );
268 QCOMPARE( features.at( 0 ).attributes().count(), 7 );
269 QCOMPARE( features.at( 0 ).attributes().at( 0 ).toString(), QStringLiteral( "MNL" ) );
270 QCOMPARE( features.at( 0 ).attributes().at( 1 ).toString(), QStringLiteral( "11" ) );
271 QCOMPARE( features.at( 0 ).attributes().at( 2 ).toString(), QStringLiteral( "282" ) );
272 QCOMPARE( features.at( 0 ).attributes().at( 3 ).toString(), QStringLiteral( "km" ) );
273 QVERIFY( features.at( 0 ).attributes().at( 4 ).toString().isEmpty() );
274 QVERIFY( features.at( 0 ).attributes().at( 5 ).toString().isEmpty() );
275 QVERIFY( features.at( 0 ).attributes().at( 6 ).toString().isEmpty() );
276 QVERIFY( !features.at( 1 ).hasGeometry() );
277 QCOMPARE( features.at( 1 ).attributes().count(), 7 );
278 QCOMPARE( features.at( 1 ).attributes().at( 0 ).toString(), QStringLiteral( "MNL" ) );
279 QCOMPARE( features.at( 1 ).attributes().at( 1 ).toString(), QStringLiteral( "11" ) );
280 QCOMPARE( features.at( 1 ).attributes().at( 2 ).toString(), QStringLiteral( "347.80000000000001" ) );
281 QCOMPARE( features.at( 1 ).attributes().at( 3 ).toString(), QStringLiteral( "km" ) );
282 QVERIFY( features.at( 1 ).attributes().at( 4 ).toString().isEmpty() );
283 QVERIFY( features.at( 1 ).attributes().at( 5 ).toString().isEmpty() );
284 QVERIFY( features.at( 1 ).attributes().at( 6 ).toString().isEmpty() );
285
286 mQgisApp->clipboard()->setText( QStringLiteral( "wkt_geom\ta\tb\tc\n\tMNL\t11\t282\tkm\t\t\t\n\tMNL\t11\t347.80000000000001\tkm\t\t\t" ) );
287 features = mQgisApp->clipboard()->copyOf();
288 QCOMPARE( features.length(), 2 );
289 QVERIFY( !features.at( 0 ).hasGeometry() );
290 QCOMPARE( features.at( 0 ).fields().count(), 3 );
291 QCOMPARE( features.at( 0 ).fields().at( 0 ).name(), QStringLiteral( "a" ) );
292 QCOMPARE( features.at( 0 ).fields().at( 1 ).name(), QStringLiteral( "b" ) );
293 QCOMPARE( features.at( 0 ).fields().at( 2 ).name(), QStringLiteral( "c" ) );
294 QCOMPARE( features.at( 0 ).attributes().count(), 7 );
295 QCOMPARE( features.at( 0 ).attributes().at( 0 ).toString(), QStringLiteral( "MNL" ) );
296 QCOMPARE( features.at( 0 ).attributes().at( 1 ).toString(), QStringLiteral( "11" ) );
297 QCOMPARE( features.at( 0 ).attributes().at( 2 ).toString(), QStringLiteral( "282" ) );
298 QCOMPARE( features.at( 0 ).attributes().at( 3 ).toString(), QStringLiteral( "km" ) );
299 QVERIFY( features.at( 0 ).attributes().at( 4 ).toString().isEmpty() );
300 QVERIFY( features.at( 0 ).attributes().at( 5 ).toString().isEmpty() );
301 QVERIFY( features.at( 0 ).attributes().at( 6 ).toString().isEmpty() );
302 QVERIFY( !features.at( 1 ).hasGeometry() );
303 QCOMPARE( features.at( 1 ).attributes().count(), 7 );
304 QCOMPARE( features.at( 1 ).attributes().at( 0 ).toString(), QStringLiteral( "MNL" ) );
305 QCOMPARE( features.at( 1 ).attributes().at( 1 ).toString(), QStringLiteral( "11" ) );
306 QCOMPARE( features.at( 1 ).attributes().at( 2 ).toString(), QStringLiteral( "347.80000000000001" ) );
307 QCOMPARE( features.at( 1 ).attributes().at( 3 ).toString(), QStringLiteral( "km" ) );
308 QVERIFY( features.at( 1 ).attributes().at( 4 ).toString().isEmpty() );
309 QVERIFY( features.at( 1 ).attributes().at( 5 ).toString().isEmpty() );
310 QVERIFY( features.at( 1 ).attributes().at( 6 ).toString().isEmpty() );
311
312 mQgisApp->clipboard()->setText( QStringLiteral( "wkt_geom\ta\tb\tc\nNULL\t1\tb\t2\nNULL\t3\tc3\t4\nPoint (5 4)\t2\tb2\t3" ) );
313 features = mQgisApp->clipboard()->copyOf();
314 QCOMPARE( features.length(), 3 );
315 QCOMPARE( features.at( 0 ).fields().count(), 3 );
316 QCOMPARE( features.at( 0 ).fields().at( 0 ).name(), QStringLiteral( "a" ) );
317 QCOMPARE( features.at( 0 ).fields().at( 1 ).name(), QStringLiteral( "b" ) );
318 QCOMPARE( features.at( 0 ).fields().at( 2 ).name(), QStringLiteral( "c" ) );
319 QVERIFY( !features.at( 0 ).hasGeometry() );
320 QCOMPARE( features.at( 0 ).attributes().count(), 3 );
321 QCOMPARE( features.at( 0 ).attributes().at( 0 ).toString(), QStringLiteral( "1" ) );
322 QCOMPARE( features.at( 0 ).attributes().at( 1 ).toString(), QStringLiteral( "b" ) );
323 QCOMPARE( features.at( 0 ).attributes().at( 2 ).toString(), QStringLiteral( "2" ) );
324 QVERIFY( !features.at( 1 ).hasGeometry() );
325 QCOMPARE( features.at( 1 ).attributes().count(), 3 );
326 QCOMPARE( features.at( 1 ).attributes().at( 0 ).toString(), QStringLiteral( "3" ) );
327 QCOMPARE( features.at( 1 ).attributes().at( 1 ).toString(), QStringLiteral( "c3" ) );
328 QCOMPARE( features.at( 1 ).attributes().at( 2 ).toString(), QStringLiteral( "4" ) );
329 QCOMPARE( features.at( 2 ).geometry().asWkt(), QStringLiteral( "Point (5 4)" ) );
330 QCOMPARE( features.at( 2 ).attributes().count(), 3 );
331 QCOMPARE( features.at( 2 ).attributes().at( 0 ).toString(), QStringLiteral( "2" ) );
332 QCOMPARE( features.at( 2 ).attributes().at( 1 ).toString(), QStringLiteral( "b2" ) );
333 QCOMPARE( features.at( 2 ).attributes().at( 2 ).toString(), QStringLiteral( "3" ) );
334
335 // when a set of features is built outside of QGIS, last one might be terminated by newline
336 // https://github.com/qgis/QGIS/issues/33617
337 mQgisApp->clipboard()->setText( QStringLiteral( "POINT (125 10)\nPOINT (111 30)\n" ) );
338 features = mQgisApp->clipboard()->copyOf();
339 QCOMPARE( features.length(), 2 );
340 QVERIFY( features.at( 0 ).hasGeometry() && !features.at( 0 ).geometry().isNull() );
341 QCOMPARE( features.at( 0 ).geometry().constGet()->wkbType(), QgsWkbTypes::Point );
342 featureGeom = features.at( 0 ).geometry();
343 point = dynamic_cast< const QgsPoint * >( featureGeom.constGet() );
344 QCOMPARE( point->x(), 125.0 );
345 QCOMPARE( point->y(), 10.0 );
346 QVERIFY( features.at( 1 ).hasGeometry() && !features.at( 1 ).geometry().isNull() );
347 QCOMPARE( features.at( 1 ).geometry().constGet()->wkbType(), QgsWkbTypes::Point );
348 point = dynamic_cast< const QgsPoint * >( features.at( 1 ).geometry().constGet() );
349 QCOMPARE( point->x(), 111.0 );
350 QCOMPARE( point->y(), 30.0 );
351
352 // on MS Windows, the <EOL> marker is CRLF
353 // https://github.com/qgis/QGIS/pull/33618#discussion_r363147854
354 mQgisApp->clipboard()->setText( QStringLiteral( "POINT (125 10)\r\nPOINT (111 30)\r\n" ) );
355 features = mQgisApp->clipboard()->copyOf();
356 QCOMPARE( features.length(), 2 );
357 QVERIFY( features.at( 0 ).hasGeometry() && !features.at( 0 ).geometry().isNull() );
358 QCOMPARE( features.at( 0 ).geometry().constGet()->wkbType(), QgsWkbTypes::Point );
359 featureGeom = features.at( 0 ).geometry();
360 point = dynamic_cast< const QgsPoint * >( featureGeom.constGet() );
361 QCOMPARE( point->x(), 125.0 );
362 QCOMPARE( point->y(), 10.0 );
363 QVERIFY( features.at( 1 ).hasGeometry() && !features.at( 1 ).geometry().isNull() );
364 QCOMPARE( features.at( 1 ).geometry().constGet()->wkbType(), QgsWkbTypes::Point );
365 point = dynamic_cast< const QgsPoint * >( features.at( 1 ).geometry().constGet() );
366 QCOMPARE( point->x(), 111.0 );
367 QCOMPARE( point->y(), 30.0 );
368 }
369
pasteGeoJson()370 void TestQgisAppClipboard::pasteGeoJson()
371 {
372 QgsFields fields;
373 fields.append( QgsField( QStringLiteral( "name" ), QVariant::String ) );
374 mQgisApp->clipboard()->setText( QStringLiteral( "{\n\"type\": \"Feature\",\"geometry\": {\"type\": \"Point\",\"coordinates\": [125, 10]},\"properties\": {\"name\": \"Dinagat Islands\"}}" ) );
375
376 QgsFeatureList features = mQgisApp->clipboard()->copyOf( fields );
377 QCOMPARE( features.length(), 1 );
378 QVERIFY( features.at( 0 ).hasGeometry() && !features.at( 0 ).geometry().isNull() );
379 QCOMPARE( features.at( 0 ).geometry().constGet()->wkbType(), QgsWkbTypes::Point );
380 QgsGeometry featureGeom = features.at( 0 ).geometry();
381 const QgsPoint *point = dynamic_cast< const QgsPoint * >( featureGeom.constGet() );
382 QCOMPARE( point->x(), 125.0 );
383 QCOMPARE( point->y(), 10.0 );
384 QCOMPARE( features.at( 0 ).attribute( "name" ).toString(), QString( "Dinagat Islands" ) );
385 }
386
retrieveFields()387 void TestQgisAppClipboard::retrieveFields()
388 {
389 //empty string
390 mQgisApp->clipboard()->setText( QString() );
391
392 QgsFields fields = mQgisApp->clipboard()->fields();
393 QCOMPARE( fields.count(), 0 );
394
395 // bad string
396 mQgisApp->clipboard()->setText( QStringLiteral( "asdasdas" ) );
397 fields = mQgisApp->clipboard()->fields();
398 QCOMPARE( fields.count(), 0 );
399
400 // geojson string
401 mQgisApp->clipboard()->setText( QStringLiteral( "{\n\"type\": \"Feature\",\"geometry\": {\"type\": \"Point\",\"coordinates\": [125, 10]},\"properties\": {\"name\": \"Dinagat Islands\",\"height\":5.5}}" ) );
402 fields = mQgisApp->clipboard()->fields();
403 QCOMPARE( fields.count(), 2 );
404 QCOMPARE( fields.at( 0 ).name(), QString( "name" ) );
405 QCOMPARE( fields.at( 0 ).type(), QVariant::String );
406 QCOMPARE( fields.at( 1 ).name(), QString( "height" ) );
407 QCOMPARE( fields.at( 1 ).type(), QVariant::Double );
408 }
409
clipboardLogic()410 void TestQgisAppClipboard::clipboardLogic()
411 {
412 //start by setting clipboard contents as text
413 mQgisApp->clipboard()->setText( QStringLiteral( "{\n\"type\": \"Feature\",\"geometry\": {\"type\": \"Point\",\"coordinates\": [125, 10]},\"properties\": {\"name\": \"Dinagat Islands\"}}" ) );
414 QgsFields fields = mQgisApp->clipboard()->fields();
415 QCOMPARE( fields.count(), 1 );
416 QCOMPARE( fields.at( 0 ).name(), QString( "name" ) );
417 QCOMPARE( fields.at( 0 ).type(), QVariant::String );
418 QgsFeatureList features = mQgisApp->clipboard()->copyOf( mQgisApp->clipboard()->fields() );
419 QCOMPARE( features.length(), 1 );
420 QCOMPARE( features.at( 0 ).attribute( "name" ).toString(), QString( "Dinagat Islands" ) );
421
422 //set clipboard to some QgsFeatures
423 fields = QgsFields();
424 fields.append( QgsField( QStringLiteral( "int_field" ), QVariant::Int ) );
425 fields.append( QgsField( QStringLiteral( "date_field" ), QVariant::Date ) );
426 QgsFeature feat( fields, 5 );
427 feat.setAttribute( QStringLiteral( "int_field" ), 9 );
428 feat.setAttribute( QStringLiteral( "date_field" ), QVariant( QDate( 2010, 9, 5 ) ) );
429 QgsFeature feat2( fields, 6 );
430 feat2.setAttribute( QStringLiteral( "int_field" ), 19 );
431 feat2.setAttribute( QStringLiteral( "date_field" ), QVariant( QDate( 2011, 9, 5 ) ) );
432 QgsFeatureStore feats;
433 feats.addFeature( feat );
434 feats.addFeature( feat2 );
435 feats.setFields( fields );
436 QgsCoordinateReferenceSystem crs( QStringLiteral( "EPSG:4326" ) );
437 feats.setCrs( crs );
438 mQgisApp->clipboard()->replaceWithCopyOf( feats );
439
440 //test result
441 fields = mQgisApp->clipboard()->fields();
442 QCOMPARE( fields.count(), 2 );
443 QCOMPARE( fields.at( 0 ).name(), QString( "int_field" ) );
444 QCOMPARE( fields.at( 0 ).type(), QVariant::Int );
445 QCOMPARE( fields.at( 1 ).name(), QString( "date_field" ) );
446 QCOMPARE( fields.at( 1 ).type(), QVariant::Date );
447 features = mQgisApp->clipboard()->copyOf( mQgisApp->clipboard()->fields() );
448 QCOMPARE( features.length(), 2 );
449 QCOMPARE( features.at( 0 ).id(), 5LL );
450 QCOMPARE( features.at( 0 ).attribute( "int_field" ).toInt(), 9 );
451 QCOMPARE( features.at( 0 ).attribute( "date_field" ).toDate(), QDate( 2010, 9, 5 ) );
452 QCOMPARE( features.at( 1 ).id(), 6LL );
453 QCOMPARE( features.at( 1 ).attribute( "int_field" ).toInt(), 19 );
454 QCOMPARE( features.at( 1 ).attribute( "date_field" ).toDate(), QDate( 2011, 9, 5 ) );
455
456 //replace with text again, make sure system clipboard is used rather than internal clipboard
457 mQgisApp->clipboard()->setText( QStringLiteral( "{\n\"type\": \"Feature\",\"geometry\": {\"type\": \"Point\",\"coordinates\": [125, 10]},\"properties\": {\"name\": \"Dinagat Islands\"}}" ) );
458 fields = mQgisApp->clipboard()->fields();
459 QCOMPARE( fields.count(), 1 );
460 QCOMPARE( fields.at( 0 ).name(), QString( "name" ) );
461 QCOMPARE( fields.at( 0 ).type(), QVariant::String );
462 features = mQgisApp->clipboard()->copyOf( mQgisApp->clipboard()->fields() );
463 QCOMPARE( features.length(), 1 );
464 QCOMPARE( features.at( 0 ).attribute( "name" ).toString(), QString( "Dinagat Islands" ) );
465 }
466
467 QGSTEST_MAIN( TestQgisAppClipboard )
468 #include "testqgisappclipboard.moc"
469