Skip to content

Commit a495c8c

Browse files
committedMay 20, 2015
Test suite for QgsFeature (preparation for implicit sharing of
QgsFeature)
1 parent 42f0993 commit a495c8c

File tree

2 files changed

+367
-0
lines changed

2 files changed

+367
-0
lines changed
 

‎tests/src/core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ ADD_QGIS_TEST(diagramexpressiontest testqgsdiagramexpression.cpp)
8585
ADD_QGIS_TEST(expressiontest testqgsexpression.cpp)
8686
ADD_QGIS_TEST(fieldtest testqgsfield.cpp)
8787
ADD_QGIS_TEST(fieldstest testqgsfields.cpp)
88+
ADD_QGIS_TEST(featuretest testqgsfeature.cpp)
8889
ADD_QGIS_TEST(scaleexpressiontest testqgsscaleexpression.cpp)
8990
ADD_QGIS_TEST(filewritertest testqgsvectorfilewriter.cpp)
9091
ADD_QGIS_TEST(projecttest testqgsproject.cpp)

‎tests/src/core/testqgsfeature.cpp

Lines changed: 366 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,366 @@
1+
/***************************************************************************
2+
testqgsfeature.cpp
3+
------------------
4+
Date : May 2015
5+
Copyright : (C) 2015 Nyall Dawson
6+
Email : nyall dot dawson at gmail dot 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 <QtTest/QtTest>
16+
#include <QObject>
17+
#include <QString>
18+
#include <QStringList>
19+
#include <QSettings>
20+
#include <QSharedPointer>
21+
22+
#include "qgsfeature.h"
23+
#include "qgsfield.h"
24+
#include "qgsgeometry.h"
25+
26+
class TestQgsFeature: public QObject
27+
{
28+
Q_OBJECT
29+
30+
private slots:
31+
void initTestCase();// will be called before the first testfunction is executed.
32+
void cleanupTestCase();// will be called after the last testfunction was executed.
33+
void init();// will be called before each testfunction is executed.
34+
void cleanup();// will be called after every testfunction.
35+
void create();//test creating a data defined container
36+
void copy();// test cpy destruction (double delete)
37+
void assignment();
38+
void gettersSetters(); //test getters and setters
39+
void attributes();
40+
void geometry();
41+
void asVariant(); //test conversion to and from a QVariant
42+
void fields();
43+
void attributeUsingField();
44+
45+
46+
private:
47+
48+
QgsFields mFields;
49+
QgsAttributes mAttrs;
50+
QScopedPointer<QgsGeometry> mGeometry;
51+
QScopedPointer<QgsGeometry> mGeometry2;
52+
};
53+
54+
void TestQgsFeature::initTestCase()
55+
{
56+
//add fields
57+
QgsField field( "field1" );
58+
mFields.append( field );
59+
QgsField field2( "field2" );
60+
mFields.append( field2 );
61+
QgsField field3( "field3" );
62+
mFields.append( field3 );
63+
64+
//test attributes
65+
mAttrs << QVariant( 5 ) << QVariant( 7 ) << QVariant( "val" );
66+
67+
mGeometry.reset( QgsGeometry::fromWkt( "MULTILINESTRING((0 0, 10 0, 10 10, 20 10),(30 30, 40 30, 40 40, 50 40))" ) );
68+
mGeometry2.reset( QgsGeometry::fromWkt( "MULTILINESTRING((0 5, 15 0, 15 10, 25 10))" ) );
69+
}
70+
71+
void TestQgsFeature::cleanupTestCase()
72+
{
73+
74+
}
75+
76+
void TestQgsFeature::init()
77+
{
78+
79+
}
80+
81+
void TestQgsFeature::cleanup()
82+
{
83+
84+
}
85+
86+
void TestQgsFeature::create()
87+
{
88+
//test constructors
89+
90+
QgsFeature featureFromId( 1000LL );
91+
QCOMPARE( featureFromId.id(), 1000LL );
92+
QCOMPARE( featureFromId.isValid(), false );
93+
QVERIFY( featureFromId.attributes().isEmpty() );
94+
95+
QgsFeature featureFromFieldsId( mFields, 1001LL );
96+
QCOMPARE( featureFromFieldsId.id(), 1001LL );
97+
QCOMPARE( *featureFromFieldsId.fields(), mFields );
98+
QCOMPARE( featureFromFieldsId.isValid(), false );
99+
//should be 3 invalid attributes
100+
QCOMPARE( featureFromFieldsId.attributes().count(), 3 );
101+
foreach ( QVariant a, featureFromFieldsId.attributes() )
102+
{
103+
QVERIFY( !a.isValid() );
104+
}
105+
}
106+
107+
void TestQgsFeature::copy()
108+
{
109+
QgsFeature original( 1000LL );
110+
original.setAttributes( mAttrs );
111+
112+
QgsFeature copy( original );
113+
QVERIFY( copy.id() == original.id() );
114+
QCOMPARE( copy.attributes(), original.attributes() );
115+
116+
copy.setFeatureId( 1001LL );
117+
QCOMPARE( original.id(), 1000LL );
118+
QVERIFY( copy.id() != original.id() );
119+
}
120+
121+
void TestQgsFeature::assignment()
122+
{
123+
QgsFeature original( 1000LL );
124+
original.setAttributes( mAttrs );
125+
QgsFeature copy;
126+
copy = original;
127+
QCOMPARE( copy.id(), original.id() );
128+
QCOMPARE( copy.attributes(), original.attributes() );
129+
130+
copy.setFeatureId( 1001LL );
131+
QCOMPARE( original.id(), 1000LL );
132+
QVERIFY( copy.id() != original.id() );
133+
QCOMPARE( copy.attributes(), original.attributes() );
134+
}
135+
136+
void TestQgsFeature::gettersSetters()
137+
{
138+
QgsFeature feature;
139+
feature.setFeatureId( 1000LL );
140+
QCOMPARE( feature.id(), 1000LL );
141+
142+
feature.setValid( true );
143+
QCOMPARE( feature.isValid(), true );
144+
145+
}
146+
147+
void TestQgsFeature::attributes()
148+
{
149+
QgsFeature feature;
150+
feature.setAttributes( mAttrs );
151+
QCOMPARE( feature.attributes(), mAttrs );
152+
QCOMPARE( feature.attributes(), mAttrs );
153+
154+
//test implicit sharing detachment
155+
QgsFeature copy( feature );
156+
QCOMPARE( copy.attributes(), feature.attributes() );
157+
copy.attributes().clear();
158+
QVERIFY( copy.attributes().isEmpty() );
159+
QCOMPARE( feature.attributes(), mAttrs );
160+
161+
//always start with a copy so that we can test implicit sharing detachment is working
162+
copy = feature;
163+
QCOMPARE( copy.attributes(), mAttrs );
164+
QgsAttributes newAttrs;
165+
newAttrs << QVariant( 1 ) << QVariant( 3 );
166+
copy.setAttributes( newAttrs );
167+
QCOMPARE( copy.attributes(), newAttrs );
168+
QCOMPARE( feature.attributes(), mAttrs );
169+
170+
//test setAttribute
171+
copy = feature;
172+
QCOMPARE( copy.attributes(), mAttrs );
173+
//invalid indexes
174+
QVERIFY( !copy.setAttribute( -1, 5 ) );
175+
QCOMPARE( copy.attributes(), mAttrs );
176+
QVERIFY( !copy.setAttribute( 10, 5 ) );
177+
QCOMPARE( copy.attributes(), mAttrs );
178+
//valid index
179+
QVERIFY( copy.setAttribute( 1, 15 ) );
180+
QCOMPARE( copy.attributes().at( 1 ).toInt(), 15 );
181+
QCOMPARE( feature.attributes(), mAttrs );
182+
183+
//test attribute by index
184+
QVERIFY( !feature.attribute( -1 ).isValid() );
185+
QVERIFY( !feature.attribute( 15 ).isValid() );
186+
QCOMPARE( feature.attribute( 1 ), mAttrs.at( 1 ) );
187+
188+
//test initAttributes
189+
copy = feature;
190+
QCOMPARE( copy.attributes(), mAttrs );
191+
copy.initAttributes( 5 );
192+
QCOMPARE( copy.attributes().count(), 5 );
193+
foreach ( QVariant a, copy.attributes() )
194+
{
195+
QVERIFY( !a.isValid() );
196+
}
197+
QCOMPARE( feature.attributes(), mAttrs );
198+
199+
//test deleteAttribute
200+
copy = feature;
201+
QCOMPARE( copy.attributes(), mAttrs );
202+
copy.deleteAttribute( 1 );
203+
QCOMPARE( copy.attributes().count(), 2 );
204+
QCOMPARE( copy.attributes().at( 0 ).toInt(), 5 );
205+
QCOMPARE( copy.attributes().at( 1 ).toString(), QString( "val" ) );
206+
QCOMPARE( feature.attributes(), mAttrs );
207+
}
208+
209+
void TestQgsFeature::geometry()
210+
{
211+
QgsFeature feature;
212+
//test no double delete of geometry when setting:
213+
feature.setGeometry( new QgsGeometry( *mGeometry2.data() ) );
214+
feature.setGeometry( new QgsGeometry( *mGeometry.data() ) );
215+
QCOMPARE( *feature.constGeometry()->asWkb(), *mGeometry.data()->asWkb() );
216+
217+
//test implicit sharing detachment
218+
QgsFeature copy( feature );
219+
QCOMPARE( *copy.constGeometry()->asWkb(), *feature.constGeometry()->asWkb() );
220+
copy.setGeometry( 0 );
221+
QVERIFY( ! copy.constGeometry() );
222+
QCOMPARE( *feature.constGeometry()->asWkb(), *mGeometry.data()->asWkb() );
223+
224+
//setGeometry
225+
//always start with a copy so that we can test implicit sharing detachment is working
226+
copy = feature;
227+
QCOMPARE( *copy.constGeometry()->asWkb(), *mGeometry.data()->asWkb() );
228+
copy.setGeometry( new QgsGeometry( *mGeometry2.data() ) );
229+
QCOMPARE( *copy.constGeometry()->asWkb(), *mGeometry2.data()->asWkb() );
230+
QCOMPARE( *feature.constGeometry()->asWkb(), *mGeometry.data()->asWkb() );
231+
232+
//test that non-const geometry triggers a detach
233+
copy = feature;
234+
QCOMPARE( *copy.constGeometry()->asWkb(), *mGeometry.data()->asWkb() );
235+
copy.geometry()->convertToType( QGis::Line );
236+
QScopedPointer<QgsGeometry> expected( new QgsGeometry( *mGeometry.data() ) );
237+
expected->convertToType( QGis::Line );
238+
QCOMPARE( *copy.constGeometry()->asWkb(), *expected->asWkb() );
239+
QCOMPARE( *feature.constGeometry()->asWkb(), *mGeometry.data()->asWkb() );
240+
241+
//setGeometry using reference
242+
copy = feature;
243+
QCOMPARE( *copy.constGeometry()->asWkb(), *mGeometry.data()->asWkb() );
244+
QgsGeometry geomByRef( *mGeometry2.data() );
245+
copy.setGeometry( geomByRef );
246+
QCOMPARE( *copy.constGeometry()->asWkb(), *geomByRef.asWkb() );
247+
QCOMPARE( *feature.constGeometry()->asWkb(), *mGeometry.data()->asWkb() );
248+
249+
//setGeometryAndOwnership
250+
copy = feature;
251+
QCOMPARE( *copy.constGeometry()->asWkb(), *mGeometry.data()->asWkb() );
252+
size_t wkbSize = mGeometry2->wkbSize();
253+
unsigned char* wkb = ( unsigned char* )malloc( wkbSize );
254+
memcpy( wkb, mGeometry2->asWkb(), wkbSize );
255+
copy.setGeometryAndOwnership( wkb, wkbSize );
256+
QCOMPARE( *copy.constGeometry()->asWkb(), *mGeometry2->asWkb() );
257+
QCOMPARE( *feature.constGeometry()->asWkb(), *mGeometry.data()->asWkb() );
258+
259+
//geometryAndOwnership
260+
copy = feature;
261+
QCOMPARE( *copy.constGeometry()->asWkb(), *mGeometry.data()->asWkb() );
262+
QgsGeometry* geom1 = copy.geometryAndOwnership();
263+
QCOMPARE( *geom1->asWkb(), *mGeometry->asWkb() );
264+
QgsGeometry* geom2 = feature.geometryAndOwnership();
265+
QCOMPARE( *geom2->asWkb(), *mGeometry->asWkb() );
266+
delete geom1;
267+
delete geom2;
268+
}
269+
270+
void TestQgsFeature::asVariant()
271+
{
272+
QgsFeature original( mFields, 1001LL );
273+
274+
//convert to and from a QVariant
275+
QVariant var = QVariant::fromValue( original );
276+
QVERIFY( var.isValid() );
277+
278+
QgsFeature fromVar = qvariant_cast<QgsFeature>( var );
279+
//QCOMPARE( fromVar, original );
280+
QCOMPARE( fromVar.id(), original.id() );
281+
QCOMPARE( *fromVar.fields(), *original.fields() );
282+
}
283+
284+
void TestQgsFeature::fields()
285+
{
286+
QgsFeature original;
287+
QVERIFY( original.fields()->isEmpty() );
288+
original.setFields( &mFields );
289+
QCOMPARE( *original.fields(), mFields );
290+
QgsFeature copy( original );
291+
QCOMPARE( *copy.fields(), *original.fields() );
292+
293+
//test detach
294+
QgsFields newFields( mFields );
295+
newFields.remove( 2 );
296+
copy.setFields( &newFields );
297+
QCOMPARE( *copy.fields(), newFields );
298+
QCOMPARE( *original.fields(), mFields );
299+
300+
//test that no init leaves attributes
301+
copy = original;
302+
copy.initAttributes( 3 );
303+
copy.setAttribute( 0, 1 );
304+
copy.setAttribute( 1, 2 );
305+
copy.setAttribute( 2, 3 );
306+
copy.setFields( &mFields, false );
307+
QCOMPARE( *copy.fields(), mFields );
308+
//should be 3 invalid attributes
309+
QCOMPARE( copy.attributes().count(), 3 );
310+
QCOMPARE( copy.attributes().at( 0 ).toInt(), 1 );
311+
QCOMPARE( copy.attributes().at( 1 ).toInt(), 2 );
312+
QCOMPARE( copy.attributes().at( 2 ).toInt(), 3 );
313+
314+
//test setting fields with init
315+
copy = original;
316+
copy.initAttributes( 3 );
317+
copy.setAttribute( 0, 1 );
318+
copy.setAttribute( 1, 2 );
319+
copy.setAttribute( 2, 3 );
320+
copy.setFields( &mFields, true );
321+
QCOMPARE( *copy.fields(), mFields );
322+
//should be 3 invalid attributes
323+
QCOMPARE( copy.attributes().count(), 3 );
324+
foreach ( QVariant a, copy.attributes() )
325+
{
326+
QVERIFY( !a.isValid() );
327+
}
328+
329+
//test fieldNameIndex
330+
copy = original;
331+
copy.setFields( &mFields );
332+
QCOMPARE( copy.fieldNameIndex( "bad" ), -1 );
333+
QCOMPARE( copy.fieldNameIndex( "field1" ), 0 );
334+
QCOMPARE( copy.fieldNameIndex( "field2" ), 1 );
335+
}
336+
337+
void TestQgsFeature::attributeUsingField()
338+
{
339+
QgsFeature feature;
340+
feature.setFields( &mFields, true );
341+
feature.setAttribute( 0, QString( "attr1" ) );
342+
feature.setAttribute( 1, QString( "attr2" ) );
343+
feature.setAttribute( 2, QString( "attr3" ) );
344+
345+
QVERIFY( !feature.attribute( "bad" ).isValid() );
346+
QCOMPARE( feature.attribute( "field1" ).toString(), QString( "attr1" ) );
347+
QCOMPARE( feature.attribute( "field2" ).toString(), QString( "attr2" ) );
348+
349+
//setAttribute using field name
350+
QVERIFY( !feature.setAttribute( "bad", QString( "test" ) ) );
351+
QgsFeature copy( feature );
352+
QVERIFY( copy.setAttribute( "field1", QString( "test" ) ) );
353+
QCOMPARE( copy.attribute( "field1" ).toString(), QString( "test" ) );
354+
//test that copy has been detached
355+
QCOMPARE( feature.attribute( "field1" ).toString(), QString( "attr1" ) );
356+
357+
//deleteAttribute by name
358+
copy = feature;
359+
QVERIFY( !copy.deleteAttribute( "bad" ) );
360+
QVERIFY( copy.deleteAttribute( "field1" ) );
361+
QVERIFY( !copy.attribute( "field1" ).isValid() );
362+
QVERIFY( feature.attribute( "field1" ).isValid() );
363+
}
364+
365+
QTEST_MAIN( TestQgsFeature )
366+
#include "testqgsfeature.moc"

0 commit comments

Comments
 (0)
Please sign in to comment.