Line data Source code
1 : ///////////////////////////////////////////////////////////////////////////////
2 : //
3 : // Project: C++ Test Suite for GDAL/OGR
4 : // Purpose: Shapefile driver testing. Ported from ogr/ogr_shape.py.
5 : // Author: Mateusz Loskot <mateusz@loskot.net>
6 : //
7 : ///////////////////////////////////////////////////////////////////////////////
8 : // Copyright (c) 2006, Mateusz Loskot <mateusz@loskot.net>
9 : // Copyright (c) 2010, Even Rouault <even dot rouault at spatialys.com>
10 : /*
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "gdal_unit_test.h"
31 :
32 : #include "ogr_api.h"
33 : #include "ogrsf_frmts.h"
34 :
35 : #include <algorithm>
36 : #include <iterator>
37 : #include <string>
38 : #include <vector>
39 :
40 : #include "gtest_include.h"
41 :
42 : namespace
43 : {
44 : using namespace tut; // for CheckEqualGeometries
45 :
46 : // Test data
47 : struct test_ogr_shape : public ::testing::Test
48 : {
49 : OGRSFDriverH drv_ = nullptr;
50 : const char *drv_name_ = "ESRI Shapefile";
51 : std::string data_{};
52 : std::string data_tmp_{};
53 : const char *test_name_ = nullptr;
54 :
55 7 : test_ogr_shape()
56 7 : {
57 7 : drv_ = OGRGetDriverByName(drv_name_);
58 :
59 : // Compose data path for test group
60 7 : data_ = tut::common::data_basedir;
61 7 : data_tmp_ = tut::common::tmp_basedir;
62 7 : }
63 :
64 7 : void TearDown() override
65 : {
66 : OGRDataSourceH ds =
67 7 : OGR_Dr_CreateDataSource(drv_, data_tmp_.c_str(), nullptr);
68 7 : if (ds == nullptr)
69 : {
70 0 : return;
71 : }
72 :
73 7 : if (test_name_)
74 : {
75 7 : const int nlyr = OGR_DS_GetLayerCount(ds);
76 13 : for (int i = 0; i < nlyr; i++)
77 : {
78 6 : OGRLayerH lyr = OGR_DS_GetLayer(ds, i);
79 6 : if (EQUAL(OGR_L_GetName(lyr), test_name_))
80 : {
81 6 : OGR_DS_DeleteLayer(ds, i);
82 : }
83 : }
84 : }
85 : }
86 :
87 7 : void SetUp() override
88 : {
89 7 : if (drv_ == nullptr)
90 : {
91 0 : GTEST_SKIP() << "ESRI Shapefile driver missing";
92 : return;
93 : }
94 :
95 7 : test_name_ =
96 7 : ::testing::UnitTest::GetInstance()->current_test_info()->name();
97 :
98 7 : OGRErr err = OGRERR_NONE;
99 :
100 7 : OGRDataSourceH ds = nullptr;
101 7 : ds = OGR_Dr_CreateDataSource(drv_, data_tmp_.c_str(), nullptr);
102 7 : ASSERT_TRUE(nullptr != ds);
103 :
104 : // Create memory Layer
105 7 : OGRLayerH lyr = nullptr;
106 7 : lyr = OGR_DS_CreateLayer(ds, test_name_, nullptr, wkbPolygon, nullptr);
107 7 : EXPECT_TRUE(nullptr != lyr);
108 7 : if (lyr == nullptr)
109 : {
110 0 : OGR_DS_Destroy(ds);
111 0 : return;
112 : }
113 :
114 : // Create schema
115 7 : OGRFieldDefnH fld = nullptr;
116 :
117 7 : fld = OGR_Fld_Create("AREA", OFTReal);
118 7 : err = OGR_L_CreateField(lyr, fld, true);
119 7 : OGR_Fld_Destroy(fld);
120 7 : EXPECT_EQ(OGRERR_NONE, err);
121 :
122 7 : fld = OGR_Fld_Create("EAS_ID", OFTInteger);
123 7 : err = OGR_L_CreateField(lyr, fld, true);
124 7 : OGR_Fld_Destroy(fld);
125 7 : EXPECT_EQ(OGRERR_NONE, err);
126 :
127 7 : fld = OGR_Fld_Create("PRFEDEA", OFTString);
128 7 : err = OGR_L_CreateField(lyr, fld, true);
129 7 : OGR_Fld_Destroy(fld);
130 7 : EXPECT_EQ(OGRERR_NONE, err);
131 :
132 : // Check schema
133 7 : OGRFeatureDefnH featDefn = OGR_L_GetLayerDefn(lyr);
134 7 : ASSERT_TRUE(nullptr != featDefn);
135 7 : EXPECT_EQ(3, OGR_FD_GetFieldCount(featDefn));
136 :
137 : // Copy ogr/poly.shp to temporary layer
138 7 : OGRFeatureH featDst = OGR_F_Create(featDefn);
139 7 : EXPECT_TRUE(nullptr != featDst);
140 7 : if (featDst)
141 : {
142 14 : std::string source(data_);
143 7 : source += SEP;
144 7 : source += "poly.shp";
145 7 : OGRDataSourceH dsSrc = OGR_Dr_Open(drv_, source.c_str(), false);
146 7 : EXPECT_TRUE(nullptr != dsSrc);
147 7 : if (dsSrc)
148 : {
149 7 : OGRLayerH lyrSrc = OGR_DS_GetLayer(dsSrc, 0);
150 7 : EXPECT_TRUE(nullptr != lyrSrc);
151 7 : if (lyrSrc)
152 : {
153 7 : OGRFeatureH featSrc = nullptr;
154 77 : while (nullptr != (featSrc = OGR_L_GetNextFeature(lyrSrc)))
155 : {
156 70 : err = OGR_F_SetFrom(featDst, featSrc, true);
157 70 : EXPECT_EQ(OGRERR_NONE, err);
158 :
159 70 : err = OGR_L_CreateFeature(lyr, featDst);
160 70 : EXPECT_EQ(OGRERR_NONE, err);
161 :
162 70 : OGR_F_Destroy(featSrc);
163 : }
164 : }
165 : // Release and close resources
166 :
167 7 : OGR_DS_Destroy(dsSrc);
168 : }
169 7 : OGR_F_Destroy(featDst);
170 : }
171 7 : OGR_DS_Destroy(ds);
172 : }
173 : };
174 :
175 : //
176 : // Template of attribute reading function and its specializations
177 : //
178 : template <typename T> inline void read_feature_attribute(OGRFeatureH, int, T &)
179 : {
180 : assert(!"Can't find read_feature_attribute specialization for given type");
181 : }
182 :
183 : template <>
184 16 : inline void read_feature_attribute(OGRFeatureH feature, int index, int &val)
185 : {
186 16 : val = OGR_F_GetFieldAsInteger(feature, index);
187 16 : }
188 :
189 : #ifdef unused
190 : template <>
191 : inline void read_feature_attribute(OGRFeatureH feature, int index, double &val)
192 : {
193 : val = OGR_F_GetFieldAsDouble(feature, index);
194 : }
195 : #endif
196 :
197 : template <>
198 1 : inline void read_feature_attribute(OGRFeatureH feature, int index,
199 : std::string &val)
200 : {
201 1 : val = OGR_F_GetFieldAsString(feature, index);
202 1 : }
203 :
204 : //
205 : // Test layer attributes from given field against expected list of values
206 : //
207 : template <typename T>
208 : ::testing::AssertionResult
209 4 : CheckEqualAttributes(OGRLayerH layer, std::string const &field, T const &list)
210 : {
211 : // Test raw pointers
212 4 : if (nullptr == layer)
213 : {
214 0 : return ::testing::AssertionFailure() << "Layer is NULL";
215 : }
216 :
217 4 : OGRFeatureDefnH featDefn = OGR_L_GetLayerDefn(layer);
218 4 : if (nullptr == featDefn)
219 : {
220 0 : return ::testing::AssertionFailure() << "Layer schema is NULL";
221 : }
222 :
223 4 : int fldIndex = OGR_FD_GetFieldIndex(featDefn, field.c_str());
224 4 : if (fldIndex < 0)
225 : {
226 0 : return ::testing::AssertionFailure() << "Can't find field " << field;
227 : }
228 :
229 : // Test value in tested field from subsequent features
230 4 : OGRFeatureH feat = nullptr;
231 4 : OGRFieldDefnH fldDefn = nullptr;
232 2 : typename T::value_type attrVal;
233 :
234 21 : for (const auto &attr : list)
235 : {
236 17 : feat = OGR_L_GetNextFeature(layer);
237 :
238 17 : fldDefn = OGR_F_GetFieldDefnRef(feat, fldIndex);
239 17 : if (nullptr == fldDefn)
240 : {
241 0 : return ::testing::AssertionFailure() << "Field schema is NULL";
242 : }
243 :
244 17 : read_feature_attribute(feat, fldIndex, attrVal);
245 :
246 17 : OGR_F_Destroy(feat);
247 :
248 : // Test attribute against expected value
249 17 : if (attr != attrVal)
250 : {
251 : return ::testing::AssertionFailure()
252 0 : << "Attributes not equal. Expected " << attr << ", got "
253 0 : << attrVal;
254 : }
255 : }
256 :
257 : // Check if not too many features filtered
258 4 : feat = OGR_L_GetNextFeature(layer);
259 4 : OGR_F_Destroy(feat);
260 :
261 4 : if (nullptr != feat)
262 : {
263 : return ::testing::AssertionFailure()
264 0 : << "Got more features than expected";
265 : }
266 4 : return ::testing::AssertionSuccess();
267 : }
268 :
269 : // Test Create/Destroy empty directory datasource
270 4 : TEST_F(test_ogr_shape, create)
271 : {
272 : // Try to remove tmp and ignore error code
273 1 : OGR_Dr_DeleteDataSource(drv_, data_tmp_.c_str());
274 :
275 1 : OGRDataSourceH ds = nullptr;
276 1 : ds = OGR_Dr_CreateDataSource(drv_, data_tmp_.c_str(), nullptr);
277 1 : ASSERT_TRUE(nullptr != ds);
278 :
279 1 : OGR_DS_Destroy(ds);
280 : }
281 :
282 : // Test attributes written to new table
283 4 : TEST_F(test_ogr_shape, attributes)
284 : {
285 1 : OGRErr err = OGRERR_NONE;
286 1 : const int size = 5;
287 1 : const int expect[size] = {168, 169, 166, 158, 165};
288 :
289 1 : std::string source(data_tmp_);
290 1 : source += SEP;
291 1 : source += test_name_;
292 1 : source += ".shp";
293 1 : OGRDataSourceH ds = OGR_Dr_Open(drv_, source.c_str(), false);
294 1 : ASSERT_TRUE(nullptr != ds);
295 :
296 1 : OGRLayerH lyr = OGR_DS_GetLayer(ds, 0);
297 1 : EXPECT_TRUE(nullptr != lyr);
298 1 : if (lyr)
299 : {
300 1 : err = OGR_L_SetAttributeFilter(lyr, "eas_id < 170");
301 1 : EXPECT_EQ(OGRERR_NONE, err);
302 :
303 : // Prepare tester collection
304 2 : std::vector<int> list;
305 1 : std::copy(expect, expect + size, std::back_inserter(list));
306 :
307 2 : EXPECT_TRUE(CheckEqualAttributes(lyr, "eas_id", list));
308 : }
309 1 : OGR_DS_Destroy(ds);
310 : }
311 :
312 : // Test geometries written to new shapefile
313 4 : TEST_F(test_ogr_shape, geometries)
314 : {
315 : // Original shapefile
316 1 : std::string orig(data_);
317 1 : orig += SEP;
318 1 : orig += "poly.shp";
319 1 : OGRDataSourceH dsOrig = OGR_Dr_Open(drv_, orig.c_str(), false);
320 1 : ASSERT_TRUE(nullptr != dsOrig);
321 :
322 1 : OGRLayerH lyrOrig = OGR_DS_GetLayer(dsOrig, 0);
323 1 : EXPECT_TRUE(nullptr != lyrOrig);
324 1 : if (lyrOrig)
325 : {
326 : // Copied shapefile
327 2 : std::string tmp(data_tmp_);
328 1 : tmp += SEP;
329 1 : tmp += test_name_;
330 1 : tmp += ".shp";
331 1 : OGRDataSourceH dsTmp = OGR_Dr_Open(drv_, tmp.c_str(), false);
332 1 : EXPECT_TRUE(nullptr != dsTmp);
333 :
334 1 : OGRLayerH lyrTmp = OGR_DS_GetLayer(dsTmp, 0);
335 1 : EXPECT_TRUE(nullptr != lyrTmp);
336 1 : if (lyrTmp)
337 : {
338 : // Iterate through features and compare geometries
339 1 : OGRFeatureH featOrig = OGR_L_GetNextFeature(lyrOrig);
340 1 : OGRFeatureH featTmp = OGR_L_GetNextFeature(lyrTmp);
341 :
342 11 : while (nullptr != featOrig && nullptr != featTmp)
343 : {
344 10 : OGRGeometryH lhs = OGR_F_GetGeometryRef(featOrig);
345 10 : OGRGeometryH rhs = OGR_F_GetGeometryRef(featTmp);
346 :
347 10 : EXPECT_TRUE(CheckEqualGeometries(lhs, rhs, 0.000000001));
348 :
349 : // TODO: add ensure_equal_attributes()
350 :
351 10 : OGR_F_Destroy(featOrig);
352 10 : OGR_F_Destroy(featTmp);
353 :
354 : // Move to next feature
355 10 : featOrig = OGR_L_GetNextFeature(lyrOrig);
356 10 : featTmp = OGR_L_GetNextFeature(lyrTmp);
357 : }
358 : }
359 1 : OGR_DS_Destroy(dsTmp);
360 : }
361 :
362 1 : OGR_DS_Destroy(dsOrig);
363 : }
364 :
365 : // Write a feature without a geometry, then read it back
366 4 : TEST_F(test_ogr_shape, no_geometry)
367 : {
368 : // Create feature without geometry
369 1 : std::string tmp(data_tmp_);
370 1 : tmp += SEP;
371 1 : tmp += test_name_;
372 1 : tmp += ".shp";
373 :
374 : // Write the feature
375 : {
376 1 : OGRDataSourceH ds = OGR_Dr_Open(drv_, tmp.c_str(), true);
377 1 : ASSERT_TRUE(nullptr != ds);
378 :
379 1 : OGRLayerH lyr = OGR_DS_GetLayer(ds, 0);
380 1 : EXPECT_TRUE(nullptr != lyr);
381 1 : if (lyr != nullptr)
382 : {
383 1 : OGRFeatureDefnH featDefn = OGR_L_GetLayerDefn(lyr);
384 1 : EXPECT_TRUE(nullptr != featDefn);
385 :
386 1 : OGRFeatureH featNonSpatial = OGR_F_Create(featDefn);
387 1 : EXPECT_TRUE(nullptr != featNonSpatial);
388 1 : if (featDefn && featNonSpatial)
389 : {
390 1 : int fldIndex = OGR_FD_GetFieldIndex(featDefn, "PRFEDEA");
391 1 : EXPECT_TRUE(fldIndex >= 0);
392 1 : if (fldIndex >= 0)
393 : {
394 1 : OGR_F_SetFieldString(featNonSpatial, fldIndex, "nulled");
395 :
396 1 : OGRErr err = OGR_L_CreateFeature(lyr, featNonSpatial);
397 1 : EXPECT_EQ(OGRERR_NONE, err);
398 : }
399 : }
400 :
401 1 : OGR_F_Destroy(featNonSpatial);
402 : }
403 1 : OGR_DS_Destroy(ds);
404 : }
405 :
406 : // Read back the non-spatial feature and get the geometry
407 : {
408 1 : OGRDataSourceH ds = OGR_Dr_Open(drv_, tmp.c_str(), false);
409 1 : ASSERT_TRUE(nullptr != ds);
410 :
411 1 : OGRLayerH lyr = OGR_DS_GetLayer(ds, 0);
412 1 : EXPECT_TRUE(nullptr != lyr);
413 1 : if (lyr != nullptr)
414 : {
415 1 : OGRErr err = OGR_L_SetAttributeFilter(lyr, "PRFEDEA = 'nulled'");
416 1 : EXPECT_EQ(OGRERR_NONE, err);
417 :
418 : // Fetch feature without geometry
419 1 : OGRFeatureH featNonSpatial = OGR_L_GetNextFeature(lyr);
420 1 : EXPECT_TRUE(nullptr != featNonSpatial);
421 1 : if (featNonSpatial != nullptr)
422 : {
423 : // Null geometry is expected
424 1 : OGRGeometryH nonGeom = OGR_F_GetGeometryRef(featNonSpatial);
425 1 : EXPECT_TRUE(nullptr == nonGeom);
426 :
427 1 : OGR_F_Destroy(featNonSpatial);
428 : }
429 : }
430 1 : OGR_DS_Destroy(ds);
431 : }
432 : }
433 :
434 : // Test ExecuteSQL() results layers without geometry
435 4 : TEST_F(test_ogr_shape, ExecuteSQL_no_geometry)
436 : {
437 1 : const int size = 10;
438 1 : const int expect[size] = {179, 173, 172, 171, 170, 169, 168, 166, 165, 158};
439 :
440 : // Open directory as a datasource
441 1 : OGRDataSourceH ds = OGR_Dr_Open(drv_, data_.c_str(), false);
442 1 : ASSERT_TRUE(nullptr != ds);
443 :
444 2 : std::string sql("select distinct eas_id from poly order by eas_id desc");
445 1 : OGRLayerH lyr = OGR_DS_ExecuteSQL(ds, sql.c_str(), nullptr, nullptr);
446 1 : EXPECT_TRUE(nullptr != lyr);
447 1 : if (lyr)
448 : {
449 : // Prepare tester collection
450 2 : std::vector<int> list;
451 1 : std::copy(expect, expect + size, std::back_inserter(list));
452 :
453 2 : EXPECT_TRUE(CheckEqualAttributes(lyr, "eas_id", list));
454 :
455 1 : OGR_DS_ReleaseResultSet(ds, lyr);
456 : }
457 1 : OGR_DS_Destroy(ds);
458 : }
459 :
460 : // Test ExecuteSQL() results layers with geometry
461 4 : TEST_F(test_ogr_shape, ExecuteSQL_geometry)
462 : {
463 : // Open directory as a datasource
464 1 : OGRDataSourceH ds = OGR_Dr_Open(drv_, data_.c_str(), false);
465 1 : ASSERT_TRUE(nullptr != ds);
466 :
467 2 : std::string sql("select * from poly where prfedea = '35043413'");
468 1 : OGRLayerH lyr = OGR_DS_ExecuteSQL(ds, sql.c_str(), nullptr, nullptr);
469 1 : EXPECT_TRUE(nullptr != lyr);
470 1 : if (lyr)
471 : {
472 : // Prepare tester collection
473 2 : std::vector<std::string> list;
474 1 : list.push_back("35043413");
475 :
476 : // Test attributes
477 2 : EXPECT_TRUE(CheckEqualAttributes(lyr, "prfedea", list));
478 :
479 : // Test geometry
480 1 : const char *wkt =
481 : "POLYGON ((479750.688 4764702.000,479658.594 4764670.000,"
482 : "479640.094 4764721.000,479735.906 4764752.000,"
483 : "479750.688 4764702.000))";
484 :
485 1 : OGRGeometryH testGeom = nullptr;
486 1 : OGRErr err = OGR_G_CreateFromWkt((char **)&wkt, nullptr, &testGeom);
487 1 : EXPECT_EQ(OGRERR_NONE, err);
488 1 : if (testGeom)
489 : {
490 1 : OGR_L_ResetReading(lyr);
491 1 : OGRFeatureH feat = OGR_L_GetNextFeature(lyr);
492 1 : EXPECT_TRUE(nullptr != feat);
493 1 : if (feat)
494 : {
495 1 : EXPECT_TRUE(CheckEqualGeometries(OGR_F_GetGeometryRef(feat),
496 : testGeom, 0.001));
497 1 : OGR_F_Destroy(feat);
498 : }
499 1 : OGR_G_DestroyGeometry(testGeom);
500 : }
501 1 : OGR_DS_ReleaseResultSet(ds, lyr);
502 : }
503 1 : OGR_DS_Destroy(ds);
504 : }
505 :
506 : // Test spatial filtering
507 4 : TEST_F(test_ogr_shape, spatial_filtering)
508 : {
509 1 : OGRErr err = OGRERR_NONE;
510 :
511 : // Read feature without geometry
512 1 : std::string tmp(data_tmp_);
513 1 : tmp += SEP;
514 1 : tmp += "poly.shp";
515 1 : OGRDataSourceH ds = OGR_Dr_Open(drv_, data_.c_str(), false);
516 1 : ASSERT_TRUE(nullptr != ds);
517 :
518 1 : OGRLayerH lyr = OGR_DS_GetLayer(ds, 0);
519 1 : EXPECT_TRUE(nullptr != lyr);
520 1 : if (lyr)
521 : {
522 : // Set empty filter for attributes
523 1 : err = OGR_L_SetAttributeFilter(lyr, nullptr);
524 1 : EXPECT_EQ(OGRERR_NONE, err);
525 :
526 : // Set spatial filter
527 1 : const char *wkt = "LINESTRING(479505 4763195,480526 4762819)";
528 1 : OGRGeometryH filterGeom = nullptr;
529 1 : err = OGR_G_CreateFromWkt((char **)&wkt, nullptr, &filterGeom);
530 1 : ASSERT_EQ(OGRERR_NONE, err);
531 1 : if (filterGeom)
532 : {
533 1 : OGR_L_SetSpatialFilter(lyr, filterGeom);
534 :
535 : // Prepare tester collection
536 2 : std::vector<int> list;
537 1 : list.push_back(158);
538 :
539 : // Test attributes
540 2 : EXPECT_TRUE(CheckEqualAttributes(lyr, "eas_id", list));
541 :
542 1 : OGR_G_DestroyGeometry(filterGeom);
543 : }
544 : }
545 1 : OGR_DS_Destroy(ds);
546 : }
547 :
548 4 : TEST(test_ogr_shape_gdal, create)
549 : {
550 : GDALDriver *shpDriver =
551 1 : GetGDALDriverManager()->GetDriverByName("ESRI Shapefile");
552 : GDALDataset *pShpDst =
553 1 : shpDriver->Create("/vsimem/test.shp", 0, 0, 0, GDT_Unknown, nullptr);
554 1 : EXPECT_EQ(pShpDst->GetAccess(), GA_Update);
555 1 : GDALClose(pShpDst);
556 1 : }
557 :
558 : } // namespace
|