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