1 /******************************************************************************
2 * Copyright (c) 2011, Michael P. Gerlek (mpg@flaxen.com)
3 *
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following
8 * conditions are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided
15 * with the distribution.
16 * * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
17 * names of its contributors may be used to endorse or promote
18 * products derived from this software without specific prior
19 * written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
32 * OF SUCH DAMAGE.
33 ****************************************************************************/
34
35 #include <pdal/pdal_test_main.hpp>
36
37 #include <pdal/Metadata.hpp>
38 #include <pdal/SpatialReference.hpp>
39 #include <pdal/PDALUtils.hpp>
40
41 using namespace pdal;
42
TEST(MetadataTest,assign)43 TEST(MetadataTest, assign)
44 {
45 MetadataNode m1("Test");
46 MetadataNode m2 = m1;
47 EXPECT_EQ(m1.name(), "Test");
48 EXPECT_EQ(m2.name(), "Test");
49 }
50
TEST(MetadataTest,test_construction)51 TEST(MetadataTest, test_construction)
52 {
53 uint32_t u32(32u);
54 int32_t i32(-32);
55 uint64_t u64(64u);
56 int64_t i64(-64);
57 int8_t i8(-8);
58 uint8_t u8(8);
59 int16_t i16(-16);
60 uint16_t u16(16);
61
62 {
63 std::vector<uint8_t> v;
64 for (uint8_t i = 0; i < 100; i++)
65 v.push_back(i);
66
67 MetadataNode m;
68 MetadataNode m2 = m.addEncoded("name", v.data(), v.size());
69 EXPECT_EQ(m2.type(), "base64Binary");
70
71 std::string base64("AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiYw==");
72 EXPECT_EQ(m2.value(), base64);
73 }
74
75
76 {
77 MetadataNode m;
78 MetadataNode m2 = m.add<int8_t>("name", i8);
79 EXPECT_EQ(m2.value(), "-8");
80 EXPECT_EQ(m2.type(), "integer");
81 }
82
83 {
84 MetadataNode m;
85 MetadataNode m2 = m.add("name", i16);
86 EXPECT_EQ(m2.value(), "-16");
87 EXPECT_EQ(m2.type(), "integer");
88 }
89
90 {
91 MetadataNode m;
92 MetadataNode m2 = m.add("name", i32);
93 EXPECT_EQ(m2.value(), "-32");
94 EXPECT_EQ(m2.type(), "integer");
95 }
96
97 {
98 MetadataNode m;
99 MetadataNode m2 = m.add("name", i64);
100 EXPECT_EQ(m2.value(), "-64");
101 EXPECT_EQ(m2.type(), "integer");
102 }
103
104 {
105 MetadataNode m;
106 MetadataNode m2 = m.add("name", i64);
107 EXPECT_EQ(m2.value(), "-64");
108 EXPECT_EQ(m2.type(), "integer");
109 }
110
111 {
112 MetadataNode m;
113 MetadataNode m2 = m.add<uint8_t>("name", u8);
114 EXPECT_EQ(m2.value(), "8");
115 EXPECT_EQ(m2.type(), "nonNegativeInteger");
116 }
117
118 {
119 MetadataNode m;
120 MetadataNode m2 = m.add("name", u16);
121 EXPECT_EQ(m2.value(), "16");
122 EXPECT_EQ(m2.type(), "nonNegativeInteger");
123 }
124
125 {
126 MetadataNode m;
127 MetadataNode m2 = m.add("name", u32);
128 EXPECT_EQ(m2.value(), "32");
129 EXPECT_EQ(m2.type(), "nonNegativeInteger");
130 }
131
132 {
133 MetadataNode m;
134 MetadataNode m2 = m.add("name", u64);
135 EXPECT_EQ(m2.value(), "64");
136 EXPECT_EQ(m2.type(), "nonNegativeInteger");
137 }
138 }
139
TEST(MetadataTest,typed_value)140 TEST(MetadataTest, typed_value)
141 {
142 MetadataNode m;
143 MetadataNode m2 = m.add("name", 127);
144
145 EXPECT_EQ(127, m2.value<int>());
146
147 double d = 123.45;
148 MetadataNode m3 = m.addEncoded("name", (unsigned char *)&d, sizeof(d));
149 EXPECT_DOUBLE_EQ(d, m3.value<double>());
150 EXPECT_EQ("zczMzMzcXkA=", m3.value());
151
152 MetadataNode m4 = m.add("name", "65539");
153 EXPECT_EQ(65539u, m4.value<unsigned>());
154
155 auto redir = Utils::redirect(std::cerr);
156 EXPECT_EQ(0u, m4.value<unsigned short>());
157 Utils::restore(std::cerr, redir);
158 }
159
160
TEST(MetadataTest,test_construction_with_srs)161 TEST(MetadataTest, test_construction_with_srs)
162 {
163 MetadataNode m;
164 SpatialReference ref("EPSG:4326");
165 MetadataNode m2 = m.add("spatialreference", ref);
166 EXPECT_EQ(m2.type(), "spatialreference");
167
168 //SpatialReference ref2 = m.getValue<SpatialReference>();
169 // std::string ref_text("GEOGCS[\"WGS 84\","
170 // DATUM[\"WGS_1984\","
171 // SPHEROID[\"WGS 84\",6378137,298.257223563,
172 // AUTHORITY[\"EPSG\",\"7030\"]],
173 // AUTHORITY[\"EPSG\",\"6326\"]],
174 // PRIMEM[\"Greenwich\",0,
175 // AUTHORITY[\"EPSG\",\"8901\"]],
176 // UNIT[\"degree\",0.0174532925199433,
177 // AUTHORITY[\"EPSG\",\"9122\"]],
178 // AUTHORITY[\"EPSG\",\"4326\"]]");
179
180 // std::cout << m.getValue<SpatialReference>();
181 }
182
183
TEST(MetadataTest,test_metadata_copy)184 TEST(MetadataTest, test_metadata_copy)
185 {
186 MetadataNode m;
187 MetadataNode m2 = m.add("val", 2u);
188 uint32_t t;
189 Utils::fromString(m2.value(), t);
190 EXPECT_EQ(t, 2u);
191 }
192
TEST(MetadataTest,test_metadata_set)193 TEST(MetadataTest, test_metadata_set)
194 {
195 MetadataNode m;
196
197 MetadataNode m1 = m.add("m1", 1u);
198 MetadataNode m2 = m.add("m2", 2);
199 MetadataNode m1prime = m.add("m1prime", "Some other metadata");
200
201 MetadataNode mm(m);
202
203 std::vector<MetadataNode> ms = mm.children();
204 EXPECT_EQ(ms.size(), 3u);
205
206 class Predicate
207 {
208 public:
209 Predicate(const std::string& name) : m_name(name)
210 {}
211
212 bool operator()(MetadataNode m)
213 { return m.name() == m_name; }
214 private:
215 std::string m_name;
216 };
217
218 MetadataNode node = mm.findChild(Predicate("m1"));
219 EXPECT_EQ(node.value(), "1");
220 node = mm.find(Predicate("m2"));
221 EXPECT_EQ(node.value(), "2");
222 node = mm.find(Predicate("m1prime"));
223 EXPECT_EQ(node.value(), "Some other metadata");
224 node = mm.find(Predicate("foo"));
225 EXPECT_EQ(node.value(), "");
226 }
227
TEST(MetadataTest,test_vlr_metadata)228 TEST(MetadataTest, test_vlr_metadata)
229 {
230 MetadataNode m;
231
232 MetadataNode bogusvlr = m.add("vlr1", "VLR1VALUE", "VLR1DESC");
233 MetadataNode vlr = m.add("vlr2", "VLR2VALUE", "VLR2DESC");
234 std::string recordId("MYRECOREDID");
235 std::string userId("MYUSERID");
236 vlr.add("record_id", recordId);
237 vlr.add("user_id", userId);
238 // Find a node whose name starts with vlr and that has child nodes
239 // with the name and recordId we're looking for.
240 auto pred = [recordId,userId](MetadataNode n)
241 {
242 auto recPred = [recordId](MetadataNode n)
243 {
244 return n.name() == "record_id" &&
245 n.value() == recordId;
246 };
247 auto userPred = [userId](MetadataNode n)
248 {
249 return n.name() == "user_id" &&
250 n.value() == userId;
251 };
252 return (Utils::startsWith(n.name(), "vlr") &&
253 !n.findChild(recPred).empty() &&
254 !n.findChild(userPred).empty());
255 };
256
257 MetadataNode found = m.find(pred);
258 EXPECT_EQ(found.name(), "vlr2");
259 EXPECT_EQ(found.value(), "VLR2VALUE");
260 EXPECT_EQ(found.description(), "VLR2DESC");
261 }
262
TEST(MetadataTest,find_child_string)263 TEST(MetadataTest, find_child_string)
264 {
265 MetadataNode top;
266 MetadataNode m = top.add("level1");
267 MetadataNode l21 = m.add("level2");
268 MetadataNode l22 = m.add("level2");
269 l21.add("210", "210");
270 l22.add("220", "220");
271
272 MetadataNode n = top.findChild("level1:level2:210");
273 EXPECT_EQ(n.value(), "210");
274 n = top.findChild("level1:level2:220");
275 EXPECT_EQ(n.value(), "220");
276 }
277
278 // Make sure that we handle double-precision values to 10 decimal places.
TEST(MetadataTest,test_float)279 TEST(MetadataTest, test_float)
280 {
281 MetadataNode n("top");
282 MetadataNode n2 = n.add("test", 1e-20);
283 EXPECT_DOUBLE_EQ(n2.value<double>(), 1e-20);
284
285 n2 = n.add("test2", 1.12345678);
286 EXPECT_DOUBLE_EQ(n2.value<double>(), 1.12345678);
287 }
288
289 // Test that pointers traverse metadata.
TEST(MetadataTest,pointer)290 TEST(MetadataTest, pointer)
291 {
292 class foo
293 {};
294
295 foo f;
296
297 MetadataNode n("top");
298 MetadataNode n2 = n.add("test", &f);
299
300 std::istringstream iss;
301 foo *f2 = n2.value<foo *>();
302 EXPECT_EQ(f2, &f);
303 }
304
305 // Test the output of infinity/nan
TEST(MetadataTest,infnan)306 TEST(MetadataTest, infnan)
307 {
308 double d = std::numeric_limits<double>::quiet_NaN();
309 MetadataNode n("top");
310 MetadataNode n2 = n.add("value", d);
311 EXPECT_EQ(n2.jsonValue(), "\"NaN\"");
312
313 d = std::numeric_limits<double>::infinity();
314 n2 = n.add("value2", d);
315 EXPECT_EQ(n2.jsonValue(), "\"Infinity\"");
316
317 d = -d;
318 n2 = n.add("value2", d);
319 EXPECT_EQ(n2.jsonValue(), "\"-Infinity\"");
320 }
321
322 // Test the addOrUpdate functions.
TEST(MetadataTest,update)323 TEST(MetadataTest, update)
324 {
325 MetadataNode root("root");
326
327 EXPECT_FALSE(root.hasChildren());
328 root.addOrUpdate("test", 21);
329 EXPECT_EQ(1U, root.children().size());
330 root.addOrUpdate("test", 22, "description");
331 EXPECT_EQ(1U, root.children().size());
332 MetadataNodeList l = root.children();
333 MetadataNode n = l.front();
334 EXPECT_EQ("test", n.name());
335 EXPECT_EQ("description", n.description());
336 EXPECT_EQ(22, n.value<int>());
337
338 MetadataNode root2("root2");
339 MetadataNode child("child");
340 child.add("subchild1", 1);
341 child.add("subchild2", 2);
342 root2.add(child);
343
344 MetadataNode child2("child");
345 child2.add("subchild3", 3);
346 child2.add("subchild4", 4);
347 child2.add("subchild5", 5);
348 root2.addOrUpdate(child2);
349
350 l = root2.children();
351 EXPECT_EQ(l.size(), 1U);
352 MetadataNode c = l.front();
353 l = c.children();
354 EXPECT_EQ(l.size(), 3U);
355 EXPECT_EQ(l[0].value<int>(), 3);
356 EXPECT_EQ(l[1].value<int>(), 4);
357 EXPECT_EQ(l[2].value<int>(), 5);
358
359 root2.add(c);
360 EXPECT_THROW(root2.addOrUpdate(c), pdal_error);
361 }
362