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