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