1 // Copyright 2008, Google Inc. All rights reserved.
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are met:
5 //
6 //  1. Redistributions of source code must retain the above copyright notice,
7 //     this list of conditions and the following disclaimer.
8 //  2. Redistributions in binary form must reproduce the above copyright notice,
9 //     this list of conditions and the following disclaimer in the documentation
10 //     and/or other materials provided with the distribution.
11 //  3. Neither the name of Google Inc. nor the names of its contributors may be
12 //     used to endorse or promote products derived from this software without
13 //     specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
16 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
18 // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 // This file contains the unit tests for the internal Attributes class.
27 
28 #include "kml/base/attributes.h"
29 #include <algorithm>
30 #include "boost/scoped_ptr.hpp"
31 #include "gtest/gtest.h"
32 
33 namespace kmlbase {
34 
35 static const char kAttr0[] = "id";
36 static const char kAttr1[] = "fraction";
37 static const char kAttr2[] = "xunits";
38 static const char kNoSuchAttr[] = "no-such-attr";
39 
40 class AttributesTest : public testing::Test {
41  protected:
SetUp()42   virtual void SetUp() {
43     attributes_.reset(new Attributes);
44   }
45   boost::scoped_ptr<Attributes> attributes_;
46 };
47 
TEST_F(AttributesTest,TestCreate)48 TEST_F(AttributesTest, TestCreate) {
49   // A list of name-value pairs as expat might produce.
50   const char* atts[] = {
51     "name",
52     "Placemark",
53     "type",
54     "kml:PlacemarkType",
55     "substitutionGroup",
56     "kml:AbstractFeatureGroup",
57     NULL
58   };
59   // Call the method under test.
60   attributes_.reset(Attributes::Create(atts));
61   ASSERT_TRUE(attributes_.get());
62   string got_val;
63   ASSERT_TRUE(attributes_->GetValue(atts[0], &got_val));
64   ASSERT_EQ(string(atts[1]), got_val);
65   ASSERT_TRUE(attributes_->GetValue(atts[2], &got_val));
66   ASSERT_EQ(string(atts[3]), got_val);
67   ASSERT_TRUE(attributes_->GetValue(atts[4], &got_val));
68   ASSERT_EQ(string(atts[5]), got_val);
69   ASSERT_FALSE(attributes_->GetValue("no-such-attr", &got_val));
70   // Verify null output is well behaved.
71   string* p = NULL;
72   ASSERT_TRUE(attributes_->GetValue(atts[0], p));
73   ASSERT_FALSE(attributes_->GetValue("no-such_attr", p));
74 }
75 
TEST_F(AttributesTest,TestCreateOdd)76 TEST_F(AttributesTest, TestCreateOdd) {
77   // A bad atts list.
78   const char* atts[] = { "a0", "a1", "b0", 0 };
79   // Call the method under test.
80   attributes_.reset(Attributes::Create(atts));
81   ASSERT_TRUE(attributes_.get());
82   string got_val;
83   ASSERT_TRUE(attributes_->GetValue(atts[0], &got_val));
84   ASSERT_EQ(string(atts[1]), got_val);
85   ASSERT_FALSE(attributes_->GetValue(atts[2], &got_val));
86 }
87 
TEST_F(AttributesTest,TestGetStringDesctructive)88 TEST_F(AttributesTest, TestGetStringDesctructive) {
89   const char* atts[] = { "id", "placemark-123", "unknown", "somevalue", 0 };
90   attributes_.reset(Attributes::Create(atts));
91   string got_val;
92   ASSERT_TRUE(attributes_->GetValue(atts[0], &got_val));
93   string got_val_again;
94   const string kAtt0(atts[0]);
95   ASSERT_TRUE(attributes_->CutValue(kAtt0, &got_val_again));
96   ASSERT_FALSE(attributes_->GetValue(atts[0], &got_val_again));
97 }
98 
TEST_F(AttributesTest,TestSetGetString)99 TEST_F(AttributesTest, TestSetGetString) {
100   const string kVal0 = "val0";
101   const string kVal1 = "val1";
102   attributes_->SetValue(kAttr0, kVal0);
103   attributes_->SetValue(kAttr1, kVal1);
104   string got_val;
105   ASSERT_TRUE(attributes_->GetValue(kAttr0, &got_val));
106   ASSERT_EQ(kVal0, got_val);
107   ASSERT_TRUE(attributes_->GetValue(kAttr1, &got_val));
108   ASSERT_EQ(kVal1, got_val);
109   ASSERT_TRUE(false == attributes_->GetValue(kNoSuchAttr, &got_val));
110   ASSERT_EQ(kVal1, got_val);
111 }
112 
TEST_F(AttributesTest,TestSetGetDouble)113 TEST_F(AttributesTest, TestSetGetDouble) {
114   const double kVal0 = 123.456;
115   const double kVal1 = 987.654321;
116   attributes_->SetValue(kAttr0, kVal0);
117   attributes_->SetValue(kAttr1, kVal1);
118   double got_val;
119   ASSERT_TRUE(attributes_->GetValue(kAttr0, &got_val));
120   ASSERT_EQ(kVal0, got_val);
121   ASSERT_TRUE(attributes_->GetValue(kAttr1, &got_val));
122   ASSERT_EQ(kVal1, got_val);
123   ASSERT_TRUE(false == attributes_->GetValue(kNoSuchAttr, &got_val));
124   ASSERT_EQ(kVal1, got_val);
125 }
126 
TEST_F(AttributesTest,TestSetGetInt)127 TEST_F(AttributesTest, TestSetGetInt) {
128   const int kVal0 = 123;
129   const int kVal1 = -987;
130   attributes_->SetValue(kAttr0, kVal0);
131   attributes_->SetValue(kAttr1, kVal1);
132   int got_val;
133   ASSERT_TRUE(attributes_->GetValue(kAttr0, &got_val));
134   ASSERT_EQ(kVal0, got_val);
135   ASSERT_TRUE(attributes_->GetValue(kAttr1, &got_val));
136   ASSERT_EQ(kVal1, got_val);
137   ASSERT_TRUE(false == attributes_->GetValue(kNoSuchAttr, &got_val));
138   ASSERT_EQ(kVal1, got_val);
139 }
140 
TEST_F(AttributesTest,TestClone)141 TEST_F(AttributesTest, TestClone) {
142   const string kVal0 = "val0";
143   const double kVal1 = 123.456789;
144   attributes_->SetValue(kAttr0, kVal0);
145   attributes_->SetValue(kAttr1, kVal1);
146   Attributes* clone = attributes_->Clone();
147   string got_string;
148   EXPECT_TRUE(clone->GetValue(kAttr0, &got_string));
149   EXPECT_EQ(kVal0, got_string);
150 
151   double got_double;
152   EXPECT_TRUE(clone->GetValue(kAttr1, &got_double));
153   EXPECT_EQ(kVal1, got_double);
154 
155   delete clone;
156   clone = NULL;
157 }
158 
TEST_F(AttributesTest,TestMerge)159 TEST_F(AttributesTest, TestMerge) {
160   const string kVal0 = "val0";
161   const double kVal1a = 123.456789;
162   const double kVal1b = 78.90123;
163   const string kVal2 = "fraction";
164   attributes_->SetValue(kAttr0, kVal0);
165   attributes_->SetValue(kAttr1, kVal1a);
166   Attributes attributes;
167   attributes.SetValue(kAttr1, kVal1b);
168   attributes.SetValue(kAttr2, kVal2);
169   attributes_->MergeAttributes(attributes);
170   string got_string;
171   ASSERT_TRUE(attributes_->GetValue(kAttr0, &got_string));
172   ASSERT_EQ(kVal0, got_string);
173   double got_double;
174   ASSERT_TRUE(attributes_->GetValue(kAttr1, &got_double));
175   ASSERT_EQ(kVal1b, got_double);
176   ASSERT_TRUE(attributes_->GetValue(kAttr2, &got_string));
177   ASSERT_EQ(kVal2, got_string);
178 }
179 
TEST_F(AttributesTest,TestSerialize)180 TEST_F(AttributesTest, TestSerialize) {
181   const string kVal0 = "val0";
182   const double kVal1 = 123.456789;
183   attributes_->SetValue(kAttr0, kVal0);
184   attributes_->SetValue(kAttr1, kVal1);
185   string serialized;
186   attributes_->Serialize(&serialized);
187   const string expecting = " " + string(kAttr1) + "=\"123.456789\" "
188     + string(kAttr0) + "=\"" + kVal0 + "\"";
189   ASSERT_EQ(expecting, serialized);
190 }
191 
TEST_F(AttributesTest,TestSplit)192 TEST_F(AttributesTest, TestSplit) {
193   // <kml xmlns="http://www.opengis.net/kml/2.2"
194   //      xmlns:ex="http://vendor.com/kml/2.2ext">
195   // Expat turns the above XML into this:
196   const char* atts[] = {
197     "xmlns", "http://www.opengis.net/kml/2.2",
198     "xmlns:ex", "http://vendor.com/kml/2.2ext",
199     NULL
200   };
201   attributes_.reset(Attributes::Create(atts));
202   ASSERT_TRUE(attributes_.get());
203   // This is the method under test.
204   boost::scoped_ptr<Attributes> xmlns_(attributes_->SplitByPrefix("xmlns"));
205   ASSERT_TRUE(xmlns_.get());
206   ASSERT_EQ(static_cast<size_t>(1), xmlns_->GetSize());
207   string val;
208   ASSERT_TRUE(xmlns_->GetValue("ex", &val));
209   ASSERT_EQ(string(atts[3]), val);
210 }
211 
TEST_F(AttributesTest,TestMatchNoDefault)212 TEST_F(AttributesTest, TestMatchNoDefault) {
213   const char* atts[] = {
214     "xmlns:kml", "http://www.opengis.net/kml/2.2",
215     "xmlns:ex", "http://vendor.com/kml/2.2ext",
216     NULL
217   };
218   attributes_.reset(Attributes::Create(atts));
219   ASSERT_TRUE(attributes_.get());
220   // This is the method under test.
221   boost::scoped_ptr<Attributes> xmlns_(attributes_->SplitByPrefix("xmlns"));
222   ASSERT_TRUE(xmlns_.get());
223   ASSERT_EQ(static_cast<size_t>(2), xmlns_->GetSize());
224   string val;
225   ASSERT_TRUE(xmlns_->GetValue("kml", &val));
226   ASSERT_EQ(string(atts[1]), val);
227   ASSERT_TRUE(xmlns_->GetValue("ex", &val));
228   ASSERT_EQ(string(atts[3]), val);
229 }
230 
TEST_F(AttributesTest,TestGetAttrNames)231 TEST_F(AttributesTest, TestGetAttrNames) {
232   // A list of name-value pairs as expat might produce.
233   const char* atts[] = {
234     "name",
235     "Placemark",
236     "type",
237     "kml:PlacemarkType",
238     "substitutionGroup",
239     "kml:AbstractFeatureGroup",
240     NULL
241   };
242   attributes_.reset(Attributes::Create(atts));
243   std::vector<string> attr_names;
244   attributes_->GetAttrNames(&attr_names);
245   ASSERT_EQ(static_cast<size_t>(3), attr_names.size());
246   ASSERT_FALSE(attr_names.end() ==
247                std::find(attr_names.begin(), attr_names.end(), "name"));
248   ASSERT_FALSE(attr_names.end() ==
249                std::find(attr_names.begin(), attr_names.end(), "type"));
250   ASSERT_FALSE(attr_names.end() == std::find(attr_names.begin(),
251                                              attr_names.end(),
252                                              "substitutionGroup"));
253 }
254 
TEST_F(AttributesTest,TestIterator)255 TEST_F(AttributesTest, TestIterator) {
256   // NOTE: the keys are in map order.
257   const char* atts[] = { "a", "z", "b", "y", "c", "x", NULL };
258   attributes_.reset(Attributes::Create(atts));
259   ASSERT_TRUE(attributes_.get());
260   StringMapIterator iter = attributes_->CreateIterator();
261   ASSERT_EQ(string(atts[0]), iter.Data().first);
262   ASSERT_EQ(string(atts[1]), iter.Data().second);
263   iter.Advance();
264   ASSERT_FALSE(iter.AtEnd());
265   ASSERT_EQ(string(atts[2]), iter.Data().first);
266   ASSERT_EQ(string(atts[3]), iter.Data().second);
267   iter.Advance();
268   ASSERT_FALSE(iter.AtEnd());
269   ASSERT_EQ(string(atts[4]), iter.Data().first);
270   ASSERT_EQ(string(atts[5]), iter.Data().second);
271   iter.Advance();
272   ASSERT_TRUE(iter.AtEnd());
273 }
274 
275 }  // end namespace kmlbase
276