001 package ps2.test;
002
003 import ps2.*;
004 import static ps2.test.TestValues.TOLERANCE;
005
006 import junit.framework.*;
007
008
009 /**
010 * Unit tests for the GeoPoint class.
011 **/
012 public class GeoPointTest extends TestCase {
013
014 /** A GeoPoint object with the same data as eq2 **/
015 private final GeoPoint eq1;
016
017 /** A GeoPoint object with the same data as eq1 **/
018 private final GeoPoint eq2;
019
020 /** A GeoPoint object with different data than eq1 **/
021 private final GeoPoint diff;
022
023
024 /** A GeoPoint representing the center of Seattle **/
025 private final GeoPoint p1;
026
027
028 /** A GeoPoint due north of Seattle **/
029 private final GeoPoint north;
030
031 /** Heading, in degrees, between p1 and north **/
032 private final double nHeading;
033
034 /** Distance, in miles, between p1 and north **/
035 private final double nDist;
036
037
038 /** A GeoPodouble due south of Seattle **/
039 private final GeoPoint south;
040
041 /** Heading, in degrees, between p1 and south **/
042 private final double sHeading;
043
044 /** Distance, in miles, between p1 and south **/
045 private final double sDist;
046
047
048 /** A GeoPoint due east of Seattle **/
049 private final GeoPoint east;
050
051 /** Heading, in degrees, between p1 and east **/
052 private final double eHeading;
053
054 /** Distance, in miles, between p1 and east **/
055 private final double eDist;
056
057
058 /** A GeoPoint due west of Seattle **/
059 private final GeoPoint west;
060
061 /** Heading, in degrees, between p1 and west **/
062 private final double wHeading;
063
064 /** Distance, in miles, between p1 and west **/
065 private final double wDist;
066
067
068 /** A GeoPoint due north east of Seattle **/
069 private final GeoPoint northEast;
070
071 /** Heading, in degrees, between p1 and north east **/
072 private final double neHeading;
073
074 /** Distance, in miles, between p1 and north east **/
075 private final double neDist;
076
077
078 /** A GeoPoint due south west of Seattle **/
079 private final GeoPoint southWest;
080
081 /** Heading, in degrees, between p1 and south west **/
082 private final double swHeading;
083
084 /** Distance, in miles, between p1 and south west **/
085 private final double swDist;
086
087
088 public GeoPointTest(String name) {
089 super(name);
090
091 int eqLat = locationToInt(47, 36, 35);
092 int eqLong = locationToInt(-122, 19, 59);
093 eq1 = new GeoPoint(eqLat, eqLong);
094 eq2 = new GeoPoint(eqLat, eqLong);
095 diff = new GeoPoint(eqLat + 50, eqLong + 50);
096
097
098 // Center of Seattle:
099 p1 = new GeoPoint(locationToInt(47, 36, 35),
100 locationToInt(-122, 19, 59));
101 // due north
102 north = new GeoPoint(locationToInt(47, 42, 35),
103 locationToInt(-122, 19, 59));
104 nHeading = 0;
105 nDist = 6.904;
106
107 // due south
108 south = new GeoPoint(locationToInt(47, 30, 35),
109 locationToInt(-122, 19, 59));
110 sHeading = 180;
111 sDist = 6.904;
112
113 // due east
114 east = new GeoPoint(locationToInt(47, 36, 35),
115 locationToInt(-122, 13, 59));
116 eHeading = 90;
117 eDist = 4.6574;
118
119 // due west
120 west = new GeoPoint(locationToInt(47, 36, 35),
121 locationToInt(-122, 25, 59));
122 wHeading = 270;
123 wDist = 4.6574;
124
125 // north east
126 northEast = new GeoPoint(locationToInt(47, 42, 35),
127 locationToInt(-122, 13, 59));
128 neHeading = 34.0033834;
129 neDist = 8.328060444;
130
131 // south west
132 southWest = new GeoPoint(locationToInt(47, 30, 35),
133 locationToInt(-122, 25, 59));
134 swHeading = 214.0033834;
135 swDist = 8.328060444;
136 }
137
138
139 /**
140 * Convert a degree, minutes, seconds latitude or longitude value
141 * to its associated integer value (to millionths of a degree).
142 * Allows invalid locations to be specified for testing, but
143 * doesn't allow negative minute/second values.
144 **/
145 static int locationToInt(int deg, int min, int sec) {
146 if (min < 0 || sec < 0) {
147 throw new RuntimeException("min and sec must be positive!");
148 }
149
150 double dmin = (double)min / 60;
151 double dsec = (double)sec / (60 * 60);
152 if (deg >= 0) {
153 return ((int)Math.round(1000000 * (deg + dmin + dsec)));
154 } else {
155 return ((int)Math.round(1000000 * (deg - dmin - dsec)));
156 }
157 }
158
159
160
161 /**
162 * Sanity check for our locationToInt() method
163 **/
164 public void testLocationToIntMethod() {
165 int lat = locationToInt(42, 21, 30);
166 int lng = locationToInt(-71, 3, 37);
167 if (lat != 42358333) {
168 fail("42 21 30 latitude must be 42358333, is " + lat);
169 } else if (lng != -71060278) {
170 fail("-71 3 37 longitude must be -71060278, is " + lng);
171 }
172 }
173
174
175 /**
176 * JUnit calls this before each testXXX method is run
177 **/
178 protected void setUp() {
179
180 }
181
182
183 ////////////////////////////////////////////////////
184 // TEST LEGAL/ILLEGAL VALUES IN GeoPoint CREATION //
185 ////////////////////////////////////////////////////
186
187
188 /**
189 * Tests that GeoPoints can be created with some legal latitude
190 * and longitude values that are in the greater Seattle area, and
191 * that the values it's provided are returned unchanged.
192 **/
193 public void testLegalValues1() {
194 int valLat = locationToInt(47, 36, 0);
195 int valLong = locationToInt(-122, 19, 50);
196 checkLegal(valLat, valLong);
197 }
198
199
200 /**
201 * Tests that GeoPoints can be created with some legal latitude
202 * and longitude values that are in the greater Seattle area, and
203 * that the values it's provided are returned unchanged.
204 **/
205 public void testLegalValues2() {
206 int valLat = locationToInt(47, 35, 58);
207 int valLong = locationToInt(-122, 20, 0);
208 checkLegal(valLat, valLong);
209 }
210
211
212 /**
213 * Helper method for asserting that a legal latitude/longitude
214 * pair can be used to create a GeoPoint and that those exact same
215 * values are then returned.
216 **/
217 void checkLegal(int lat, int lng) {
218 GeoPoint g = null;
219 try {
220 g = new GeoPoint(lat, lng);
221 } catch (Exception ex) {
222 // Failed
223 fail("Didn't allow legal (latitude,longitude) of (" +
224 lat + ", " + lng + ")");
225 return;
226 }
227
228 if (g.getLatitude() != lat) {
229 fail("Latitude should have been set to " + lat +
230 ", was set to " + g.getLatitude() + " instead.");
231
232 } else if (g.getLongitude() != lng) {
233 fail("Longitude should have been set to " + lng +
234 ", was set to " + g.getLongitude() + " instead.");
235 }
236 }
237
238
239 //////////////////////////////
240 // TEST GeoPoint.distanceTo //
241 //////////////////////////////
242
243 /**
244 * Test that distance 0 is handled correctly: same object
245 **/
246 public void testDistance01() {
247 assertEquals("Distance between a GeoPoint and itself must be 0",
248 0.0, p1.distanceTo(p1), TOLERANCE);
249 }
250
251
252 /**
253 * Test that distance 0 is handled correctly: equal objects
254 **/
255 public void testDistance02() {
256 assertEquals("Distance between two equal GeoPoints must be 0",
257 0.0, eq1.distanceTo(eq2), TOLERANCE);
258 }
259
260
261 /**
262 * Test that points due north are handled correctly
263 **/
264 public void testDistanceDueNorth() {
265 checkDist(p1, north, nDist);
266 }
267
268
269 /**
270 * Test that points due south are handled correctly
271 **/
272 public void testDistanceDueSouth() {
273 checkDist(p1, south, sDist);
274 }
275
276
277 /**
278 * Test that points due east are handled correctly
279 **/
280 public void testDistanceDueEast() {
281 checkDist(p1, east, eDist);
282 }
283
284
285 /**
286 * Test that points due west are handled correctly
287 **/
288 public void testDistanceDueWest() {
289 checkDist(p1, west, wDist);
290 }
291
292
293 /**
294 * Test that points north east are handled correctly
295 **/
296 public void testDistanceDueNorthEast() {
297 checkDist(p1, northEast, neDist);
298 }
299
300
301 /**
302 * Test that points south west are handled correctly
303 **/
304 public void testDistanceDueSouthWest() {
305 checkDist(p1, southWest, swDist);
306 }
307
308
309 /**
310 * Helper method that asserts that the distance between p1 and p2
311 * is dist AND that the distance between p2 and p1 is also dist.
312 **/
313 void checkDist(GeoPoint p1, GeoPoint p2, double dist) {
314 assertEquals("Distance between these two points is " +
315 dist + ", not " + p1.distanceTo(p2),
316 dist, p1.distanceTo(p2), TOLERANCE);
317 assertEquals("Reversing between these two points is " +
318 dist + ", not " + p2.distanceTo(p1),
319 dist, p2.distanceTo(p1), TOLERANCE);
320 }
321
322
323 /////////////////////////////
324 // TEST GeoPoint.headingTo //
325 /////////////////////////////
326
327 /**
328 * Test that points due north are handled correctly
329 **/
330 public void testHeadingDueNorth() {
331 checkHeading(p1, north, nHeading);
332 }
333
334
335 /**
336 * Test that points due south are handled correctly
337 **/
338 public void testHeadingDueSouth() {
339 checkHeading(p1, south, sHeading);
340 }
341
342
343 /**
344 * Test that points due east are handled correctly
345 **/
346 public void testHeadingDueEast() {
347 checkHeading(p1, east, eHeading);
348 }
349
350
351 /**
352 * Test that points due west are handled correctly
353 **/
354 public void testHeadingDueWest() {
355 checkHeading(p1, west, wHeading);
356 }
357
358
359 /**
360 * Test that points north east are handled correctly
361 **/
362 public void testHeadingNorthEast() {
363 checkHeading(p1, northEast, neHeading);
364 }
365
366
367 /**
368 * Test that points south west are handled correctly
369 **/
370 public void testHeadingSouthWest() {
371 checkHeading(p1, southWest, swHeading);
372 }
373
374
375 /**
376 * Helper method that asserts that the heading between p1 and p2
377 * is heading AND that the distance between p2 and p1 is heading + 180.
378 **/
379 void checkHeading(GeoPoint p1, GeoPoint p2, double heading) {
380 assertEquals("Heading between these two points is " +
381 heading + ", not " + p1.headingTo(p2),
382 heading, p1.headingTo(p2), TOLERANCE);
383 assertEquals("Reversing between these two points is " +
384 (heading + 180) + ", not " + p2.headingTo(p1),
385 heading, ((p2.headingTo(p1) + 180) % 360), TOLERANCE);
386 }
387
388
389 //////////////////////////
390 // TEST GeoPoint.equals //
391 //////////////////////////
392
393 /**
394 * Test positive case: same object
395 **/
396 public void testEquals1() {
397 assertTrue("A GeoPoint must be equal() to itself",
398 eq1.equals(eq1));
399 }
400
401
402 /**
403 * Test positive case: equal objects
404 **/
405 public void testEquals2() {
406 assertTrue("Two GeoPoints with the same data must be equal()",
407 eq1.equals(eq2));
408 }
409
410
411 /**
412 * Test that null values are handled correctly
413 **/
414 public void testNotEqualsNull() {
415 if(!eq1.equals(null))
416 return; // gp != null which is good.
417 fail("Null not handled: equals(null) returns true or causes other problems (NullPointerException?).");
418 }
419
420
421 /**
422 * Test that two GeoPoints with different data do not register as
423 * equal.
424 **/
425 public void testNotEqualsDiff() {
426 assertFalse("Two GeoPoints with different data must not be equal()",
427 eq1.equals(diff));
428 }
429
430
431 /**
432 * Test that two GeoPoints with "swapped" latitude and longitude
433 * values (i.e., they both sum to the same value) do not register
434 * as equal.
435 **/
436 public void testNotEqualsSwapped() {
437 int lat = locationToInt(1, 2, 3);
438 int lng = locationToInt(4, 5, 6);
439 GeoPoint e1 = new GeoPoint(lat, lng);
440 GeoPoint e2 = new GeoPoint(lng, lat);
441 assertFalse("Two GeoPoints with swapped data must not be equal()",
442 e1.equals(e2));
443 }
444
445
446 ////////////////////////////
447 // TEST GeoPoint.hashCode //
448 ////////////////////////////
449
450 /**
451 * Test positive case: same object
452 **/
453 public void testHashCode1() {
454 assertEquals("A GeoPoint's hashCode must remain constant",
455 eq1.hashCode(), eq1.hashCode());
456 }
457
458
459 /**
460 * Test positive case: equal objects
461 **/
462 public void testHashCode2() {
463 assertEquals("GeoPoints with same data must have the same hashCode",
464 eq1.hashCode(), eq2.hashCode());
465 }
466 }