Line data Source code
1 : ///////////////////////////////////////////////////////////////////////////////
2 : //
3 : // Project: C++ Test Suite for GDAL/OGR
4 : // Purpose: Test general OGR features.
5 : // Author: Mateusz Loskot <mateusz@loskot.net>
6 : //
7 : ///////////////////////////////////////////////////////////////////////////////
8 : // Copyright (c) 2006, Mateusz Loskot <mateusz@loskot.net>
9 : /*
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "gdal_unit_test.h"
14 :
15 : #include "ogr_p.h"
16 : #include "ogrsf_frmts.h"
17 : #include "../../ogr/ogrsf_frmts/osm/gpb.h"
18 : #include "ogr_recordbatch.h"
19 :
20 : #include <string>
21 : #include <algorithm>
22 : #include <cmath>
23 : #include <fstream>
24 : #include <limits>
25 :
26 : #ifdef HAVE_SQLITE3
27 : #include <sqlite3.h>
28 : #endif
29 :
30 : #include "gtest_include.h"
31 :
32 : namespace
33 : {
34 :
35 : // Common fixture with test data
36 : struct test_ogr : public ::testing::Test
37 : {
38 : std::string data_{tut::common::data_basedir};
39 : std::string data_tmp_{tut::common::tmp_basedir};
40 : };
41 :
42 : // Test OGR driver registrar access
43 4 : TEST_F(test_ogr, GetGDALDriverManager)
44 : {
45 1 : ASSERT_TRUE(nullptr != GetGDALDriverManager());
46 : }
47 :
48 : template <class T>
49 16 : void testSpatialReferenceLeakOnCopy(OGRSpatialReference *poSRS)
50 : {
51 16 : ASSERT_EQ(1, poSRS->GetReferenceCount());
52 : {
53 : int nCurCount;
54 16 : int nLastCount = 1;
55 16 : T value;
56 16 : value.assignSpatialReference(poSRS);
57 16 : nCurCount = poSRS->GetReferenceCount();
58 16 : ASSERT_GT(nCurCount, nLastCount);
59 16 : nLastCount = nCurCount;
60 :
61 16 : T value2(value);
62 16 : nCurCount = poSRS->GetReferenceCount();
63 16 : ASSERT_GT(nCurCount, nLastCount);
64 16 : nLastCount = nCurCount;
65 :
66 16 : T value3;
67 16 : value3 = value;
68 16 : nCurCount = poSRS->GetReferenceCount();
69 16 : ASSERT_GT(nCurCount, nLastCount);
70 16 : nLastCount = nCurCount;
71 :
72 : // coverity[copy_assignment_call]
73 16 : value3 = value;
74 16 : ASSERT_EQ(nLastCount, poSRS->GetReferenceCount());
75 : }
76 16 : ASSERT_EQ(1, poSRS->GetReferenceCount());
77 : }
78 :
79 : // Test if copy does not leak or double delete the spatial reference
80 4 : TEST_F(test_ogr, SpatialReference_leak)
81 : {
82 1 : OGRSpatialReference *poSRS = new OGRSpatialReference();
83 1 : ASSERT_TRUE(nullptr != poSRS);
84 :
85 1 : testSpatialReferenceLeakOnCopy<OGRPoint>(poSRS);
86 1 : testSpatialReferenceLeakOnCopy<OGRLineString>(poSRS);
87 1 : testSpatialReferenceLeakOnCopy<OGRLinearRing>(poSRS);
88 1 : testSpatialReferenceLeakOnCopy<OGRCircularString>(poSRS);
89 1 : testSpatialReferenceLeakOnCopy<OGRCompoundCurve>(poSRS);
90 1 : testSpatialReferenceLeakOnCopy<OGRCurvePolygon>(poSRS);
91 1 : testSpatialReferenceLeakOnCopy<OGRPolygon>(poSRS);
92 1 : testSpatialReferenceLeakOnCopy<OGRGeometryCollection>(poSRS);
93 1 : testSpatialReferenceLeakOnCopy<OGRMultiSurface>(poSRS);
94 1 : testSpatialReferenceLeakOnCopy<OGRMultiPolygon>(poSRS);
95 1 : testSpatialReferenceLeakOnCopy<OGRMultiPoint>(poSRS);
96 1 : testSpatialReferenceLeakOnCopy<OGRMultiCurve>(poSRS);
97 1 : testSpatialReferenceLeakOnCopy<OGRMultiLineString>(poSRS);
98 1 : testSpatialReferenceLeakOnCopy<OGRTriangle>(poSRS);
99 1 : testSpatialReferenceLeakOnCopy<OGRPolyhedralSurface>(poSRS);
100 1 : testSpatialReferenceLeakOnCopy<OGRTriangulatedSurface>(poSRS);
101 :
102 1 : delete poSRS;
103 :
104 : // Check that assignSpatialReference() works when passed the SRS
105 : // object it already owns and whose has a single reference.
106 1 : poSRS = new OGRSpatialReference();
107 2 : OGRPoint oPoint;
108 1 : oPoint.assignSpatialReference(poSRS);
109 1 : poSRS->Release();
110 1 : oPoint.assignSpatialReference(oPoint.getSpatialReference());
111 : }
112 :
113 : template <class T> T *make();
114 :
115 6 : template <> OGRPoint *make()
116 : {
117 6 : return new OGRPoint(1.0, 2.0, 3.0);
118 : }
119 :
120 18 : template <> OGRLineString *make()
121 : {
122 18 : OGRLineString *poLineString = new OGRLineString();
123 :
124 18 : poLineString->addPoint(1.0, 2.0, 3.0);
125 18 : poLineString->addPoint(1.1, 2.1, 3.1);
126 18 : poLineString->addPoint(1.2, 2.2, 3.2);
127 :
128 18 : return poLineString;
129 : }
130 :
131 22 : template <> OGRLinearRing *make()
132 : {
133 22 : OGRLinearRing *poLinearRing = new OGRLinearRing();
134 :
135 22 : poLinearRing->addPoint(1.0, 2.0, 3.0);
136 22 : poLinearRing->addPoint(1.1, 2.1, 3.1);
137 22 : poLinearRing->addPoint(1.2, 2.2, 3.2);
138 22 : poLinearRing->addPoint(1.0, 2.0, 3.0);
139 :
140 22 : return poLinearRing;
141 : }
142 :
143 14 : template <> OGRCircularString *make()
144 : {
145 14 : OGRCircularString *poCircularString = new OGRCircularString();
146 :
147 14 : poCircularString->addPoint(1.0, 2.0, 3.0);
148 14 : poCircularString->addPoint(1.1, 2.1, 3.1);
149 14 : poCircularString->addPoint(1.2, 2.2, 3.2);
150 :
151 14 : return poCircularString;
152 : }
153 :
154 12 : template <> OGRCompoundCurve *make()
155 : {
156 12 : OGRCompoundCurve *poCompoundCurve = new OGRCompoundCurve();
157 :
158 12 : poCompoundCurve->addCurveDirectly(make<OGRLineString>());
159 12 : OGRCircularString *poCircularString = make<OGRCircularString>();
160 12 : poCircularString->reversePoints();
161 12 : poCompoundCurve->addCurveDirectly(poCircularString);
162 :
163 12 : return poCompoundCurve;
164 : }
165 :
166 4 : template <> OGRCurvePolygon *make()
167 : {
168 4 : OGRCurvePolygon *poCurvePolygon = new OGRCurvePolygon();
169 :
170 4 : poCurvePolygon->addRingDirectly(make<OGRCompoundCurve>());
171 4 : poCurvePolygon->addRingDirectly(make<OGRCompoundCurve>());
172 :
173 4 : return poCurvePolygon;
174 : }
175 :
176 8 : template <> OGRPolygon *make()
177 : {
178 8 : OGRPolygon *poPolygon = new OGRPolygon();
179 :
180 8 : poPolygon->addRingDirectly(make<OGRLinearRing>());
181 8 : poPolygon->addRingDirectly(make<OGRLinearRing>());
182 :
183 8 : return poPolygon;
184 : }
185 :
186 2 : template <> OGRGeometryCollection *make()
187 : {
188 2 : OGRGeometryCollection *poCollection = new OGRGeometryCollection();
189 :
190 2 : poCollection->addGeometryDirectly(make<OGRPoint>());
191 2 : poCollection->addGeometryDirectly(make<OGRLinearRing>());
192 :
193 2 : return poCollection;
194 : }
195 :
196 2 : template <> OGRMultiSurface *make()
197 : {
198 2 : OGRMultiSurface *poCollection = new OGRMultiSurface();
199 :
200 2 : poCollection->addGeometryDirectly(make<OGRPolygon>());
201 2 : poCollection->addGeometryDirectly(make<OGRCurvePolygon>());
202 :
203 2 : return poCollection;
204 : }
205 :
206 2 : template <> OGRMultiPolygon *make()
207 : {
208 2 : OGRMultiPolygon *poCollection = new OGRMultiPolygon();
209 :
210 2 : poCollection->addGeometryDirectly(make<OGRPolygon>());
211 :
212 2 : return poCollection;
213 : }
214 :
215 2 : template <> OGRMultiPoint *make()
216 : {
217 2 : OGRMultiPoint *poCollection = new OGRMultiPoint();
218 :
219 2 : poCollection->addGeometryDirectly(make<OGRPoint>());
220 :
221 2 : return poCollection;
222 : }
223 :
224 2 : template <> OGRMultiCurve *make()
225 : {
226 2 : OGRMultiCurve *poCollection = new OGRMultiCurve();
227 :
228 2 : poCollection->addGeometryDirectly(make<OGRLineString>());
229 2 : poCollection->addGeometryDirectly(make<OGRCompoundCurve>());
230 :
231 2 : return poCollection;
232 : }
233 :
234 2 : template <> OGRMultiLineString *make()
235 : {
236 2 : OGRMultiLineString *poCollection = new OGRMultiLineString();
237 :
238 2 : poCollection->addGeometryDirectly(make<OGRLineString>());
239 2 : poCollection->addGeometryDirectly(make<OGRLinearRing>());
240 :
241 2 : return poCollection;
242 : }
243 :
244 4 : template <> OGRTriangle *make()
245 : {
246 8 : OGRPoint p1(0, 0), p2(0, 1), p3(1, 1);
247 8 : return new OGRTriangle(p1, p2, p3);
248 : }
249 :
250 2 : template <> OGRTriangulatedSurface *make()
251 : {
252 2 : OGRTriangulatedSurface *poTS = new OGRTriangulatedSurface();
253 2 : poTS->addGeometryDirectly(make<OGRTriangle>());
254 2 : return poTS;
255 : }
256 :
257 2 : template <> OGRPolyhedralSurface *make()
258 : {
259 2 : OGRPolyhedralSurface *poPS = new OGRPolyhedralSurface();
260 2 : poPS->addGeometryDirectly(make<OGRPolygon>());
261 2 : return poPS;
262 : }
263 :
264 16 : template <class T> void testCopyEquals()
265 : {
266 16 : auto poOrigin = std::unique_ptr<T>(make<T>());
267 16 : ASSERT_TRUE(nullptr != poOrigin);
268 :
269 16 : T value2(*poOrigin);
270 :
271 16 : ASSERT_TRUE(CPL_TO_BOOL(poOrigin->Equals(&value2)))
272 0 : << poOrigin->getGeometryName() << ": copy constructor changed a value";
273 :
274 16 : T value3;
275 16 : value3 = *poOrigin;
276 16 : value3 = *poOrigin;
277 16 : auto &value3Ref(value3);
278 16 : value3 = value3Ref;
279 :
280 : #ifdef DEBUG_VERBOSE
281 : char *wkt1 = NULL, *wkt2 = NULL;
282 : poOrigin->exportToWkt(&wkt1);
283 : value3.exportToWkt(&wkt2);
284 : printf("%s %s\n", wkt1, wkt2);
285 : CPLFree(wkt1);
286 : CPLFree(wkt2);
287 : #endif
288 16 : ASSERT_TRUE(CPL_TO_BOOL(poOrigin->Equals(&value3)))
289 0 : << poOrigin->getGeometryName()
290 0 : << ": assignment operator changed a value";
291 :
292 16 : value3 = T();
293 16 : ASSERT_TRUE(value3.IsEmpty());
294 : }
295 :
296 : // Test if copy constructor and assignment operators succeeds on copying the
297 : // geometry data
298 4 : TEST_F(test_ogr, SpatialReference_leak_copy_constructor)
299 : {
300 1 : testCopyEquals<OGRPoint>();
301 1 : testCopyEquals<OGRLineString>();
302 1 : testCopyEquals<OGRLinearRing>();
303 1 : testCopyEquals<OGRCircularString>();
304 1 : testCopyEquals<OGRCompoundCurve>();
305 1 : testCopyEquals<OGRCurvePolygon>();
306 1 : testCopyEquals<OGRPolygon>();
307 1 : testCopyEquals<OGRGeometryCollection>();
308 1 : testCopyEquals<OGRMultiSurface>();
309 1 : testCopyEquals<OGRMultiPolygon>();
310 1 : testCopyEquals<OGRMultiPoint>();
311 1 : testCopyEquals<OGRMultiCurve>();
312 1 : testCopyEquals<OGRMultiLineString>();
313 1 : testCopyEquals<OGRTriangle>();
314 1 : testCopyEquals<OGRPolyhedralSurface>();
315 1 : testCopyEquals<OGRTriangulatedSurface>();
316 1 : }
317 :
318 : // Test crazy usage of OGRGeometryCollection copy constructor
319 4 : TEST_F(test_ogr, OGRGeometryCollection_copy_constructor_illegal_use)
320 : {
321 2 : OGRGeometryCollection gc;
322 1 : gc.addGeometryDirectly(new OGRPoint(1, 2));
323 :
324 2 : OGRMultiPolygon mp;
325 1 : mp.addGeometryDirectly(new OGRPolygon());
326 :
327 1 : OGRGeometryCollection *mp_as_gc = ∓
328 1 : CPLErrorReset();
329 : {
330 2 : CPLErrorHandlerPusher oPusher(CPLQuietErrorHandler);
331 : // coverity[copy_assignment_call]
332 1 : *mp_as_gc = gc;
333 : }
334 1 : EXPECT_STREQ(CPLGetLastErrorMsg(),
335 : "Illegal use of OGRGeometryCollection::operator=(): trying to "
336 : "assign an incompatible sub-geometry");
337 1 : EXPECT_TRUE(mp.IsEmpty());
338 1 : }
339 :
340 : // Test crazy usage of OGRCurvePolygon copy constructor
341 4 : TEST_F(test_ogr, OGRCurvePolygon_copy_constructor_illegal_use)
342 : {
343 2 : OGRCurvePolygon cp;
344 1 : auto poCC = new OGRCircularString();
345 1 : poCC->addPoint(0, 0);
346 1 : poCC->addPoint(1, 1);
347 1 : poCC->addPoint(2, 0);
348 1 : poCC->addPoint(1, -1);
349 1 : poCC->addPoint(0, 0);
350 1 : cp.addRingDirectly(poCC);
351 :
352 2 : OGRPolygon poly;
353 1 : auto poLR = new OGRLinearRing();
354 1 : poLR->addPoint(0, 0);
355 1 : poLR->addPoint(1, 1);
356 1 : poLR->addPoint(2, 0);
357 1 : poLR->addPoint(1, -1);
358 1 : poLR->addPoint(0, 0);
359 1 : poly.addRingDirectly(poLR);
360 :
361 1 : OGRCurvePolygon *poly_as_cp = &poly;
362 1 : CPLErrorReset();
363 : {
364 2 : CPLErrorHandlerPusher oPusher(CPLQuietErrorHandler);
365 : // coverity[copy_assignment_call]
366 1 : *poly_as_cp = cp;
367 : }
368 1 : EXPECT_STREQ(CPLGetLastErrorMsg(),
369 : "Illegal use of OGRCurvePolygon::operator=(): trying to "
370 : "assign an incompatible sub-geometry");
371 1 : EXPECT_TRUE(poly.IsEmpty());
372 1 : }
373 :
374 16 : template <class T> void testMove()
375 : {
376 16 : auto poSRS = new OGRSpatialReference();
377 : {
378 16 : auto poOrigin = std::unique_ptr<T>(make<T>());
379 16 : ASSERT_TRUE(nullptr != poOrigin);
380 16 : poOrigin->assignSpatialReference(poSRS);
381 :
382 16 : T valueCopy(*poOrigin);
383 16 : const int refCountBefore = poSRS->GetReferenceCount();
384 16 : T fromMoved(std::move(*poOrigin));
385 16 : EXPECT_EQ(poSRS->GetReferenceCount(), refCountBefore);
386 :
387 16 : ASSERT_TRUE(CPL_TO_BOOL(fromMoved.Equals(&valueCopy)))
388 0 : << valueCopy.getGeometryName()
389 0 : << ": move constructor changed a value";
390 16 : EXPECT_EQ(fromMoved.getSpatialReference(), poSRS);
391 :
392 16 : T valueCopy2(valueCopy);
393 16 : EXPECT_EQ(valueCopy.getSpatialReference(), poSRS);
394 16 : T value3;
395 16 : const int refCountBefore2 = poSRS->GetReferenceCount();
396 16 : value3 = std::move(valueCopy);
397 16 : EXPECT_EQ(poSRS->GetReferenceCount(), refCountBefore2);
398 :
399 16 : ASSERT_TRUE(CPL_TO_BOOL(value3.Equals(&valueCopy2)))
400 0 : << valueCopy2.getGeometryName()
401 0 : << ": move assignment operator changed a value";
402 16 : EXPECT_EQ(value3.getSpatialReference(), poSRS);
403 : }
404 16 : EXPECT_EQ(poSRS->GetReferenceCount(), 1);
405 16 : poSRS->Release();
406 : }
407 :
408 4 : TEST_F(test_ogr, geometry_move)
409 : {
410 1 : testMove<OGRPoint>();
411 1 : testMove<OGRLineString>();
412 1 : testMove<OGRLinearRing>();
413 1 : testMove<OGRCircularString>();
414 1 : testMove<OGRCompoundCurve>();
415 1 : testMove<OGRCurvePolygon>();
416 1 : testMove<OGRPolygon>();
417 1 : testMove<OGRGeometryCollection>();
418 1 : testMove<OGRMultiSurface>();
419 1 : testMove<OGRMultiPolygon>();
420 1 : testMove<OGRMultiPoint>();
421 1 : testMove<OGRMultiCurve>();
422 1 : testMove<OGRMultiLineString>();
423 1 : testMove<OGRTriangle>();
424 1 : testMove<OGRPolyhedralSurface>();
425 1 : testMove<OGRTriangulatedSurface>();
426 1 : }
427 :
428 4 : TEST_F(test_ogr, geometry_get_point)
429 : {
430 : {
431 1 : OGRPoint p;
432 1 : double x = 1, y = 2;
433 1 : OGR_G_SetPoints((OGRGeometryH)&p, 1, &x, 0, &y, 0, nullptr, 0);
434 1 : ASSERT_EQ(p.getCoordinateDimension(), 2);
435 1 : ASSERT_EQ(p.getX(), 1);
436 1 : ASSERT_EQ(p.getY(), 2);
437 1 : ASSERT_EQ(p.getZ(), 0);
438 : }
439 :
440 : {
441 1 : OGRPoint p;
442 1 : double x = 1, y = 2, z = 3;
443 1 : OGR_G_SetPoints((OGRGeometryH)&p, 1, &x, 0, &y, 0, &z, 0);
444 1 : ASSERT_EQ(p.getCoordinateDimension(), 3);
445 1 : ASSERT_EQ(p.getX(), 1);
446 1 : ASSERT_EQ(p.getY(), 2);
447 1 : ASSERT_EQ(p.getZ(), 3);
448 : }
449 :
450 : {
451 2 : OGRPoint p;
452 1 : CPLPushErrorHandler(CPLQuietErrorHandler);
453 1 : OGR_G_SetPoints((OGRGeometryH)&p, 1, nullptr, 0, nullptr, 0, nullptr,
454 : 0);
455 1 : CPLPopErrorHandler();
456 : }
457 :
458 : {
459 1 : OGRLineString ls;
460 1 : double x = 1, y = 2;
461 1 : OGR_G_SetPoints((OGRGeometryH)&ls, 1, &x, 0, &y, 0, nullptr, 0);
462 1 : ASSERT_EQ(ls.getCoordinateDimension(), 2);
463 1 : ASSERT_EQ(ls.getX(0), 1);
464 1 : ASSERT_EQ(ls.getY(0), 2);
465 1 : ASSERT_EQ(ls.getZ(0), 0);
466 : }
467 :
468 : {
469 1 : OGRLineString ls;
470 1 : double x = 1, y = 2;
471 1 : OGR_G_SetPoints((OGRGeometryH)&ls, 1, &x, 0, &y, 0, nullptr, 0);
472 1 : ASSERT_EQ(ls.getCoordinateDimension(), 2);
473 1 : ASSERT_EQ(ls.getX(0), 1);
474 1 : ASSERT_EQ(ls.getY(0), 2);
475 1 : ASSERT_EQ(ls.getZ(0), 0);
476 : }
477 :
478 : {
479 1 : OGRLineString ls;
480 1 : double x = 1, y = 2;
481 1 : OGR_G_SetPoints((OGRGeometryH)&ls, 1, &x, 8, &y, 8, nullptr, 0);
482 1 : ASSERT_EQ(ls.getCoordinateDimension(), 2);
483 1 : ASSERT_EQ(ls.getX(0), 1);
484 1 : ASSERT_EQ(ls.getY(0), 2);
485 1 : ASSERT_EQ(ls.getZ(0), 0);
486 : }
487 :
488 : {
489 1 : OGRLineString ls;
490 1 : double x = 1, y = 2, z = 3;
491 1 : OGR_G_SetPoints((OGRGeometryH)&ls, 1, &x, 0, &y, 0, &z, 0);
492 1 : ASSERT_EQ(ls.getCoordinateDimension(), 3);
493 1 : ASSERT_EQ(ls.getX(0), 1);
494 1 : ASSERT_EQ(ls.getY(0), 2);
495 1 : ASSERT_EQ(ls.getZ(0), 3);
496 : }
497 :
498 : {
499 1 : OGRLineString ls;
500 1 : double x = 1, y = 2, z = 3;
501 1 : OGR_G_SetPoints((OGRGeometryH)&ls, 1, &x, 8, &y, 8, &z, 8);
502 1 : ASSERT_EQ(ls.getCoordinateDimension(), 3);
503 1 : ASSERT_EQ(ls.getX(0), 1);
504 1 : ASSERT_EQ(ls.getY(0), 2);
505 1 : ASSERT_EQ(ls.getZ(0), 3);
506 : }
507 :
508 : {
509 2 : OGRLineString ls;
510 1 : CPLPushErrorHandler(CPLQuietErrorHandler);
511 1 : OGR_G_SetPoints((OGRGeometryH)&ls, 1, nullptr, 0, nullptr, 0, nullptr,
512 : 0);
513 1 : CPLPopErrorHandler();
514 : }
515 : }
516 :
517 4 : TEST_F(test_ogr, OGR_G_CreateGeometry_unknown)
518 : {
519 1 : EXPECT_EQ(OGR_G_CreateGeometry(wkbUnknown), nullptr);
520 1 : }
521 :
522 4 : TEST_F(test_ogr, style_manager)
523 : {
524 1 : OGRStyleMgrH hSM = OGR_SM_Create(nullptr);
525 1 : EXPECT_TRUE(OGR_SM_InitStyleString(
526 : hSM, "PEN(w:2px,c:#000000,id:\"mapinfo-pen-2,ogr-pen-0\")"));
527 1 : OGRStyleToolH hTool = OGR_SM_GetPart(hSM, 0, nullptr);
528 1 : EXPECT_TRUE(hTool != nullptr);
529 1 : if (hTool)
530 : {
531 : int bValueIsNull;
532 :
533 1 : EXPECT_NEAR(OGR_ST_GetParamDbl(hTool, OGRSTPenWidth, &bValueIsNull),
534 : 2.0 * (1.0 / (72.0 * 39.37)) * 1000, 1e-6);
535 1 : EXPECT_EQ(OGR_ST_GetUnit(hTool), OGRSTUMM);
536 :
537 1 : OGR_ST_SetUnit(hTool, OGRSTUPixel, 1.0);
538 1 : EXPECT_EQ(OGR_ST_GetParamDbl(hTool, OGRSTPenWidth, &bValueIsNull), 2.0);
539 1 : EXPECT_EQ(OGR_ST_GetUnit(hTool), OGRSTUPixel);
540 1 : OGR_ST_Destroy(hTool);
541 : }
542 :
543 1 : OGR_SM_Destroy(hSM);
544 1 : }
545 :
546 4 : TEST_F(test_ogr, OGRParseDate)
547 : {
548 : OGRField sField;
549 1 : EXPECT_EQ(OGRParseDate("2017/11/31 12:34:56", &sField, 0), TRUE);
550 1 : EXPECT_EQ(sField.Date.Year, 2017);
551 1 : EXPECT_EQ(sField.Date.Month, 11);
552 1 : EXPECT_EQ(sField.Date.Day, 31);
553 1 : EXPECT_EQ(sField.Date.Hour, 12);
554 1 : EXPECT_EQ(sField.Date.Minute, 34);
555 1 : EXPECT_EQ(sField.Date.Second, 56.0f);
556 1 : EXPECT_EQ(sField.Date.TZFlag, 0);
557 :
558 1 : EXPECT_EQ(OGRParseDate("2017/11/31 12:34:56+00", &sField, 0), TRUE);
559 1 : EXPECT_EQ(sField.Date.TZFlag, 100);
560 :
561 1 : EXPECT_EQ(OGRParseDate("2017/11/31 12:34:56+12:00", &sField, 0), TRUE);
562 1 : EXPECT_EQ(sField.Date.TZFlag, 100 + 12 * 4);
563 :
564 1 : EXPECT_EQ(OGRParseDate("2017/11/31 12:34:56+1200", &sField, 0), TRUE);
565 1 : EXPECT_EQ(sField.Date.TZFlag, 100 + 12 * 4);
566 :
567 1 : EXPECT_EQ(OGRParseDate("2017/11/31 12:34:56+815", &sField, 0), TRUE);
568 1 : EXPECT_EQ(sField.Date.TZFlag, 100 + 8 * 4 + 1);
569 :
570 1 : EXPECT_EQ(OGRParseDate("2017/11/31 12:34:56-12:00", &sField, 0), TRUE);
571 1 : EXPECT_EQ(sField.Date.TZFlag, 100 - 12 * 4);
572 :
573 1 : EXPECT_EQ(OGRParseDate(" 2017/11/31 12:34:56", &sField, 0), TRUE);
574 1 : EXPECT_EQ(sField.Date.Year, 2017);
575 :
576 1 : EXPECT_EQ(OGRParseDate("2017/11/31 12:34:56.789", &sField, 0), TRUE);
577 1 : EXPECT_EQ(sField.Date.Second, 56.789f);
578 :
579 : // Leap second
580 1 : EXPECT_EQ(OGRParseDate("2017/11/31 12:34:60", &sField, 0), TRUE);
581 1 : EXPECT_EQ(sField.Date.Second, 60.0f);
582 :
583 1 : EXPECT_EQ(OGRParseDate("2017-11-31T12:34:56", &sField, 0), TRUE);
584 1 : EXPECT_EQ(sField.Date.Year, 2017);
585 1 : EXPECT_EQ(sField.Date.Month, 11);
586 1 : EXPECT_EQ(sField.Date.Day, 31);
587 1 : EXPECT_EQ(sField.Date.Hour, 12);
588 1 : EXPECT_EQ(sField.Date.Minute, 34);
589 1 : EXPECT_EQ(sField.Date.Second, 56.0f);
590 1 : EXPECT_EQ(sField.Date.TZFlag, 0);
591 :
592 1 : EXPECT_EQ(OGRParseDate("2017-11-31T12:34:56Z", &sField, 0), TRUE);
593 1 : EXPECT_EQ(sField.Date.Second, 56.0f);
594 1 : EXPECT_EQ(sField.Date.TZFlag, 100);
595 :
596 1 : EXPECT_EQ(OGRParseDate("2017-11-31T12:34:56.789Z", &sField, 0), TRUE);
597 1 : EXPECT_EQ(sField.Date.Second, 56.789f);
598 1 : EXPECT_EQ(sField.Date.TZFlag, 100);
599 :
600 1 : EXPECT_EQ(OGRParseDate("2017-11-31", &sField, 0), TRUE);
601 1 : EXPECT_EQ(sField.Date.Year, 2017);
602 1 : EXPECT_EQ(sField.Date.Month, 11);
603 1 : EXPECT_EQ(sField.Date.Day, 31);
604 1 : EXPECT_EQ(sField.Date.Hour, 0);
605 1 : EXPECT_EQ(sField.Date.Minute, 0);
606 1 : EXPECT_EQ(sField.Date.Second, 0.0f);
607 1 : EXPECT_EQ(sField.Date.TZFlag, 0);
608 :
609 1 : EXPECT_EQ(OGRParseDate("2017-11-31Z", &sField, 0), TRUE);
610 1 : EXPECT_EQ(sField.Date.Year, 2017);
611 1 : EXPECT_EQ(sField.Date.Month, 11);
612 1 : EXPECT_EQ(sField.Date.Day, 31);
613 1 : EXPECT_EQ(sField.Date.Hour, 0);
614 1 : EXPECT_EQ(sField.Date.Minute, 0);
615 1 : EXPECT_EQ(sField.Date.Second, 0.0f);
616 1 : EXPECT_EQ(sField.Date.TZFlag, 0);
617 :
618 1 : EXPECT_EQ(OGRParseDate("12:34", &sField, 0), TRUE);
619 1 : EXPECT_EQ(sField.Date.Year, 0);
620 1 : EXPECT_EQ(sField.Date.Month, 0);
621 1 : EXPECT_EQ(sField.Date.Day, 0);
622 1 : EXPECT_EQ(sField.Date.Hour, 12);
623 1 : EXPECT_EQ(sField.Date.Minute, 34);
624 1 : EXPECT_EQ(sField.Date.Second, 0.0f);
625 1 : EXPECT_EQ(sField.Date.TZFlag, 0);
626 :
627 1 : EXPECT_EQ(OGRParseDate("12:34:56", &sField, 0), TRUE);
628 1 : EXPECT_EQ(OGRParseDate("12:34:56.789", &sField, 0), TRUE);
629 :
630 1 : EXPECT_EQ(OGRParseDate("T12:34:56", &sField, 0), TRUE);
631 1 : EXPECT_EQ(sField.Date.Year, 0);
632 1 : EXPECT_EQ(sField.Date.Month, 0);
633 1 : EXPECT_EQ(sField.Date.Day, 0);
634 1 : EXPECT_EQ(sField.Date.Hour, 12);
635 1 : EXPECT_EQ(sField.Date.Minute, 34);
636 1 : EXPECT_EQ(sField.Date.Second, 56.0f);
637 1 : EXPECT_EQ(sField.Date.TZFlag, 0);
638 :
639 1 : EXPECT_EQ(OGRParseDate("T123456", &sField, 0), TRUE);
640 1 : EXPECT_EQ(sField.Date.Year, 0);
641 1 : EXPECT_EQ(sField.Date.Month, 0);
642 1 : EXPECT_EQ(sField.Date.Day, 0);
643 1 : EXPECT_EQ(sField.Date.Hour, 12);
644 1 : EXPECT_EQ(sField.Date.Minute, 34);
645 1 : EXPECT_EQ(sField.Date.Second, 56.0f);
646 1 : EXPECT_EQ(sField.Date.TZFlag, 0);
647 :
648 1 : EXPECT_EQ(OGRParseDate("T123456.789", &sField, 0), TRUE);
649 1 : EXPECT_EQ(sField.Date.Year, 0);
650 1 : EXPECT_EQ(sField.Date.Month, 0);
651 1 : EXPECT_EQ(sField.Date.Day, 0);
652 1 : EXPECT_EQ(sField.Date.Hour, 12);
653 1 : EXPECT_EQ(sField.Date.Minute, 34);
654 1 : EXPECT_EQ(sField.Date.Second, 56.789f);
655 1 : EXPECT_EQ(sField.Date.TZFlag, 0);
656 :
657 1 : CPLPushErrorHandler(CPLQuietErrorHandler);
658 1 : EXPECT_TRUE(!OGRParseDate("123456-01-01", &sField, 0));
659 1 : CPLPopErrorHandler();
660 1 : EXPECT_TRUE(!OGRParseDate("2017", &sField, 0));
661 1 : EXPECT_TRUE(!OGRParseDate("2017x-01-01", &sField, 0));
662 1 : EXPECT_TRUE(!OGRParseDate("2017-1-01", &sField, 0));
663 1 : EXPECT_TRUE(!OGRParseDate("2017-01-1", &sField, 0));
664 1 : EXPECT_TRUE(!OGRParseDate("2017-01-01x", &sField, 0));
665 1 : EXPECT_TRUE(!OGRParseDate("12:", &sField, 0));
666 1 : EXPECT_TRUE(!OGRParseDate("12:3", &sField, 0));
667 1 : EXPECT_TRUE(!OGRParseDate("1:23", &sField, 0));
668 1 : EXPECT_TRUE(!OGRParseDate("12:34:5", &sField, 0));
669 1 : EXPECT_TRUE(!OGRParseDate("1a:34", &sField, 0));
670 1 : EXPECT_TRUE(!OGRParseDate("2017-a-31T12:34:56", &sField, 0));
671 1 : EXPECT_TRUE(!OGRParseDate("2017-00-31T12:34:56", &sField, 0));
672 1 : EXPECT_TRUE(!OGRParseDate("2017-13-31T12:34:56", &sField, 0));
673 1 : EXPECT_TRUE(!OGRParseDate("2017-01-00T12:34:56", &sField, 0));
674 1 : EXPECT_TRUE(!OGRParseDate("2017-01-aT12:34:56", &sField, 0));
675 1 : EXPECT_TRUE(!OGRParseDate("2017-01-32T12:34:56", &sField, 0));
676 1 : EXPECT_TRUE(!OGRParseDate("a:34:56", &sField, 0));
677 1 : EXPECT_TRUE(!OGRParseDate("2017-01-01Ta:34:56", &sField, 0));
678 1 : EXPECT_TRUE(!OGRParseDate("2017-01-01T25:34:56", &sField, 0));
679 1 : EXPECT_TRUE(!OGRParseDate("2017-01-01T00:a:00", &sField, 0));
680 1 : EXPECT_TRUE(!OGRParseDate("2017-01-01T00: 34:56", &sField, 0));
681 1 : EXPECT_TRUE(!OGRParseDate("2017-01-01T00:61:00", &sField, 0));
682 1 : EXPECT_TRUE(!OGRParseDate("2017-01-01T00:00:61", &sField, 0));
683 1 : EXPECT_TRUE(!OGRParseDate("2017-01-01T00:00:a", &sField, 0));
684 :
685 : // Test OGRPARSEDATE_OPTION_LAX
686 1 : EXPECT_EQ(OGRParseDate("2017-1-9", &sField, OGRPARSEDATE_OPTION_LAX), TRUE);
687 1 : EXPECT_EQ(sField.Date.Year, 2017);
688 1 : EXPECT_EQ(sField.Date.Month, 1);
689 1 : EXPECT_EQ(sField.Date.Day, 9);
690 :
691 1 : EXPECT_EQ(OGRParseDate("2017-1-31", &sField, OGRPARSEDATE_OPTION_LAX),
692 : TRUE);
693 1 : EXPECT_EQ(sField.Date.Year, 2017);
694 1 : EXPECT_EQ(sField.Date.Month, 1);
695 1 : EXPECT_EQ(sField.Date.Day, 31);
696 :
697 1 : EXPECT_EQ(OGRParseDate("2017-1-31T1:2:3", &sField, OGRPARSEDATE_OPTION_LAX),
698 : TRUE);
699 1 : EXPECT_EQ(sField.Date.Year, 2017);
700 1 : EXPECT_EQ(sField.Date.Month, 1);
701 1 : EXPECT_EQ(sField.Date.Day, 31);
702 1 : EXPECT_EQ(sField.Date.Hour, 1);
703 1 : EXPECT_EQ(sField.Date.Minute, 2);
704 1 : EXPECT_EQ(sField.Date.Second, 3.0f);
705 1 : EXPECT_EQ(sField.Date.TZFlag, 0);
706 :
707 1 : EXPECT_EQ(OGRParseDate("2017-1-31T1:3", &sField, OGRPARSEDATE_OPTION_LAX),
708 : TRUE);
709 1 : EXPECT_EQ(sField.Date.Year, 2017);
710 1 : EXPECT_EQ(sField.Date.Month, 1);
711 1 : EXPECT_EQ(sField.Date.Day, 31);
712 1 : EXPECT_EQ(sField.Date.Hour, 1);
713 1 : EXPECT_EQ(sField.Date.Minute, 3);
714 1 : EXPECT_EQ(sField.Date.Second, 0.0f);
715 1 : EXPECT_EQ(sField.Date.TZFlag, 0);
716 :
717 1 : EXPECT_EQ(OGRParseDate("1:3", &sField, OGRPARSEDATE_OPTION_LAX), TRUE);
718 1 : EXPECT_EQ(sField.Date.Year, 0);
719 1 : EXPECT_EQ(sField.Date.Month, 0);
720 1 : EXPECT_EQ(sField.Date.Day, 0);
721 1 : EXPECT_EQ(sField.Date.Hour, 1);
722 1 : EXPECT_EQ(sField.Date.Minute, 3);
723 1 : EXPECT_EQ(sField.Date.Second, 0.0f);
724 1 : EXPECT_EQ(sField.Date.TZFlag, 0);
725 :
726 1 : EXPECT_TRUE(!OGRParseDate("2017-a-01", &sField, OGRPARSEDATE_OPTION_LAX));
727 1 : EXPECT_TRUE(!OGRParseDate("2017-0-01", &sField, OGRPARSEDATE_OPTION_LAX));
728 1 : EXPECT_TRUE(!OGRParseDate("2017-1", &sField, OGRPARSEDATE_OPTION_LAX));
729 1 : EXPECT_TRUE(!OGRParseDate("2017-1-", &sField, OGRPARSEDATE_OPTION_LAX));
730 1 : EXPECT_TRUE(!OGRParseDate("2017-1-a", &sField, OGRPARSEDATE_OPTION_LAX));
731 1 : EXPECT_TRUE(!OGRParseDate("2017-1-0", &sField, OGRPARSEDATE_OPTION_LAX));
732 1 : EXPECT_TRUE(!OGRParseDate("2017-1-32", &sField, OGRPARSEDATE_OPTION_LAX));
733 1 : EXPECT_TRUE(
734 : !OGRParseDate("2017-1-1Ta:00:00", &sField, OGRPARSEDATE_OPTION_LAX));
735 1 : EXPECT_TRUE(!OGRParseDate("2017-1-1T1", &sField, OGRPARSEDATE_OPTION_LAX));
736 1 : EXPECT_TRUE(
737 : !OGRParseDate("2017-1-1T00:a:00", &sField, OGRPARSEDATE_OPTION_LAX));
738 1 : EXPECT_TRUE(!OGRParseDate("2017-1-1T1:", &sField, OGRPARSEDATE_OPTION_LAX));
739 1 : EXPECT_TRUE(
740 : !OGRParseDate("2017-1-1T00:00:a", &sField, OGRPARSEDATE_OPTION_LAX));
741 1 : EXPECT_TRUE(!OGRParseDate("1a:3", &sField, OGRPARSEDATE_OPTION_LAX));
742 1 : }
743 :
744 : // Test OGRPolygon::IsPointOnSurface()
745 4 : TEST_F(test_ogr, IsPointOnSurface)
746 : {
747 1 : OGRPolygon oPoly;
748 :
749 1 : OGRPoint oEmptyPoint;
750 1 : ASSERT_TRUE(!oPoly.IsPointOnSurface(&oEmptyPoint));
751 :
752 1 : OGRPoint oPoint;
753 1 : oPoint.setX(1);
754 1 : oPoint.setY(1);
755 1 : ASSERT_TRUE(!oPoly.IsPointOnSurface(&oPoint));
756 :
757 1 : const char *pszPoly =
758 : "POLYGON((0 0,0 10,10 10,10 0,0 0),(4 4,4 6,6 6,6 4,4 4))";
759 1 : oPoly.importFromWkt(&pszPoly);
760 :
761 1 : ASSERT_TRUE(!oPoly.IsPointOnSurface(&oEmptyPoint));
762 :
763 1 : ASSERT_EQ(oPoly.IsPointOnSurface(&oPoint), TRUE);
764 :
765 1 : oPoint.setX(5);
766 1 : oPoint.setY(5);
767 1 : ASSERT_TRUE(!oPoly.IsPointOnSurface(&oPoint));
768 : }
769 :
770 : // Test gpb.h
771 4 : TEST_F(test_ogr, gpb_h)
772 : {
773 1 : ASSERT_EQ(GetVarUIntSize(0), 1);
774 1 : ASSERT_EQ(GetVarUIntSize(127), 1);
775 1 : ASSERT_EQ(GetVarUIntSize(128), 2);
776 1 : ASSERT_EQ(GetVarUIntSize((1 << 14) - 1), 2);
777 1 : ASSERT_EQ(GetVarUIntSize(1 << 14), 3);
778 1 : ASSERT_EQ(GetVarUIntSize(GUINT64_MAX), 10);
779 :
780 1 : ASSERT_EQ(GetVarIntSize(0), 1);
781 1 : ASSERT_EQ(GetVarIntSize(127), 1);
782 1 : ASSERT_EQ(GetVarIntSize(128), 2);
783 1 : ASSERT_EQ(GetVarIntSize((1 << 14) - 1), 2);
784 1 : ASSERT_EQ(GetVarIntSize(1 << 14), 3);
785 1 : ASSERT_EQ(GetVarIntSize(GINT64_MAX), 9);
786 1 : ASSERT_EQ(GetVarIntSize(-1), 10);
787 1 : ASSERT_EQ(GetVarIntSize(GINT64_MIN), 10);
788 :
789 1 : ASSERT_EQ(GetVarSIntSize(0), 1);
790 1 : ASSERT_EQ(GetVarSIntSize(63), 1);
791 1 : ASSERT_EQ(GetVarSIntSize(64), 2);
792 1 : ASSERT_EQ(GetVarSIntSize(-1), 1);
793 1 : ASSERT_EQ(GetVarSIntSize(-64), 1);
794 1 : ASSERT_EQ(GetVarSIntSize(-65), 2);
795 1 : ASSERT_EQ(GetVarSIntSize(GINT64_MIN), 10);
796 1 : ASSERT_EQ(GetVarSIntSize(GINT64_MAX), 10);
797 :
798 1 : ASSERT_EQ(GetTextSize(""), 1);
799 1 : ASSERT_EQ(GetTextSize(" "), 2);
800 1 : ASSERT_EQ(GetTextSize(std::string(" ")), 2);
801 :
802 1 : GByte abyBuffer[11] = {0};
803 : GByte *pabyBuffer;
804 : const GByte *pabyBufferRO;
805 :
806 1 : pabyBuffer = abyBuffer;
807 1 : WriteVarUInt(&pabyBuffer, 0);
808 1 : ASSERT_EQ(pabyBuffer - abyBuffer, 1);
809 1 : pabyBufferRO = abyBuffer;
810 1 : ASSERT_EQ(ReadVarUInt64(&pabyBufferRO), 0U);
811 :
812 1 : pabyBuffer = abyBuffer;
813 1 : WriteVarUInt(&pabyBuffer, 127);
814 1 : ASSERT_EQ(pabyBuffer - abyBuffer, 1);
815 1 : pabyBufferRO = abyBuffer;
816 1 : ASSERT_EQ(ReadVarUInt64(&pabyBufferRO), 127U);
817 :
818 1 : pabyBuffer = abyBuffer;
819 1 : WriteVarUInt(&pabyBuffer, 0xDEADBEEFU);
820 1 : ASSERT_EQ(pabyBuffer - abyBuffer, 5);
821 1 : pabyBufferRO = abyBuffer;
822 1 : ASSERT_EQ(ReadVarUInt64(&pabyBufferRO), 0xDEADBEEFU);
823 :
824 1 : pabyBuffer = abyBuffer;
825 1 : WriteVarUInt(&pabyBuffer, GUINT64_MAX);
826 1 : ASSERT_EQ(pabyBuffer - abyBuffer, 10);
827 1 : pabyBufferRO = abyBuffer;
828 1 : ASSERT_EQ(ReadVarUInt64(&pabyBufferRO), GUINT64_MAX);
829 :
830 1 : pabyBuffer = abyBuffer;
831 1 : WriteVarInt(&pabyBuffer, GINT64_MAX);
832 1 : ASSERT_EQ(pabyBuffer - abyBuffer, 9);
833 1 : pabyBufferRO = abyBuffer;
834 1 : ASSERT_EQ(ReadVarInt64(&pabyBufferRO), GINT64_MAX);
835 :
836 1 : pabyBuffer = abyBuffer;
837 1 : WriteVarInt(&pabyBuffer, -1);
838 1 : ASSERT_EQ(pabyBuffer - abyBuffer, 10);
839 1 : pabyBufferRO = abyBuffer;
840 1 : ASSERT_EQ(ReadVarInt64(&pabyBufferRO), -1);
841 :
842 1 : pabyBuffer = abyBuffer;
843 1 : WriteVarInt(&pabyBuffer, GINT64_MIN);
844 1 : ASSERT_EQ(pabyBuffer - abyBuffer, 10);
845 1 : pabyBufferRO = abyBuffer;
846 1 : ASSERT_EQ(ReadVarInt64(&pabyBufferRO), GINT64_MIN);
847 :
848 1 : pabyBuffer = abyBuffer;
849 1 : WriteVarSInt(&pabyBuffer, 0);
850 1 : ASSERT_EQ(pabyBuffer - abyBuffer, 1);
851 : {
852 : GIntBig nVal;
853 1 : pabyBufferRO = abyBuffer;
854 1 : READ_VARSINT64(pabyBufferRO, abyBuffer + 10, nVal);
855 1 : ASSERT_EQ(nVal, 0);
856 : }
857 :
858 1 : pabyBuffer = abyBuffer;
859 1 : WriteVarSInt(&pabyBuffer, 1);
860 1 : ASSERT_EQ(pabyBuffer - abyBuffer, 1);
861 : {
862 : GIntBig nVal;
863 1 : pabyBufferRO = abyBuffer;
864 1 : READ_VARSINT64(pabyBufferRO, abyBuffer + 10, nVal);
865 1 : ASSERT_EQ(nVal, 1);
866 : }
867 :
868 1 : pabyBuffer = abyBuffer;
869 1 : WriteVarSInt(&pabyBuffer, -1);
870 1 : ASSERT_EQ(pabyBuffer - abyBuffer, 1);
871 : {
872 : GIntBig nVal;
873 1 : pabyBufferRO = abyBuffer;
874 1 : READ_VARSINT64(pabyBufferRO, abyBuffer + 10, nVal);
875 1 : ASSERT_EQ(nVal, -1);
876 : }
877 :
878 1 : pabyBuffer = abyBuffer;
879 1 : WriteVarSInt(&pabyBuffer, GINT64_MAX);
880 1 : ASSERT_EQ(pabyBuffer - abyBuffer, 10);
881 : {
882 : GIntBig nVal;
883 1 : pabyBufferRO = abyBuffer;
884 1 : READ_VARSINT64(pabyBufferRO, abyBuffer + 10, nVal);
885 1 : ASSERT_EQ(nVal, GINT64_MAX);
886 : }
887 :
888 1 : pabyBuffer = abyBuffer;
889 1 : WriteVarSInt(&pabyBuffer, GINT64_MIN);
890 1 : ASSERT_EQ(pabyBuffer - abyBuffer, 10);
891 : {
892 : GIntBig nVal;
893 1 : pabyBufferRO = abyBuffer;
894 1 : READ_VARSINT64(pabyBufferRO, abyBuffer + 10, nVal);
895 1 : ASSERT_EQ(nVal, GINT64_MIN);
896 : }
897 :
898 1 : pabyBuffer = abyBuffer;
899 1 : WriteText(&pabyBuffer, "x");
900 1 : ASSERT_EQ(pabyBuffer - abyBuffer, 2);
901 1 : ASSERT_EQ(abyBuffer[0], 1);
902 1 : ASSERT_EQ(abyBuffer[1], 'x');
903 :
904 1 : pabyBuffer = abyBuffer;
905 1 : WriteText(&pabyBuffer, std::string("x"));
906 1 : ASSERT_EQ(pabyBuffer - abyBuffer, 2);
907 1 : ASSERT_EQ(abyBuffer[0], 1);
908 1 : ASSERT_EQ(abyBuffer[1], 'x');
909 :
910 1 : pabyBuffer = abyBuffer;
911 1 : WriteFloat32(&pabyBuffer, 1.25f);
912 1 : ASSERT_EQ(pabyBuffer - abyBuffer, 4);
913 1 : pabyBufferRO = abyBuffer;
914 1 : ASSERT_EQ(ReadFloat32(&pabyBufferRO, abyBuffer + 4), 1.25f);
915 :
916 1 : pabyBuffer = abyBuffer;
917 1 : WriteFloat64(&pabyBuffer, 1.25);
918 1 : ASSERT_EQ(pabyBuffer - abyBuffer, 8);
919 1 : pabyBufferRO = abyBuffer;
920 1 : ASSERT_EQ(ReadFloat64(&pabyBufferRO, abyBuffer + 8), 1.25);
921 : }
922 :
923 : // Test OGRGeometry::toXXXXX()
924 4 : TEST_F(test_ogr, OGRGeometry_toXXXXX)
925 : {
926 : #define CONCAT(X, Y) X##Y
927 : #define TEST_OGRGEOMETRY_TO(X) \
928 : { \
929 : CONCAT(OGR, X) o; \
930 : OGRGeometry *poGeom = &o; \
931 : ASSERT_EQ(poGeom->CONCAT(to, X)(), &o); \
932 : }
933 :
934 1 : TEST_OGRGEOMETRY_TO(Point);
935 1 : TEST_OGRGEOMETRY_TO(LineString);
936 1 : TEST_OGRGEOMETRY_TO(LinearRing);
937 1 : TEST_OGRGEOMETRY_TO(CircularString);
938 1 : TEST_OGRGEOMETRY_TO(CompoundCurve);
939 1 : TEST_OGRGEOMETRY_TO(CurvePolygon);
940 1 : TEST_OGRGEOMETRY_TO(Polygon);
941 1 : TEST_OGRGEOMETRY_TO(GeometryCollection);
942 1 : TEST_OGRGEOMETRY_TO(MultiSurface);
943 1 : TEST_OGRGEOMETRY_TO(MultiPolygon);
944 1 : TEST_OGRGEOMETRY_TO(MultiPoint);
945 1 : TEST_OGRGEOMETRY_TO(MultiCurve);
946 1 : TEST_OGRGEOMETRY_TO(MultiLineString);
947 1 : TEST_OGRGEOMETRY_TO(Triangle);
948 1 : TEST_OGRGEOMETRY_TO(PolyhedralSurface);
949 1 : TEST_OGRGEOMETRY_TO(TriangulatedSurface);
950 : {
951 1 : OGRLineString o;
952 1 : OGRGeometry *poGeom = &o;
953 1 : ASSERT_EQ(poGeom->toCurve(), &o);
954 : }
955 : {
956 1 : OGRPolygon o;
957 1 : OGRGeometry *poGeom = &o;
958 1 : ASSERT_EQ(poGeom->toSurface(), &o);
959 : }
960 :
961 : {
962 1 : OGRPoint o;
963 : // ASSERT_EQ(o.toPoint(), &o);
964 : }
965 :
966 : {
967 1 : OGRLineString o;
968 1 : ASSERT_EQ(o.toCurve(), &o);
969 1 : ASSERT_EQ(o.toSimpleCurve(), &o);
970 : // ASSERT_EQ(o.toLineString(), &o);
971 :
972 : {
973 1 : OGRCurve &oRef = o;
974 1 : ASSERT_EQ(oRef.toLineString(), &o);
975 : }
976 :
977 : {
978 1 : OGRSimpleCurve &oRef = o;
979 1 : ASSERT_EQ(oRef.toLineString(), &o);
980 : }
981 : }
982 :
983 : {
984 1 : OGRLinearRing o;
985 1 : ASSERT_EQ(o.toCurve(), &o);
986 1 : ASSERT_EQ(o.toSimpleCurve(), &o);
987 : // ASSERT_EQ(o.toLinearRing(), &o);
988 :
989 : {
990 1 : OGRCurve &oRef = o;
991 1 : ASSERT_EQ(oRef.toLinearRing(), &o);
992 : }
993 : {
994 1 : OGRSimpleCurve &oRef = o;
995 1 : ASSERT_EQ(oRef.toLinearRing(), &o);
996 : }
997 : {
998 1 : OGRLineString &oRef = o;
999 1 : ASSERT_EQ(oRef.toLinearRing(), &o);
1000 : }
1001 : }
1002 :
1003 : {
1004 1 : OGRCircularString o;
1005 1 : ASSERT_EQ(o.toCurve(), &o);
1006 1 : ASSERT_EQ(o.toSimpleCurve(), &o);
1007 : // ASSERT_EQ(o.toCircularString(), &o);
1008 :
1009 : {
1010 1 : OGRCurve &oRef = o;
1011 1 : ASSERT_EQ(oRef.toCircularString(), &o);
1012 : }
1013 :
1014 : {
1015 1 : OGRSimpleCurve &oRef = o;
1016 1 : ASSERT_EQ(oRef.toCircularString(), &o);
1017 : }
1018 : }
1019 :
1020 : {
1021 1 : OGRCompoundCurve o;
1022 1 : ASSERT_EQ(o.toCurve(), &o);
1023 : // ASSERT_EQ(o.toCompoundCurve(), &o);
1024 :
1025 : {
1026 1 : OGRCurve &oRef = o;
1027 1 : ASSERT_EQ(oRef.toCompoundCurve(), &o);
1028 : }
1029 : }
1030 :
1031 : {
1032 1 : OGRCurvePolygon o;
1033 1 : ASSERT_EQ(o.toSurface(), &o);
1034 : // ASSERT_EQ(o.toCurvePolygon(), &o);
1035 :
1036 : {
1037 1 : OGRSurface &oRef = o;
1038 1 : ASSERT_EQ(oRef.toCurvePolygon(), &o);
1039 : }
1040 : }
1041 :
1042 : {
1043 1 : OGRPolygon o;
1044 1 : ASSERT_EQ(o.toSurface(), &o);
1045 1 : ASSERT_EQ(o.toCurvePolygon(), &o);
1046 : // ASSERT_EQ(o.toPolygon(), &o);
1047 :
1048 : {
1049 1 : OGRSurface &oRef = o;
1050 1 : ASSERT_EQ(oRef.toPolygon(), &o);
1051 : }
1052 :
1053 : {
1054 1 : OGRCurvePolygon &oRef = o;
1055 1 : ASSERT_EQ(oRef.toPolygon(), &o);
1056 : }
1057 : }
1058 :
1059 : {
1060 1 : OGRTriangle o;
1061 1 : ASSERT_EQ(o.toSurface(), &o);
1062 1 : ASSERT_EQ(o.toCurvePolygon(), &o);
1063 1 : ASSERT_EQ(o.toPolygon(), &o);
1064 : // ASSERT_EQ(o.toTriangle(), &o);
1065 :
1066 : {
1067 1 : OGRSurface &oRef = o;
1068 1 : ASSERT_EQ(oRef.toTriangle(), &o);
1069 : }
1070 :
1071 : {
1072 1 : OGRCurvePolygon &oRef = o;
1073 1 : ASSERT_EQ(oRef.toTriangle(), &o);
1074 : }
1075 :
1076 : {
1077 1 : OGRPolygon &oRef = o;
1078 1 : ASSERT_EQ(oRef.toTriangle(), &o);
1079 : }
1080 : }
1081 :
1082 : {
1083 1 : OGRMultiPoint o;
1084 1 : ASSERT_EQ(o.toGeometryCollection(), &o);
1085 : // ASSERT_EQ(o.toMultiPoint(), &o);
1086 :
1087 : {
1088 1 : OGRGeometryCollection &oRef = o;
1089 1 : ASSERT_EQ(oRef.toMultiPoint(), &o);
1090 : }
1091 : }
1092 :
1093 : {
1094 1 : OGRMultiCurve o;
1095 1 : ASSERT_EQ(o.toGeometryCollection(), &o);
1096 : // ASSERT_EQ(o.toMultiCurve(), &o);
1097 :
1098 : {
1099 1 : OGRGeometryCollection &oRef = o;
1100 1 : ASSERT_EQ(oRef.toMultiCurve(), &o);
1101 : }
1102 : }
1103 :
1104 : {
1105 1 : OGRMultiLineString o;
1106 1 : ASSERT_EQ(o.toGeometryCollection(), &o);
1107 1 : ASSERT_EQ(o.toMultiCurve(), &o);
1108 : // ASSERT_EQ(o.toMultiLineString(), &o);
1109 :
1110 : {
1111 1 : OGRMultiCurve &oRef = o;
1112 1 : ASSERT_EQ(oRef.toMultiLineString(), &o);
1113 : }
1114 :
1115 : {
1116 1 : OGRGeometryCollection &oRef = o;
1117 1 : ASSERT_EQ(oRef.toMultiLineString(), &o);
1118 : }
1119 : }
1120 :
1121 : {
1122 1 : OGRMultiSurface o;
1123 1 : ASSERT_EQ(o.toGeometryCollection(), &o);
1124 : // ASSERT_EQ(o.toMultiSurface(), &o);
1125 :
1126 : {
1127 1 : OGRGeometryCollection &oRef = o;
1128 1 : ASSERT_EQ(oRef.toMultiSurface(), &o);
1129 : }
1130 : }
1131 :
1132 : {
1133 1 : OGRMultiPolygon o;
1134 1 : ASSERT_EQ(o.toGeometryCollection(), &o);
1135 1 : ASSERT_EQ(o.toMultiSurface(), &o);
1136 : // ASSERT_EQ(o.toMultiPolygon(), &o);
1137 :
1138 : {
1139 1 : OGRMultiSurface &oRef = o;
1140 1 : ASSERT_EQ(oRef.toMultiPolygon(), &o);
1141 : }
1142 :
1143 : {
1144 1 : OGRGeometryCollection &oRef = o;
1145 1 : ASSERT_EQ(oRef.toMultiPolygon(), &o);
1146 : }
1147 : }
1148 :
1149 : {
1150 1 : OGRPolyhedralSurface o;
1151 1 : ASSERT_EQ(o.toSurface(), &o);
1152 : // ASSERT_EQ(o.toPolyhedralSurface(), &o);
1153 :
1154 : {
1155 1 : OGRSurface &oRef = o;
1156 1 : ASSERT_EQ(oRef.toPolyhedralSurface(), &o);
1157 : }
1158 : }
1159 :
1160 : {
1161 1 : OGRTriangulatedSurface o;
1162 1 : ASSERT_EQ(o.toSurface(), &o);
1163 1 : ASSERT_EQ(o.toPolyhedralSurface(), &o);
1164 : // ASSERT_EQ(o.toTriangulatedSurface(), &o);
1165 :
1166 : {
1167 1 : OGRSurface &oRef = o;
1168 1 : ASSERT_EQ(oRef.toTriangulatedSurface(), &o);
1169 : }
1170 :
1171 : {
1172 1 : OGRPolyhedralSurface &oRef = o;
1173 1 : ASSERT_EQ(oRef.toTriangulatedSurface(), &o);
1174 : }
1175 : }
1176 : }
1177 :
1178 34 : template <typename T> void TestIterator(T *obj, int nExpectedPointCount)
1179 : {
1180 34 : int nCount = 0;
1181 71 : for (auto &elt : obj)
1182 : {
1183 25 : nCount++;
1184 25 : CPL_IGNORE_RET_VAL(elt);
1185 : }
1186 34 : ASSERT_EQ(nCount, nExpectedPointCount);
1187 :
1188 34 : nCount = 0;
1189 34 : const T *const_obj(obj);
1190 71 : for (const auto &elt : const_obj)
1191 : {
1192 25 : nCount++;
1193 25 : CPL_IGNORE_RET_VAL(elt);
1194 : }
1195 34 : ASSERT_EQ(nCount, nExpectedPointCount);
1196 : }
1197 :
1198 : template <typename Concrete, typename Abstract = Concrete>
1199 34 : void TestIterator(const char *pszWKT = nullptr, int nExpectedPointCount = 0)
1200 : {
1201 68 : Concrete obj;
1202 34 : if (pszWKT)
1203 : {
1204 18 : obj.importFromWkt(&pszWKT);
1205 : }
1206 34 : TestIterator<Abstract>(&obj, nExpectedPointCount);
1207 34 : }
1208 :
1209 : // Test geometry visitor
1210 4 : TEST_F(test_ogr, OGRGeometry_visitor)
1211 : {
1212 : static const struct
1213 : {
1214 : const char *pszWKT;
1215 : int nExpectedPointCount;
1216 : } asTests[] = {
1217 : {"POINT(0 0)", 1},
1218 : {"LINESTRING(0 0)", 1},
1219 : {"POLYGON((0 0),(0 0))", 2},
1220 : {"MULTIPOINT(0 0)", 1},
1221 : {"MULTILINESTRING((0 0))", 1},
1222 : {"MULTIPOLYGON(((0 0)))", 1},
1223 : {"GEOMETRYCOLLECTION(POINT(0 0))", 1},
1224 : {"CIRCULARSTRING(0 0,1 1,0 0)", 3},
1225 : {"COMPOUNDCURVE((0 0,1 1))", 2},
1226 : {"CURVEPOLYGON((0 0,1 1,1 0,0 0))", 4},
1227 : {"MULTICURVE((0 0))", 1},
1228 : {"MULTISURFACE(((0 0)))", 1},
1229 : {"TRIANGLE((0 0,0 1,1 1,0 0))", 4},
1230 : {"POLYHEDRALSURFACE(((0 0,0 1,1 1,0 0)))", 4},
1231 : {"TIN(((0 0,0 1,1 1,0 0)))", 4},
1232 : };
1233 :
1234 : class PointCounterVisitor : public OGRDefaultGeometryVisitor
1235 : {
1236 : int m_nPoints = 0;
1237 :
1238 : public:
1239 15 : PointCounterVisitor()
1240 15 : {
1241 15 : }
1242 :
1243 : using OGRDefaultGeometryVisitor::visit;
1244 :
1245 31 : void visit(OGRPoint *) override
1246 : {
1247 31 : m_nPoints++;
1248 31 : }
1249 :
1250 15 : int getNumPoints() const
1251 : {
1252 15 : return m_nPoints;
1253 : }
1254 : };
1255 :
1256 : class PointCounterConstVisitor : public OGRDefaultConstGeometryVisitor
1257 : {
1258 : int m_nPoints = 0;
1259 :
1260 : public:
1261 15 : PointCounterConstVisitor()
1262 15 : {
1263 15 : }
1264 :
1265 : using OGRDefaultConstGeometryVisitor::visit;
1266 :
1267 31 : void visit(const OGRPoint *) override
1268 : {
1269 31 : m_nPoints++;
1270 31 : }
1271 :
1272 15 : int getNumPoints() const
1273 : {
1274 15 : return m_nPoints;
1275 : }
1276 : };
1277 :
1278 16 : for (size_t i = 0; i < CPL_ARRAYSIZE(asTests); i++)
1279 : {
1280 15 : OGRGeometry *poGeom = nullptr;
1281 15 : OGRGeometryFactory::createFromWkt(asTests[i].pszWKT, nullptr, &poGeom);
1282 15 : PointCounterVisitor oVisitor;
1283 15 : poGeom->accept(&oVisitor);
1284 15 : ASSERT_EQ(oVisitor.getNumPoints(), asTests[i].nExpectedPointCount);
1285 15 : PointCounterConstVisitor oConstVisitor;
1286 15 : poGeom->accept(&oConstVisitor);
1287 15 : ASSERT_EQ(oConstVisitor.getNumPoints(), asTests[i].nExpectedPointCount);
1288 15 : delete poGeom;
1289 : }
1290 :
1291 : {
1292 2 : OGRLineString ls;
1293 1 : ls.setNumPoints(2);
1294 2 : auto oIter1 = ls.begin();
1295 1 : EXPECT_TRUE(oIter1 != ls.end());
1296 1 : EXPECT_TRUE(!(oIter1 != ls.begin()));
1297 2 : auto oIter2 = ls.begin();
1298 1 : EXPECT_TRUE(!(oIter1 != oIter2));
1299 1 : ++oIter2;
1300 1 : EXPECT_TRUE(oIter1 != oIter2);
1301 1 : ++oIter2;
1302 1 : EXPECT_TRUE(oIter1 != oIter2);
1303 : }
1304 :
1305 : {
1306 2 : OGRLineString ls;
1307 1 : EXPECT_TRUE(!(ls.begin() != ls.end()));
1308 : }
1309 :
1310 1 : TestIterator<OGRLineString>();
1311 1 : TestIterator<OGRLineString>("LINESTRING(0 0)", 1);
1312 1 : TestIterator<OGRLineString, OGRCurve>("LINESTRING(0 0)", 1);
1313 1 : TestIterator<OGRLineString, OGRCurve>();
1314 1 : TestIterator<OGRLinearRing>();
1315 1 : TestIterator<OGRCircularString>();
1316 1 : TestIterator<OGRCircularString>("CIRCULARSTRING(0 0,1 1,0 0)", 3);
1317 1 : TestIterator<OGRCircularString, OGRCurve>("CIRCULARSTRING(0 0,1 1,0 0)", 3);
1318 1 : TestIterator<OGRCompoundCurve>();
1319 1 : TestIterator<OGRCompoundCurve>("COMPOUNDCURVE((0 0,1 1))", 1);
1320 1 : TestIterator<OGRCompoundCurve, OGRCurve>(
1321 : "COMPOUNDCURVE((0 0,1 1),CIRCULARSTRING(1 1,2 2,3 3))", 4);
1322 1 : TestIterator<OGRCompoundCurve>("COMPOUNDCURVE(CIRCULARSTRING EMPTY)", 1);
1323 1 : TestIterator<OGRCurvePolygon>();
1324 1 : TestIterator<OGRCurvePolygon>("CURVEPOLYGON((0 0,1 1,1 0,0 0))", 1);
1325 1 : TestIterator<OGRPolygon>();
1326 1 : TestIterator<OGRPolygon>("POLYGON((0 0,1 1,1 0,0 0))", 1);
1327 1 : TestIterator<OGRGeometryCollection>();
1328 1 : TestIterator<OGRGeometryCollection>("GEOMETRYCOLLECTION(POINT(0 0))", 1);
1329 1 : TestIterator<OGRMultiSurface>();
1330 1 : TestIterator<OGRMultiSurface>("MULTISURFACE(((0 0)))", 1);
1331 1 : TestIterator<OGRMultiPolygon>();
1332 1 : TestIterator<OGRMultiPolygon>("MULTIPOLYGON(((0 0)))", 1);
1333 1 : TestIterator<OGRMultiPoint>();
1334 1 : TestIterator<OGRMultiPoint>("MULTIPOINT(0 0)", 1);
1335 1 : TestIterator<OGRMultiCurve>();
1336 1 : TestIterator<OGRMultiCurve>("MULTICURVE((0 0))", 1);
1337 1 : TestIterator<OGRMultiLineString>();
1338 1 : TestIterator<OGRMultiLineString>("MULTILINESTRING((0 0))", 1);
1339 1 : TestIterator<OGRTriangle>();
1340 1 : TestIterator<OGRTriangle>("TRIANGLE((0 0,0 1,1 1,0 0))", 1);
1341 1 : TestIterator<OGRPolyhedralSurface>();
1342 1 : TestIterator<OGRPolyhedralSurface>("POLYHEDRALSURFACE(((0 0,0 1,1 1,0 0)))",
1343 : 1);
1344 1 : TestIterator<OGRTriangulatedSurface>();
1345 1 : TestIterator<OGRTriangulatedSurface>("TIN(((0 0,0 1,1 1,0 0)))", 1);
1346 :
1347 : // Test that the update of the iterated point of a linestring is
1348 : // immediately taken into account
1349 : // (https://github.com/OSGeo/gdal/issues/6215)
1350 : {
1351 1 : OGRLineString oLS;
1352 1 : oLS.addPoint(1, 2);
1353 1 : oLS.addPoint(3, 4);
1354 1 : int i = 0;
1355 3 : for (auto &&p : oLS)
1356 : {
1357 2 : p.setX(i * 10);
1358 2 : p.setY(i * 10 + 1);
1359 2 : p.setZ(i * 10 + 2);
1360 2 : p.setM(i * 10 + 3);
1361 2 : ASSERT_EQ(oLS.getX(i), p.getX());
1362 2 : ASSERT_EQ(oLS.getY(i), p.getY());
1363 2 : ASSERT_EQ(oLS.getZ(i), p.getZ());
1364 2 : ASSERT_EQ(oLS.getM(i), p.getM());
1365 2 : ++i;
1366 : }
1367 : }
1368 :
1369 : {
1370 : class PointCounterVisitorAndUpdate : public OGRDefaultGeometryVisitor
1371 : {
1372 : public:
1373 : PointCounterVisitorAndUpdate() = default;
1374 :
1375 : using OGRDefaultGeometryVisitor::visit;
1376 :
1377 2 : void visit(OGRPoint *poPoint) override
1378 : {
1379 2 : poPoint->setZ(100);
1380 2 : poPoint->setM(1000);
1381 2 : }
1382 : };
1383 :
1384 1 : OGRLineString oLS;
1385 1 : oLS.addPoint(1, 2);
1386 1 : oLS.addPoint(3, 4);
1387 0 : PointCounterVisitorAndUpdate oVisitor;
1388 1 : oLS.accept(&oVisitor);
1389 :
1390 1 : ASSERT_EQ(oLS.getZ(0), 100.0);
1391 1 : ASSERT_EQ(oLS.getZ(1), 100.0);
1392 1 : ASSERT_EQ(oLS.getM(0), 1000.0);
1393 1 : ASSERT_EQ(oLS.getM(1), 1000.0);
1394 : }
1395 : }
1396 :
1397 : // Test OGRToOGCGeomType()
1398 4 : TEST_F(test_ogr, OGRToOGCGeomType)
1399 : {
1400 1 : EXPECT_STREQ(OGRToOGCGeomType(wkbPoint), "POINT");
1401 1 : EXPECT_STREQ(OGRToOGCGeomType(wkbPointM), "POINT");
1402 1 : EXPECT_STREQ(OGRToOGCGeomType(wkbPoint, /*bCamelCase=*/true), "Point");
1403 1 : EXPECT_STREQ(
1404 : OGRToOGCGeomType(wkbPoint, /*bCamelCase=*/true, /*bAddZM=*/true),
1405 : "Point");
1406 1 : EXPECT_STREQ(
1407 : OGRToOGCGeomType(wkbPoint25D, /*bCamelCase=*/true, /*bAddZM=*/true),
1408 : "PointZ");
1409 1 : EXPECT_STREQ(
1410 : OGRToOGCGeomType(wkbPointM, /*bCamelCase=*/true, /*bAddZM=*/true),
1411 : "PointM");
1412 1 : EXPECT_STREQ(
1413 : OGRToOGCGeomType(wkbPointZM, /*bCamelCase=*/true, /*bAddZM=*/true),
1414 : "PointZM");
1415 1 : EXPECT_STREQ(OGRToOGCGeomType(wkbPointZM, /*bCamelCase=*/true,
1416 : /*bAddZM=*/true, /*bAddSpaceBeforeZM=*/true),
1417 : "Point ZM");
1418 1 : }
1419 :
1420 : // Test layer, dataset-feature and layer-feature iterators
1421 4 : TEST_F(test_ogr, DatasetFeature_and_LayerFeature_iterators)
1422 : {
1423 1 : if (!GDALGetDriverByName("ESRI Shapefile"))
1424 : {
1425 0 : GTEST_SKIP() << "ESRI Shapefile driver missing";
1426 : return;
1427 : }
1428 :
1429 1 : std::string file(data_ + SEP + "poly.shp");
1430 1 : GDALDatasetUniquePtr poDS(GDALDataset::Open(file.c_str(), GDAL_OF_VECTOR));
1431 1 : ASSERT_TRUE(poDS != nullptr);
1432 :
1433 : {
1434 1 : GIntBig nExpectedFID = 0;
1435 11 : for (const auto &oFeatureLayerPair : poDS->GetFeatures())
1436 : {
1437 10 : ASSERT_EQ(oFeatureLayerPair.feature->GetFID(), nExpectedFID);
1438 10 : nExpectedFID++;
1439 10 : ASSERT_EQ(oFeatureLayerPair.layer, poDS->GetLayer(0));
1440 : }
1441 1 : ASSERT_EQ(nExpectedFID, 10);
1442 : }
1443 :
1444 1 : ASSERT_EQ(poDS->GetLayers().size(), 1U);
1445 1 : ASSERT_EQ(poDS->GetLayers()[0], poDS->GetLayer(0));
1446 1 : ASSERT_EQ(poDS->GetLayers()[static_cast<size_t>(0)], poDS->GetLayer(0));
1447 1 : ASSERT_EQ(poDS->GetLayers()["poly"], poDS->GetLayer(0));
1448 :
1449 2 : for (auto poLayer : poDS->GetLayers())
1450 : {
1451 1 : GIntBig nExpectedFID = 0;
1452 11 : for (const auto &poFeature : poLayer)
1453 : {
1454 10 : ASSERT_EQ(poFeature->GetFID(), nExpectedFID);
1455 10 : nExpectedFID++;
1456 : }
1457 1 : ASSERT_EQ(nExpectedFID, 10);
1458 :
1459 1 : nExpectedFID = 0;
1460 11 : for (const auto &oFeatureLayerPair : poDS->GetFeatures())
1461 : {
1462 10 : ASSERT_EQ(oFeatureLayerPair.feature->GetFID(), nExpectedFID);
1463 10 : nExpectedFID++;
1464 10 : ASSERT_EQ(oFeatureLayerPair.layer, poLayer);
1465 : }
1466 1 : ASSERT_EQ(nExpectedFID, 10);
1467 :
1468 1 : nExpectedFID = 0;
1469 5 : OGR_FOR_EACH_FEATURE_BEGIN(hFeat, reinterpret_cast<OGRLayerH>(poLayer))
1470 : {
1471 5 : if (nExpectedFID == 0)
1472 : {
1473 1 : nExpectedFID = 1;
1474 1 : continue;
1475 : }
1476 4 : ASSERT_EQ(OGR_F_GetFID(hFeat), nExpectedFID);
1477 4 : nExpectedFID++;
1478 4 : if (nExpectedFID == 5)
1479 1 : break;
1480 : }
1481 5 : OGR_FOR_EACH_FEATURE_END(hFeat)
1482 1 : ASSERT_EQ(nExpectedFID, 5);
1483 :
1484 1 : auto oIter = poLayer->begin();
1485 1 : CPLPushErrorHandler(CPLQuietErrorHandler);
1486 : // Only one feature iterator can be active at a time
1487 1 : auto oIter2 = poLayer->begin();
1488 1 : CPLPopErrorHandler();
1489 1 : ASSERT_TRUE(!(oIter2 != poLayer->end()));
1490 1 : ASSERT_TRUE(oIter != poLayer->end());
1491 : }
1492 :
1493 1 : poDS.reset(GetGDALDriverManager()->GetDriverByName("Memory")->Create(
1494 : "", 0, 0, 0, GDT_Unknown, nullptr));
1495 1 : int nCountLayers = 0;
1496 1 : for (auto poLayer : poDS->GetLayers())
1497 : {
1498 0 : CPL_IGNORE_RET_VAL(poLayer);
1499 0 : nCountLayers++;
1500 : }
1501 1 : ASSERT_EQ(nCountLayers, 0);
1502 :
1503 1 : poDS->CreateLayer("foo");
1504 1 : poDS->CreateLayer("bar", nullptr);
1505 3 : for (auto poLayer : poDS->GetLayers())
1506 : {
1507 2 : if (nCountLayers == 0)
1508 : {
1509 1 : EXPECT_STREQ(poLayer->GetName(), "foo")
1510 0 : << "layer " << poLayer->GetName();
1511 : }
1512 1 : else if (nCountLayers == 1)
1513 : {
1514 1 : EXPECT_STREQ(poLayer->GetName(), "bar")
1515 0 : << "layer " << poLayer->GetName();
1516 : }
1517 2 : nCountLayers++;
1518 : }
1519 1 : ASSERT_EQ(nCountLayers, 2);
1520 :
1521 : // std::copy requires a InputIterator
1522 1 : std::vector<OGRLayer *> oTarget;
1523 1 : oTarget.resize(2);
1524 1 : auto layers = poDS->GetLayers();
1525 1 : std::copy(layers.begin(), layers.end(), oTarget.begin());
1526 1 : ASSERT_EQ(oTarget[0], layers[0]);
1527 1 : ASSERT_EQ(oTarget[1], layers[1]);
1528 :
1529 : // but in practice not necessarily uses the postincrement iterator.
1530 1 : oTarget.clear();
1531 1 : oTarget.resize(2);
1532 1 : auto input_iterator = layers.begin();
1533 1 : auto output_iterator = oTarget.begin();
1534 3 : while (input_iterator != layers.end())
1535 : {
1536 2 : *output_iterator++ = *input_iterator++;
1537 : }
1538 1 : ASSERT_EQ(oTarget[0], layers[0]);
1539 1 : ASSERT_EQ(oTarget[1], layers[1]);
1540 :
1541 : // Test copy constructor
1542 : {
1543 1 : GDALDataset::Layers::Iterator srcIter(poDS->GetLayers().begin());
1544 1 : ++srcIter;
1545 : // coverity[copy_constructor_call]
1546 1 : GDALDataset::Layers::Iterator newIter(srcIter);
1547 1 : ASSERT_EQ(*newIter, layers[1]);
1548 : }
1549 :
1550 : // Test assignment operator
1551 : {
1552 1 : GDALDataset::Layers::Iterator srcIter(poDS->GetLayers().begin());
1553 1 : ++srcIter;
1554 1 : GDALDataset::Layers::Iterator newIter;
1555 : // coverity[copy_assignent_call]
1556 1 : newIter = srcIter;
1557 1 : ASSERT_EQ(*newIter, layers[1]);
1558 : }
1559 :
1560 : // Test move constructor
1561 : {
1562 1 : GDALDataset::Layers::Iterator srcIter(poDS->GetLayers().begin());
1563 1 : ++srcIter;
1564 1 : GDALDataset::Layers::Iterator newIter(std::move(srcIter));
1565 1 : ASSERT_EQ(*newIter, layers[1]);
1566 : }
1567 :
1568 : // Test move assignment operator
1569 : {
1570 1 : GDALDataset::Layers::Iterator srcIter(poDS->GetLayers().begin());
1571 1 : ++srcIter;
1572 1 : GDALDataset::Layers::Iterator newIter;
1573 1 : newIter = std::move(srcIter);
1574 1 : ASSERT_EQ(*newIter, layers[1]);
1575 : }
1576 : }
1577 :
1578 : // Test field iterator
1579 4 : TEST_F(test_ogr, field_iterator)
1580 : {
1581 1 : OGRFeatureDefn *poFeatureDefn = new OGRFeatureDefn();
1582 1 : poFeatureDefn->Reference();
1583 : {
1584 2 : OGRFieldDefn oFieldDefn("str_field", OFTString);
1585 1 : poFeatureDefn->AddFieldDefn(&oFieldDefn);
1586 : }
1587 : {
1588 2 : OGRFieldDefn oFieldDefn("int_field", OFTInteger);
1589 1 : poFeatureDefn->AddFieldDefn(&oFieldDefn);
1590 : }
1591 : {
1592 2 : OGRFieldDefn oFieldDefn("int64_field", OFTInteger64);
1593 1 : poFeatureDefn->AddFieldDefn(&oFieldDefn);
1594 : }
1595 : {
1596 2 : OGRFieldDefn oFieldDefn("double_field", OFTReal);
1597 1 : poFeatureDefn->AddFieldDefn(&oFieldDefn);
1598 : }
1599 : {
1600 2 : OGRFieldDefn oFieldDefn("null_field", OFTReal);
1601 1 : poFeatureDefn->AddFieldDefn(&oFieldDefn);
1602 : }
1603 : {
1604 2 : OGRFieldDefn oFieldDefn("unset_field", OFTReal);
1605 1 : poFeatureDefn->AddFieldDefn(&oFieldDefn);
1606 : }
1607 : {
1608 2 : OGRFieldDefn oFieldDefn("dt_field", OFTDateTime);
1609 1 : poFeatureDefn->AddFieldDefn(&oFieldDefn);
1610 : }
1611 : {
1612 2 : OGRFieldDefn oFieldDefn("strlist_field", OFTStringList);
1613 1 : poFeatureDefn->AddFieldDefn(&oFieldDefn);
1614 : }
1615 : {
1616 2 : OGRFieldDefn oFieldDefn("intlist_field", OFTIntegerList);
1617 1 : poFeatureDefn->AddFieldDefn(&oFieldDefn);
1618 : }
1619 : {
1620 2 : OGRFieldDefn oFieldDefn("int64list_field", OFTInteger64List);
1621 1 : poFeatureDefn->AddFieldDefn(&oFieldDefn);
1622 : }
1623 : {
1624 2 : OGRFieldDefn oFieldDefn("doublelist_field", OFTRealList);
1625 1 : poFeatureDefn->AddFieldDefn(&oFieldDefn);
1626 : }
1627 1 : OGRFeature oFeature(poFeatureDefn);
1628 :
1629 : {
1630 1 : OGRFeature oFeatureTmp(poFeatureDefn);
1631 1 : oFeatureTmp[0] = "bar";
1632 2 : ASSERT_STREQ(oFeatureTmp[0].GetString(), "bar");
1633 : {
1634 : // Proxy reference
1635 1 : auto &&x = oFeatureTmp[0];
1636 1 : auto &xRef(x);
1637 1 : x = xRef;
1638 2 : ASSERT_STREQ(oFeatureTmp[0].GetString(), "bar");
1639 : }
1640 : {
1641 1 : oFeatureTmp[0] = oFeatureTmp[0];
1642 2 : ASSERT_STREQ(oFeatureTmp[0].GetString(), "bar");
1643 : }
1644 : {
1645 : // Proxy reference
1646 1 : auto &&x = oFeatureTmp[0];
1647 1 : x = "baz";
1648 1 : ASSERT_STREQ(x.GetString(), "baz");
1649 : }
1650 1 : oFeatureTmp["str_field"] = std::string("foo");
1651 1 : oFeatureTmp["int_field"] = 123;
1652 1 : oFeatureTmp["int64_field"] = oFeatureTmp["int_field"];
1653 1 : ASSERT_EQ(oFeatureTmp["int64_field"].GetInteger64(), 123);
1654 1 : oFeatureTmp["int64_field"] = static_cast<GIntBig>(1234567890123);
1655 1 : oFeatureTmp["double_field"] = 123.45;
1656 1 : oFeatureTmp["null_field"].SetNull();
1657 1 : oFeatureTmp["unset_field"].clear();
1658 1 : oFeatureTmp["unset_field"].Unset();
1659 1 : oFeatureTmp["dt_field"].SetDateTime(2018, 4, 5, 12, 34, 56.75f, 0);
1660 1 : oFeatureTmp["strlist_field"] = CPLStringList().List();
1661 1 : oFeatureTmp["strlist_field"] = std::vector<std::string>();
1662 3 : oFeatureTmp["strlist_field"] = std::vector<std::string>{"foo", "bar"};
1663 : oFeatureTmp["strlist_field"] =
1664 1 : static_cast<CSLConstList>(oFeatureTmp["strlist_field"]);
1665 1 : ASSERT_EQ(
1666 : CSLCount(static_cast<CSLConstList>(oFeatureTmp["strlist_field"])),
1667 : 2);
1668 1 : oFeatureTmp["intlist_field"] = std::vector<int>();
1669 1 : oFeatureTmp["intlist_field"] = std::vector<int>{12, 34};
1670 1 : oFeatureTmp["int64list_field"] = std::vector<GIntBig>();
1671 : oFeatureTmp["int64list_field"] =
1672 1 : std::vector<GIntBig>{1234567890123, 34};
1673 1 : oFeatureTmp["doublelist_field"] = std::vector<double>();
1674 1 : oFeatureTmp["doublelist_field"] = std::vector<double>{12.25, 56.75};
1675 :
1676 12 : for (const auto &oField : oFeatureTmp)
1677 : {
1678 11 : oFeature[oField.GetIndex()] = oField;
1679 : }
1680 : }
1681 :
1682 : {
1683 1 : int x = oFeature[1];
1684 1 : ASSERT_EQ(x, 123);
1685 : }
1686 : {
1687 1 : int x = oFeature["int_field"];
1688 1 : ASSERT_EQ(x, 123);
1689 : }
1690 : {
1691 1 : GIntBig x = oFeature["int64_field"];
1692 1 : ASSERT_EQ(x, static_cast<GIntBig>(1234567890123));
1693 : }
1694 : {
1695 1 : double x = oFeature["double_field"];
1696 1 : ASSERT_EQ(x, 123.45);
1697 : }
1698 : {
1699 1 : const char *x = oFeature["str_field"];
1700 1 : ASSERT_STREQ(x, "foo");
1701 : }
1702 1 : bool bExceptionHit = false;
1703 : try
1704 : {
1705 1 : oFeature["inexisting_field"];
1706 : }
1707 1 : catch (const OGRFeature::FieldNotFoundException &)
1708 : {
1709 1 : bExceptionHit = true;
1710 : }
1711 1 : ASSERT_TRUE(bExceptionHit);
1712 :
1713 1 : int iIter = 0;
1714 1 : const OGRFeature *poConstFeature = &oFeature;
1715 12 : for (const auto &oField : *poConstFeature)
1716 : {
1717 11 : ASSERT_EQ(oField.GetIndex(), iIter);
1718 11 : ASSERT_EQ(oField.GetDefn(), poFeatureDefn->GetFieldDefn(iIter));
1719 22 : ASSERT_EQ(CPLString(oField.GetName()),
1720 : CPLString(oField.GetDefn()->GetNameRef()));
1721 11 : ASSERT_EQ(oField.GetType(), oField.GetDefn()->GetType());
1722 11 : ASSERT_EQ(oField.GetSubType(), oField.GetDefn()->GetSubType());
1723 11 : if (iIter == 0)
1724 : {
1725 1 : ASSERT_EQ(oField.IsUnset(), false);
1726 1 : ASSERT_EQ(oField.IsNull(), false);
1727 2 : ASSERT_EQ(CPLString(oField.GetRawValue()->String),
1728 : CPLString("foo"));
1729 2 : ASSERT_EQ(CPLString(oField.GetString()), CPLString("foo"));
1730 2 : ASSERT_EQ(CPLString(oField.GetAsString()), CPLString("foo"));
1731 : }
1732 10 : else if (iIter == 1)
1733 : {
1734 1 : ASSERT_EQ(oField.GetRawValue()->Integer, 123);
1735 1 : ASSERT_EQ(oField.GetInteger(), 123);
1736 1 : ASSERT_EQ(oField.GetAsInteger(), 123);
1737 1 : ASSERT_EQ(oField.GetAsInteger64(), 123);
1738 1 : ASSERT_EQ(oField.GetAsDouble(), 123.0);
1739 2 : ASSERT_EQ(CPLString(oField.GetAsString()), CPLString("123"));
1740 : }
1741 9 : else if (iIter == 2)
1742 : {
1743 1 : ASSERT_EQ(oField.GetRawValue()->Integer64, 1234567890123);
1744 1 : ASSERT_EQ(oField.GetInteger64(), 1234567890123);
1745 1 : ASSERT_EQ(oField.GetAsInteger(), 2147483647);
1746 1 : ASSERT_EQ(oField.GetAsInteger64(), 1234567890123);
1747 1 : ASSERT_EQ(oField.GetAsDouble(), 1234567890123.0);
1748 2 : ASSERT_EQ(CPLString(oField.GetAsString()),
1749 : CPLString("1234567890123"));
1750 : }
1751 8 : else if (iIter == 3)
1752 : {
1753 1 : ASSERT_EQ(oField.GetRawValue()->Real, 123.45);
1754 1 : ASSERT_EQ(oField.GetDouble(), 123.45);
1755 1 : ASSERT_EQ(oField.GetAsInteger(), 123);
1756 1 : ASSERT_EQ(oField.GetAsInteger64(), 123);
1757 1 : ASSERT_EQ(oField.GetAsDouble(), 123.45);
1758 2 : ASSERT_EQ(CPLString(oField.GetAsString()), CPLString("123.45"));
1759 : }
1760 7 : else if (iIter == 4)
1761 : {
1762 1 : ASSERT_EQ(oField.IsUnset(), false);
1763 1 : ASSERT_EQ(oField.IsNull(), true);
1764 : }
1765 6 : else if (iIter == 5)
1766 : {
1767 1 : ASSERT_EQ(oField.IsUnset(), true);
1768 1 : ASSERT_EQ(oField.empty(), true);
1769 1 : ASSERT_EQ(oField.IsNull(), false);
1770 : }
1771 5 : else if (iIter == 6)
1772 : {
1773 : int nYear, nMonth, nDay, nHour, nMin, nTZFlag;
1774 : float fSec;
1775 1 : ASSERT_EQ(oField.GetDateTime(&nYear, &nMonth, &nDay, &nHour, &nMin,
1776 : &fSec, &nTZFlag),
1777 : true);
1778 1 : ASSERT_EQ(nYear, 2018);
1779 1 : ASSERT_EQ(nMonth, 4);
1780 1 : ASSERT_EQ(nDay, 5);
1781 1 : ASSERT_EQ(nHour, 12);
1782 1 : ASSERT_EQ(nMin, 34);
1783 1 : ASSERT_EQ(fSec, 56.75f);
1784 1 : ASSERT_EQ(nTZFlag, 0);
1785 : }
1786 4 : else if (iIter == 7)
1787 : {
1788 : std::vector<std::string> oExpected{std::string("foo"),
1789 5 : std::string("bar")};
1790 1 : decltype(oExpected) oGot = oField;
1791 1 : ASSERT_EQ(oGot.size(), oExpected.size());
1792 3 : for (size_t i = 0; i < oExpected.size(); i++)
1793 2 : ASSERT_EQ(oGot[i], oExpected[i]);
1794 : }
1795 3 : else if (iIter == 8)
1796 : {
1797 1 : std::vector<int> oExpected{12, 34};
1798 1 : decltype(oExpected) oGot = oField;
1799 1 : ASSERT_EQ(oGot.size(), oExpected.size());
1800 3 : for (size_t i = 0; i < oExpected.size(); i++)
1801 2 : ASSERT_EQ(oGot[i], oExpected[i]);
1802 : }
1803 2 : else if (iIter == 9)
1804 : {
1805 1 : std::vector<GIntBig> oExpected{1234567890123, 34};
1806 1 : decltype(oExpected) oGot = oField;
1807 1 : ASSERT_EQ(oGot.size(), oExpected.size());
1808 3 : for (size_t i = 0; i < oExpected.size(); i++)
1809 2 : ASSERT_EQ(oGot[i], oExpected[i]);
1810 : }
1811 1 : else if (iIter == 10)
1812 : {
1813 1 : std::vector<double> oExpected{12.25, 56.75};
1814 1 : decltype(oExpected) oGot = oField;
1815 1 : ASSERT_EQ(oGot.size(), oExpected.size());
1816 3 : for (size_t i = 0; i < oExpected.size(); i++)
1817 2 : ASSERT_EQ(oGot[i], oExpected[i]);
1818 : }
1819 11 : iIter++;
1820 : }
1821 1 : poFeatureDefn->Release();
1822 : }
1823 :
1824 : // Test OGRLinearRing::isPointOnRingBoundary()
1825 4 : TEST_F(test_ogr, isPointOnRingBoundary)
1826 : {
1827 1 : OGRPolygon oPoly;
1828 1 : const char *pszPoly = "POLYGON((10 9,11 10,10 11,9 10,10 9))";
1829 1 : oPoly.importFromWkt(&pszPoly);
1830 1 : auto poRing = oPoly.getExteriorRing();
1831 :
1832 : // On first vertex
1833 : {
1834 1 : OGRPoint p(10, 9);
1835 1 : ASSERT_TRUE(poRing->isPointOnRingBoundary(&p, false));
1836 : }
1837 :
1838 : // On second vertex
1839 : {
1840 1 : OGRPoint p(11, 10);
1841 1 : ASSERT_TRUE(poRing->isPointOnRingBoundary(&p, false));
1842 : }
1843 :
1844 : // Middle of first segment
1845 : {
1846 1 : OGRPoint p(10.5, 9.5);
1847 1 : ASSERT_TRUE(poRing->isPointOnRingBoundary(&p, false));
1848 : }
1849 :
1850 : // "Before" first segment
1851 : {
1852 1 : OGRPoint p(10 - 1, 9 - 1);
1853 1 : ASSERT_TRUE(!poRing->isPointOnRingBoundary(&p, false));
1854 : }
1855 :
1856 : // "After" first segment
1857 : {
1858 1 : OGRPoint p(11 + 1, 10 + 1);
1859 1 : ASSERT_TRUE(!poRing->isPointOnRingBoundary(&p, false));
1860 : }
1861 :
1862 : // On third vertex
1863 : {
1864 1 : OGRPoint p(10, 11);
1865 1 : ASSERT_TRUE(poRing->isPointOnRingBoundary(&p, false));
1866 : }
1867 :
1868 : // Middle of second segment
1869 : {
1870 1 : OGRPoint p(10.5, 10.5);
1871 1 : ASSERT_TRUE(poRing->isPointOnRingBoundary(&p, false));
1872 : }
1873 :
1874 : // On fourth vertex
1875 : {
1876 1 : OGRPoint p(9, 10);
1877 1 : ASSERT_TRUE(poRing->isPointOnRingBoundary(&p, false));
1878 : }
1879 :
1880 : // Middle of third segment
1881 : {
1882 1 : OGRPoint p(9.5, 10.5);
1883 1 : ASSERT_TRUE(poRing->isPointOnRingBoundary(&p, false));
1884 : }
1885 :
1886 : // Middle of fourth segment
1887 : {
1888 1 : OGRPoint p(9.5, 9.5);
1889 1 : ASSERT_TRUE(poRing->isPointOnRingBoundary(&p, false));
1890 : }
1891 : }
1892 :
1893 : // Test OGRGeometry::exportToWkt()
1894 4 : TEST_F(test_ogr, OGRGeometry_exportToWkt)
1895 : {
1896 1 : char *pszWKT = nullptr;
1897 1 : OGRPoint p(1, 2);
1898 1 : p.exportToWkt(&pszWKT);
1899 1 : ASSERT_TRUE(pszWKT != nullptr);
1900 1 : EXPECT_STREQ(pszWKT, "POINT (1 2)");
1901 1 : CPLFree(pszWKT);
1902 : }
1903 :
1904 : // Test OGRGeometry::clone()
1905 4 : TEST_F(test_ogr, OGRGeometry_clone)
1906 : {
1907 1 : const char *apszWKT[] = {
1908 : "POINT (0 0)",
1909 : "POINT ZM EMPTY",
1910 : "LINESTRING (0 0)",
1911 : "LINESTRING ZM EMPTY",
1912 : "POLYGON ((0 0),(0 0))",
1913 : "MULTIPOLYGON ZM EMPTY",
1914 : "MULTIPOINT ((0 0))",
1915 : "MULTIPOINT ZM EMPTY",
1916 : "MULTILINESTRING ((0 0))",
1917 : "MULTILINESTRING ZM EMPTY",
1918 : "MULTIPOLYGON (((0 0)))",
1919 : "MULTIPOLYGON ZM EMPTY",
1920 : "GEOMETRYCOLLECTION (POINT (0 0))",
1921 : "GEOMETRYCOLLECTION ZM EMPTY",
1922 : "CIRCULARSTRING (0 0,1 1,0 0)",
1923 : "CIRCULARSTRING Z EMPTY",
1924 : "CIRCULARSTRING ZM EMPTY",
1925 : "COMPOUNDCURVE ((0 0,1 1))",
1926 : "COMPOUNDCURVE ZM EMPTY",
1927 : "CURVEPOLYGON ((0 0,1 1,1 0,0 0))",
1928 : "CURVEPOLYGON ZM EMPTY",
1929 : "MULTICURVE ((0 0))",
1930 : "MULTICURVE ZM EMPTY",
1931 : "MULTISURFACE (((0 0)))",
1932 : "MULTISURFACE ZM EMPTY",
1933 : "TRIANGLE ((0 0,0 1,1 1,0 0))",
1934 : "TRIANGLE ZM EMPTY",
1935 : "POLYHEDRALSURFACE (((0 0,0 1,1 1,0 0)))",
1936 : "POLYHEDRALSURFACE ZM EMPTY",
1937 : "TIN (((0 0,0 1,1 1,0 0)))",
1938 : "TIN ZM EMPTY",
1939 : };
1940 1 : OGRSpatialReference oSRS;
1941 32 : for (const char *pszWKT : apszWKT)
1942 : {
1943 31 : OGRGeometry *poGeom = nullptr;
1944 31 : OGRGeometryFactory::createFromWkt(pszWKT, &oSRS, &poGeom);
1945 31 : auto poClone = poGeom->clone();
1946 31 : ASSERT_TRUE(poClone != nullptr);
1947 31 : char *outWKT = nullptr;
1948 31 : poClone->exportToWkt(&outWKT, wkbVariantIso);
1949 31 : EXPECT_STREQ(pszWKT, outWKT);
1950 31 : CPLFree(outWKT);
1951 31 : delete poClone;
1952 31 : delete poGeom;
1953 : }
1954 : }
1955 :
1956 : // Test OGRLineString::removePoint()
1957 4 : TEST_F(test_ogr, OGRLineString_removePoint)
1958 : {
1959 : {
1960 1 : OGRLineString ls;
1961 1 : ls.addPoint(0, 1);
1962 1 : ls.addPoint(2, 3);
1963 1 : ls.addPoint(4, 5);
1964 1 : ASSERT_TRUE(!ls.removePoint(-1));
1965 1 : ASSERT_TRUE(!ls.removePoint(3));
1966 1 : ASSERT_EQ(ls.getNumPoints(), 3);
1967 1 : ASSERT_TRUE(ls.removePoint(1));
1968 1 : ASSERT_EQ(ls.getNumPoints(), 2);
1969 1 : ASSERT_EQ(ls.getX(0), 0.0);
1970 1 : ASSERT_EQ(ls.getY(0), 1.0);
1971 1 : ASSERT_EQ(ls.getX(1), 4.0);
1972 1 : ASSERT_EQ(ls.getY(1), 5.0);
1973 1 : ASSERT_TRUE(ls.removePoint(1));
1974 1 : ASSERT_EQ(ls.getNumPoints(), 1);
1975 1 : ASSERT_TRUE(ls.removePoint(0));
1976 1 : ASSERT_EQ(ls.getNumPoints(), 0);
1977 : }
1978 : {
1979 : // With Z, M
1980 1 : OGRLineString ls;
1981 1 : ls.addPoint(0, 1, 20, 30);
1982 1 : ls.addPoint(2, 3, 40, 50);
1983 1 : ls.addPoint(4, 5, 60, 70);
1984 1 : ASSERT_TRUE(!ls.removePoint(-1));
1985 1 : ASSERT_TRUE(!ls.removePoint(3));
1986 1 : ASSERT_EQ(ls.getNumPoints(), 3);
1987 1 : ASSERT_TRUE(ls.removePoint(1));
1988 1 : ASSERT_EQ(ls.getNumPoints(), 2);
1989 1 : ASSERT_EQ(ls.getX(0), 0.0);
1990 1 : ASSERT_EQ(ls.getY(0), 1.0);
1991 1 : ASSERT_EQ(ls.getZ(0), 20.0);
1992 1 : ASSERT_EQ(ls.getM(0), 30.0);
1993 1 : ASSERT_EQ(ls.getX(1), 4.0);
1994 1 : ASSERT_EQ(ls.getY(1), 5.0);
1995 1 : ASSERT_EQ(ls.getZ(1), 60.0);
1996 1 : ASSERT_EQ(ls.getM(1), 70.0);
1997 1 : ASSERT_TRUE(ls.removePoint(1));
1998 1 : ASSERT_EQ(ls.getNumPoints(), 1);
1999 1 : ASSERT_TRUE(ls.removePoint(0));
2000 1 : ASSERT_EQ(ls.getNumPoints(), 0);
2001 : }
2002 : }
2003 :
2004 : // Test effect of MarkSuppressOnClose() on DXF
2005 4 : TEST_F(test_ogr, DXF_MarkSuppressOnClose)
2006 : {
2007 1 : CPLString tmpFilename(CPLGenerateTempFilename(nullptr));
2008 1 : tmpFilename += ".dxf";
2009 1 : auto poDrv = GDALDriver::FromHandle(GDALGetDriverByName("DXF"));
2010 1 : if (poDrv)
2011 : {
2012 : auto poDS(GDALDatasetUniquePtr(
2013 1 : poDrv->Create(tmpFilename, 0, 0, 0, GDT_Unknown, nullptr)));
2014 1 : ASSERT_TRUE(poDS != nullptr);
2015 :
2016 : OGRLayer *poLayer =
2017 1 : poDS->CreateLayer("test", nullptr, wkbPoint, nullptr);
2018 1 : ASSERT_TRUE(poLayer != nullptr);
2019 :
2020 101 : for (double x = 0; x < 100; x++)
2021 : {
2022 : OGRFeature *poFeature =
2023 100 : OGRFeature::CreateFeature(poLayer->GetLayerDefn());
2024 100 : ASSERT_TRUE(poFeature != nullptr);
2025 100 : OGRPoint pt(x, 42);
2026 100 : ASSERT_EQ(OGRERR_NONE, poFeature->SetGeometry(&pt));
2027 100 : ASSERT_EQ(OGRERR_NONE, poLayer->CreateFeature(poFeature));
2028 100 : OGRFeature::DestroyFeature(poFeature);
2029 : }
2030 :
2031 1 : poDS->MarkSuppressOnClose();
2032 :
2033 1 : poDS.reset();
2034 : VSIStatBufL sStat;
2035 1 : ASSERT_TRUE(0 != VSIStatL(tmpFilename, &sStat));
2036 : }
2037 : }
2038 :
2039 : // Test OGREnvelope
2040 4 : TEST_F(test_ogr, OGREnvelope)
2041 : {
2042 1 : OGREnvelope s1;
2043 1 : ASSERT_TRUE(!s1.IsInit());
2044 : {
2045 1 : OGREnvelope s2(s1);
2046 1 : ASSERT_TRUE(s1 == s2);
2047 1 : ASSERT_TRUE(!(s1 != s2));
2048 : }
2049 :
2050 1 : s1.MinX = 0;
2051 1 : s1.MinY = 1;
2052 1 : s1.MaxX = 2;
2053 1 : s1.MaxY = 3;
2054 1 : ASSERT_TRUE(s1.IsInit());
2055 : {
2056 1 : OGREnvelope s2(s1);
2057 1 : ASSERT_TRUE(s1 == s2);
2058 1 : ASSERT_TRUE(!(s1 != s2));
2059 1 : s2.MinX += 1;
2060 1 : ASSERT_TRUE(s1 != s2);
2061 1 : ASSERT_TRUE(!(s1 == s2));
2062 : }
2063 : }
2064 :
2065 : // Test OGREnvelope3D
2066 4 : TEST_F(test_ogr, OGREnvelope3D)
2067 : {
2068 1 : OGREnvelope3D s1;
2069 1 : EXPECT_TRUE(!s1.IsInit());
2070 : {
2071 1 : OGREnvelope3D s2(s1);
2072 1 : EXPECT_TRUE(s1 == s2);
2073 1 : EXPECT_TRUE(!(s1 != s2));
2074 : }
2075 :
2076 1 : s1.MinX = 0;
2077 1 : s1.MinY = 1;
2078 1 : s1.MaxX = 2;
2079 1 : s1.MaxY = 3;
2080 1 : EXPECT_TRUE(s1.IsInit());
2081 1 : EXPECT_FALSE(s1.Is3D());
2082 1 : s1.MinZ = 4;
2083 1 : s1.MaxZ = 5;
2084 1 : EXPECT_TRUE(s1.Is3D());
2085 : {
2086 1 : OGREnvelope3D s2(s1);
2087 1 : EXPECT_TRUE(s1 == s2);
2088 1 : EXPECT_TRUE(!(s1 != s2));
2089 1 : s2.MinX += 1;
2090 1 : EXPECT_TRUE(s1 != s2);
2091 1 : EXPECT_TRUE(!(s1 == s2));
2092 : }
2093 1 : }
2094 :
2095 : // Test OGRStyleMgr::InitStyleString() with a style name
2096 : // (https://github.com/OSGeo/gdal/issues/5555)
2097 4 : TEST_F(test_ogr, InitStyleString_with_style_name)
2098 : {
2099 1 : OGRStyleTableH hStyleTable = OGR_STBL_Create();
2100 1 : OGR_STBL_AddStyle(hStyleTable, "@my_style", "PEN(c:#FF0000,w:5px)");
2101 1 : OGRStyleMgrH hSM = OGR_SM_Create(hStyleTable);
2102 1 : EXPECT_EQ(OGR_SM_GetPartCount(hSM, nullptr), 0);
2103 1 : EXPECT_TRUE(OGR_SM_InitStyleString(hSM, "@my_style"));
2104 1 : EXPECT_EQ(OGR_SM_GetPartCount(hSM, nullptr), 1);
2105 1 : EXPECT_TRUE(!OGR_SM_InitStyleString(hSM, "@i_do_not_exist"));
2106 1 : OGR_SM_Destroy(hSM);
2107 1 : OGR_STBL_Destroy(hStyleTable);
2108 1 : }
2109 :
2110 : // Test OGR_L_GetArrowStream
2111 4 : TEST_F(test_ogr, OGR_L_GetArrowStream)
2112 : {
2113 : auto poDS = std::unique_ptr<GDALDataset>(
2114 : GetGDALDriverManager()->GetDriverByName("Memory")->Create(
2115 1 : "", 0, 0, 0, GDT_Unknown, nullptr));
2116 1 : auto poLayer = poDS->CreateLayer("test");
2117 : {
2118 2 : OGRFieldDefn oFieldDefn("str", OFTString);
2119 1 : poLayer->CreateField(&oFieldDefn);
2120 : }
2121 : {
2122 2 : OGRFieldDefn oFieldDefn("bool", OFTInteger);
2123 1 : oFieldDefn.SetSubType(OFSTBoolean);
2124 1 : poLayer->CreateField(&oFieldDefn);
2125 : }
2126 : {
2127 2 : OGRFieldDefn oFieldDefn("int16", OFTInteger);
2128 1 : oFieldDefn.SetSubType(OFSTInt16);
2129 1 : poLayer->CreateField(&oFieldDefn);
2130 : }
2131 : {
2132 2 : OGRFieldDefn oFieldDefn("int32", OFTInteger);
2133 1 : poLayer->CreateField(&oFieldDefn);
2134 : }
2135 : {
2136 2 : OGRFieldDefn oFieldDefn("int64", OFTInteger64);
2137 1 : poLayer->CreateField(&oFieldDefn);
2138 : }
2139 : {
2140 2 : OGRFieldDefn oFieldDefn("float32", OFTReal);
2141 1 : oFieldDefn.SetSubType(OFSTFloat32);
2142 1 : poLayer->CreateField(&oFieldDefn);
2143 : }
2144 : {
2145 2 : OGRFieldDefn oFieldDefn("float64", OFTReal);
2146 1 : poLayer->CreateField(&oFieldDefn);
2147 : }
2148 : {
2149 2 : OGRFieldDefn oFieldDefn("date", OFTDate);
2150 1 : poLayer->CreateField(&oFieldDefn);
2151 : }
2152 : {
2153 2 : OGRFieldDefn oFieldDefn("time", OFTTime);
2154 1 : poLayer->CreateField(&oFieldDefn);
2155 : }
2156 : {
2157 2 : OGRFieldDefn oFieldDefn("datetime", OFTDateTime);
2158 1 : poLayer->CreateField(&oFieldDefn);
2159 : }
2160 : {
2161 2 : OGRFieldDefn oFieldDefn("binary", OFTBinary);
2162 1 : poLayer->CreateField(&oFieldDefn);
2163 : }
2164 : {
2165 2 : OGRFieldDefn oFieldDefn("strlist", OFTStringList);
2166 1 : poLayer->CreateField(&oFieldDefn);
2167 : }
2168 : {
2169 2 : OGRFieldDefn oFieldDefn("boollist", OFTIntegerList);
2170 1 : oFieldDefn.SetSubType(OFSTBoolean);
2171 1 : poLayer->CreateField(&oFieldDefn);
2172 : }
2173 : {
2174 2 : OGRFieldDefn oFieldDefn("int16list", OFTIntegerList);
2175 1 : oFieldDefn.SetSubType(OFSTInt16);
2176 1 : poLayer->CreateField(&oFieldDefn);
2177 : }
2178 : {
2179 2 : OGRFieldDefn oFieldDefn("int32list", OFTIntegerList);
2180 1 : poLayer->CreateField(&oFieldDefn);
2181 : }
2182 : {
2183 2 : OGRFieldDefn oFieldDefn("int64list", OFTInteger64List);
2184 1 : poLayer->CreateField(&oFieldDefn);
2185 : }
2186 : {
2187 2 : OGRFieldDefn oFieldDefn("float32list", OFTRealList);
2188 1 : oFieldDefn.SetSubType(OFSTFloat32);
2189 1 : poLayer->CreateField(&oFieldDefn);
2190 : }
2191 : {
2192 2 : OGRFieldDefn oFieldDefn("float64list", OFTRealList);
2193 1 : poLayer->CreateField(&oFieldDefn);
2194 : }
2195 1 : auto poFDefn = poLayer->GetLayerDefn();
2196 : struct ArrowArrayStream stream;
2197 1 : ASSERT_TRUE(
2198 : OGR_L_GetArrowStream(OGRLayer::ToHandle(poLayer), &stream, nullptr));
2199 : {
2200 : // Cannot start a new stream while one is active
2201 : struct ArrowArrayStream stream2;
2202 1 : CPLPushErrorHandler(CPLQuietErrorHandler);
2203 1 : ASSERT_TRUE(OGR_L_GetArrowStream(OGRLayer::ToHandle(poLayer), &stream2,
2204 : nullptr) == false);
2205 1 : CPLPopErrorHandler();
2206 : }
2207 1 : ASSERT_TRUE(stream.release != nullptr);
2208 :
2209 : struct ArrowSchema schema;
2210 1 : CPLErrorReset();
2211 1 : ASSERT_TRUE(stream.get_last_error(&stream) == nullptr);
2212 1 : ASSERT_EQ(stream.get_schema(&stream, &schema), 0);
2213 1 : ASSERT_TRUE(stream.get_last_error(&stream) == nullptr);
2214 1 : ASSERT_TRUE(schema.release != nullptr);
2215 1 : ASSERT_EQ(schema.n_children,
2216 : 1 + poFDefn->GetFieldCount() + poFDefn->GetGeomFieldCount());
2217 1 : schema.release(&schema);
2218 :
2219 : struct ArrowArray array;
2220 : // Next batch ==> End of stream
2221 1 : ASSERT_EQ(stream.get_next(&stream, &array), 0);
2222 1 : ASSERT_TRUE(array.release == nullptr);
2223 :
2224 : // Release stream
2225 1 : stream.release(&stream);
2226 :
2227 : {
2228 1 : auto poFeature = std::unique_ptr<OGRFeature>(new OGRFeature(poFDefn));
2229 1 : poFeature->SetField("bool", 1);
2230 1 : poFeature->SetField("int16", -12345);
2231 1 : poFeature->SetField("int32", 12345678);
2232 1 : poFeature->SetField("int64", static_cast<GIntBig>(12345678901234));
2233 1 : poFeature->SetField("float32", 1.25);
2234 1 : poFeature->SetField("float64", 1.250123);
2235 1 : poFeature->SetField("str", "abc");
2236 1 : poFeature->SetField("date", "2022-05-31");
2237 1 : poFeature->SetField("time", "12:34:56.789");
2238 1 : poFeature->SetField("datetime", "2022-05-31T12:34:56.789Z");
2239 1 : poFeature->SetField("boollist", "[False,True]");
2240 1 : poFeature->SetField("int16list", "[-12345,12345]");
2241 1 : poFeature->SetField("int32list", "[-12345678,12345678]");
2242 1 : poFeature->SetField("int64list", "[-12345678901234,12345678901234]");
2243 1 : poFeature->SetField("float32list", "[-1.25,1.25]");
2244 1 : poFeature->SetField("float64list", "[-1.250123,1.250123]");
2245 1 : poFeature->SetField("strlist", "[\"abc\",\"defghi\"]");
2246 1 : poFeature->SetField(poFDefn->GetFieldIndex("binary"), 2, "\xDE\xAD");
2247 1 : OGRGeometry *poGeom = nullptr;
2248 1 : OGRGeometryFactory::createFromWkt("POINT(1 2)", nullptr, &poGeom);
2249 1 : poFeature->SetGeometryDirectly(poGeom);
2250 1 : ASSERT_EQ(poLayer->CreateFeature(poFeature.get()), OGRERR_NONE);
2251 : }
2252 :
2253 : // Get a new stream now that we've released it
2254 1 : ASSERT_TRUE(
2255 : OGR_L_GetArrowStream(OGRLayer::ToHandle(poLayer), &stream, nullptr));
2256 1 : ASSERT_TRUE(stream.release != nullptr);
2257 :
2258 1 : ASSERT_EQ(stream.get_next(&stream, &array), 0);
2259 1 : ASSERT_TRUE(array.release != nullptr);
2260 1 : ASSERT_EQ(array.n_children,
2261 : 1 + poFDefn->GetFieldCount() + poFDefn->GetGeomFieldCount());
2262 1 : ASSERT_EQ(array.length, poLayer->GetFeatureCount(false));
2263 1 : ASSERT_EQ(array.null_count, 0);
2264 1 : ASSERT_EQ(array.n_buffers, 1);
2265 1 : ASSERT_TRUE(array.buffers[0] == nullptr); // no bitmap
2266 21 : for (int i = 0; i < array.n_children; i++)
2267 : {
2268 20 : ASSERT_TRUE(array.children[i]->release != nullptr);
2269 20 : ASSERT_EQ(array.children[i]->length, array.length);
2270 20 : ASSERT_TRUE(array.children[i]->n_buffers >= 2);
2271 20 : ASSERT_TRUE(array.children[i]->buffers[0] == nullptr); // no bitmap
2272 20 : ASSERT_EQ(array.children[i]->null_count, 0);
2273 20 : ASSERT_TRUE(array.children[i]->buffers[1] != nullptr);
2274 20 : if (array.children[i]->n_buffers == 3)
2275 : {
2276 3 : ASSERT_TRUE(array.children[i]->buffers[2] != nullptr);
2277 : }
2278 : }
2279 1 : array.release(&array);
2280 :
2281 : // Next batch ==> End of stream
2282 1 : ASSERT_EQ(stream.get_next(&stream, &array), 0);
2283 1 : ASSERT_TRUE(array.release == nullptr);
2284 :
2285 : // Release stream
2286 1 : stream.release(&stream);
2287 :
2288 : // Insert 2 empty features
2289 : {
2290 1 : auto poFeature = std::unique_ptr<OGRFeature>(new OGRFeature(poFDefn));
2291 1 : ASSERT_EQ(poLayer->CreateFeature(poFeature.get()), OGRERR_NONE);
2292 : }
2293 :
2294 : {
2295 1 : auto poFeature = std::unique_ptr<OGRFeature>(new OGRFeature(poFDefn));
2296 1 : ASSERT_EQ(poLayer->CreateFeature(poFeature.get()), OGRERR_NONE);
2297 : }
2298 :
2299 : // Get a new stream now that we've released it
2300 : {
2301 : char **papszOptions =
2302 1 : CSLSetNameValue(nullptr, "MAX_FEATURES_IN_BATCH", "2");
2303 1 : ASSERT_TRUE(OGR_L_GetArrowStream(OGRLayer::ToHandle(poLayer), &stream,
2304 : papszOptions));
2305 1 : CSLDestroy(papszOptions);
2306 : }
2307 1 : ASSERT_TRUE(stream.release != nullptr);
2308 :
2309 1 : ASSERT_EQ(stream.get_next(&stream, &array), 0);
2310 1 : ASSERT_TRUE(array.release != nullptr);
2311 1 : ASSERT_EQ(array.n_children,
2312 : 1 + poFDefn->GetFieldCount() + poFDefn->GetGeomFieldCount());
2313 1 : ASSERT_EQ(array.length, 2);
2314 21 : for (int i = 0; i < array.n_children; i++)
2315 : {
2316 20 : ASSERT_TRUE(array.children[i]->release != nullptr);
2317 20 : ASSERT_EQ(array.children[i]->length, array.length);
2318 20 : ASSERT_TRUE(array.children[i]->n_buffers >= 2);
2319 20 : if (i > 0)
2320 : {
2321 19 : ASSERT_TRUE(array.children[i]->buffers[0] !=
2322 : nullptr); // we have a bitmap
2323 19 : ASSERT_EQ(array.children[i]->null_count, 1);
2324 : }
2325 20 : ASSERT_TRUE(array.children[i]->buffers[1] != nullptr);
2326 20 : if (array.children[i]->n_buffers == 3)
2327 : {
2328 3 : ASSERT_TRUE(array.children[i]->buffers[2] != nullptr);
2329 : }
2330 : }
2331 1 : array.release(&array);
2332 :
2333 : // Next batch
2334 1 : ASSERT_EQ(stream.get_next(&stream, &array), 0);
2335 1 : ASSERT_TRUE(array.release != nullptr);
2336 1 : ASSERT_EQ(array.n_children,
2337 : 1 + poFDefn->GetFieldCount() + poFDefn->GetGeomFieldCount());
2338 1 : ASSERT_EQ(array.length, 1);
2339 1 : array.release(&array);
2340 :
2341 : // Next batch ==> End of stream
2342 1 : ASSERT_EQ(stream.get_next(&stream, &array), 0);
2343 1 : ASSERT_TRUE(array.release == nullptr);
2344 :
2345 : // Release stream
2346 1 : stream.release(&stream);
2347 :
2348 : // Get a new stream now that we've released it
2349 1 : ASSERT_TRUE(
2350 : OGR_L_GetArrowStream(OGRLayer::ToHandle(poLayer), &stream, nullptr));
2351 1 : ASSERT_TRUE(stream.release != nullptr);
2352 :
2353 : // Free dataset & layer
2354 1 : poDS.reset();
2355 :
2356 : // Test releasing the stream after the dataset/layer has been closed
2357 1 : CPLPushErrorHandler(CPLQuietErrorHandler);
2358 1 : CPLErrorReset();
2359 1 : ASSERT_TRUE(stream.get_schema(&stream, &schema) != 0);
2360 1 : ASSERT_TRUE(stream.get_last_error(&stream) != nullptr);
2361 1 : ASSERT_TRUE(stream.get_next(&stream, &array) != 0);
2362 1 : CPLPopErrorHandler();
2363 1 : stream.release(&stream);
2364 : }
2365 :
2366 : // Test field domain cloning
2367 4 : TEST_F(test_ogr, field_domain_cloning)
2368 : {
2369 : // range domain
2370 : OGRField min;
2371 1 : min.Real = 5.5;
2372 : OGRField max;
2373 1 : max.Real = 6.5;
2374 : OGRRangeFieldDomain oRange("name", "description", OGRFieldType::OFTReal,
2375 : OGRFieldSubType::OFSTBoolean, min, true, max,
2376 2 : true);
2377 1 : oRange.SetMergePolicy(OGRFieldDomainMergePolicy::OFDMP_GEOMETRY_WEIGHTED);
2378 1 : oRange.SetSplitPolicy(OGRFieldDomainSplitPolicy::OFDSP_GEOMETRY_RATIO);
2379 1 : std::unique_ptr<OGRRangeFieldDomain> poClonedRange(oRange.Clone());
2380 1 : ASSERT_EQ(poClonedRange->GetName(), oRange.GetName());
2381 1 : ASSERT_EQ(poClonedRange->GetDescription(), oRange.GetDescription());
2382 1 : bool originalInclusive = false;
2383 1 : bool cloneInclusive = false;
2384 1 : ASSERT_EQ(poClonedRange->GetMin(originalInclusive).Real,
2385 : oRange.GetMin(cloneInclusive).Real);
2386 1 : ASSERT_EQ(originalInclusive, cloneInclusive);
2387 1 : ASSERT_EQ(poClonedRange->GetMax(originalInclusive).Real,
2388 : oRange.GetMax(cloneInclusive).Real);
2389 1 : ASSERT_EQ(originalInclusive, cloneInclusive);
2390 1 : ASSERT_EQ(poClonedRange->GetFieldType(), oRange.GetFieldType());
2391 1 : ASSERT_EQ(poClonedRange->GetFieldSubType(), oRange.GetFieldSubType());
2392 1 : ASSERT_EQ(poClonedRange->GetSplitPolicy(), oRange.GetSplitPolicy());
2393 1 : ASSERT_EQ(poClonedRange->GetMergePolicy(), oRange.GetMergePolicy());
2394 :
2395 : // glob domain
2396 : OGRGlobFieldDomain oGlob("name", "description", OGRFieldType::OFTString,
2397 2 : OGRFieldSubType::OFSTBoolean, "*a*");
2398 1 : oGlob.SetMergePolicy(OGRFieldDomainMergePolicy::OFDMP_GEOMETRY_WEIGHTED);
2399 1 : oGlob.SetSplitPolicy(OGRFieldDomainSplitPolicy::OFDSP_GEOMETRY_RATIO);
2400 1 : std::unique_ptr<OGRGlobFieldDomain> poClonedGlob(oGlob.Clone());
2401 1 : ASSERT_EQ(poClonedGlob->GetName(), oGlob.GetName());
2402 1 : ASSERT_EQ(poClonedGlob->GetDescription(), oGlob.GetDescription());
2403 1 : ASSERT_EQ(poClonedGlob->GetGlob(), oGlob.GetGlob());
2404 1 : ASSERT_EQ(poClonedGlob->GetFieldType(), oGlob.GetFieldType());
2405 1 : ASSERT_EQ(poClonedGlob->GetFieldSubType(), oGlob.GetFieldSubType());
2406 1 : ASSERT_EQ(poClonedGlob->GetSplitPolicy(), oGlob.GetSplitPolicy());
2407 1 : ASSERT_EQ(poClonedGlob->GetMergePolicy(), oGlob.GetMergePolicy());
2408 :
2409 : // coded value domain
2410 : OGRCodedFieldDomain oCoded("name", "description", OGRFieldType::OFTString,
2411 2 : OGRFieldSubType::OFSTBoolean, {OGRCodedValue()});
2412 1 : oCoded.SetMergePolicy(OGRFieldDomainMergePolicy::OFDMP_GEOMETRY_WEIGHTED);
2413 1 : oCoded.SetSplitPolicy(OGRFieldDomainSplitPolicy::OFDSP_GEOMETRY_RATIO);
2414 1 : std::unique_ptr<OGRCodedFieldDomain> poClonedCoded(oCoded.Clone());
2415 1 : ASSERT_EQ(poClonedCoded->GetName(), oCoded.GetName());
2416 1 : ASSERT_EQ(poClonedCoded->GetDescription(), oCoded.GetDescription());
2417 1 : ASSERT_EQ(poClonedCoded->GetFieldType(), oCoded.GetFieldType());
2418 1 : ASSERT_EQ(poClonedCoded->GetFieldSubType(), oCoded.GetFieldSubType());
2419 1 : ASSERT_EQ(poClonedCoded->GetSplitPolicy(), oCoded.GetSplitPolicy());
2420 1 : ASSERT_EQ(poClonedCoded->GetMergePolicy(), oCoded.GetMergePolicy());
2421 : }
2422 :
2423 : // Test field comments
2424 4 : TEST_F(test_ogr, field_comments)
2425 : {
2426 1 : OGRFieldDefn oFieldDefn("field1", OFTString);
2427 1 : ASSERT_EQ(oFieldDefn.GetComment(), "");
2428 1 : oFieldDefn.SetComment("my comment");
2429 1 : ASSERT_EQ(oFieldDefn.GetComment(), "my comment");
2430 :
2431 1 : OGRFieldDefn oFieldDefn2(&oFieldDefn);
2432 1 : ASSERT_EQ(oFieldDefn2.GetComment(), "my comment");
2433 1 : ASSERT_TRUE(oFieldDefn.IsSame(&oFieldDefn2));
2434 :
2435 1 : oFieldDefn2.SetComment("my comment 2");
2436 1 : ASSERT_FALSE(oFieldDefn.IsSame(&oFieldDefn2));
2437 : }
2438 :
2439 : // Test OGRFeatureDefn C++ GetFields() iterator
2440 4 : TEST_F(test_ogr, feature_defn_fields_iterator)
2441 : {
2442 2 : OGRFeatureDefn oFDefn;
2443 : {
2444 2 : OGRFieldDefn oFieldDefn("field1", OFTString);
2445 1 : oFDefn.AddFieldDefn(&oFieldDefn);
2446 : }
2447 : {
2448 2 : OGRFieldDefn oFieldDefn("field2", OFTString);
2449 1 : oFDefn.AddFieldDefn(&oFieldDefn);
2450 : }
2451 1 : EXPECT_EQ(oFDefn.GetFields().size(), oFDefn.GetFieldCount());
2452 1 : int i = 0;
2453 3 : for (const auto *poFieldDefn : oFDefn.GetFields())
2454 : {
2455 2 : EXPECT_EQ(oFDefn.GetFields()[i], oFDefn.GetFieldDefn(i));
2456 2 : EXPECT_EQ(poFieldDefn, oFDefn.GetFieldDefn(i));
2457 2 : ++i;
2458 : }
2459 1 : EXPECT_EQ(i, oFDefn.GetFieldCount());
2460 1 : }
2461 :
2462 : // Test OGRFeatureDefn C++ GetGeomFields() iterator
2463 4 : TEST_F(test_ogr, feature_defn_geomfields_iterator)
2464 : {
2465 2 : OGRFeatureDefn oFDefn;
2466 : {
2467 2 : OGRGeomFieldDefn oGeomFieldDefn("field1", wkbUnknown);
2468 1 : oFDefn.AddGeomFieldDefn(&oGeomFieldDefn);
2469 : }
2470 : {
2471 2 : OGRGeomFieldDefn oGeomFieldDefn("field2", wkbUnknown);
2472 1 : oFDefn.AddGeomFieldDefn(&oGeomFieldDefn);
2473 : }
2474 1 : EXPECT_EQ(oFDefn.GetGeomFields().size(), oFDefn.GetGeomFieldCount());
2475 1 : int i = 0;
2476 4 : for (const auto *poGeomFieldDefn : oFDefn.GetGeomFields())
2477 : {
2478 3 : EXPECT_EQ(oFDefn.GetGeomFields()[i], oFDefn.GetGeomFieldDefn(i));
2479 3 : EXPECT_EQ(poGeomFieldDefn, oFDefn.GetGeomFieldDefn(i));
2480 3 : ++i;
2481 : }
2482 1 : EXPECT_EQ(i, oFDefn.GetGeomFieldCount());
2483 1 : }
2484 :
2485 : // Test GDALDataset QueryLoggerFunc callback
2486 4 : TEST_F(test_ogr, GDALDatasetSetQueryLoggerFunc)
2487 : {
2488 1 : if (GDALGetDriverByName("GPKG") == nullptr)
2489 : {
2490 0 : GTEST_SKIP() << "GPKG driver missing";
2491 : }
2492 :
2493 1 : auto tmpGPKG{testing::TempDir() + "/poly-1-feature.gpkg"};
2494 : {
2495 2 : std::string srcfilename(data_ + SEP + "poly-1-feature.gpkg");
2496 2 : std::ifstream src(srcfilename, std::ios::binary);
2497 2 : std::ofstream dst(tmpGPKG, std::ios::binary);
2498 1 : dst << src.rdbuf();
2499 : }
2500 :
2501 : struct QueryLogEntry
2502 : {
2503 : std::string sql;
2504 : std::string error;
2505 : int64_t numRecords;
2506 : int64_t executionTimeMilliseconds;
2507 : };
2508 :
2509 : // Note: this must be constructed before poDS or the order
2510 : // of destruction will make the callback call the already
2511 : // destructed vector
2512 1 : std::vector<QueryLogEntry> queryLog;
2513 :
2514 : auto poDS = std::unique_ptr<GDALDataset>(
2515 1 : GDALDataset::Open(tmpGPKG.c_str(), GDAL_OF_VECTOR | GDAL_OF_UPDATE));
2516 1 : ASSERT_TRUE(poDS);
2517 1 : auto hDS = GDALDataset::ToHandle(poDS.get());
2518 1 : ASSERT_TRUE(hDS);
2519 :
2520 1 : const bool retVal = GDALDatasetSetQueryLoggerFunc(
2521 : hDS,
2522 18 : [](const char *pszSQL, const char *pszError, int64_t lNumRecords,
2523 : int64_t lExecutionTimeMilliseconds, void *pQueryLoggerArg)
2524 : {
2525 18 : std::vector<QueryLogEntry> *queryLogLocal{
2526 : reinterpret_cast<std::vector<QueryLogEntry> *>(
2527 : pQueryLoggerArg)};
2528 36 : QueryLogEntry entryLocal;
2529 18 : if (pszSQL)
2530 : {
2531 18 : entryLocal.sql = pszSQL;
2532 : }
2533 18 : entryLocal.numRecords = lNumRecords;
2534 18 : entryLocal.executionTimeMilliseconds = lExecutionTimeMilliseconds;
2535 18 : if (pszError)
2536 : {
2537 1 : entryLocal.error = pszError;
2538 : }
2539 18 : queryLogLocal->push_back(entryLocal);
2540 18 : },
2541 1 : &queryLog);
2542 :
2543 1 : ASSERT_TRUE(retVal);
2544 1 : auto hLayer{GDALDatasetGetLayer(hDS, 0)};
2545 1 : ASSERT_TRUE(hLayer);
2546 1 : ASSERT_STREQ(OGR_L_GetName(hLayer), "poly");
2547 : auto poFeature = std::unique_ptr<OGRFeature>(
2548 1 : OGRFeature::FromHandle(OGR_L_GetNextFeature(hLayer)));
2549 1 : auto hFeature = OGRFeature::ToHandle(poFeature.get());
2550 1 : ASSERT_TRUE(hFeature);
2551 1 : ASSERT_GT(queryLog.size(), 1);
2552 :
2553 1 : QueryLogEntry entry{queryLog.back()};
2554 1 : ASSERT_EQ(entry.sql.find("SELECT", 0), 0);
2555 1 : ASSERT_TRUE(entry.executionTimeMilliseconds >= 0);
2556 1 : ASSERT_EQ(entry.numRecords, -1);
2557 1 : ASSERT_TRUE(entry.error.empty());
2558 :
2559 : // Test erroneous query
2560 1 : OGRLayerH queryResultLayerH{GDALDatasetExecuteSQL(
2561 : hDS, "SELECT * FROM not_existing_table", nullptr, nullptr)};
2562 1 : GDALDatasetReleaseResultSet(hDS, queryResultLayerH);
2563 1 : ASSERT_FALSE(queryResultLayerH);
2564 :
2565 1 : entry = queryLog.back();
2566 1 : ASSERT_EQ(entry.sql.find("SELECT * FROM not_existing_table", 0), 0);
2567 1 : ASSERT_EQ(entry.executionTimeMilliseconds, -1);
2568 1 : ASSERT_EQ(entry.numRecords, -1);
2569 1 : ASSERT_FALSE(entry.error.empty());
2570 :
2571 : // Test prepared arg substitution
2572 1 : hFeature = OGR_F_Create(OGR_L_GetLayerDefn(hLayer));
2573 1 : poFeature.reset(OGRFeature::FromHandle(hFeature));
2574 1 : OGR_F_SetFieldInteger(hFeature, 1, 123);
2575 1 : OGRErr err = OGR_L_CreateFeature(hLayer, hFeature);
2576 1 : ASSERT_EQ(OGRERR_NONE, err);
2577 :
2578 : auto insertEntry = std::find_if(
2579 : queryLog.cbegin(), queryLog.cend(),
2580 16 : [](const QueryLogEntry &e)
2581 17 : { return e.sql.find(R"sql(INSERT INTO "poly")sql", 0) == 0; });
2582 :
2583 1 : ASSERT_TRUE(insertEntry != queryLog.end());
2584 1 : ASSERT_EQ(
2585 : insertEntry->sql.find(
2586 : R"sql(INSERT INTO "poly" ( "geom", "AREA", "EAS_ID", "PRFEDEA") VALUES (NULL, NULL, 123, NULL))sql",
2587 : 0),
2588 : 0);
2589 : }
2590 :
2591 4 : TEST_F(test_ogr, OGRParseDateTimeYYYYMMDDTHHMMZ)
2592 : {
2593 : {
2594 1 : char szInput[] = "2023-07-11T17:27Z";
2595 : OGRField sField;
2596 1 : EXPECT_EQ(
2597 : OGRParseDateTimeYYYYMMDDTHHMMZ(szInput, strlen(szInput), &sField),
2598 : true);
2599 1 : EXPECT_EQ(sField.Date.Year, 2023);
2600 1 : EXPECT_EQ(sField.Date.Month, 7);
2601 1 : EXPECT_EQ(sField.Date.Day, 11);
2602 1 : EXPECT_EQ(sField.Date.Hour, 17);
2603 1 : EXPECT_EQ(sField.Date.Minute, 27);
2604 1 : EXPECT_EQ(sField.Date.Second, 0.0f);
2605 1 : EXPECT_EQ(sField.Date.TZFlag, 100);
2606 : }
2607 : {
2608 1 : char szInput[] = "2023-07-11T17:27";
2609 : OGRField sField;
2610 1 : EXPECT_EQ(
2611 : OGRParseDateTimeYYYYMMDDTHHMMZ(szInput, strlen(szInput), &sField),
2612 : true);
2613 1 : EXPECT_EQ(sField.Date.Year, 2023);
2614 1 : EXPECT_EQ(sField.Date.Month, 7);
2615 1 : EXPECT_EQ(sField.Date.Day, 11);
2616 1 : EXPECT_EQ(sField.Date.Hour, 17);
2617 1 : EXPECT_EQ(sField.Date.Minute, 27);
2618 1 : EXPECT_EQ(sField.Date.Second, 0.0f);
2619 1 : EXPECT_EQ(sField.Date.TZFlag, 0);
2620 : }
2621 : {
2622 : // Invalid
2623 1 : char szInput[] = "2023-07-11T17:2";
2624 : OGRField sField;
2625 : // coverity[overrun-buffer-val]
2626 1 : EXPECT_EQ(
2627 : OGRParseDateTimeYYYYMMDDTHHMMZ(szInput, strlen(szInput), &sField),
2628 : false);
2629 : }
2630 : {
2631 : // Invalid
2632 1 : char szInput[] = "2023-07-11T17:99";
2633 : OGRField sField;
2634 1 : EXPECT_EQ(
2635 : OGRParseDateTimeYYYYMMDDTHHMMZ(szInput, strlen(szInput), &sField),
2636 : false);
2637 : }
2638 1 : }
2639 :
2640 4 : TEST_F(test_ogr, OGRParseDateTimeYYYYMMDDTHHMMSSZ)
2641 : {
2642 : {
2643 1 : char szInput[] = "2023-07-11T17:27:34Z";
2644 : OGRField sField;
2645 1 : EXPECT_EQ(
2646 : OGRParseDateTimeYYYYMMDDTHHMMSSZ(szInput, strlen(szInput), &sField),
2647 : true);
2648 1 : EXPECT_EQ(sField.Date.Year, 2023);
2649 1 : EXPECT_EQ(sField.Date.Month, 7);
2650 1 : EXPECT_EQ(sField.Date.Day, 11);
2651 1 : EXPECT_EQ(sField.Date.Hour, 17);
2652 1 : EXPECT_EQ(sField.Date.Minute, 27);
2653 1 : EXPECT_EQ(sField.Date.Second, 34.0f);
2654 1 : EXPECT_EQ(sField.Date.TZFlag, 100);
2655 : }
2656 : {
2657 1 : char szInput[] = "2023-07-11T17:27:34";
2658 : OGRField sField;
2659 1 : EXPECT_EQ(
2660 : OGRParseDateTimeYYYYMMDDTHHMMSSZ(szInput, strlen(szInput), &sField),
2661 : true);
2662 1 : EXPECT_EQ(sField.Date.Year, 2023);
2663 1 : EXPECT_EQ(sField.Date.Month, 7);
2664 1 : EXPECT_EQ(sField.Date.Day, 11);
2665 1 : EXPECT_EQ(sField.Date.Hour, 17);
2666 1 : EXPECT_EQ(sField.Date.Minute, 27);
2667 1 : EXPECT_EQ(sField.Date.Second, 34.0f);
2668 1 : EXPECT_EQ(sField.Date.TZFlag, 0);
2669 : }
2670 : {
2671 : // Invalid
2672 1 : char szInput[] = "2023-07-11T17:27:3";
2673 : OGRField sField;
2674 : // coverity[overrun-buffer-val]
2675 1 : EXPECT_EQ(
2676 : OGRParseDateTimeYYYYMMDDTHHMMSSZ(szInput, strlen(szInput), &sField),
2677 : false);
2678 : }
2679 : {
2680 : // Invalid
2681 1 : char szInput[] = "2023-07-11T17:27:99";
2682 : OGRField sField;
2683 1 : EXPECT_EQ(
2684 : OGRParseDateTimeYYYYMMDDTHHMMSSZ(szInput, strlen(szInput), &sField),
2685 : false);
2686 : }
2687 1 : }
2688 :
2689 4 : TEST_F(test_ogr, OGRParseDateTimeYYYYMMDDTHHMMSSsssZ)
2690 : {
2691 : {
2692 1 : char szInput[] = "2023-07-11T17:27:34.123Z";
2693 : OGRField sField;
2694 1 : EXPECT_EQ(OGRParseDateTimeYYYYMMDDTHHMMSSsssZ(szInput, strlen(szInput),
2695 : &sField),
2696 : true);
2697 1 : EXPECT_EQ(sField.Date.Year, 2023);
2698 1 : EXPECT_EQ(sField.Date.Month, 7);
2699 1 : EXPECT_EQ(sField.Date.Day, 11);
2700 1 : EXPECT_EQ(sField.Date.Hour, 17);
2701 1 : EXPECT_EQ(sField.Date.Minute, 27);
2702 1 : EXPECT_EQ(sField.Date.Second, 34.123f);
2703 1 : EXPECT_EQ(sField.Date.TZFlag, 100);
2704 : }
2705 : {
2706 1 : char szInput[] = "2023-07-11T17:27:34.123";
2707 : OGRField sField;
2708 1 : EXPECT_EQ(OGRParseDateTimeYYYYMMDDTHHMMSSsssZ(szInput, strlen(szInput),
2709 : &sField),
2710 : true);
2711 1 : EXPECT_EQ(sField.Date.Year, 2023);
2712 1 : EXPECT_EQ(sField.Date.Month, 7);
2713 1 : EXPECT_EQ(sField.Date.Day, 11);
2714 1 : EXPECT_EQ(sField.Date.Hour, 17);
2715 1 : EXPECT_EQ(sField.Date.Minute, 27);
2716 1 : EXPECT_EQ(sField.Date.Second, 34.123f);
2717 1 : EXPECT_EQ(sField.Date.TZFlag, 0);
2718 : }
2719 : {
2720 : // Invalid
2721 1 : char szInput[] = "2023-07-11T17:27:34.12";
2722 : OGRField sField;
2723 : // coverity[overrun-buffer-val]
2724 1 : EXPECT_EQ(OGRParseDateTimeYYYYMMDDTHHMMSSsssZ(szInput, strlen(szInput),
2725 : &sField),
2726 : false);
2727 : }
2728 : {
2729 : // Invalid
2730 1 : char szInput[] = "2023-07-11T17:27:99.123";
2731 : OGRField sField;
2732 1 : EXPECT_EQ(OGRParseDateTimeYYYYMMDDTHHMMSSsssZ(szInput, strlen(szInput),
2733 : &sField),
2734 : false);
2735 : }
2736 1 : }
2737 :
2738 4 : TEST_F(test_ogr, OGRGetISO8601DateTime)
2739 : {
2740 : OGRField sField;
2741 1 : sField.Date.Year = 2023;
2742 1 : sField.Date.Month = 7;
2743 1 : sField.Date.Day = 11;
2744 1 : sField.Date.Hour = 17;
2745 1 : sField.Date.Minute = 27;
2746 1 : sField.Date.Second = 34.567f;
2747 1 : sField.Date.TZFlag = 100;
2748 : {
2749 : char szResult[OGR_SIZEOF_ISO8601_DATETIME_BUFFER];
2750 : OGRISO8601Format sFormat;
2751 1 : sFormat.ePrecision = OGRISO8601Precision::AUTO;
2752 1 : OGRGetISO8601DateTime(&sField, sFormat, szResult);
2753 1 : EXPECT_STREQ(szResult, "2023-07-11T17:27:34.567Z");
2754 : }
2755 : {
2756 : char szResult[OGR_SIZEOF_ISO8601_DATETIME_BUFFER];
2757 : OGRISO8601Format sFormat;
2758 1 : sFormat.ePrecision = OGRISO8601Precision::MILLISECOND;
2759 1 : OGRGetISO8601DateTime(&sField, sFormat, szResult);
2760 1 : EXPECT_STREQ(szResult, "2023-07-11T17:27:34.567Z");
2761 : }
2762 : {
2763 : char szResult[OGR_SIZEOF_ISO8601_DATETIME_BUFFER];
2764 : OGRISO8601Format sFormat;
2765 1 : sFormat.ePrecision = OGRISO8601Precision::SECOND;
2766 1 : OGRGetISO8601DateTime(&sField, sFormat, szResult);
2767 1 : EXPECT_STREQ(szResult, "2023-07-11T17:27:35Z");
2768 : }
2769 : {
2770 : char szResult[OGR_SIZEOF_ISO8601_DATETIME_BUFFER];
2771 : OGRISO8601Format sFormat;
2772 1 : sFormat.ePrecision = OGRISO8601Precision::MINUTE;
2773 1 : OGRGetISO8601DateTime(&sField, sFormat, szResult);
2774 1 : EXPECT_STREQ(szResult, "2023-07-11T17:27Z");
2775 : }
2776 1 : sField.Date.Second = 34.0f;
2777 : {
2778 : char szResult[OGR_SIZEOF_ISO8601_DATETIME_BUFFER];
2779 : OGRISO8601Format sFormat;
2780 1 : sFormat.ePrecision = OGRISO8601Precision::AUTO;
2781 1 : OGRGetISO8601DateTime(&sField, sFormat, szResult);
2782 1 : EXPECT_STREQ(szResult, "2023-07-11T17:27:34Z");
2783 : }
2784 1 : }
2785 :
2786 : // Test calling importFromWkb() multiple times on the same geometry object
2787 4 : TEST_F(test_ogr, importFromWkbReuse)
2788 : {
2789 : {
2790 2 : OGRPoint oPoint;
2791 : {
2792 1 : size_t nBytesConsumed = 0;
2793 1 : EXPECT_EQ(oPoint.importFromWkb(
2794 : reinterpret_cast<const GByte *>(
2795 : "\x01\x01\x00\x00\x00" // Point
2796 : "\x00\x00\x00\x00\x00\x00\xf0\x3f" // 1.0
2797 : "\x00\x00\x00\x00\x00\x00\x00\x40"), // 2.0
2798 : 21, wkbVariantIso, nBytesConsumed),
2799 : OGRERR_NONE);
2800 1 : EXPECT_EQ(nBytesConsumed, 21);
2801 1 : EXPECT_EQ(oPoint.getX(), 1.0);
2802 1 : EXPECT_EQ(oPoint.getY(), 2.0);
2803 : }
2804 : {
2805 1 : size_t nBytesConsumed = 0;
2806 1 : EXPECT_EQ(oPoint.importFromWkb(
2807 : reinterpret_cast<const GByte *>(
2808 : "\x01\x01\x00\x00\x00" // Point
2809 : "\x00\x00\x00\x00\x00\x00\x00\x40" // 2.0
2810 : "\x00\x00\x00\x00\x00\x00\xf0\x3f" // 1.0
2811 : ),
2812 : 21, wkbVariantIso, nBytesConsumed),
2813 : OGRERR_NONE);
2814 1 : EXPECT_EQ(nBytesConsumed, 21);
2815 1 : EXPECT_EQ(oPoint.getX(), 2.0);
2816 1 : EXPECT_EQ(oPoint.getY(), 1.0);
2817 : }
2818 : }
2819 :
2820 : {
2821 1 : OGRLineString oLS;
2822 : {
2823 1 : size_t nBytesConsumed = 0;
2824 1 : EXPECT_EQ(oLS.importFromWkb(
2825 : reinterpret_cast<const GByte *>(
2826 : "\x01\x02\x00\x00\x00" // LineString
2827 : "\x01\x00\x00\x00" // 1 point
2828 : "\x00\x00\x00\x00\x00\x00\xf0\x3f" // 1.0
2829 : "\x00\x00\x00\x00\x00\x00\x00\x40"), // 2.0
2830 : 25, wkbVariantIso, nBytesConsumed),
2831 : OGRERR_NONE);
2832 1 : EXPECT_EQ(nBytesConsumed, 25);
2833 1 : ASSERT_EQ(oLS.getNumPoints(), 1);
2834 1 : EXPECT_EQ(oLS.getX(0), 1.0);
2835 1 : EXPECT_EQ(oLS.getY(0), 2.0);
2836 : }
2837 : {
2838 1 : size_t nBytesConsumed = 0;
2839 1 : EXPECT_EQ(oLS.importFromWkb(
2840 : reinterpret_cast<const GByte *>(
2841 : "\x01\x02\x00\x00\x00" // LineString
2842 : "\x02\x00\x00\x00" // 2 points
2843 : "\x00\x00\x00\x00\x00\x00\xf0\x3f" // 1.0
2844 : "\x00\x00\x00\x00\x00\x00\x00\x40" // 2.0
2845 : "\x00\x00\x00\x00\x00\x00\x00\x40" // 2.0
2846 : "\x00\x00\x00\x00\x00\x00\xf0\x3f"), // 1.0
2847 : 41, wkbVariantIso, nBytesConsumed),
2848 : OGRERR_NONE);
2849 1 : EXPECT_EQ(nBytesConsumed, 41);
2850 1 : ASSERT_EQ(oLS.getNumPoints(), 2);
2851 1 : EXPECT_EQ(oLS.getX(0), 1.0);
2852 1 : EXPECT_EQ(oLS.getY(0), 2.0);
2853 1 : EXPECT_EQ(oLS.getX(1), 2.0);
2854 1 : EXPECT_EQ(oLS.getY(1), 1.0);
2855 : }
2856 : {
2857 1 : size_t nBytesConsumed = 0;
2858 1 : EXPECT_EQ(oLS.importFromWkb(
2859 : reinterpret_cast<const GByte *>(
2860 : "\x01\x02\x00\x00\x00" // LineString
2861 : "\x01\x00\x00\x00" // 1 point
2862 : "\x00\x00\x00\x00\x00\x00\x00\x40" // 2.0
2863 : "\x00\x00\x00\x00\x00\x00\xf0\x3f"), // 1.0
2864 : 25, wkbVariantIso, nBytesConsumed),
2865 : OGRERR_NONE);
2866 1 : EXPECT_EQ(nBytesConsumed, 25);
2867 1 : ASSERT_EQ(oLS.getNumPoints(), 1);
2868 1 : EXPECT_EQ(oLS.getX(0), 2.0);
2869 1 : EXPECT_EQ(oLS.getY(0), 1.0);
2870 : }
2871 : }
2872 :
2873 : {
2874 1 : OGRPolygon oPoly;
2875 : {
2876 1 : size_t nBytesConsumed = 0;
2877 1 : EXPECT_EQ(oPoly.importFromWkb(
2878 : reinterpret_cast<const GByte *>(
2879 : "\x01\x03\x00\x00\x00" // Polygon
2880 : "\x01\x00\x00\x00" // 1 ring
2881 : "\x01\x00\x00\x00" // 1 point
2882 : "\x00\x00\x00\x00\x00\x00\xf0\x3f" // 1.0
2883 : "\x00\x00\x00\x00\x00\x00\x00\x40"), // 2.0
2884 : 29, wkbVariantIso, nBytesConsumed),
2885 : OGRERR_NONE);
2886 1 : EXPECT_EQ(nBytesConsumed, 29);
2887 1 : ASSERT_TRUE(oPoly.getExteriorRing() != nullptr);
2888 1 : ASSERT_EQ(oPoly.getNumInteriorRings(), 0);
2889 1 : auto poLS = oPoly.getExteriorRing();
2890 1 : ASSERT_EQ(poLS->getNumPoints(), 1);
2891 1 : EXPECT_EQ(poLS->getX(0), 1.0);
2892 1 : EXPECT_EQ(poLS->getY(0), 2.0);
2893 : }
2894 : {
2895 1 : size_t nBytesConsumed = 0;
2896 1 : EXPECT_EQ(oPoly.importFromWkb(
2897 : reinterpret_cast<const GByte *>(
2898 : "\x01\x03\x00\x00\x00" // Polygon
2899 : "\x01\x00\x00\x00" // 1 ring
2900 : "\x01\x00\x00\x00" // 1 point
2901 : "\x00\x00\x00\x00\x00\x00\x00\x40" // 2.0
2902 : "\x00\x00\x00\x00\x00\x00\xf0\x3f"), // 1.0
2903 : 29, wkbVariantIso, nBytesConsumed),
2904 : OGRERR_NONE);
2905 1 : EXPECT_EQ(nBytesConsumed, 29);
2906 1 : ASSERT_TRUE(oPoly.getExteriorRing() != nullptr);
2907 1 : ASSERT_EQ(oPoly.getNumInteriorRings(), 0);
2908 1 : auto poLS = oPoly.getExteriorRing();
2909 1 : ASSERT_EQ(poLS->getNumPoints(), 1);
2910 1 : EXPECT_EQ(poLS->getX(0), 2.0);
2911 1 : EXPECT_EQ(poLS->getY(0), 1.0);
2912 : }
2913 : {
2914 1 : size_t nBytesConsumed = 0;
2915 1 : EXPECT_EQ(oPoly.importFromWkb(reinterpret_cast<const GByte *>(
2916 : "\x01\x03\x00\x00\x00" // Polygon
2917 : "\x00\x00\x00\x00"), // 0 ring
2918 : 9, wkbVariantIso, nBytesConsumed),
2919 : OGRERR_NONE);
2920 1 : EXPECT_EQ(nBytesConsumed, 9);
2921 1 : ASSERT_TRUE(oPoly.getExteriorRing() == nullptr);
2922 1 : ASSERT_EQ(oPoly.getNumInteriorRings(), 0);
2923 : }
2924 : {
2925 1 : size_t nBytesConsumed = 0;
2926 1 : EXPECT_EQ(oPoly.importFromWkb(
2927 : reinterpret_cast<const GByte *>(
2928 : "\x01\x03\x00\x00\x00" // Polygon
2929 : "\x01\x00\x00\x00" // 1 ring
2930 : "\x01\x00\x00\x00" // 1 point
2931 : "\x00\x00\x00\x00\x00\x00\xf0\x3f" // 1.0
2932 : "\x00\x00\x00\x00\x00\x00\x00\x40"), // 2.0
2933 : 29, wkbVariantIso, nBytesConsumed),
2934 : OGRERR_NONE);
2935 1 : EXPECT_EQ(nBytesConsumed, 29);
2936 1 : ASSERT_TRUE(oPoly.getExteriorRing() != nullptr);
2937 1 : ASSERT_EQ(oPoly.getNumInteriorRings(), 0);
2938 1 : auto poLS = oPoly.getExteriorRing();
2939 1 : ASSERT_EQ(poLS->getNumPoints(), 1);
2940 1 : EXPECT_EQ(poLS->getX(0), 1.0);
2941 1 : EXPECT_EQ(poLS->getY(0), 2.0);
2942 : }
2943 : {
2944 1 : size_t nBytesConsumed = 0;
2945 1 : EXPECT_EQ(oPoly.importFromWkb(
2946 : reinterpret_cast<const GByte *>(
2947 : "\x01\x03\x00\x00\x00" // Polygon
2948 : "\x01\x00\x00\x00" // 1 ring
2949 : "\x01\x00\x00\x00" // 1 point
2950 : "\x00\x00\x00\x00\x00\x00\x00\x40" // 2.0
2951 : "\x00\x00\x00\x00\x00\x00\xf0\x3f"), // 1.0
2952 : static_cast<size_t>(-1), wkbVariantIso,
2953 : nBytesConsumed),
2954 : OGRERR_NONE);
2955 1 : EXPECT_EQ(nBytesConsumed, 29);
2956 1 : ASSERT_TRUE(oPoly.getExteriorRing() != nullptr);
2957 1 : ASSERT_EQ(oPoly.getNumInteriorRings(), 0);
2958 1 : auto poLS = oPoly.getExteriorRing();
2959 1 : ASSERT_EQ(poLS->getNumPoints(), 1);
2960 1 : EXPECT_EQ(poLS->getX(0), 2.0);
2961 1 : EXPECT_EQ(poLS->getY(0), 1.0);
2962 : }
2963 : {
2964 1 : size_t nBytesConsumed = 0;
2965 : // Truncated WKB
2966 1 : EXPECT_NE(oPoly.importFromWkb(reinterpret_cast<const GByte *>(
2967 : "\x01\x03\x00\x00\x00" // Polygon
2968 : "\x01\x00\x00\x00" // 1 ring
2969 : "\x01\x00\x00\x00"), // 1 point
2970 : 13, wkbVariantIso, nBytesConsumed),
2971 : OGRERR_NONE);
2972 1 : ASSERT_TRUE(oPoly.getExteriorRing() == nullptr);
2973 1 : ASSERT_EQ(oPoly.getNumInteriorRings(), 0);
2974 : }
2975 : }
2976 :
2977 : {
2978 1 : OGRMultiLineString oMLS;
2979 : {
2980 1 : size_t nBytesConsumed = 0;
2981 1 : EXPECT_EQ(oMLS.importFromWkb(
2982 : reinterpret_cast<const GByte *>(
2983 : "\x01\x05\x00\x00\x00" // MultiLineString
2984 : "\x01\x00\x00\x00" // 1-part
2985 : "\x01\x02\x00\x00\x00" // LineString
2986 : "\x01\x00\x00\x00" // 1 point
2987 : "\x00\x00\x00\x00\x00\x00\xf0\x3f" // 1.0
2988 : "\x00\x00\x00\x00\x00\x00\x00\x40"), // 2.0
2989 : 34, wkbVariantIso, nBytesConsumed),
2990 : OGRERR_NONE);
2991 1 : EXPECT_EQ(nBytesConsumed, 34);
2992 1 : ASSERT_EQ(oMLS.getNumGeometries(), 1);
2993 1 : auto poLS = oMLS.getGeometryRef(0);
2994 1 : ASSERT_EQ(poLS->getNumPoints(), 1);
2995 1 : EXPECT_EQ(poLS->getX(0), 1.0);
2996 1 : EXPECT_EQ(poLS->getY(0), 2.0);
2997 : }
2998 : {
2999 1 : size_t nBytesConsumed = 0;
3000 1 : EXPECT_EQ(oMLS.importFromWkb(
3001 : reinterpret_cast<const GByte *>(
3002 : "\x01\x05\x00\x00\x00" // MultiLineString
3003 : "\x01\x00\x00\x00" // 1-part
3004 : "\x01\x02\x00\x00\x00" // LineString
3005 : "\x01\x00\x00\x00" // 1 point
3006 : "\x00\x00\x00\x00\x00\x00\x00\x40" // 2.0
3007 : "\x00\x00\x00\x00\x00\x00\xf0\x3f"), // 1.0
3008 : 34, wkbVariantIso, nBytesConsumed),
3009 : OGRERR_NONE);
3010 1 : EXPECT_EQ(nBytesConsumed, 34);
3011 1 : ASSERT_EQ(oMLS.getNumGeometries(), 1);
3012 1 : auto poLS = oMLS.getGeometryRef(0);
3013 1 : ASSERT_EQ(poLS->getNumPoints(), 1);
3014 1 : EXPECT_EQ(poLS->getX(0), 2.0);
3015 1 : EXPECT_EQ(poLS->getY(0), 1.0);
3016 : }
3017 : {
3018 1 : size_t nBytesConsumed = 0;
3019 1 : EXPECT_EQ(oMLS.importFromWkb(
3020 : reinterpret_cast<const GByte *>(
3021 : "\x01\x05\x00\x00\x00" // MultiLineString
3022 : "\x01\x00\x00\x00" // 1-part
3023 : "\x01\x02\x00\x00\x00" // LineString
3024 : "\x01\x00\x00\x00" // 1 point
3025 : "\x00\x00\x00\x00\x00\x00\xf0\x3f" // 1.0
3026 : "\x00\x00\x00\x00\x00\x00\x00\x40"), // 2.0
3027 : static_cast<size_t>(-1), wkbVariantIso,
3028 : nBytesConsumed),
3029 : OGRERR_NONE);
3030 1 : EXPECT_EQ(nBytesConsumed, 34);
3031 1 : ASSERT_EQ(oMLS.getNumGeometries(), 1);
3032 1 : auto poLS = oMLS.getGeometryRef(0);
3033 1 : ASSERT_EQ(poLS->getNumPoints(), 1);
3034 1 : EXPECT_EQ(poLS->getX(0), 1.0);
3035 1 : EXPECT_EQ(poLS->getY(0), 2.0);
3036 : }
3037 : {
3038 1 : size_t nBytesConsumed = 0;
3039 : // Truncated WKB
3040 1 : EXPECT_NE(oMLS.importFromWkb(
3041 : reinterpret_cast<const GByte *>(
3042 : "\x01\x05\x00\x00\x00" // MultiLineString
3043 : "\x01\x00\x00\x00" // 1-part
3044 : "\x01\x02\x00\x00\x00" // LineString
3045 : "\x01\x00\x00\x00" // 1 point
3046 : ),
3047 : 18, wkbVariantIso, nBytesConsumed),
3048 : OGRERR_NONE);
3049 1 : ASSERT_EQ(oMLS.getNumGeometries(), 0);
3050 : }
3051 : }
3052 :
3053 : {
3054 1 : OGRMultiPolygon oMP;
3055 : {
3056 1 : size_t nBytesConsumed = 0;
3057 1 : EXPECT_EQ(oMP.importFromWkb(
3058 : reinterpret_cast<const GByte *>(
3059 : "\x01\x06\x00\x00\x00" // MultiPolygon
3060 : "\x01\x00\x00\x00" // 1-part
3061 : "\x01\x03\x00\x00\x00" // Polygon
3062 : "\x01\x00\x00\x00" // 1 ring
3063 : "\x01\x00\x00\x00" // 1 point
3064 : "\x00\x00\x00\x00\x00\x00\xf0\x3f" // 1.0
3065 : "\x00\x00\x00\x00\x00\x00\x00\x40"), // 2.0
3066 : 38, wkbVariantIso, nBytesConsumed),
3067 : OGRERR_NONE);
3068 1 : EXPECT_EQ(nBytesConsumed, 38);
3069 1 : ASSERT_EQ(oMP.getNumGeometries(), 1);
3070 1 : auto poPoly = oMP.getGeometryRef(0);
3071 1 : ASSERT_TRUE(poPoly->getExteriorRing() != nullptr);
3072 1 : ASSERT_EQ(poPoly->getNumInteriorRings(), 0);
3073 1 : auto poLS = poPoly->getExteriorRing();
3074 1 : ASSERT_EQ(poLS->getNumPoints(), 1);
3075 1 : EXPECT_EQ(poLS->getX(0), 1.0);
3076 1 : EXPECT_EQ(poLS->getY(0), 2.0);
3077 : }
3078 : {
3079 1 : size_t nBytesConsumed = 0;
3080 1 : EXPECT_EQ(oMP.importFromWkb(
3081 : reinterpret_cast<const GByte *>(
3082 : "\x01\x06\x00\x00\x00" // MultiPolygon
3083 : "\x01\x00\x00\x00" // 1-part
3084 : "\x01\x03\x00\x00\x00" // Polygon
3085 : "\x01\x00\x00\x00" // 1 ring
3086 : "\x01\x00\x00\x00" // 1 point
3087 : "\x00\x00\x00\x00\x00\x00\x00\x40" // 2.0
3088 : "\x00\x00\x00\x00\x00\x00\xf0\x3f"), // 1.0
3089 : 38, wkbVariantIso, nBytesConsumed),
3090 : OGRERR_NONE);
3091 1 : EXPECT_EQ(nBytesConsumed, 38);
3092 1 : ASSERT_EQ(oMP.getNumGeometries(), 1);
3093 1 : auto poPoly = oMP.getGeometryRef(0);
3094 1 : ASSERT_TRUE(poPoly->getExteriorRing() != nullptr);
3095 1 : ASSERT_EQ(poPoly->getNumInteriorRings(), 0);
3096 1 : auto poLS = poPoly->getExteriorRing();
3097 1 : ASSERT_EQ(poLS->getNumPoints(), 1);
3098 1 : EXPECT_EQ(poLS->getX(0), 2.0);
3099 1 : EXPECT_EQ(poLS->getY(0), 1.0);
3100 : }
3101 : {
3102 1 : size_t nBytesConsumed = 0;
3103 1 : EXPECT_EQ(oMP.importFromWkb(
3104 : reinterpret_cast<const GByte *>(
3105 : "\x01\x06\x00\x00\x00" // MultiPolygon
3106 : "\x01\x00\x00\x00" // 1-part
3107 : "\x01\x03\x00\x00\x00" // Polygon
3108 : "\x01\x00\x00\x00" // 1 ring
3109 : "\x01\x00\x00\x00" // 1 point
3110 : "\x00\x00\x00\x00\x00\x00\xf0\x3f" // 1.0
3111 : "\x00\x00\x00\x00\x00\x00\x00\x40"), // 2.0
3112 : static_cast<size_t>(-1), wkbVariantIso,
3113 : nBytesConsumed),
3114 : OGRERR_NONE);
3115 1 : EXPECT_EQ(nBytesConsumed, 38);
3116 1 : ASSERT_EQ(oMP.getNumGeometries(), 1);
3117 1 : auto poPoly = oMP.getGeometryRef(0);
3118 1 : ASSERT_TRUE(poPoly->getExteriorRing() != nullptr);
3119 1 : ASSERT_EQ(poPoly->getNumInteriorRings(), 0);
3120 1 : auto poLS = poPoly->getExteriorRing();
3121 1 : ASSERT_EQ(poLS->getNumPoints(), 1);
3122 1 : EXPECT_EQ(poLS->getX(0), 1.0);
3123 1 : EXPECT_EQ(poLS->getY(0), 2.0);
3124 : }
3125 : {
3126 1 : size_t nBytesConsumed = 0;
3127 : // Truncated WKB
3128 1 : EXPECT_NE(
3129 : oMP.importFromWkb(reinterpret_cast<const GByte *>(
3130 : "\x01\x06\x00\x00\x00" // MultiPolygon
3131 : "\x01\x00\x00\x00" // 1-part
3132 : "\x01\x03\x00\x00\x00" // Polygon
3133 : "\x01\x00\x00\x00" // 1 ring
3134 : "\x01\x00\x00\x00" // 1 point
3135 : ),
3136 : 22, wkbVariantIso, nBytesConsumed),
3137 : OGRERR_NONE);
3138 1 : ASSERT_EQ(oMP.getNumGeometries(), 0);
3139 : }
3140 : }
3141 : }
3142 :
3143 : // Test sealing functionality on OGRFieldDefn
3144 4 : TEST_F(test_ogr, OGRFieldDefn_sealing)
3145 : {
3146 2 : OGRFieldDefn oFieldDefn("test", OFTString);
3147 1 : oFieldDefn.Seal();
3148 :
3149 : {
3150 1 : CPLErrorReset();
3151 2 : CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
3152 1 : oFieldDefn.SetName("new_name");
3153 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3154 : }
3155 :
3156 : {
3157 1 : CPLErrorReset();
3158 2 : CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
3159 1 : oFieldDefn.SetType(OFTInteger);
3160 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3161 : }
3162 :
3163 : {
3164 1 : CPLErrorReset();
3165 2 : CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
3166 1 : oFieldDefn.SetSubType(OFSTJSON);
3167 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3168 : }
3169 :
3170 : {
3171 1 : CPLErrorReset();
3172 2 : CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
3173 1 : oFieldDefn.SetWidth(1);
3174 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3175 : }
3176 :
3177 : {
3178 1 : CPLErrorReset();
3179 2 : CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
3180 1 : oFieldDefn.SetPrecision(1);
3181 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3182 : }
3183 :
3184 : {
3185 1 : CPLErrorReset();
3186 2 : CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
3187 1 : oFieldDefn.SetDefault("");
3188 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3189 : }
3190 :
3191 : {
3192 1 : CPLErrorReset();
3193 2 : CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
3194 1 : oFieldDefn.SetUnique(true);
3195 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3196 : }
3197 :
3198 : {
3199 1 : CPLErrorReset();
3200 2 : CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
3201 1 : oFieldDefn.SetNullable(false);
3202 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3203 : }
3204 :
3205 : {
3206 1 : CPLErrorReset();
3207 2 : CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
3208 1 : oFieldDefn.SetComment("");
3209 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3210 : }
3211 :
3212 : {
3213 1 : CPLErrorReset();
3214 2 : CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
3215 1 : oFieldDefn.SetAlternativeName("");
3216 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3217 : }
3218 :
3219 : {
3220 1 : CPLErrorReset();
3221 2 : CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
3222 1 : oFieldDefn.SetDomainName("");
3223 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3224 : }
3225 :
3226 : {
3227 1 : CPLErrorReset();
3228 2 : CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
3229 1 : oFieldDefn.SetTZFlag(0);
3230 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3231 : }
3232 :
3233 : {
3234 2 : auto oTemporaryUnsealer(oFieldDefn.GetTemporaryUnsealer());
3235 1 : CPLErrorReset();
3236 1 : oFieldDefn.SetName("new_name");
3237 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") == nullptr);
3238 : }
3239 :
3240 : {
3241 1 : CPLErrorReset();
3242 2 : CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
3243 1 : oFieldDefn.SetName("new_name");
3244 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3245 : }
3246 :
3247 : {
3248 1 : CPLErrorReset();
3249 1 : whileUnsealing(&oFieldDefn)->SetName("new_name");
3250 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_None);
3251 : }
3252 1 : }
3253 :
3254 : // Test sealing functionality on OGRGeomFieldDefn
3255 4 : TEST_F(test_ogr, OGRGeomFieldDefn_sealing)
3256 : {
3257 2 : OGRGeomFieldDefn oFieldDefn("test", wkbUnknown);
3258 :
3259 1 : oFieldDefn.Seal();
3260 :
3261 : {
3262 1 : CPLErrorReset();
3263 2 : CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
3264 1 : oFieldDefn.SetName("new_name");
3265 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3266 : }
3267 :
3268 : {
3269 1 : CPLErrorReset();
3270 2 : CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
3271 1 : oFieldDefn.SetType(wkbPoint);
3272 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3273 : }
3274 :
3275 : {
3276 1 : CPLErrorReset();
3277 2 : CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
3278 1 : oFieldDefn.SetSpatialRef(nullptr);
3279 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3280 : }
3281 :
3282 : {
3283 1 : CPLErrorReset();
3284 2 : CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
3285 1 : oFieldDefn.SetNullable(false);
3286 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3287 : }
3288 :
3289 : {
3290 2 : auto oTemporaryUnsealer(oFieldDefn.GetTemporaryUnsealer());
3291 1 : CPLErrorReset();
3292 1 : oFieldDefn.SetName("new_name");
3293 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_None);
3294 : }
3295 :
3296 : {
3297 1 : CPLErrorReset();
3298 2 : CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
3299 1 : oFieldDefn.SetName("new_name");
3300 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3301 : }
3302 :
3303 : {
3304 1 : CPLErrorReset();
3305 1 : whileUnsealing(&oFieldDefn)->SetName("new_name");
3306 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_None);
3307 : }
3308 1 : }
3309 :
3310 : // Test sealing functionality on OGRFeatureDefn
3311 4 : TEST_F(test_ogr, OGRFeatureDefn_sealing)
3312 : {
3313 2 : OGRFeatureDefn oFDefn;
3314 1 : CPLErrorReset();
3315 : {
3316 1 : oFDefn.SetName("new_name");
3317 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_None);
3318 : }
3319 : {
3320 2 : OGRFieldDefn oFieldDefn("test", OFTString);
3321 1 : oFDefn.AddFieldDefn(&oFieldDefn);
3322 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_None);
3323 : }
3324 : {
3325 2 : OGRGeomFieldDefn oFieldDefn("test", wkbUnknown);
3326 1 : oFDefn.AddGeomFieldDefn(&oFieldDefn);
3327 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_None);
3328 : }
3329 :
3330 : {
3331 1 : CPLErrorReset();
3332 2 : CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
3333 1 : oFDefn.Unseal(true);
3334 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "unsealed") != nullptr);
3335 :
3336 1 : CPLErrorReset();
3337 2 : auto oTemporaryUnsealer1(oFDefn.GetTemporaryUnsealer(false));
3338 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "unsealed") != nullptr);
3339 1 : CPLErrorReset();
3340 2 : auto oTemporaryUnsealer2(oFDefn.GetTemporaryUnsealer(false));
3341 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_None);
3342 : }
3343 :
3344 1 : oFDefn.Seal(true);
3345 :
3346 : {
3347 1 : CPLErrorReset();
3348 2 : CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
3349 1 : oFDefn.Seal(true);
3350 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3351 : }
3352 :
3353 : {
3354 1 : CPLErrorReset();
3355 2 : CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
3356 1 : oFDefn.SetName("new_name");
3357 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3358 : }
3359 :
3360 : {
3361 1 : CPLErrorReset();
3362 2 : CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
3363 2 : OGRFieldDefn oFieldDefn("test2", OFTString);
3364 1 : oFDefn.AddFieldDefn(&oFieldDefn);
3365 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3366 : }
3367 :
3368 : {
3369 1 : CPLErrorReset();
3370 2 : CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
3371 1 : oFDefn.DeleteFieldDefn(0);
3372 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3373 : }
3374 :
3375 : {
3376 1 : CPLErrorReset();
3377 2 : CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
3378 1 : int map[] = {0};
3379 1 : oFDefn.ReorderFieldDefns(map);
3380 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3381 : }
3382 :
3383 : {
3384 1 : CPLErrorReset();
3385 2 : CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
3386 2 : OGRGeomFieldDefn oFieldDefn("test2", wkbUnknown);
3387 1 : oFDefn.AddGeomFieldDefn(&oFieldDefn);
3388 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3389 : }
3390 :
3391 : {
3392 1 : CPLErrorReset();
3393 2 : CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
3394 1 : oFDefn.DeleteGeomFieldDefn(0);
3395 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3396 : }
3397 :
3398 : {
3399 2 : auto oTemporaryUnsealer(oFDefn.GetTemporaryUnsealer(false));
3400 1 : CPLErrorReset();
3401 1 : oFDefn.SetName("new_name");
3402 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_None);
3403 :
3404 2 : CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
3405 1 : CPLErrorReset();
3406 1 : oFDefn.GetFieldDefn(0)->SetName("new_name");
3407 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3408 :
3409 1 : CPLErrorReset();
3410 1 : oFDefn.GetGeomFieldDefn(0)->SetName("new_name");
3411 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3412 : }
3413 :
3414 : {
3415 :
3416 2 : CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
3417 1 : CPLErrorReset();
3418 1 : oFDefn.GetFieldDefn(0)->SetName("new_name");
3419 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3420 :
3421 1 : CPLErrorReset();
3422 1 : oFDefn.GetGeomFieldDefn(0)->SetName("new_name");
3423 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3424 : }
3425 :
3426 : {
3427 2 : auto oTemporaryUnsealer(oFDefn.GetTemporaryUnsealer(true));
3428 1 : CPLErrorReset();
3429 1 : oFDefn.SetName("new_name");
3430 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_None);
3431 :
3432 1 : oFDefn.GetFieldDefn(0)->SetName("new_name");
3433 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_None);
3434 :
3435 2 : auto oTemporaryUnsealer2(oFDefn.GetTemporaryUnsealer(true));
3436 :
3437 1 : oFDefn.GetGeomFieldDefn(0)->SetName("new_name");
3438 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_None);
3439 : }
3440 :
3441 : {
3442 :
3443 2 : CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
3444 1 : CPLErrorReset();
3445 1 : oFDefn.GetFieldDefn(0)->SetName("new_name");
3446 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3447 :
3448 1 : CPLErrorReset();
3449 1 : oFDefn.GetGeomFieldDefn(0)->SetName("new_name");
3450 1 : EXPECT_TRUE(strstr(CPLGetLastErrorMsg(), "sealed") != nullptr);
3451 : }
3452 :
3453 : {
3454 1 : CPLErrorReset();
3455 1 : whileUnsealing(&oFDefn)->SetName("new_name");
3456 1 : EXPECT_EQ(CPLGetLastErrorType(), CE_None);
3457 : }
3458 1 : }
3459 :
3460 : // Test wkbExportOptions
3461 4 : TEST_F(test_ogr, wkbExportOptions_default)
3462 : {
3463 1 : OGRwkbExportOptions *psOptions = OGRwkbExportOptionsCreate();
3464 1 : ASSERT_TRUE(psOptions != nullptr);
3465 2 : OGRPoint p(1.23456789012345678, 2.23456789012345678, 3);
3466 2 : std::vector<GByte> abyWKB(p.WkbSize());
3467 1 : OGR_G_ExportToWkbEx(OGRGeometry::ToHandle(&p), &abyWKB[0], psOptions);
3468 1 : OGRwkbExportOptionsDestroy(psOptions);
3469 :
3470 2 : std::vector<GByte> abyRegularWKB(p.WkbSize());
3471 1 : OGR_G_ExportToWkb(OGRGeometry::ToHandle(&p), wkbNDR, &abyRegularWKB[0]);
3472 :
3473 1 : EXPECT_TRUE(abyWKB == abyRegularWKB);
3474 : }
3475 :
3476 : // Test wkbExportOptions
3477 4 : TEST_F(test_ogr, wkbExportOptions)
3478 : {
3479 1 : OGRwkbExportOptions *psOptions = OGRwkbExportOptionsCreate();
3480 1 : ASSERT_TRUE(psOptions != nullptr);
3481 1 : OGRwkbExportOptionsSetByteOrder(psOptions, wkbXDR);
3482 1 : OGRwkbExportOptionsSetVariant(psOptions, wkbVariantIso);
3483 :
3484 1 : auto hPrec = OGRGeomCoordinatePrecisionCreate();
3485 1 : OGRGeomCoordinatePrecisionSet(hPrec, 1e-1, 1e-2, 1e-4);
3486 1 : OGRwkbExportOptionsSetPrecision(psOptions, hPrec);
3487 1 : OGRGeomCoordinatePrecisionDestroy(hPrec);
3488 :
3489 : OGRPoint p(1.23456789012345678, -1.23456789012345678, 1.23456789012345678,
3490 1 : 1.23456789012345678);
3491 1 : std::vector<GByte> abyWKB(p.WkbSize());
3492 1 : OGR_G_ExportToWkbEx(OGRGeometry::ToHandle(&p), &abyWKB[0], psOptions);
3493 1 : OGRwkbExportOptionsDestroy(psOptions);
3494 :
3495 : const std::vector<GByte> expectedWKB{
3496 : 0x00, 0x00, 0x00, 0x0B, 0xB9, 0x3F, 0xF3, 0x80, 0x00, 0x00,
3497 : 0x00, 0x00, 0x00, 0xBF, 0xF3, 0x80, 0x00, 0x00, 0x00, 0x00,
3498 : 0x00, 0x3F, 0xF3, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F,
3499 1 : 0xF3, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00};
3500 1 : EXPECT_TRUE(abyWKB == expectedWKB);
3501 :
3502 1 : OGRGeometry *poGeom = nullptr;
3503 1 : OGRGeometryFactory::createFromWkb(abyWKB.data(), nullptr, &poGeom);
3504 1 : ASSERT_NE(poGeom, nullptr);
3505 1 : EXPECT_NEAR(poGeom->toPoint()->getX(), 1.2, 1e-1);
3506 1 : EXPECT_NEAR(poGeom->toPoint()->getY(), -1.2, 1e-1);
3507 1 : EXPECT_NEAR(poGeom->toPoint()->getZ(), 1.23, 1e-2);
3508 1 : EXPECT_NEAR(poGeom->toPoint()->getM(), 1.2346, 1e-4);
3509 1 : delete poGeom;
3510 : }
3511 :
3512 : // Test OGRGeometry::roundCoordinatesIEEE754()
3513 4 : TEST_F(test_ogr, roundCoordinatesIEEE754)
3514 : {
3515 2 : OGRLineString oLS;
3516 1 : oLS.addPoint(1.2345678901234, -1.2345678901234, -1.2345678901234, 0.012345);
3517 1 : oLS.addPoint(-1.2345678901234, 1.2345678901234, 1.2345678901234, -0.012345);
3518 1 : oLS.addPoint(std::numeric_limits<double>::infinity(),
3519 : std::numeric_limits<double>::quiet_NaN());
3520 1 : OGRGeomCoordinateBinaryPrecision sBinaryPrecision;
3521 2 : OGRGeomCoordinatePrecision sPrecision;
3522 1 : sPrecision.dfXYResolution = 1e-10;
3523 1 : sPrecision.dfZResolution = 1e-3;
3524 1 : sPrecision.dfMResolution = 1e-5;
3525 1 : sBinaryPrecision.SetFrom(sPrecision);
3526 2 : OGRLineString oLSOri(oLS);
3527 1 : oLS.roundCoordinatesIEEE754(sBinaryPrecision);
3528 1 : EXPECT_NE(oLS.getX(0), oLSOri.getX(0));
3529 1 : EXPECT_NE(oLS.getY(0), oLSOri.getY(0));
3530 1 : EXPECT_NE(oLS.getZ(0), oLSOri.getZ(0));
3531 1 : EXPECT_NE(oLS.getM(0), oLSOri.getM(0));
3532 1 : EXPECT_NEAR(oLS.getX(0), oLSOri.getX(0), sPrecision.dfXYResolution);
3533 1 : EXPECT_NEAR(oLS.getY(0), oLSOri.getY(0), sPrecision.dfXYResolution);
3534 1 : EXPECT_NEAR(oLS.getZ(0), oLSOri.getZ(0), sPrecision.dfZResolution);
3535 1 : EXPECT_NEAR(oLS.getM(0), oLSOri.getM(0), sPrecision.dfMResolution);
3536 1 : EXPECT_NEAR(oLS.getX(1), oLSOri.getX(1), sPrecision.dfXYResolution);
3537 1 : EXPECT_NEAR(oLS.getY(1), oLSOri.getY(1), sPrecision.dfXYResolution);
3538 1 : EXPECT_NEAR(oLS.getZ(1), oLSOri.getZ(1), sPrecision.dfZResolution);
3539 1 : EXPECT_NEAR(oLS.getM(1), oLSOri.getM(1), sPrecision.dfMResolution);
3540 1 : EXPECT_EQ(oLS.getX(2), std::numeric_limits<double>::infinity());
3541 1 : EXPECT_TRUE(std::isnan(oLS.getY(2)));
3542 1 : }
3543 :
3544 : // Test discarding of bits in WKB export
3545 4 : TEST_F(test_ogr, wkb_linestring_2d_xy_precision)
3546 : {
3547 2 : OGRLineString oLS;
3548 1 : oLS.addPoint(1.2345678901234, -1.2345678901234);
3549 1 : oLS.addPoint(-1.2345678901234, 1.2345678901234);
3550 1 : OGRwkbExportOptions sOptions;
3551 2 : OGRGeomCoordinatePrecision sPrecision;
3552 1 : sPrecision.dfXYResolution = 1e-10;
3553 1 : sOptions.sPrecision.SetFrom(sPrecision);
3554 2 : std::vector<GByte> abyWKB(oLS.WkbSize());
3555 1 : oLS.exportToWkb(&abyWKB[0], &sOptions);
3556 3 : for (int i = 0; i < oLS.getDimension() * oLS.getNumPoints(); ++i)
3557 : {
3558 2 : EXPECT_EQ(abyWKB[5 + 4 + 0 + 8 * i], 0);
3559 : }
3560 1 : OGRGeometry *poGeom = nullptr;
3561 1 : OGRGeometryFactory::createFromWkb(abyWKB.data(), nullptr, &poGeom);
3562 1 : EXPECT_NE(poGeom->toLineString()->getX(0), oLS.getX(0));
3563 1 : EXPECT_NE(poGeom->toLineString()->getY(0), oLS.getY(0));
3564 1 : EXPECT_NEAR(poGeom->toLineString()->getX(0), oLS.getX(0),
3565 : sPrecision.dfXYResolution);
3566 1 : EXPECT_NEAR(poGeom->toLineString()->getY(0), oLS.getY(0),
3567 : sPrecision.dfXYResolution);
3568 1 : EXPECT_NEAR(poGeom->toLineString()->getX(1), oLS.getX(1),
3569 : sPrecision.dfXYResolution);
3570 1 : EXPECT_NEAR(poGeom->toLineString()->getY(1), oLS.getY(1),
3571 : sPrecision.dfXYResolution);
3572 1 : delete poGeom;
3573 1 : }
3574 :
3575 : // Test discarding of bits in WKB export
3576 4 : TEST_F(test_ogr, wkb_linestring_3d_discard_lsb_bits)
3577 : {
3578 2 : OGRLineString oLS;
3579 1 : oLS.addPoint(1.2345678901234, -1.2345678901234, -1.2345678901234);
3580 1 : oLS.addPoint(-1.2345678901234, 1.2345678901234, 1.2345678901234);
3581 1 : OGRwkbExportOptions sOptions;
3582 2 : OGRGeomCoordinatePrecision sPrecision;
3583 1 : sPrecision.dfXYResolution = 1e-10;
3584 1 : sPrecision.dfZResolution = 1e-3;
3585 1 : sOptions.sPrecision.SetFrom(sPrecision);
3586 2 : std::vector<GByte> abyWKB(oLS.WkbSize());
3587 1 : oLS.exportToWkb(&abyWKB[0], &sOptions);
3588 3 : for (int i = 0; i < oLS.getDimension() * oLS.getNumPoints(); ++i)
3589 : {
3590 2 : EXPECT_EQ(abyWKB[5 + 4 + 0 + 8 * i], 0);
3591 : }
3592 1 : OGRGeometry *poGeom = nullptr;
3593 1 : OGRGeometryFactory::createFromWkb(abyWKB.data(), nullptr, &poGeom);
3594 1 : EXPECT_NE(poGeom->toLineString()->getX(0), oLS.getX(0));
3595 1 : EXPECT_NE(poGeom->toLineString()->getY(0), oLS.getY(0));
3596 1 : EXPECT_NE(poGeom->toLineString()->getZ(0), oLS.getZ(0));
3597 1 : EXPECT_NEAR(poGeom->toLineString()->getX(0), oLS.getX(0),
3598 : sPrecision.dfXYResolution);
3599 1 : EXPECT_NEAR(poGeom->toLineString()->getY(0), oLS.getY(0),
3600 : sPrecision.dfXYResolution);
3601 1 : EXPECT_NEAR(poGeom->toLineString()->getZ(0), oLS.getZ(0),
3602 : sPrecision.dfZResolution);
3603 1 : EXPECT_NEAR(poGeom->toLineString()->getX(1), oLS.getX(1),
3604 : sPrecision.dfXYResolution);
3605 1 : EXPECT_NEAR(poGeom->toLineString()->getY(1), oLS.getY(1),
3606 : sPrecision.dfXYResolution);
3607 1 : EXPECT_NEAR(poGeom->toLineString()->getZ(1), oLS.getZ(1),
3608 : sPrecision.dfZResolution);
3609 1 : delete poGeom;
3610 1 : }
3611 :
3612 : // Test discarding of bits in WKB export
3613 4 : TEST_F(test_ogr, wkb_linestring_xym_discard_lsb_bits)
3614 : {
3615 2 : OGRLineString oLS;
3616 1 : oLS.addPointM(1.2345678901234, -1.2345678901234, -1.2345678901234);
3617 1 : oLS.addPointM(-1.2345678901234, 1.2345678901234, 1.2345678901234);
3618 1 : OGRwkbExportOptions sOptions;
3619 2 : OGRGeomCoordinatePrecision sPrecision;
3620 1 : sPrecision.dfXYResolution = 1e-10;
3621 1 : sPrecision.dfMResolution = 1e-3;
3622 1 : sOptions.sPrecision.SetFrom(sPrecision);
3623 2 : std::vector<GByte> abyWKB(oLS.WkbSize());
3624 1 : oLS.exportToWkb(&abyWKB[0], &sOptions);
3625 3 : for (int i = 0; i < oLS.getDimension() * oLS.getNumPoints(); ++i)
3626 : {
3627 2 : EXPECT_EQ(abyWKB[5 + 4 + 0 + 8 * i], 0);
3628 : }
3629 1 : OGRGeometry *poGeom = nullptr;
3630 1 : OGRGeometryFactory::createFromWkb(abyWKB.data(), nullptr, &poGeom);
3631 1 : EXPECT_NE(poGeom->toLineString()->getX(0), oLS.getX(0));
3632 1 : EXPECT_NE(poGeom->toLineString()->getY(0), oLS.getY(0));
3633 1 : EXPECT_NE(poGeom->toLineString()->getM(0), oLS.getM(0));
3634 1 : EXPECT_NEAR(poGeom->toLineString()->getX(0), oLS.getX(0),
3635 : sPrecision.dfXYResolution);
3636 1 : EXPECT_NEAR(poGeom->toLineString()->getY(0), oLS.getY(0),
3637 : sPrecision.dfXYResolution);
3638 1 : EXPECT_NEAR(poGeom->toLineString()->getM(0), oLS.getM(0),
3639 : sPrecision.dfMResolution);
3640 1 : EXPECT_NEAR(poGeom->toLineString()->getX(1), oLS.getX(1),
3641 : sPrecision.dfXYResolution);
3642 1 : EXPECT_NEAR(poGeom->toLineString()->getY(1), oLS.getY(1),
3643 : sPrecision.dfXYResolution);
3644 1 : EXPECT_NEAR(poGeom->toLineString()->getM(1), oLS.getM(1),
3645 : sPrecision.dfMResolution);
3646 1 : delete poGeom;
3647 1 : }
3648 :
3649 : // Test discarding of bits in WKB export
3650 4 : TEST_F(test_ogr, wkb_linestring_xyzm_discard_lsb_bits)
3651 : {
3652 2 : OGRLineString oLS;
3653 1 : oLS.addPoint(1.2345678901234, -1.2345678901234, -1.2345678901234, 0.012345);
3654 1 : oLS.addPoint(-1.2345678901234, 1.2345678901234, 1.2345678901234, 0.012345);
3655 1 : OGRwkbExportOptions sOptions;
3656 2 : OGRGeomCoordinatePrecision sPrecision;
3657 1 : sPrecision.dfXYResolution = 1e-10;
3658 1 : sPrecision.dfZResolution = 1e-3;
3659 1 : sPrecision.dfMResolution = 1e-5;
3660 1 : sOptions.sPrecision.SetFrom(sPrecision);
3661 2 : std::vector<GByte> abyWKB(oLS.WkbSize());
3662 1 : oLS.exportToWkb(&abyWKB[0], &sOptions);
3663 3 : for (int i = 0; i < oLS.getDimension() * oLS.getNumPoints(); ++i)
3664 : {
3665 2 : EXPECT_EQ(abyWKB[5 + 4 + 0 + 8 * i], 0);
3666 : }
3667 1 : OGRGeometry *poGeom = nullptr;
3668 1 : OGRGeometryFactory::createFromWkb(abyWKB.data(), nullptr, &poGeom);
3669 1 : EXPECT_NE(poGeom->toLineString()->getX(0), oLS.getX(0));
3670 1 : EXPECT_NE(poGeom->toLineString()->getY(0), oLS.getY(0));
3671 1 : EXPECT_NE(poGeom->toLineString()->getZ(0), oLS.getZ(0));
3672 1 : EXPECT_NE(poGeom->toLineString()->getM(0), oLS.getM(0));
3673 1 : EXPECT_NEAR(poGeom->toLineString()->getX(0), oLS.getX(0),
3674 : sPrecision.dfXYResolution);
3675 1 : EXPECT_NEAR(poGeom->toLineString()->getY(0), oLS.getY(0),
3676 : sPrecision.dfXYResolution);
3677 1 : EXPECT_NEAR(poGeom->toLineString()->getZ(0), oLS.getZ(0),
3678 : sPrecision.dfZResolution);
3679 1 : EXPECT_NEAR(poGeom->toLineString()->getM(0), oLS.getM(0),
3680 : sPrecision.dfMResolution);
3681 1 : EXPECT_NEAR(poGeom->toLineString()->getX(1), oLS.getX(1),
3682 : sPrecision.dfXYResolution);
3683 1 : EXPECT_NEAR(poGeom->toLineString()->getY(1), oLS.getY(1),
3684 : sPrecision.dfXYResolution);
3685 1 : EXPECT_NEAR(poGeom->toLineString()->getZ(1), oLS.getZ(1),
3686 : sPrecision.dfZResolution);
3687 1 : EXPECT_NEAR(poGeom->toLineString()->getM(1), oLS.getM(1),
3688 : sPrecision.dfMResolution);
3689 1 : delete poGeom;
3690 1 : }
3691 :
3692 : // Test discarding of bits in WKB export
3693 4 : TEST_F(test_ogr, wkb_polygon_2d_xy_precision)
3694 : {
3695 2 : OGRLinearRing oLS;
3696 1 : oLS.addPoint(1.2345678901234, -1.2345678901234);
3697 1 : oLS.addPoint(-1.2345678901234, -1.2345678901234);
3698 1 : oLS.addPoint(-2.2345678901234, 1.2345678901234);
3699 1 : oLS.addPoint(1.2345678901234, -1.2345678901234);
3700 2 : OGRPolygon oPoly;
3701 1 : oPoly.addRing(&oLS);
3702 1 : OGRwkbExportOptions sOptions;
3703 2 : OGRGeomCoordinatePrecision sPrecision;
3704 1 : sPrecision.dfXYResolution = 1e-10;
3705 1 : sOptions.sPrecision.SetFrom(sPrecision);
3706 2 : std::vector<GByte> abyWKB(oPoly.WkbSize());
3707 1 : oPoly.exportToWkb(&abyWKB[0], &sOptions);
3708 5 : for (int i = 0; i < oLS.getDimension() * oLS.getNumPoints(); ++i)
3709 : {
3710 4 : EXPECT_EQ(abyWKB[5 + 4 + 4 + 0 + 8 * i], 0);
3711 : }
3712 1 : OGRGeometry *poGeom = nullptr;
3713 1 : OGRGeometryFactory::createFromWkb(abyWKB.data(), nullptr, &poGeom);
3714 1 : EXPECT_NE(poGeom->toPolygon()->getExteriorRing()->getX(0), oLS.getX(0));
3715 1 : EXPECT_NE(poGeom->toPolygon()->getExteriorRing()->getY(0), oLS.getY(0));
3716 1 : EXPECT_NEAR(poGeom->toPolygon()->getExteriorRing()->getX(0), oLS.getX(0),
3717 : sPrecision.dfXYResolution);
3718 1 : EXPECT_NEAR(poGeom->toPolygon()->getExteriorRing()->getY(0), oLS.getY(0),
3719 : sPrecision.dfXYResolution);
3720 1 : EXPECT_NEAR(poGeom->toPolygon()->getExteriorRing()->getX(1), oLS.getX(1),
3721 : sPrecision.dfXYResolution);
3722 1 : EXPECT_NEAR(poGeom->toPolygon()->getExteriorRing()->getY(1), oLS.getY(1),
3723 : sPrecision.dfXYResolution);
3724 1 : delete poGeom;
3725 1 : }
3726 :
3727 : // Test discarding of bits in WKB export
3728 4 : TEST_F(test_ogr, wkb_polygon_3d_discard_lsb_bits)
3729 : {
3730 2 : OGRLinearRing oLS;
3731 1 : oLS.addPoint(1.2345678901234, -1.2345678901234, 1.2345678901234);
3732 1 : oLS.addPoint(-1.2345678901234, -1.2345678901234, -1.2345678901234);
3733 1 : oLS.addPoint(-2.2345678901234, 1.2345678901234, -1.2345678901234);
3734 1 : oLS.addPoint(1.2345678901234, -1.2345678901234, 1.2345678901234);
3735 2 : OGRPolygon oPoly;
3736 1 : oPoly.addRing(&oLS);
3737 2 : OGRSpatialReference oSRS;
3738 1 : oSRS.importFromEPSG(4326);
3739 1 : OGRwkbExportOptions sOptions;
3740 2 : OGRGeomCoordinatePrecision sPrecision;
3741 1 : sPrecision.SetFromMeter(&oSRS, 1e-3, 1e-3, 0);
3742 1 : sOptions.sPrecision.SetFrom(sPrecision);
3743 2 : std::vector<GByte> abyWKB(oPoly.WkbSize());
3744 1 : oPoly.exportToWkb(&abyWKB[0], &sOptions);
3745 5 : for (int i = 0; i < oLS.getDimension() * oLS.getNumPoints(); ++i)
3746 : {
3747 4 : EXPECT_EQ(abyWKB[5 + 4 + 4 + 0 + 8 * i], 0);
3748 : }
3749 1 : OGRGeometry *poGeom = nullptr;
3750 1 : OGRGeometryFactory::createFromWkb(abyWKB.data(), nullptr, &poGeom);
3751 1 : EXPECT_NE(poGeom->toPolygon()->getExteriorRing()->getX(0), oLS.getX(0));
3752 1 : EXPECT_NE(poGeom->toPolygon()->getExteriorRing()->getY(0), oLS.getY(0));
3753 1 : EXPECT_NE(poGeom->toPolygon()->getExteriorRing()->getZ(0), oLS.getZ(0));
3754 1 : EXPECT_NEAR(poGeom->toPolygon()->getExteriorRing()->getX(0), oLS.getX(0),
3755 : 8.9e-9);
3756 1 : EXPECT_NEAR(poGeom->toPolygon()->getExteriorRing()->getY(0), oLS.getY(0),
3757 : 8.9e-9);
3758 1 : EXPECT_NEAR(poGeom->toPolygon()->getExteriorRing()->getZ(0), oLS.getZ(0),
3759 : 1e-3);
3760 1 : EXPECT_NEAR(poGeom->toPolygon()->getExteriorRing()->getX(1), oLS.getX(1),
3761 : 8.9e-9);
3762 1 : EXPECT_NEAR(poGeom->toPolygon()->getExteriorRing()->getY(1), oLS.getY(1),
3763 : 8.9e-9);
3764 1 : EXPECT_NEAR(poGeom->toPolygon()->getExteriorRing()->getZ(1), oLS.getZ(1),
3765 : 1e-3);
3766 1 : delete poGeom;
3767 1 : }
3768 :
3769 : // Test discarding of bits in WKB export
3770 4 : TEST_F(test_ogr, wkb_polygon_xym_discard_lsb_bits)
3771 : {
3772 2 : OGRLinearRing oLS;
3773 1 : oLS.addPointM(1.2345678901234, -1.2345678901234, 1.2345678901234);
3774 1 : oLS.addPointM(-1.2345678901234, -1.2345678901234, -1.2345678901234);
3775 1 : oLS.addPointM(-2.2345678901234, 1.2345678901234, -1.2345678901234);
3776 1 : oLS.addPointM(1.2345678901234, -1.2345678901234, 1.2345678901234);
3777 2 : OGRPolygon oPoly;
3778 1 : oPoly.addRing(&oLS);
3779 2 : OGRSpatialReference oSRS;
3780 1 : oSRS.importFromEPSG(4326);
3781 1 : OGRwkbExportOptions sOptions;
3782 2 : OGRGeomCoordinatePrecision sPrecision;
3783 1 : sPrecision.SetFromMeter(&oSRS, 1e-3, 0, 1e-3);
3784 1 : sOptions.sPrecision.SetFrom(sPrecision);
3785 2 : std::vector<GByte> abyWKB(oPoly.WkbSize());
3786 1 : oPoly.exportToWkb(&abyWKB[0], &sOptions);
3787 5 : for (int i = 0; i < oLS.getDimension() * oLS.getNumPoints(); ++i)
3788 : {
3789 4 : EXPECT_EQ(abyWKB[5 + 4 + 4 + 0 + 8 * i], 0);
3790 : }
3791 1 : OGRGeometry *poGeom = nullptr;
3792 1 : OGRGeometryFactory::createFromWkb(abyWKB.data(), nullptr, &poGeom);
3793 1 : EXPECT_NE(poGeom->toPolygon()->getExteriorRing()->getX(0), oLS.getX(0));
3794 1 : EXPECT_NE(poGeom->toPolygon()->getExteriorRing()->getY(0), oLS.getY(0));
3795 1 : EXPECT_NE(poGeom->toPolygon()->getExteriorRing()->getM(0), oLS.getM(0));
3796 1 : EXPECT_NEAR(poGeom->toPolygon()->getExteriorRing()->getX(0), oLS.getX(0),
3797 : 8.9e-9);
3798 1 : EXPECT_NEAR(poGeom->toPolygon()->getExteriorRing()->getY(0), oLS.getY(0),
3799 : 8.9e-9);
3800 1 : EXPECT_NEAR(poGeom->toPolygon()->getExteriorRing()->getM(0), oLS.getM(0),
3801 : 1e-3);
3802 1 : EXPECT_NEAR(poGeom->toPolygon()->getExteriorRing()->getX(1), oLS.getX(1),
3803 : 8.9e-9);
3804 1 : EXPECT_NEAR(poGeom->toPolygon()->getExteriorRing()->getY(1), oLS.getY(1),
3805 : 8.9e-9);
3806 1 : EXPECT_NEAR(poGeom->toPolygon()->getExteriorRing()->getM(1), oLS.getM(1),
3807 : 1e-3);
3808 1 : delete poGeom;
3809 1 : }
3810 :
3811 : // Test discarding of bits in WKB export
3812 4 : TEST_F(test_ogr, wkb_polygon_xyzm_discard_lsb_bits)
3813 : {
3814 2 : OGRLinearRing oLS;
3815 1 : oLS.addPoint(1.2345678901234, -1.2345678901234, 1.2345678901234, 0.012345);
3816 1 : oLS.addPoint(-1.2345678901234, -1.2345678901234, -1.2345678901234, 12345);
3817 1 : oLS.addPoint(-2.2345678901234, 1.2345678901234, -1.2345678901234, 0.012345);
3818 1 : oLS.addPoint(1.2345678901234, -1.2345678901234, 1.2345678901234, 0.012345);
3819 2 : OGRPolygon oPoly;
3820 1 : oPoly.addRing(&oLS);
3821 2 : OGRSpatialReference oSRS;
3822 1 : oSRS.importFromEPSG(4326);
3823 1 : OGRwkbExportOptions sOptions;
3824 2 : OGRGeomCoordinatePrecision sPrecision;
3825 1 : sPrecision.SetFromMeter(&oSRS, 1e-3, 1e-3, 1e-4);
3826 1 : sOptions.sPrecision.SetFrom(sPrecision);
3827 2 : std::vector<GByte> abyWKB(oPoly.WkbSize());
3828 1 : oPoly.exportToWkb(&abyWKB[0], &sOptions);
3829 5 : for (int i = 0; i < oLS.getDimension() * oLS.getNumPoints(); ++i)
3830 : {
3831 4 : EXPECT_EQ(abyWKB[5 + 4 + 4 + 0 + 8 * i], 0);
3832 : }
3833 1 : OGRGeometry *poGeom = nullptr;
3834 1 : OGRGeometryFactory::createFromWkb(abyWKB.data(), nullptr, &poGeom);
3835 1 : EXPECT_NE(poGeom->toPolygon()->getExteriorRing()->getX(0), oLS.getX(0));
3836 1 : EXPECT_NE(poGeom->toPolygon()->getExteriorRing()->getY(0), oLS.getY(0));
3837 1 : EXPECT_NE(poGeom->toPolygon()->getExteriorRing()->getZ(0), oLS.getZ(0));
3838 1 : EXPECT_NE(poGeom->toPolygon()->getExteriorRing()->getM(0), oLS.getM(0));
3839 1 : EXPECT_NEAR(poGeom->toPolygon()->getExteriorRing()->getX(0), oLS.getX(0),
3840 : 8.9e-9);
3841 1 : EXPECT_NEAR(poGeom->toPolygon()->getExteriorRing()->getY(0), oLS.getY(0),
3842 : 8.9e-9);
3843 1 : EXPECT_NEAR(poGeom->toPolygon()->getExteriorRing()->getZ(0), oLS.getZ(0),
3844 : 1e-3);
3845 1 : EXPECT_NEAR(poGeom->toPolygon()->getExteriorRing()->getM(0), oLS.getM(0),
3846 : 1e-4);
3847 1 : EXPECT_NEAR(poGeom->toPolygon()->getExteriorRing()->getX(1), oLS.getX(1),
3848 : 8.9e-9);
3849 1 : EXPECT_NEAR(poGeom->toPolygon()->getExteriorRing()->getY(1), oLS.getY(1),
3850 : 8.9e-9);
3851 1 : EXPECT_NEAR(poGeom->toPolygon()->getExteriorRing()->getZ(1), oLS.getZ(1),
3852 : 1e-3);
3853 1 : EXPECT_NEAR(poGeom->toPolygon()->getExteriorRing()->getM(1), oLS.getM(1),
3854 : 1e-4);
3855 1 : delete poGeom;
3856 1 : }
3857 :
3858 : // Test OGRFeature::SerializeToBinary() and DeserializeFromBinary();
3859 4 : TEST_F(test_ogr, OGRFeature_SerializeToBinary)
3860 : {
3861 : {
3862 2 : OGRFeatureDefn oFDefn;
3863 1 : oFDefn.SetGeomType(wkbNone);
3864 1 : oFDefn.Reference();
3865 :
3866 : {
3867 2 : OGRFeature oFeatSrc(&oFDefn);
3868 1 : oFeatSrc.SetFID(1);
3869 2 : std::vector<GByte> abyBuffer;
3870 :
3871 1 : EXPECT_TRUE(oFeatSrc.SerializeToBinary(abyBuffer));
3872 1 : EXPECT_EQ(abyBuffer.size(), 1);
3873 1 : EXPECT_EQ(abyBuffer[0], 1);
3874 :
3875 2 : OGRFeature oFeatDst(&oFDefn);
3876 1 : EXPECT_FALSE(oFeatDst.DeserializeFromBinary(abyBuffer.data(), 0));
3877 1 : EXPECT_TRUE(oFeatDst.DeserializeFromBinary(abyBuffer.data(),
3878 : abyBuffer.size()));
3879 1 : EXPECT_EQ(oFeatDst.GetFID(), 1);
3880 : }
3881 :
3882 : {
3883 2 : OGRFeature oFeatSrc(&oFDefn);
3884 1 : oFeatSrc.SetFID(static_cast<GIntBig>(-12345678901234));
3885 2 : std::vector<GByte> abyBuffer;
3886 :
3887 1 : EXPECT_TRUE(oFeatSrc.SerializeToBinary(abyBuffer));
3888 :
3889 2 : OGRFeature oFeatDst(&oFDefn);
3890 : // Try truncated buffers
3891 8 : for (size_t i = 0; i < abyBuffer.size(); ++i)
3892 : {
3893 7 : EXPECT_FALSE(
3894 : oFeatDst.DeserializeFromBinary(abyBuffer.data(), i));
3895 : }
3896 1 : EXPECT_TRUE(oFeatDst.DeserializeFromBinary(abyBuffer.data(),
3897 : abyBuffer.size()));
3898 1 : EXPECT_EQ(oFeatDst.GetFID(), static_cast<GIntBig>(-12345678901234));
3899 : }
3900 : }
3901 :
3902 : {
3903 1 : OGRFeatureDefn oFDefn;
3904 1 : oFDefn.Reference();
3905 : {
3906 2 : OGRFieldDefn oFieldDefn("int", OFTInteger);
3907 1 : oFDefn.AddFieldDefn(&oFieldDefn);
3908 : }
3909 : {
3910 2 : OGRFieldDefn oFieldDefn("int64", OFTInteger64);
3911 1 : oFDefn.AddFieldDefn(&oFieldDefn);
3912 : }
3913 : {
3914 2 : OGRFieldDefn oFieldDefn("real", OFTReal);
3915 1 : oFDefn.AddFieldDefn(&oFieldDefn);
3916 : }
3917 : {
3918 2 : OGRFieldDefn oFieldDefn("str", OFTString);
3919 1 : oFDefn.AddFieldDefn(&oFieldDefn);
3920 : }
3921 : {
3922 2 : OGRFieldDefn oFieldDefn("binary", OFTBinary);
3923 1 : oFDefn.AddFieldDefn(&oFieldDefn);
3924 : }
3925 : {
3926 2 : OGRFieldDefn oFieldDefn("intlist", OFTIntegerList);
3927 1 : oFDefn.AddFieldDefn(&oFieldDefn);
3928 : }
3929 : {
3930 2 : OGRFieldDefn oFieldDefn("int64list", OFTInteger64List);
3931 1 : oFDefn.AddFieldDefn(&oFieldDefn);
3932 : }
3933 : {
3934 2 : OGRFieldDefn oFieldDefn("reallist", OFTRealList);
3935 1 : oFDefn.AddFieldDefn(&oFieldDefn);
3936 : }
3937 : {
3938 2 : OGRFieldDefn oFieldDefn("strlist", OFTStringList);
3939 1 : oFDefn.AddFieldDefn(&oFieldDefn);
3940 : }
3941 : {
3942 2 : OGRFieldDefn oFieldDefn("date", OFTDate);
3943 1 : oFDefn.AddFieldDefn(&oFieldDefn);
3944 : }
3945 : {
3946 2 : OGRFieldDefn oFieldDefn("time", OFTTime);
3947 1 : oFDefn.AddFieldDefn(&oFieldDefn);
3948 : }
3949 : {
3950 2 : OGRFieldDefn oFieldDefn("datetime", OFTDateTime);
3951 1 : oFDefn.AddFieldDefn(&oFieldDefn);
3952 : }
3953 :
3954 : {
3955 2 : OGRFeature oFeatSrc(&oFDefn);
3956 2 : std::vector<GByte> abyBuffer;
3957 :
3958 1 : EXPECT_TRUE(oFeatSrc.SerializeToBinary(abyBuffer));
3959 1 : EXPECT_EQ(abyBuffer.size(), 5);
3960 :
3961 2 : OGRFeature oFeatDst(&oFDefn);
3962 6 : for (size_t i = 0; i < abyBuffer.size(); ++i)
3963 : {
3964 5 : EXPECT_FALSE(
3965 : oFeatDst.DeserializeFromBinary(abyBuffer.data(), i));
3966 : }
3967 1 : EXPECT_TRUE(oFeatDst.DeserializeFromBinary(abyBuffer.data(),
3968 : abyBuffer.size()));
3969 1 : EXPECT_TRUE(oFeatDst.Equal(&oFeatSrc));
3970 : }
3971 :
3972 : {
3973 1 : OGRFeature oFeatSrc(&oFDefn);
3974 1 : std::vector<GByte> abyBuffer;
3975 :
3976 1 : const int iFieldInt = oFDefn.GetFieldIndex("int");
3977 1 : ASSERT_TRUE(iFieldInt >= 0);
3978 1 : oFeatSrc.SetFieldNull(iFieldInt);
3979 1 : EXPECT_TRUE(oFeatSrc.SerializeToBinary(abyBuffer));
3980 1 : EXPECT_EQ(abyBuffer.size(), 5);
3981 :
3982 2 : OGRFeature oFeatDst(&oFDefn);
3983 :
3984 : // Try truncated buffers
3985 6 : for (size_t i = 0; i < abyBuffer.size(); ++i)
3986 : {
3987 5 : EXPECT_FALSE(
3988 : oFeatDst.DeserializeFromBinary(abyBuffer.data(), i));
3989 : }
3990 :
3991 1 : EXPECT_TRUE(oFeatDst.DeserializeFromBinary(abyBuffer.data(),
3992 : abyBuffer.size()));
3993 1 : EXPECT_TRUE(oFeatDst.Equal(&oFeatSrc));
3994 : }
3995 :
3996 : {
3997 1 : OGRFeature oFeatSrc(&oFDefn);
3998 1 : oFeatSrc.SetFID(1);
3999 1 : oFeatSrc.SetField("int", -123);
4000 1 : oFeatSrc.SetField("int64", static_cast<GIntBig>(-12345678901234));
4001 1 : oFeatSrc.SetField("real", 1.25);
4002 1 : oFeatSrc.SetField("str", "foo");
4003 1 : const int iFieldBinary = oFDefn.GetFieldIndex("binary");
4004 1 : ASSERT_TRUE(iFieldBinary >= 0);
4005 1 : oFeatSrc.SetField(iFieldBinary, 3,
4006 : static_cast<const void *>("abc"));
4007 1 : oFeatSrc.SetField("intlist", 2,
4008 2 : std::vector<int>{1, -123456}.data());
4009 1 : oFeatSrc.SetField("int64list", 2,
4010 2 : std::vector<GIntBig>{1, -12345678901234}.data());
4011 1 : oFeatSrc.SetField("reallist", 2,
4012 2 : std::vector<double>{1.5, -2.5}.data());
4013 2 : CPLStringList aosList;
4014 1 : aosList.AddString("foo");
4015 1 : aosList.AddString("barbaz");
4016 1 : oFeatSrc.SetField("strlist", aosList.List());
4017 1 : oFeatSrc.SetField("date", 2023, 1, 3);
4018 1 : oFeatSrc.SetField("time", 0, 0, 0, 12, 34, 56.789f);
4019 1 : oFeatSrc.SetField("datetime", 2023, 1, 3, 12, 34, 56.789f);
4020 2 : OGRPoint p(1, 2);
4021 1 : oFeatSrc.SetGeometry(&p);
4022 2 : std::vector<GByte> abyBuffer;
4023 :
4024 1 : EXPECT_TRUE(oFeatSrc.SerializeToBinary(abyBuffer));
4025 :
4026 2 : OGRFeature oFeatDst(&oFDefn);
4027 :
4028 : // Try truncated buffers
4029 118 : for (size_t i = 0; i < abyBuffer.size(); ++i)
4030 : {
4031 117 : EXPECT_FALSE(
4032 : oFeatDst.DeserializeFromBinary(abyBuffer.data(), i));
4033 : }
4034 :
4035 : // Try corrupted buffers
4036 : {
4037 2 : CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
4038 118 : for (size_t i = 0; i < abyBuffer.size(); ++i)
4039 : {
4040 : // Might succeed or fail, but shouldn't crash..
4041 117 : const GByte backup = abyBuffer[i];
4042 117 : abyBuffer[i] = static_cast<GByte>(~abyBuffer[i]);
4043 117 : (void)oFeatDst.DeserializeFromBinary(abyBuffer.data(),
4044 : abyBuffer.size());
4045 117 : abyBuffer[i] = backup;
4046 : }
4047 : }
4048 :
4049 1 : EXPECT_TRUE(oFeatDst.DeserializeFromBinary(abyBuffer.data(),
4050 : abyBuffer.size()));
4051 : // oFeatSrc.DumpReadable(stdout);
4052 : // oFeatDst.DumpReadable(stdout);
4053 1 : EXPECT_TRUE(oFeatDst.Equal(&oFeatSrc));
4054 : }
4055 : }
4056 : }
4057 :
4058 : // Test OGRGeometry::IsRectangle()
4059 4 : TEST_F(test_ogr, OGRGeometry_IsRectangle)
4060 : {
4061 : // Not a polygon
4062 : {
4063 1 : OGRGeometry *poGeom = nullptr;
4064 1 : OGRGeometryFactory::createFromWkt("POINT EMPTY", nullptr, &poGeom);
4065 1 : ASSERT_NE(poGeom, nullptr);
4066 1 : EXPECT_FALSE(poGeom->IsRectangle());
4067 1 : delete poGeom;
4068 : }
4069 : // Polygon empty
4070 : {
4071 1 : OGRGeometry *poGeom = nullptr;
4072 1 : OGRGeometryFactory::createFromWkt("POLYGON EMPTY", nullptr, &poGeom);
4073 1 : ASSERT_NE(poGeom, nullptr);
4074 1 : EXPECT_FALSE(poGeom->IsRectangle());
4075 1 : delete poGeom;
4076 : }
4077 : // Polygon with inner ring
4078 : {
4079 1 : OGRGeometry *poGeom = nullptr;
4080 1 : OGRGeometryFactory::createFromWkt(
4081 : "POLYGON ((0 0,0 1,1 1,1 0,0 0),(0.2 0.2,0.2 0.8,0.8 0.8,0.8 "
4082 : "0.2,0.2 0.2))",
4083 : nullptr, &poGeom);
4084 1 : ASSERT_NE(poGeom, nullptr);
4085 1 : EXPECT_FALSE(poGeom->IsRectangle());
4086 1 : delete poGeom;
4087 : }
4088 : // Polygon with 3 points
4089 : {
4090 1 : OGRGeometry *poGeom = nullptr;
4091 1 : OGRGeometryFactory::createFromWkt("POLYGON ((0 0,0 1,1 1))", nullptr,
4092 : &poGeom);
4093 1 : ASSERT_NE(poGeom, nullptr);
4094 1 : EXPECT_FALSE(poGeom->IsRectangle());
4095 1 : delete poGeom;
4096 : }
4097 : // Polygon with 6 points
4098 : {
4099 1 : OGRGeometry *poGeom = nullptr;
4100 1 : OGRGeometryFactory::createFromWkt(
4101 : "POLYGON ((0 0,0.1 0,0.2 0,0.3 0,1 1,0 0))", nullptr, &poGeom);
4102 1 : ASSERT_NE(poGeom, nullptr);
4103 1 : EXPECT_FALSE(poGeom->IsRectangle());
4104 1 : delete poGeom;
4105 : }
4106 : // Polygon with 5 points, but last one not matching first (invalid)
4107 : {
4108 1 : OGRGeometry *poGeom = nullptr;
4109 1 : OGRGeometryFactory::createFromWkt(
4110 : "POLYGON ((0 0,0 1,1 1,1 0,-999 -999))", nullptr, &poGeom);
4111 1 : ASSERT_NE(poGeom, nullptr);
4112 1 : EXPECT_FALSE(poGeom->IsRectangle());
4113 1 : delete poGeom;
4114 : }
4115 : // Polygon with 5 points, but not rectangle
4116 : {
4117 1 : OGRGeometry *poGeom = nullptr;
4118 1 : OGRGeometryFactory::createFromWkt("POLYGON ((0 0,0 1.1,1 1,1 0,0 0))",
4119 : nullptr, &poGeom);
4120 1 : ASSERT_NE(poGeom, nullptr);
4121 1 : EXPECT_FALSE(poGeom->IsRectangle());
4122 1 : delete poGeom;
4123 : }
4124 : // Rectangle (type 1)
4125 : {
4126 1 : OGRGeometry *poGeom = nullptr;
4127 1 : OGRGeometryFactory::createFromWkt("POLYGON ((0 0,0 1,1 1,1 0,0 0))",
4128 : nullptr, &poGeom);
4129 1 : ASSERT_NE(poGeom, nullptr);
4130 1 : EXPECT_TRUE(poGeom->IsRectangle());
4131 1 : delete poGeom;
4132 : }
4133 : // Rectangle2(type 1)
4134 : {
4135 1 : OGRGeometry *poGeom = nullptr;
4136 1 : OGRGeometryFactory::createFromWkt("POLYGON ((0 0,1 0,1 1,0 1,0 0))",
4137 : nullptr, &poGeom);
4138 1 : ASSERT_NE(poGeom, nullptr);
4139 1 : EXPECT_TRUE(poGeom->IsRectangle());
4140 1 : delete poGeom;
4141 : }
4142 : }
4143 :
4144 : // Test OGRGeometry::removeEmptyParts()
4145 4 : TEST_F(test_ogr, OGRGeometry_removeEmptyParts)
4146 : {
4147 : {
4148 1 : OGRGeometry *poGeom = nullptr;
4149 1 : OGRGeometryFactory::createFromWkt("POINT EMPTY", nullptr, &poGeom);
4150 1 : ASSERT_NE(poGeom, nullptr);
4151 1 : EXPECT_FALSE(poGeom->hasEmptyParts());
4152 1 : poGeom->removeEmptyParts();
4153 1 : EXPECT_TRUE(poGeom->IsEmpty());
4154 1 : delete poGeom;
4155 : }
4156 : {
4157 1 : OGRGeometry *poGeom = nullptr;
4158 1 : OGRGeometryFactory::createFromWkt("POLYGON ((0 0,0 1,1 0,0 0))",
4159 : nullptr, &poGeom);
4160 1 : ASSERT_NE(poGeom, nullptr);
4161 1 : EXPECT_FALSE(poGeom->hasEmptyParts());
4162 1 : poGeom->removeEmptyParts();
4163 1 : EXPECT_NE(poGeom->toPolygon()->getExteriorRing(), nullptr);
4164 1 : delete poGeom;
4165 : }
4166 : {
4167 1 : OGRGeometry *poGeom = nullptr;
4168 1 : OGRGeometryFactory::createFromWkt("POLYGON ((0 0,0 1,1 0,0 0))",
4169 : nullptr, &poGeom);
4170 1 : ASSERT_NE(poGeom, nullptr);
4171 1 : poGeom->toPolygon()->addRingDirectly(new OGRLinearRing());
4172 1 : EXPECT_EQ(poGeom->toPolygon()->getNumInteriorRings(), 1);
4173 1 : EXPECT_TRUE(poGeom->hasEmptyParts());
4174 1 : poGeom->removeEmptyParts();
4175 1 : EXPECT_NE(poGeom->toPolygon()->getExteriorRing(), nullptr);
4176 1 : EXPECT_EQ(poGeom->toPolygon()->getNumInteriorRings(), 0);
4177 1 : EXPECT_FALSE(poGeom->hasEmptyParts());
4178 1 : delete poGeom;
4179 : }
4180 : {
4181 1 : OGRGeometry *poGeom = nullptr;
4182 1 : OGRGeometryFactory::createFromWkt("COMPOUNDCURVE ((0 0,1 1))", nullptr,
4183 : &poGeom);
4184 1 : ASSERT_NE(poGeom, nullptr);
4185 1 : EXPECT_FALSE(poGeom->hasEmptyParts());
4186 1 : poGeom->removeEmptyParts();
4187 1 : EXPECT_EQ(poGeom->toCompoundCurve()->getNumCurves(), 1);
4188 1 : delete poGeom;
4189 : }
4190 : {
4191 1 : OGRGeometry *poGeom = nullptr;
4192 1 : OGRGeometryFactory::createFromWkt("COMPOUNDCURVE ((0 0,1 1),(1 1,2 2))",
4193 : nullptr, &poGeom);
4194 1 : ASSERT_NE(poGeom, nullptr);
4195 1 : poGeom->toCompoundCurve()->getCurve(1)->empty();
4196 1 : EXPECT_EQ(poGeom->toCompoundCurve()->getNumCurves(), 2);
4197 1 : EXPECT_TRUE(poGeom->hasEmptyParts());
4198 1 : poGeom->removeEmptyParts();
4199 1 : EXPECT_FALSE(poGeom->hasEmptyParts());
4200 1 : EXPECT_EQ(poGeom->toCompoundCurve()->getNumCurves(), 1);
4201 1 : delete poGeom;
4202 : }
4203 : {
4204 1 : OGRGeometry *poGeom = nullptr;
4205 1 : OGRGeometryFactory::createFromWkt("GEOMETRYCOLLECTION (POINT(0 0))",
4206 : nullptr, &poGeom);
4207 1 : ASSERT_NE(poGeom, nullptr);
4208 1 : EXPECT_FALSE(poGeom->hasEmptyParts());
4209 1 : poGeom->removeEmptyParts();
4210 1 : EXPECT_EQ(poGeom->toGeometryCollection()->getNumGeometries(), 1);
4211 1 : delete poGeom;
4212 : }
4213 : {
4214 1 : OGRGeometry *poGeom = nullptr;
4215 1 : OGRGeometryFactory::createFromWkt(
4216 : "GEOMETRYCOLLECTION (POINT EMPTY,POINT(0 0),POINT EMPTY)", nullptr,
4217 : &poGeom);
4218 1 : ASSERT_NE(poGeom, nullptr);
4219 1 : EXPECT_EQ(poGeom->toGeometryCollection()->getNumGeometries(), 3);
4220 1 : EXPECT_TRUE(poGeom->hasEmptyParts());
4221 1 : poGeom->removeEmptyParts();
4222 1 : EXPECT_FALSE(poGeom->hasEmptyParts());
4223 1 : EXPECT_EQ(poGeom->toGeometryCollection()->getNumGeometries(), 1);
4224 1 : delete poGeom;
4225 : }
4226 : {
4227 1 : OGRGeometry *poGeom = nullptr;
4228 1 : OGRGeometryFactory::createFromWkt("GEOMETRYCOLLECTION EMPTY", nullptr,
4229 : &poGeom);
4230 1 : ASSERT_NE(poGeom, nullptr);
4231 1 : OGRGeometry *poPoly = nullptr;
4232 1 : OGRGeometryFactory::createFromWkt("POLYGON ((0 0,0 1,1 0,0 0))",
4233 : nullptr, &poPoly);
4234 1 : EXPECT_NE(poPoly, nullptr);
4235 1 : if (poPoly)
4236 : {
4237 1 : poPoly->toPolygon()->addRingDirectly(new OGRLinearRing());
4238 1 : poGeom->toGeometryCollection()->addGeometryDirectly(poPoly);
4239 1 : EXPECT_EQ(poGeom->toGeometryCollection()->getNumGeometries(), 1);
4240 1 : EXPECT_TRUE(poGeom->hasEmptyParts());
4241 1 : poGeom->removeEmptyParts();
4242 1 : EXPECT_FALSE(poGeom->hasEmptyParts());
4243 1 : EXPECT_EQ(poGeom->toGeometryCollection()->getNumGeometries(), 1);
4244 : }
4245 1 : delete poGeom;
4246 : }
4247 : {
4248 1 : OGRGeometry *poGeom = nullptr;
4249 1 : OGRGeometryFactory::createFromWkt(
4250 : "POLYHEDRALSURFACE (((0 0,0 1,1 1,0 0)))", nullptr, &poGeom);
4251 1 : ASSERT_NE(poGeom, nullptr);
4252 1 : EXPECT_FALSE(poGeom->hasEmptyParts());
4253 1 : poGeom->removeEmptyParts();
4254 1 : EXPECT_EQ(poGeom->toPolyhedralSurface()->getNumGeometries(), 1);
4255 1 : delete poGeom;
4256 : }
4257 : {
4258 1 : OGRGeometry *poGeom = nullptr;
4259 1 : OGRGeometryFactory::createFromWkt(
4260 : "POLYHEDRALSURFACE (((0 0,0 1,1 1,0 0)))", nullptr, &poGeom);
4261 1 : ASSERT_NE(poGeom, nullptr);
4262 1 : poGeom->toPolyhedralSurface()->addGeometryDirectly(new OGRPolygon());
4263 1 : EXPECT_EQ(poGeom->toPolyhedralSurface()->getNumGeometries(), 2);
4264 1 : EXPECT_TRUE(poGeom->hasEmptyParts());
4265 1 : poGeom->removeEmptyParts();
4266 1 : EXPECT_FALSE(poGeom->hasEmptyParts());
4267 1 : EXPECT_EQ(poGeom->toPolyhedralSurface()->getNumGeometries(), 1);
4268 1 : delete poGeom;
4269 : }
4270 : }
4271 :
4272 : // Test OGRCurve::reversePoints()
4273 4 : TEST_F(test_ogr, OGRCurve_reversePoints)
4274 : {
4275 : {
4276 1 : OGRGeometry *poGeom = nullptr;
4277 1 : OGRGeometryFactory::createFromWkt(
4278 : "COMPOUNDCURVE ZM (CIRCULARSTRING ZM (0 0 10 20,1 1 11 21,2 0 12 "
4279 : "22),(2 0 12 22,3 0 13 2))",
4280 : nullptr, &poGeom);
4281 1 : ASSERT_NE(poGeom, nullptr);
4282 1 : poGeom->toCurve()->reversePoints();
4283 1 : char *pszWKT = nullptr;
4284 1 : poGeom->exportToWkt(&pszWKT, wkbVariantIso);
4285 1 : EXPECT_TRUE(pszWKT != nullptr);
4286 1 : if (pszWKT)
4287 : {
4288 1 : EXPECT_STREQ(
4289 : pszWKT, "COMPOUNDCURVE ZM ((3 0 13 2,2 0 12 22),CIRCULARSTRING "
4290 : "ZM (2 0 12 22,1 1 11 21,0 0 10 20))");
4291 : }
4292 1 : CPLFree(pszWKT);
4293 1 : delete poGeom;
4294 : }
4295 : }
4296 :
4297 : // Test OGRGeometryFactory::transformWithOptions()
4298 4 : TEST_F(test_ogr, transformWithOptions)
4299 : {
4300 : // Projected CRS to national geographic CRS (not including poles or antimeridian)
4301 1 : auto [poGeom, err] = OGRGeometryFactory::createFromWkt(
4302 1 : "LINESTRING(700000 6600000, 700001 6600001)");
4303 1 : ASSERT_NE(poGeom, nullptr);
4304 :
4305 1 : OGRSpatialReference oEPSG_2154;
4306 1 : oEPSG_2154.importFromEPSG(2154); // "RGF93 v1 / Lambert-93"
4307 1 : OGRSpatialReference oEPSG_4171;
4308 1 : oEPSG_4171.importFromEPSG(4171); // "RGF93 v1"
4309 1 : oEPSG_4171.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
4310 : auto poCT = std::unique_ptr<OGRCoordinateTransformation>(
4311 1 : OGRCreateCoordinateTransformation(&oEPSG_2154, &oEPSG_4171));
4312 1 : OGRGeometryFactory::TransformWithOptionsCache oCache;
4313 : auto poNewGeom =
4314 : std::unique_ptr<OGRGeometry>(OGRGeometryFactory::transformWithOptions(
4315 1 : poGeom.get(), poCT.get(), nullptr, oCache));
4316 1 : ASSERT_NE(poNewGeom, nullptr);
4317 1 : EXPECT_NEAR(poNewGeom->toLineString()->getX(0), 3, 1e-8);
4318 1 : EXPECT_NEAR(poNewGeom->toLineString()->getY(0), 46.5, 1e-8);
4319 : }
4320 :
4321 : #ifdef HAVE_GEOS
4322 :
4323 : // Test OGRGeometryFactory::transformWithOptions()
4324 4 : TEST_F(test_ogr, transformWithOptions_GEOS)
4325 : {
4326 : // Projected CRS to national geographic CRS including antimeridian
4327 1 : auto [poGeom, err] = OGRGeometryFactory::createFromWkt(
4328 1 : "LINESTRING(657630.64 4984896.17,815261.43 4990738.26)");
4329 1 : ASSERT_NE(poGeom, nullptr);
4330 :
4331 1 : OGRSpatialReference oEPSG_6329;
4332 1 : oEPSG_6329.importFromEPSG(6329); // "NAD83(2011) / UTM zone 60N"
4333 1 : OGRSpatialReference oEPSG_6318;
4334 1 : oEPSG_6318.importFromEPSG(6318); // "NAD83(2011)"
4335 1 : oEPSG_6318.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
4336 : auto poCT = std::unique_ptr<OGRCoordinateTransformation>(
4337 1 : OGRCreateCoordinateTransformation(&oEPSG_6329, &oEPSG_6318));
4338 1 : OGRGeometryFactory::TransformWithOptionsCache oCache;
4339 : auto poNewGeom =
4340 : std::unique_ptr<OGRGeometry>(OGRGeometryFactory::transformWithOptions(
4341 1 : poGeom.get(), poCT.get(), nullptr, oCache));
4342 1 : ASSERT_NE(poNewGeom, nullptr);
4343 1 : EXPECT_EQ(poNewGeom->getGeometryType(), wkbMultiLineString);
4344 1 : if (poNewGeom->getGeometryType() == wkbMultiLineString)
4345 : {
4346 1 : const auto poMLS = poNewGeom->toMultiLineString();
4347 1 : EXPECT_EQ(poMLS->getNumGeometries(), 2);
4348 1 : if (poMLS->getNumGeometries() == 2)
4349 : {
4350 1 : const auto poLS = poMLS->getGeometryRef(0);
4351 1 : EXPECT_EQ(poLS->getNumPoints(), 2);
4352 1 : if (poLS->getNumPoints() == 2)
4353 : {
4354 1 : EXPECT_NEAR(poLS->getX(0), 179, 1e-6);
4355 1 : EXPECT_NEAR(poLS->getY(0), 45, 1e-6);
4356 1 : EXPECT_NEAR(poLS->getX(1), 180, 1e-6);
4357 1 : EXPECT_NEAR(poLS->getY(1), 45.004384301691303, 1e-6);
4358 : }
4359 : }
4360 : }
4361 : }
4362 : #endif
4363 :
4364 : // Test OGRCurvePolygon::addRingDirectly
4365 4 : TEST_F(test_ogr, OGRCurvePolygon_addRingDirectly)
4366 : {
4367 1 : OGRCurvePolygon cp;
4368 : OGRGeometry *ring;
4369 :
4370 : // closed CircularString
4371 1 : OGRGeometryFactory::createFromWkt(
4372 : "CIRCULARSTRING (0 0, 1 1, 2 0, 1 -1, 0 0)", nullptr, &ring);
4373 1 : ASSERT_TRUE(ring);
4374 1 : EXPECT_EQ(cp.addRingDirectly(ring->toCurve()), OGRERR_NONE);
4375 :
4376 : // open CircularString
4377 1 : OGRGeometryFactory::createFromWkt("CIRCULARSTRING (0 0, 1 1, 2 0)", nullptr,
4378 : &ring);
4379 1 : ASSERT_TRUE(ring);
4380 : {
4381 : CPLConfigOptionSetter oSetter("OGR_GEOMETRY_ACCEPT_UNCLOSED_RING", "NO",
4382 1 : false);
4383 1 : ASSERT_EQ(cp.addRingDirectly(ring->toCurve()),
4384 : OGRERR_UNSUPPORTED_GEOMETRY_TYPE);
4385 : }
4386 1 : EXPECT_EQ(cp.addRingDirectly(ring->toCurve()), OGRERR_NONE);
4387 :
4388 : // closed CompoundCurve
4389 1 : OGRGeometryFactory::createFromWkt(
4390 : "COMPOUNDCURVE( CIRCULARSTRING (0 0, 1 1, 2 0), (2 0, 0 0))", nullptr,
4391 : &ring);
4392 1 : ASSERT_TRUE(ring);
4393 1 : EXPECT_EQ(cp.addRingDirectly(ring->toCurve()), OGRERR_NONE);
4394 :
4395 : // closed LineString
4396 1 : OGRGeometryFactory::createFromWkt("LINESTRING (0 0, 1 0, 1 1, 0 1, 0 0)",
4397 : nullptr, &ring);
4398 1 : ASSERT_TRUE(ring);
4399 1 : EXPECT_EQ(cp.addRingDirectly(ring->toCurve()), OGRERR_NONE);
4400 :
4401 : // LinearRing
4402 1 : auto lr = std::make_unique<OGRLinearRing>();
4403 1 : lr->addPoint(0, 0);
4404 1 : lr->addPoint(1, 0);
4405 1 : lr->addPoint(1, 1);
4406 1 : lr->addPoint(0, 1);
4407 1 : lr->addPoint(0, 0);
4408 1 : ASSERT_TRUE(ring);
4409 1 : ASSERT_EQ(cp.addRingDirectly(lr.get()), OGRERR_UNSUPPORTED_GEOMETRY_TYPE);
4410 : }
4411 :
4412 : // Test OGRPolygon::addRingDirectly
4413 4 : TEST_F(test_ogr, OGRPolygon_addRingDirectly)
4414 : {
4415 1 : OGRPolygon p;
4416 : OGRGeometry *ring;
4417 :
4418 : // closed CircularString
4419 1 : OGRGeometryFactory::createFromWkt(
4420 : "CIRCULARSTRING (0 0, 1 1, 2 0, 1 -1, 0 0)", nullptr, &ring);
4421 1 : ASSERT_TRUE(ring);
4422 1 : EXPECT_EQ(p.addRingDirectly(ring->toCurve()),
4423 : OGRERR_UNSUPPORTED_GEOMETRY_TYPE);
4424 1 : delete ring;
4425 :
4426 : // closed LineString
4427 1 : OGRGeometryFactory::createFromWkt("LINESTRING (0 0, 1 0, 1 1, 0 1, 0 0)",
4428 : nullptr, &ring);
4429 1 : ASSERT_TRUE(ring);
4430 1 : EXPECT_EQ(p.addRingDirectly(ring->toCurve()),
4431 : OGRERR_UNSUPPORTED_GEOMETRY_TYPE);
4432 1 : delete ring;
4433 :
4434 : // open LineString
4435 1 : OGRGeometryFactory::createFromWkt("LINESTRING (0 0, 1 0)", nullptr, &ring);
4436 1 : ASSERT_TRUE(ring);
4437 1 : EXPECT_EQ(p.addRingDirectly(ring->toCurve()),
4438 : OGRERR_UNSUPPORTED_GEOMETRY_TYPE);
4439 1 : delete ring;
4440 :
4441 : // LinearRing
4442 1 : auto lr = std::make_unique<OGRLinearRing>();
4443 1 : lr->addPoint(0, 0);
4444 1 : lr->addPoint(1, 0);
4445 1 : lr->addPoint(1, 1);
4446 1 : lr->addPoint(0, 1);
4447 1 : lr->addPoint(0, 0);
4448 1 : ASSERT_EQ(p.addRingDirectly(lr.release()), OGRERR_NONE);
4449 : }
4450 :
4451 4 : TEST_F(test_ogr, OGRFeature_SetGeometry)
4452 : {
4453 1 : OGRFeatureDefn *poFeatureDefn = new OGRFeatureDefn();
4454 1 : poFeatureDefn->Reference();
4455 :
4456 1 : OGRFeature oFeat(poFeatureDefn);
4457 1 : auto [poGeom, err] = OGRGeometryFactory::createFromWkt("POINT (3 7)");
4458 1 : ASSERT_EQ(err, OGRERR_NONE);
4459 :
4460 1 : ASSERT_EQ(oFeat.SetGeometry(std::move(poGeom)), OGRERR_NONE);
4461 1 : EXPECT_EQ(oFeat.GetGeometryRef()->toPoint()->getX(), 3);
4462 1 : EXPECT_EQ(oFeat.GetGeometryRef()->toPoint()->getY(), 7);
4463 :
4464 : // set it again to make sure previous feature geometry is freed
4465 1 : std::tie(poGeom, err) = OGRGeometryFactory::createFromWkt("POINT (2 8)");
4466 1 : ASSERT_EQ(err, OGRERR_NONE);
4467 1 : ASSERT_EQ(oFeat.SetGeometry(std::move(poGeom)), OGRERR_NONE);
4468 1 : EXPECT_EQ(oFeat.GetGeometryRef()->toPoint()->getX(), 2);
4469 1 : EXPECT_EQ(oFeat.GetGeometryRef()->toPoint()->getY(), 8);
4470 :
4471 1 : poFeatureDefn->Release();
4472 : }
4473 :
4474 4 : TEST_F(test_ogr, OGRFeature_SetGeomField)
4475 : {
4476 1 : OGRFeatureDefn *poFeatureDefn = new OGRFeatureDefn();
4477 1 : poFeatureDefn->Reference();
4478 :
4479 1 : OGRGeomFieldDefn oGeomField("second", wkbPoint);
4480 1 : poFeatureDefn->AddGeomFieldDefn(&oGeomField);
4481 :
4482 1 : OGRFeature oFeat(poFeatureDefn);
4483 :
4484 : // failure
4485 : {
4486 1 : auto [poGeom, err] = OGRGeometryFactory::createFromWkt("POINT (3 7)");
4487 1 : ASSERT_EQ(err, OGRERR_NONE);
4488 1 : EXPECT_EQ(oFeat.SetGeomField(13, std::move(poGeom)), OGRERR_FAILURE);
4489 : }
4490 :
4491 : // success
4492 : {
4493 1 : auto [poGeom, err] = OGRGeometryFactory::createFromWkt("POINT (3 7)");
4494 1 : ASSERT_EQ(err, OGRERR_NONE);
4495 1 : EXPECT_EQ(oFeat.SetGeomField(1, std::move(poGeom)), OGRERR_NONE);
4496 : }
4497 :
4498 1 : poFeatureDefn->Release();
4499 : }
4500 :
4501 : } // namespace
|