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