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 location utility functions.
27
28 #include "kml/engine/location_util.h"
29 #include "kml/base/file.h"
30 #include "kml/dom.h"
31 #include "kml/engine/bbox.h"
32 #include "kml/engine/kml_file.h"
33 #include "gtest/gtest.h"
34
35 using kmlbase::File;
36 using kmldom::CoordinatesPtr;
37 using kmldom::KmlFactory;
38 using kmldom::LatLonBoxPtr;
39 using kmldom::LatLonAltBoxPtr;
40 using kmldom::LinearRingPtr;
41 using kmldom::LineStringPtr;
42 using kmldom::LocationPtr;
43 using kmldom::ModelPtr;
44 using kmldom::MultiGeometryPtr;
45 using kmldom::PhotoOverlayPtr;
46 using kmldom::PlacemarkPtr;
47 using kmldom::PointPtr;
48 using kmldom::PolygonPtr;
49
50 // The following define is a convenience for testing inside Google.
51 #ifdef GOOGLE_INTERNAL
52 #include "kml/base/google_internal_test.h"
53 #endif
54
55 #ifndef DATADIR
56 #error *** DATADIR must be defined! ***
57 #endif
58
59 namespace kmlengine {
60
61 // Avoid linking in kmlconvenience...
CreatePointCoordinates(double lat,double lon)62 static PointPtr CreatePointCoordinates(double lat, double lon) {
63 KmlFactory* kml_factory = KmlFactory::GetFactory();
64 PointPtr point = kml_factory->CreatePoint();
65 CoordinatesPtr coordinates = KmlFactory::GetFactory()->CreateCoordinates();
66 coordinates->add_latlng(lat, lon);
67 point->set_coordinates(coordinates);
68 return point;
69 }
70
71 // This tests the GetCenter() function.
TEST(LocationUtilTest,TestGetCenter)72 TEST(LocationUtilTest, TestGetCenter) {
73 KmlFactory* factory = KmlFactory::GetFactory();
74 // NULL output pointer(s) should not crash.
75 LatLonBoxPtr llb = factory->CreateLatLonBox();
76 GetCenter(llb, NULL, NULL);
77 double lat, lon;
78 GetCenter(llb, &lat, NULL);
79 // Missing lon pointer still saves a result for lat.
80 ASSERT_EQ(0.0, lat);
81 GetCenter(llb, NULL, &lon);
82 // Missing lat pointer still saves a result for lon.
83 ASSERT_EQ(0.0, lat);
84 // A default LatLonBox is well defined thus so is its center.
85 GetCenter(llb, &lat, &lon);
86 ASSERT_EQ(0.0, lat);
87 ASSERT_EQ(0.0, lon);
88 // A default LatLonAltBox is well defined thus so is its center.
89 LatLonAltBoxPtr llab = factory->CreateLatLonAltBox();
90 GetCenter(llab, &lat, &lon);
91 ASSERT_EQ(0.0, lat);
92 ASSERT_EQ(0.0, lon);
93 }
94
TEST(LocationUtilTest,TestGetFeatureLatLon)95 TEST(LocationUtilTest, TestGetFeatureLatLon) {
96 KmlFactory* factory = KmlFactory::GetFactory();
97 const double kLat(-22.22);
98 const double kLon(42.123);
99 PlacemarkPtr placemark = factory->CreatePlacemark();
100 placemark->set_geometry(CreatePointCoordinates(kLat, kLon));
101 double lat, lon;
102 ASSERT_TRUE(GetFeatureLatLon(placemark, &lat, &lon));
103 ASSERT_EQ(kLat, lat);
104 ASSERT_EQ(kLon, lon);
105 }
106
TEST(LocationUtilTest,TestGetModelLatLon)107 TEST(LocationUtilTest, TestGetModelLatLon) {
108 KmlFactory* factory = KmlFactory::GetFactory();
109 const double kLat(-22.22);
110 const double kLon(42.123);
111 ModelPtr model = factory->CreateModel();
112 LocationPtr location = factory->CreateLocation();
113 location->set_latitude(kLat);
114 location->set_longitude(kLon);
115 model->set_location(location);
116 double lat, lon;
117 ASSERT_TRUE(GetModelLatLon(model, &lat, &lon));
118 ASSERT_EQ(kLat, lat);
119 ASSERT_EQ(kLon, lon);
120 }
121
TEST(LocationUtilTest,TestGetPlacemarkLatLon)122 TEST(LocationUtilTest, TestGetPlacemarkLatLon) {
123 KmlFactory* factory = KmlFactory::GetFactory();
124 const double kLat(-22.22);
125 const double kLon(42.123);
126 PlacemarkPtr placemark = factory->CreatePlacemark();
127 placemark->set_geometry(CreatePointCoordinates(kLat, kLon));
128 double lat, lon;
129 ASSERT_TRUE(GetPlacemarkLatLon(placemark, &lat, &lon));
130 ASSERT_EQ(kLat, lat);
131 ASSERT_EQ(kLon, lon);
132 }
133
TEST(LocationUtilTest,TestGetPointLatLon)134 TEST(LocationUtilTest, TestGetPointLatLon) {
135 const double kLat(-22.22);
136 const double kLon(42.123);
137 double lat, lon;
138 ASSERT_TRUE(GetPointLatLon(CreatePointCoordinates(kLat, kLon), &lat, &lon));
139 ASSERT_EQ(kLat, lat);
140 ASSERT_EQ(kLon, lon);
141 }
142
143 // This internal utility function parses the testcase file to a KmlFile.
ParseFromDataDirFile(const string & subdir,const string & filename)144 static KmlFilePtr ParseFromDataDirFile(const string& subdir,
145 const string& filename) {
146 string kml_data;
147 const string kml_file =
148 File::JoinPaths(File::JoinPaths(string(DATADIR), subdir), filename);
149 return File::ReadFileToString(kml_file, &kml_data) ?
150 KmlFile::CreateFromParse(kml_data, NULL) : NULL;
151 }
152
153 // This is a table of test cases.
154 static const struct {
155 const char* subdir; // Subdirectory of testdata.
156 const char* kml_filename; // Path relative to subdir.
157 const char* feature_id; // id= of Feature within file.
158 bool has_bounds; // Expected return value of GetFeatureBounds.
159 double north; // Expected values of Bbox fields iff has_bounds == true.
160 double south;
161 double east;
162 double west;
163 bool has_loc; // Expected return value of GetFeatureLatLon.
164 double lat; // Expected values of GetFeatureLatLon iff has_loc == true.
165 double lon;
166 } kTestCases[] = {
167 { // A 2d Placemark.
168 "kml", "kmlsamples.kml", "simple-placemark",
169 true, 37.4222899014025, 37.4222899014025, -122.082203542568,
170 -122.082203542568,
171 true, 37.4222899014025, -122.082203542568 },
172 { // A 3d Placemark.
173 "kml", "kmlsamples.kml", "floating-placemark",
174 true, 37.4220033612141, 37.4220033612141, -122.084075, -122.084075,
175 true, 37.4220033612141, -122.084075 },
176 { // A Placemark with no Geometry.
177 "kml", "kmlsamples.kml", "descriptive-html-placemark",
178 false, 0, 0, 0, 0,
179 false, 0, 0 },
180 { // A 2d LineString Placemark.
181 "kml", "kmlsamples.kml", "tessellated-linestring-placemark",
182 true, 36.1067787047714, 36.0905099328766, -112.081423783034,
183 -112.087026775269,
184 true, 36.098644318824, -112.0842252791515 },
185 { // A 3d LineString Placemark (altitudeMode=absolute, and alt != 0).
186 "kml", "kmlsamples.kml", "purple-line-placemark", true, 36.0944767260255,
187 36.086463123013, -112.265654928602, -112.269526855561,
188 true, 36.09046992451925, -112.2675908920815 },
189 { // A Polygon with only an outerBoundaryIs.
190 "kml", "kmlsamples.kml", "b41", true, 37.4228181532365, 37.4220817196725,
191 -122.08509907149, -122.086016227378,
192 true, 37.4224499364545, -122.085557649434 },
193 { // A Polygon with holes.
194 "kml", "kmlsamples.kml", "pentagon", true, 38.872910162817, 38.868757801256,
195 -77.0531553685479, -77.0584405629039,
196 true, 38.8708339820365, -77.0557979657259 },
197 { // A Folder with multiple Features, but none with any location info.
198 "kml", "kmlsamples.kml", "screen-overlays-folder",
199 false, 0, 0, 0, 0,
200 false, 0, 0 },
201 { // Model
202 "kml", "model-macky.kml", "model-macky",
203 true, 40.009993372683, 40.009993372683, -105.272774533734,
204 -105.272774533734,
205 true, 40.009993372683, -105.272774533734
206 },
207 { // PhotoOverlay
208 "kml", "photooverlay-zermatt.kml", "photooverlay-zermatt",
209 true, 45.968226693, 45.968226693, 7.71792711000002, 7.71792711000002,
210 true, 45.968226693, 7.71792711000002
211 },
212 #if 0
213 { // TODO: GroundOverlay
214 "kml", "kmlsamples.kml", "large-groundoverlay",
215 true, 45.968226693, 45.968226693, 7.71792711000002, 7.71792711000002,
216 true, 45.968226693, 7.71792711000002
217 },
218 #endif
219 { // A Folder with multiple Point Placemarks.
220 "kml", "kmlsamples.kml", "placemarks-folder",
221 true, 37.4222899014025, 37.4215692786755, -122.082203542568,
222 -122.085766700618,
223 true, 37.421929590039, -122.083985121593
224 },
225 { // A Folder with multiple LineString Placemarks.
226 "kml", "kmlsamples.kml", "paths-folder",
227 true, 36.1067787047714, 36.0795495214565, -112.080622229595,
228 -112.269526855561,
229 true, 36.09316411311395, -112.175074542578
230 },
231 { // A Folder with multiple Polygon Placemarks.
232 "kml", "kmlsamples.kml", "google-campus-folder",
233 true, 37.4228181532365, 37.4212932884059, -122.082850226966,
234 -122.086016227378,
235 true, 37.4220557208212, -122.084433227172
236 },
237 { // A Document with multiple Folders each with multiple Features.
238 "kml", "kmlsamples.kml", "root-document",
239 true, 38.872910162817, 36.0795495214565, -77.0531553685479,
240 -122.086016227378,
241 true, 37.476229842136746, -99.569585797962958
242 }
243 };
244
TEST(LocationUtilTest,RunTestCases)245 TEST(LocationUtilTest, RunTestCases) {
246 size_t size = sizeof(kTestCases)/sizeof(kTestCases[0]);
247 for (size_t i = 0; i < size; ++i) {
248 KmlFilePtr kml_file =
249 ParseFromDataDirFile(kTestCases[i].subdir, kTestCases[i].kml_filename);
250 // Assert basic sanity of KmlFile.
251 ASSERT_TRUE(kml_file) << kTestCases[i].kml_filename;
252 ASSERT_TRUE(kml_file->get_root());
253 kmldom::FeaturePtr feature = kmldom::AsFeature(
254 kml_file->GetObjectById(kTestCases[i].feature_id));
255 // Asserts both that this id is found and is a Feature.
256 ASSERT_TRUE(feature);
257 Bbox bbox;
258 ASSERT_EQ(kTestCases[i].has_bounds, GetFeatureBounds(feature, &bbox))
259 << kTestCases[i].kml_filename << " " << kTestCases[i].feature_id;
260 // GetFeatureBounds returns the same no matter the state of the bbox arg.
261 ASSERT_EQ(kTestCases[i].has_bounds, GetFeatureBounds(feature, NULL));
262 if (kTestCases[i].has_bounds) {
263 // If has_bounds then the test case n,s,e,w are valid to test.
264 ASSERT_EQ(kTestCases[i].north, bbox.get_north());
265 ASSERT_EQ(kTestCases[i].south, bbox.get_south());
266 ASSERT_EQ(kTestCases[i].east, bbox.get_east());
267 ASSERT_EQ(kTestCases[i].west, bbox.get_west());
268 }
269 double lat, lon;
270 ASSERT_EQ(kTestCases[i].has_loc, GetFeatureLatLon(feature, &lat, &lon));
271 // GetFeatureBounds returns same no matter the state of the lat/lon args.
272 ASSERT_EQ(kTestCases[i].has_loc, GetFeatureLatLon(feature, &lat, NULL));
273 ASSERT_EQ(kTestCases[i].has_loc, GetFeatureLatLon(feature, NULL, &lon));
274 ASSERT_EQ(kTestCases[i].has_loc, GetFeatureLatLon(feature, NULL, NULL));
275 if (kTestCases[i].has_loc) {
276 // If has_loc then the test case lat,lon are valid to test.
277 ASSERT_DOUBLE_EQ(kTestCases[i].lat, lat);
278 ASSERT_DOUBLE_EQ(kTestCases[i].lon, lon);
279 }
280 }
281 }
282
283 // Test GetGeometryBounds on null/empty args.
TEST(LocationUtilTest,TestGetGeometryBoundsNullEmpty)284 TEST(LocationUtilTest, TestGetGeometryBoundsNullEmpty) {
285 ASSERT_FALSE(GetGeometryBounds(NULL, NULL));
286 KmlFactory* kml_factory = KmlFactory::GetFactory();
287 Bbox bbox;
288 PointPtr point = kml_factory->CreatePoint();
289 ASSERT_FALSE(GetGeometryBounds(point, NULL));
290 ASSERT_FALSE(GetGeometryBounds(point, &bbox));
291 LineStringPtr linestring = kml_factory->CreateLineString();
292 ASSERT_FALSE(GetGeometryBounds(linestring, NULL));
293 ASSERT_FALSE(GetGeometryBounds(linestring, &bbox));
294 LinearRingPtr linearring = kml_factory->CreateLinearRing();
295 ASSERT_FALSE(GetGeometryBounds(linearring, NULL));
296 ASSERT_FALSE(GetGeometryBounds(linearring, &bbox));
297 PolygonPtr poly = kml_factory->CreatePolygon();
298 ASSERT_FALSE(GetGeometryBounds(poly, &bbox)); // Issue 148
299 poly->set_outerboundaryis(kml_factory->CreateOuterBoundaryIs());
300 ASSERT_FALSE(GetGeometryBounds(poly, &bbox));
301 ModelPtr model = kml_factory->CreateModel();
302 ASSERT_FALSE(GetGeometryBounds(model, NULL));
303 ASSERT_FALSE(GetGeometryBounds(model, &bbox));
304 MultiGeometryPtr multigeometry = kml_factory->CreateMultiGeometry();
305 ASSERT_FALSE(GetGeometryBounds(multigeometry, NULL));
306 ASSERT_FALSE(GetGeometryBounds(multigeometry, &bbox));
307 }
308
309 } // end namespace kmlengine
310