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