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 Clone() function.
27
28 #include "kml/engine/clone.h"
29 #include "kml/dom.h"
30 #include "gtest/gtest.h"
31
32 using kmlbase::Vec3;
33 using kmldom::CoordinatesPtr;
34 using kmldom::ElementPtr;
35 using kmldom::FolderPtr;
36 using kmldom::GroundOverlayPtr;
37 using kmldom::IconStylePtr;
38 using kmldom::IconStyleIconPtr;
39 using kmldom::KmlFactory;
40 using kmldom::PlacemarkPtr;
41 using kmldom::PointPtr;
42 using kmldom::SnippetPtr;
43
44 namespace kmlengine {
45
46 class CloneTest : public testing::Test {
47 protected:
SetUp()48 virtual void SetUp() {
49 KmlFactory* factory = KmlFactory::GetFactory();
50 coordinates_ = factory->CreateCoordinates();
51 folder_ = factory->CreateFolder();
52 groundoverlay_ = factory->CreateGroundOverlay();
53 placemark_ = factory->CreatePlacemark();
54 point_ = factory->CreatePoint();
55 snippet_ = factory->CreateSnippet();
56 }
57
58 CoordinatesPtr coordinates_;
59 FolderPtr folder_;
60 GroundOverlayPtr groundoverlay_;
61 PlacemarkPtr placemark_;
62 PointPtr point_;
63 SnippetPtr snippet_;
64 };
65
66 // Verify that a NULL element is handled properly.
TEST_F(CloneTest,TestNullClone)67 TEST_F(CloneTest, TestNullClone) {
68 ElementPtr clone = Clone(NULL);
69 ASSERT_FALSE(clone);
70 }
71
72 // Verify that a empty complex element is cloned properly.
TEST_F(CloneTest,TestEmptyClone)73 TEST_F(CloneTest, TestEmptyClone) {
74 ElementPtr clone = Clone(placemark_);
75 ASSERT_EQ(clone->Type(), placemark_->Type());
76 }
77
78 // Verify that a complex element with some fields clones properly.
TEST_F(CloneTest,TestCloneFields)79 TEST_F(CloneTest, TestCloneFields) {
80 const string kName("clone my name");
81 const string kId("clone-my-id");
82 const bool kVisibility = false;
83
84 // Set the fields.
85 placemark_->set_name(kName);
86 placemark_->set_id(kId);
87 placemark_->set_visibility(kVisibility);
88
89 // Clone it.
90 ElementPtr clone = Clone(placemark_);
91
92 // Verify all values were set in the clone.
93 ASSERT_EQ(clone->Type(), placemark_->Type());
94 PlacemarkPtr cloned_placemark = AsPlacemark(clone);
95 ASSERT_TRUE(cloned_placemark->has_id());
96 ASSERT_EQ(kId, cloned_placemark->get_id());
97 ASSERT_TRUE(cloned_placemark->has_name());
98 ASSERT_EQ(kName, cloned_placemark->get_name());
99 ASSERT_TRUE(cloned_placemark->has_visibility());
100 ASSERT_EQ(kVisibility, cloned_placemark->get_visibility());
101 }
102
103 // Verify that a complex element with both some fields and complex children
104 // clones properly.
TEST_F(CloneTest,TestCloneChildren)105 TEST_F(CloneTest, TestCloneChildren) {
106 const string kDescription("clone my description");
107 const string kId("clone-my-id");
108 const bool kOpen = false;
109
110 // Set some fields.
111 folder_->set_description(kDescription);
112 folder_->set_id(kId);
113 folder_->set_open(kOpen);
114 folder_->add_feature(placemark_);
115
116 // Clone it.
117 ElementPtr clone = Clone(folder_);
118
119 // Verify all values were set in the clone.
120 ASSERT_EQ(clone->Type(), folder_->Type());
121 FolderPtr cloned_folder = AsFolder(clone);
122 ASSERT_TRUE(cloned_folder->has_id());
123 ASSERT_EQ(kId, cloned_folder->get_id());
124 ASSERT_FALSE(cloned_folder->has_name());
125 ASSERT_TRUE(cloned_folder->has_description());
126 ASSERT_EQ(kDescription, cloned_folder->get_description());
127 ASSERT_FALSE(cloned_folder->has_visibility());
128 ASSERT_TRUE(cloned_folder->has_open());
129 ASSERT_EQ(kOpen, cloned_folder->get_open());
130 ASSERT_EQ(static_cast<size_t>(1),
131 cloned_folder->get_feature_array_size());
132 ASSERT_EQ(placemark_->Type(),
133 cloned_folder->get_feature_array_at(0)->Type());
134 }
135
136 // Verify that an element with an array of complex children and fields
137 // clones properly.
TEST_F(CloneTest,TestCloneArray)138 TEST_F(CloneTest, TestCloneArray) {
139 // <Folder><Placemark><Point/><Placemark/><GroundOverlay/></Folder>
140 placemark_->set_geometry(point_);
141 folder_->add_feature(placemark_);
142 folder_->add_feature(groundoverlay_);
143
144 // Clone the Folder.
145 ElementPtr clone = Clone(folder_);
146
147 // Verify the contents of the Feature array child in the Folder.
148 FolderPtr cloned_folder = AsFolder(clone);
149 ASSERT_EQ(static_cast<size_t>(2),
150 cloned_folder->get_feature_array_size());
151 ASSERT_EQ(placemark_->Type(),
152 cloned_folder->get_feature_array_at(0)->Type());
153 ASSERT_EQ(groundoverlay_->Type(),
154 cloned_folder->get_feature_array_at(1)->Type());
155
156 // Verify the Placemark has a Point Geometry.
157 PlacemarkPtr cloned_placemark =
158 AsPlacemark(cloned_folder->get_feature_array_at(0));
159 ASSERT_TRUE(cloned_placemark->has_geometry());
160 ASSERT_EQ(point_->Type(),
161 cloned_placemark->get_geometry()->Type());
162 }
163
164 // Verify that <Point>-style <coordinates> is cloned properly.
TEST_F(CloneTest,TestClonePointCoordinates)165 TEST_F(CloneTest, TestClonePointCoordinates) {
166 // Make a point.
167 const double kLat(38.38);
168 const double kLon(-122.122);
169 const double kAlt(42.42);
170 coordinates_->add_latlngalt(kLat, kLon, kAlt);
171
172 // Clone <coordinates>
173 ElementPtr clone = Clone(coordinates_);
174
175 // Verify that a new <coordinates> was created and has the expected content.
176 CoordinatesPtr coordinates_clone = AsCoordinates(clone);
177 ASSERT_TRUE(coordinates_clone);
178 ASSERT_EQ(static_cast<size_t>(1),
179 coordinates_clone->get_coordinates_array_size());
180 Vec3 vec3 = coordinates_clone->get_coordinates_array_at(0);
181 ASSERT_DOUBLE_EQ(kLat, vec3.get_latitude());
182 ASSERT_DOUBLE_EQ(kLon, vec3.get_longitude());
183 ASSERT_DOUBLE_EQ(kAlt, vec3.get_altitude());
184 }
185
186 // Verify that LineString/LinearRing-style <coordinates> is cloned properly.
TEST_F(CloneTest,TestCloneLineCoordinates)187 TEST_F(CloneTest, TestCloneLineCoordinates) {
188 // Create a <coordinates> as might be found in <LineString>/<LinearRing>.
189 const size_t kNumPoints(1001);
190 size_t i;
191 for (i = 0; i < kNumPoints; ++i) {
192 coordinates_->add_latlngalt(static_cast<double>(i % 90),
193 static_cast<double>(i % 180),
194 static_cast<double>(i));
195 }
196
197 // Clone the <coordinates>
198 ElementPtr element = Clone(coordinates_);
199
200 // Verify all the points came over okay.
201 CoordinatesPtr cloned_coordinates = AsCoordinates(element);
202 ASSERT_TRUE(cloned_coordinates);
203 ASSERT_EQ(static_cast<size_t>(kNumPoints),
204 cloned_coordinates->get_coordinates_array_size());
205 for (i = 0; i < kNumPoints; ++i) {
206 Vec3 vec3 = cloned_coordinates->get_coordinates_array_at(i);
207 ASSERT_EQ(static_cast<double>(i % 90), vec3.get_latitude());
208 ASSERT_EQ(static_cast<double>(i % 180), vec3.get_longitude());
209 ASSERT_EQ(static_cast<double>(i), vec3.get_altitude());
210 }
211 }
212
213 // Verify that <Snippet> is cloned properly.
TEST_F(CloneTest,TestCloneSnippet)214 TEST_F(CloneTest, TestCloneSnippet) {
215 // Clone an empty/default Snippet.
216 ElementPtr element = Clone(snippet_);
217 SnippetPtr cloned_snippet = AsSnippet(element);
218 ASSERT_TRUE(cloned_snippet);
219 ASSERT_EQ(snippet_->get_maxlines(),
220 cloned_snippet->get_maxlines());
221 ASSERT_EQ(snippet_->get_text(), cloned_snippet->get_text());
222
223 const string kText("some snippet text");
224 snippet_->set_text(kText);
225 cloned_snippet = AsSnippet(Clone(snippet_));
226 ASSERT_EQ(kText, cloned_snippet->get_text());
227 }
228
229 // <IconStyle>'s <Icon> uses has_icon(), etc but is Type_IconStyleIcon.
TEST_F(CloneTest,TestCloneIconStyle)230 TEST_F(CloneTest, TestCloneIconStyle) {
231 IconStyleIconPtr icon = KmlFactory::GetFactory()->CreateIconStyleIcon();
232 const string kImage("icon.png");
233 icon->set_href(kImage);
234 IconStylePtr iconstyle = KmlFactory::GetFactory()->CreateIconStyle();
235 iconstyle->set_icon(icon);
236 ASSERT_TRUE(iconstyle->has_icon());
237 ASSERT_EQ(kmldom::Type_IconStyleIcon, iconstyle->get_icon()->Type());
238
239 IconStylePtr clone = AsIconStyle(Clone(iconstyle));
240 ASSERT_TRUE(clone);
241 ASSERT_EQ(kmldom::Type_IconStyle, clone->Type());
242 ASSERT_TRUE(clone->has_icon());
243 ASSERT_TRUE(clone->get_icon()->has_href());
244 ASSERT_EQ(kmldom::Type_IconStyleIcon, clone->get_icon()->Type());
245 ASSERT_EQ(kImage, clone->get_icon()->get_href());
246 }
247
TEST_F(CloneTest,TestCloneWithMisplacedChild)248 TEST_F(CloneTest, TestCloneWithMisplacedChild) {
249 kmldom::IconPtr icon =
250 kmldom::AsIcon(kmldom::Parse("<Icon><x>64</x></Icon>", NULL));
251 ASSERT_TRUE(icon);
252 ASSERT_EQ(static_cast<size_t>(1), icon->get_misplaced_elements_array_size());
253 ASSERT_EQ(static_cast<size_t>(0), icon->get_unknown_elements_array_size());
254 kmldom::IconPtr clone = kmldom::AsIcon(Clone(icon));
255 ASSERT_TRUE(clone);
256 ASSERT_EQ(static_cast<size_t>(1), clone->get_misplaced_elements_array_size());
257 ASSERT_EQ(static_cast<size_t>(0), clone->get_unknown_elements_array_size());
258 ASSERT_FALSE(kmldom::SerializePretty(clone).empty());
259 }
260
TEST_F(CloneTest,TestCloneWithFullyUnknownChild)261 TEST_F(CloneTest, TestCloneWithFullyUnknownChild) {
262 // This originally appeared as IconStyle Icon's child, but the bug is
263 // manifested in cloning any element with a fully unknown child.
264 kmldom::IconPtr icon =
265 kmldom::AsIcon(kmldom::Parse("<Icon><w>64</w></Icon>", NULL));
266 ASSERT_TRUE(icon);
267 ASSERT_EQ(static_cast<size_t>(0), icon->get_misplaced_elements_array_size());
268 ASSERT_EQ(static_cast<size_t>(1), icon->get_unknown_elements_array_size());
269 kmldom::IconPtr clone = kmldom::AsIcon(Clone(icon));
270 ASSERT_TRUE(clone);
271 ASSERT_EQ(static_cast<size_t>(0), clone->get_misplaced_elements_array_size());
272 ASSERT_EQ(static_cast<size_t>(1), clone->get_unknown_elements_array_size());
273 ASSERT_FALSE(kmldom::SerializePretty(clone).empty());
274 }
275
276 } // end namespace kmlengine
277