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