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 }