/MapView/UnitTesting/RouteMeTests.m

http://github.com/route-me/route-me · Objective C · 409 lines · 338 code · 60 blank · 11 comment · 6 complexity · a7feb33e7225b89eac828cc4eaa11569 MD5 · raw file

  1. //
  2. // RouteMeTests.m
  3. // MapView
  4. //
  5. // Created by Hal Mueller on 4/6/09.
  6. // Copyright 2009 Route-Me Contributors. All rights reserved.
  7. //
  8. #import "RouteMeTests.h"
  9. #import "RMMapView.h"
  10. #import "RMCloudMadeMapSource.h"
  11. #import "RMGeoHash.h"
  12. #import "RMMarker.h"
  13. #import "RMMarkerManager.h"
  14. @implementation RouteMeTests
  15. #define kAccuracyThreshold .0001
  16. #define kAccuracyThresholdForGeographicCoordinates .00001
  17. #define kAccuracyThresholdForPixelCoordinates kAccuracyThreshold
  18. - (void)setUp {
  19. [super setUp];
  20. CGRect appRect = [[UIScreen mainScreen] applicationFrame];
  21. contentView = [[UIView alloc] initWithFrame:appRect];
  22. contentView.backgroundColor = [UIColor greenColor];
  23. initialCenter.latitude = 66.44;
  24. initialCenter.longitude = -178.0;
  25. mapView = [[RMMapView alloc] initWithFrame:CGRectMake(10,20,200,300)
  26. WithLocation:initialCenter];
  27. [contentView addSubview:mapView];
  28. }
  29. -(void)tearDown {
  30. [mapView release]; mapView = nil;
  31. [super tearDown];
  32. }
  33. - (void)testObjectCreation
  34. {
  35. STAssertNotNil((mapView = [[RMMapView alloc] init]), @"mapView alloc/init failed");
  36. STAssertNoThrow([mapView release], @"mapView release failed");
  37. mapView = nil;
  38. id myTilesource;
  39. STAssertNotNil((myTilesource = [[RMCloudMadeMapSource alloc] initWithAccessKey:@"0199bdee456e59ce950b0156029d6934" styleNumber:999]),
  40. @"tilesource creation failed");
  41. STAssertNoThrow([myTilesource release], @"tilesource release failed");
  42. STAssertNil((myTilesource = [[RMCloudMadeMapSource alloc] initWithAccessKey:nil styleNumber:999]),
  43. @"empty CloudMade key does not trigger error");
  44. STAssertNoThrow([myTilesource release], @"tilesource release failed");
  45. STAssertThrows((myTilesource = [[RMCloudMadeMapSource alloc] initWithAccessKey:@"0199bdee456e59ce950b0156029d693" styleNumber:999]),
  46. @"bogus CloudMade key does not trigger error");
  47. STAssertNoThrow([myTilesource release], @"tilesource release failed");
  48. }
  49. - (void)testGeohashing
  50. {
  51. CLLocationCoordinate2D location1, location2;
  52. location1.latitude = 38.89;
  53. location1.longitude = -77.0;
  54. STAssertEqualStrings([RMGeoHash fromLocation:location1 withPrecision:6], @"dqcjr2", @"6-digit geohash location1 failed");
  55. STAssertEqualStrings([RMGeoHash fromLocation:location1 withPrecision:4], @"dqcj", @"4-digit geohash location1 failed");
  56. location2.latitude = 38.89;
  57. location2.longitude = -77.1;
  58. STAssertEqualStrings([RMGeoHash fromLocation:location2 withPrecision:6], @"dqcjjx", @"geohash location2 failed");
  59. STAssertEqualStrings([RMGeoHash fromLocation:location2 withPrecision:4], @"dqcj", @"4-digit geohash location1 failed");
  60. }
  61. - (void)testProgrammaticViewCreation
  62. {
  63. STAssertNotNil(mapView, @"mapview creation failed");
  64. STAssertNotNil([mapView contents], @"mapView contents should not be nil");
  65. }
  66. - (void)testMarkerCreation
  67. {
  68. // create markers from -183 to -169 longitude
  69. initialCenter.longitude = -178.0;
  70. CLLocationCoordinate2D markerPosition;
  71. NSUInteger nRows = 1;
  72. NSUInteger nColumns = 8;
  73. double columnSpacing = 2.0;
  74. UIImage *markerImage = [UIImage imageNamed:@"marker-red.png"];
  75. STAssertNotNil(markerImage, @"testMarkerCreation marker image did not load");
  76. markerPosition.latitude = initialCenter.latitude - ((nRows - 1)/2.0 * columnSpacing);
  77. NSUInteger i, j;
  78. for (i = 0; i < nRows; i++) {
  79. markerPosition.longitude = initialCenter.longitude - ((nColumns - 1)/2.0 * columnSpacing);
  80. for (j = 0; j < nColumns; j++) {
  81. markerPosition.longitude += columnSpacing;
  82. RMMarker *newMarker = [[RMMarker alloc] initWithUIImage:markerImage];
  83. STAssertNotNil(newMarker, @"testMarkerCreation marker creation failed");
  84. [newMarker setData:[NSArray arrayWithObjects:[NSNumber numberWithDouble:markerPosition.longitude],[NSNumber numberWithDouble:markerPosition.latitude],nil]];
  85. [mapView.contents.markerManager addMarker:newMarker
  86. AtLatLong:markerPosition];
  87. }
  88. markerPosition.latitude += columnSpacing;
  89. }
  90. }
  91. - (void)testMarkerCoordinatesFarEast
  92. {
  93. [mapView.contents setZoom:3.0];
  94. // create markers from +177 to +191 longitude
  95. initialCenter.longitude = +176.0;
  96. CLLocationCoordinate2D markerPosition;
  97. NSUInteger nColumns = 8;
  98. double columnSpacing = 2.0;
  99. UIImage *markerImage = [UIImage imageNamed:@"marker-red.png"];
  100. markerPosition.latitude = initialCenter.latitude;
  101. markerPosition.longitude = initialCenter.longitude - ((nColumns - 1)/2.0 * columnSpacing);
  102. NSUInteger j;
  103. NSMutableArray *testMarkers = [NSMutableArray arrayWithCapacity:nColumns];
  104. for (j = 0; j < nColumns; j++) {
  105. markerPosition.longitude += columnSpacing;
  106. RMMarker *newMarker = [[RMMarker alloc] initWithUIImage:markerImage];
  107. [testMarkers addObject:newMarker];
  108. [newMarker setData:[NSArray arrayWithObjects:[NSNumber numberWithDouble:markerPosition.longitude],[NSNumber numberWithDouble:markerPosition.latitude],nil]];
  109. [mapView.contents.markerManager addMarker:newMarker
  110. AtLatLong:markerPosition];
  111. }
  112. STAssertGreaterThan(columnSpacing, 0.0, @"this test requires positive columnSpacing");
  113. RMMarkerManager *mangler = [[mapView contents] markerManager];
  114. [[mapView contents] moveBy:CGSizeMake(-5.0, 0.0)];
  115. #ifdef DEBUG
  116. RMSphericalTrapezium screenLimitsDegrees = [[mapView contents] latitudeLongitudeBoundingBoxForScreen];
  117. RMLog(@"screen limits west: %4.1f east %4.1f", screenLimitsDegrees.southwest.longitude, screenLimitsDegrees.northeast.longitude);
  118. RMLog(@"screen limits south: %4.1f north %4.1f", screenLimitsDegrees.southwest.latitude, screenLimitsDegrees.northeast.latitude);
  119. #endif
  120. for (j = 1; j < nColumns; j++) {
  121. RMMarker *leftMarker = [testMarkers objectAtIndex:j - 1];
  122. RMMarker *rightMarker = [testMarkers objectAtIndex:j];
  123. CGPoint leftScreenPosition = [mangler screenCoordinatesForMarker:leftMarker];
  124. CGPoint rightScreenPosition = [mangler screenCoordinatesForMarker:rightMarker];
  125. RMLatLong leftMarkerCoordinate, rightMarkerCoordinate;
  126. leftMarkerCoordinate.longitude = [[(NSArray *)leftMarker.data objectAtIndex:0] doubleValue];
  127. leftMarkerCoordinate.latitude = [[(NSArray *)leftMarker.data objectAtIndex:1] doubleValue];
  128. rightMarkerCoordinate.longitude = [[(NSArray *)rightMarker.data objectAtIndex:0] doubleValue];
  129. rightMarkerCoordinate.latitude = [[(NSArray *)rightMarker.data objectAtIndex:1] doubleValue];
  130. STAssertLessThan(leftScreenPosition.x, rightScreenPosition.x,
  131. @"screen position calculation failed (markers %d, %d): left (%f, %f) right (%f, %f) mapped to left (%f, %f) right (%f, %f)",
  132. j-1, j,
  133. // write these out as longitude/latitude instead of standard latitude/longitude to make comparisons easier
  134. leftMarkerCoordinate.longitude, leftMarkerCoordinate.latitude,
  135. rightMarkerCoordinate.longitude, rightMarkerCoordinate.latitude,
  136. leftScreenPosition.x, leftScreenPosition.y, rightScreenPosition.x, rightScreenPosition.y);
  137. CLLocationCoordinate2D computedLatitudeLongitude =
  138. [mangler latitudeLongitudeForMarker:leftMarker];
  139. STAssertEqualsWithAccuracy(leftMarkerCoordinate.longitude, computedLatitudeLongitude.longitude, kAccuracyThresholdForGeographicCoordinates,
  140. @"round-trip computation of longitude failed %f %f",
  141. leftMarkerCoordinate.longitude, computedLatitudeLongitude.longitude);
  142. STAssertEqualsWithAccuracy(leftMarkerCoordinate.latitude, computedLatitudeLongitude.latitude, kAccuracyThresholdForGeographicCoordinates,
  143. @"round-trip computation of latitude failed %f %f",
  144. leftMarkerCoordinate.latitude, computedLatitudeLongitude.latitude);
  145. }
  146. }
  147. - (void)testMarkerCoordinatesFarWest
  148. {
  149. [mapView.contents setZoom:3.0];
  150. // create markers from -177 to -169 longitude
  151. initialCenter.longitude = -178.0;
  152. CLLocationCoordinate2D markerPosition;
  153. NSUInteger nColumns = 8;
  154. double columnSpacing = 2.0;
  155. UIImage *markerImage = [UIImage imageNamed:@"marker-red.png"];
  156. markerPosition.latitude = initialCenter.latitude;
  157. markerPosition.longitude = initialCenter.longitude - ((nColumns - 1)/2.0 * columnSpacing);
  158. NSUInteger j;
  159. NSMutableArray *testMarkers = [NSMutableArray arrayWithCapacity:nColumns];
  160. for (j = 0; j < nColumns; j++) {
  161. markerPosition.longitude += columnSpacing;
  162. RMMarker *newMarker = [[RMMarker alloc] initWithUIImage:markerImage];
  163. [testMarkers addObject:newMarker];
  164. [newMarker setData:[NSArray arrayWithObjects:[NSNumber numberWithDouble:markerPosition.longitude],[NSNumber numberWithDouble:markerPosition.latitude],nil]];
  165. [mapView.contents.markerManager addMarker:newMarker
  166. AtLatLong:markerPosition];
  167. }
  168. STAssertGreaterThan(columnSpacing, 0.0, @"this test requires positive columnSpacing");
  169. RMMarkerManager *mangler = [[mapView contents] markerManager];
  170. [[mapView contents] moveBy:CGSizeMake(-5.0, 0.0)];
  171. #ifdef DEBUG
  172. RMSphericalTrapezium screenLimitsDegrees = [[mapView contents] latitudeLongitudeBoundingBoxForScreen];
  173. RMLog(@"screen limits west: %4.1f east %4.1f", screenLimitsDegrees.southwest.longitude, screenLimitsDegrees.northeast.longitude);
  174. RMLog(@"screen limits south: %4.1f north %4.1f", screenLimitsDegrees.southwest.latitude, screenLimitsDegrees.northeast.latitude);
  175. #endif
  176. for (j = 1; j < nColumns; j++) {
  177. RMMarker *leftMarker = [testMarkers objectAtIndex:j - 1];
  178. RMMarker *rightMarker = [testMarkers objectAtIndex:j];
  179. CGPoint leftScreenPosition = [mangler screenCoordinatesForMarker:leftMarker];
  180. CGPoint rightScreenPosition = [mangler screenCoordinatesForMarker:rightMarker];
  181. RMLatLong leftMarkerCoordinate, rightMarkerCoordinate;
  182. leftMarkerCoordinate.longitude = [[(NSArray *)leftMarker.data objectAtIndex:0] doubleValue];
  183. leftMarkerCoordinate.latitude = [[(NSArray *)leftMarker.data objectAtIndex:1] doubleValue];
  184. rightMarkerCoordinate.longitude = [[(NSArray *)rightMarker.data objectAtIndex:0] doubleValue];
  185. rightMarkerCoordinate.latitude = [[(NSArray *)rightMarker.data objectAtIndex:1] doubleValue];
  186. STAssertLessThan(leftScreenPosition.x, rightScreenPosition.x,
  187. @"screen position calculation failed (markers %d, %d): left (%f, %f) right (%f, %f) mapped to left (%f, %f) right (%f, %f)",
  188. j-1, j,
  189. leftMarkerCoordinate.longitude, leftMarkerCoordinate.latitude,
  190. rightMarkerCoordinate.longitude, rightMarkerCoordinate.latitude,
  191. leftScreenPosition.x, leftScreenPosition.y, rightScreenPosition.x, rightScreenPosition.y);
  192. CLLocationCoordinate2D computedLatitudeLongitude =
  193. [mangler latitudeLongitudeForMarker:leftMarker];
  194. STAssertEqualsWithAccuracy(leftMarkerCoordinate.longitude, computedLatitudeLongitude.longitude, kAccuracyThresholdForGeographicCoordinates,
  195. @"round-trip computation of longitude failed %f %f",
  196. leftMarkerCoordinate.longitude, computedLatitudeLongitude.longitude);
  197. STAssertEqualsWithAccuracy(leftMarkerCoordinate.latitude, computedLatitudeLongitude.latitude, kAccuracyThresholdForGeographicCoordinates,
  198. @"round-trip computation of latitude failed %f %f",
  199. leftMarkerCoordinate.latitude, computedLatitudeLongitude.latitude);
  200. }
  201. }
  202. - (void)testScreenCoordinatesPacificNorthwest
  203. {
  204. [[mapView contents] setZoom: 10];
  205. CLLocationCoordinate2D coord = {45.5,-121};
  206. [mapView moveToLatLong:coord];
  207. CGPoint point1 = [mapView latLongToPixel:coord];
  208. coord.longitude -= .125;
  209. CGPoint point2 = [mapView latLongToPixel:coord];
  210. coord.longitude -= .125;
  211. CGPoint point3 = [mapView latLongToPixel:coord];
  212. STAssertEqualsWithAccuracy(point1.y, point2.y, kAccuracyThresholdForPixelCoordinates,
  213. @"Y pixel values should be equal");
  214. STAssertEqualsWithAccuracy(point2.y, point3.y, kAccuracyThresholdForPixelCoordinates,
  215. @"Y pixel values should be equal");
  216. STAssertLessThan(point3.x, point2.x,
  217. @"X pixel coordinates should be increasing left to right");
  218. STAssertLessThan(point2.x, point1.x,
  219. @"X pixel coordinates should be increasing left to right");
  220. }
  221. - (void)testScreenCoordinatesFarEast
  222. {
  223. [[mapView contents] setZoom: 10];
  224. CLLocationCoordinate2D coord = {45.5,179.9};
  225. [mapView moveToLatLong:coord];
  226. CGPoint point1 = [mapView latLongToPixel:coord];
  227. coord.longitude += .125;
  228. CGPoint point2 = [mapView latLongToPixel:coord];
  229. coord.longitude += .125;
  230. CGPoint point3 = [mapView latLongToPixel:coord];
  231. STAssertEqualsWithAccuracy(point1.y, point2.y, kAccuracyThresholdForPixelCoordinates,
  232. @"Y pixel values should be equal");
  233. STAssertEqualsWithAccuracy(point2.y, point3.y, kAccuracyThresholdForPixelCoordinates,
  234. @"Y pixel values should be equal");
  235. STAssertLessThan(point1.x, point2.x,
  236. @"X pixel coordinates should be increasing left to right");
  237. STAssertLessThan(point2.x, point3.x,
  238. @"X pixel coordinates should be increasing left to right");
  239. }
  240. - (void)testScreenCoordinatesFarWest
  241. {
  242. [[mapView contents] setZoom: 10];
  243. CLLocationCoordinate2D coord = {45.5,-179.9};
  244. [mapView moveToLatLong:coord];
  245. CGPoint point1 = [mapView latLongToPixel:coord];
  246. coord.longitude -= .125;
  247. CGPoint point2 = [mapView latLongToPixel:coord];
  248. coord.longitude -= .125;
  249. CGPoint point3 = [mapView latLongToPixel:coord];
  250. STAssertEqualsWithAccuracy(point1.y, point2.y, kAccuracyThresholdForPixelCoordinates,
  251. @"Y pixel values should be equal");
  252. STAssertEqualsWithAccuracy(point2.y, point3.y, kAccuracyThresholdForPixelCoordinates,
  253. @"Y pixel values should be equal");
  254. STAssertLessThan(point3.x, point2.x,
  255. @"X pixel coordinates should be increasing left to right");
  256. STAssertLessThan(point2.x, point1.x,
  257. @"X pixel coordinates should be increasing left to right");
  258. }
  259. - (void)testZoomBounds
  260. {
  261. double contentsMaxZoom, tilesourceMaxZoom, contentsZoom;
  262. contentsMaxZoom = [[mapView contents] maxZoom];
  263. tilesourceMaxZoom = [[[mapView contents] tileSource] maxZoom];
  264. contentsZoom = [[mapView contents] zoom];
  265. STAssertLessThanOrEqual(contentsMaxZoom, tilesourceMaxZoom, @"map's maxZoom exceeds tilesource's maxZoom");
  266. STAssertLessThanOrEqual(contentsZoom, tilesourceMaxZoom, @"map's zoom exceeds tilesource's maxZoom");
  267. double targetZoom = tilesourceMaxZoom + 0.4;
  268. [[mapView contents] setZoom:targetZoom]; // try to exceed tilesource limit
  269. contentsZoom = [[mapView contents] zoom];
  270. STAssertEqualsWithAccuracy(contentsZoom, tilesourceMaxZoom, kAccuracyThreshold, @"map's zoom wrong after trying to exceed tilesource's maxZoom");
  271. targetZoom = tilesourceMaxZoom + 0.5;
  272. [[mapView contents] setZoom:targetZoom]; // try to exceed tilesource limit
  273. contentsZoom = [[mapView contents] zoom];
  274. STAssertEqualsWithAccuracy(contentsZoom, tilesourceMaxZoom, kAccuracyThreshold, @"map's zoom wrong after trying to exceed tilesource's maxZoom");
  275. targetZoom = tilesourceMaxZoom - 1.6;
  276. [[mapView contents] setZoom:targetZoom];
  277. CGPoint pivotPoint = CGPointMake(5., 5.);
  278. [[mapView contents] zoomInToNextNativeZoomAt:pivotPoint];
  279. contentsZoom = [[mapView contents] zoom];
  280. STAssertEqualsWithAccuracy(contentsZoom, tilesourceMaxZoom - 1.0, kAccuracyThreshold,
  281. @"map's zoom %f wrong after zoomInToNextNativeZoomAt: for maxZoom-1 %f",
  282. contentsZoom, tilesourceMaxZoom);
  283. [[mapView contents] zoomInToNextNativeZoomAt:pivotPoint];
  284. contentsZoom = [[mapView contents] zoom];
  285. STAssertEqualsWithAccuracy(contentsZoom, tilesourceMaxZoom, kAccuracyThreshold,
  286. @"map's zoom [%f] wrong after zoomInToNextNativeZoomAt: for maxZoom %f (first)",
  287. contentsZoom, tilesourceMaxZoom);
  288. [[mapView contents] zoomInToNextNativeZoomAt:pivotPoint];
  289. contentsZoom = [[mapView contents] zoom];
  290. STAssertEqualsWithAccuracy(contentsZoom, tilesourceMaxZoom, kAccuracyThreshold,
  291. @"map's zoom %f wrong after zoomInToNextNativeZoomAt: for maxZoom %f (second)",
  292. contentsZoom, tilesourceMaxZoom);
  293. targetZoom = tilesourceMaxZoom - 1.5;
  294. [[mapView contents] setZoom:targetZoom];
  295. pivotPoint = CGPointMake(5., 5.);
  296. [[mapView contents] zoomInToNextNativeZoomAt:pivotPoint];
  297. contentsZoom = [[mapView contents] zoom];
  298. STAssertEqualsWithAccuracy(contentsZoom, tilesourceMaxZoom - 1.0, kAccuracyThreshold,
  299. @"map's zoom %f wrong after zoomInToNextNativeZoomAt: for maxZoom-1 %f",
  300. contentsZoom, tilesourceMaxZoom);
  301. [[mapView contents] zoomInToNextNativeZoomAt:pivotPoint];
  302. contentsZoom = [[mapView contents] zoom];
  303. STAssertEqualsWithAccuracy(contentsZoom, tilesourceMaxZoom, kAccuracyThreshold,
  304. @"map's zoom [%f] wrong after zoomInToNextNativeZoomAt: for maxZoom %f (first)",
  305. contentsZoom, tilesourceMaxZoom);
  306. [[mapView contents] zoomInToNextNativeZoomAt:pivotPoint];
  307. contentsZoom = [[mapView contents] zoom];
  308. STAssertEqualsWithAccuracy(contentsZoom, tilesourceMaxZoom, kAccuracyThreshold,
  309. @"map's zoom %f wrong after zoomInToNextNativeZoomAt: for maxZoom %f (second)",
  310. contentsZoom, tilesourceMaxZoom);
  311. double contentsMinZoom = 3.0;
  312. [[mapView contents] setMinZoom:contentsMinZoom];
  313. targetZoom = contentsMinZoom + 0.6;
  314. [[mapView contents] setZoom:targetZoom];
  315. contentsZoom = [[mapView contents] zoom];
  316. NSLog(@"zoom: %f minZoom: %f", contentsZoom, [[mapView contents] minZoom]);
  317. [[mapView contents] zoomOutToNextNativeZoomAt:pivotPoint];
  318. contentsZoom = [[mapView contents] zoom];
  319. STAssertEqualsWithAccuracy(contentsZoom, contentsMinZoom, kAccuracyThreshold,
  320. @"map's zoom %f wrong after first zoomOutToNextNativeZoomAt: for minZoom %f",
  321. contentsZoom, contentsMinZoom);
  322. [[mapView contents] zoomOutToNextNativeZoomAt:pivotPoint];
  323. contentsZoom = [[mapView contents] zoom];
  324. STAssertEqualsWithAccuracy(contentsZoom, contentsMinZoom, kAccuracyThreshold,
  325. @"map's zoom %f wrong after second zoomOutToNextNativeZoomAt: for minZoom %f",
  326. contentsZoom, contentsMinZoom);
  327. contentsMinZoom = 3.0;
  328. [[mapView contents] setMinZoom:contentsMinZoom];
  329. targetZoom = contentsMinZoom + 1.6;
  330. [[mapView contents] setZoom:targetZoom];
  331. contentsZoom = [[mapView contents] zoom];
  332. NSLog(@"zoom: %f minZoom: %f", contentsZoom, [[mapView contents] minZoom]);
  333. [[mapView contents] zoomOutToNextNativeZoomAt:pivotPoint];
  334. contentsZoom = [[mapView contents] zoom];
  335. STAssertEqualsWithAccuracy(contentsZoom, contentsMinZoom+1.0, kAccuracyThreshold,
  336. @"map's zoom %f wrong after first zoomOutToNextNativeZoomAt: for minZoom %f",
  337. contentsZoom, contentsMinZoom);
  338. [[mapView contents] zoomOutToNextNativeZoomAt:pivotPoint];
  339. contentsZoom = [[mapView contents] zoom];
  340. STAssertEqualsWithAccuracy(contentsZoom, contentsMinZoom, kAccuracyThreshold,
  341. @"map's zoom %f wrong after second zoomOutToNextNativeZoomAt: for minZoom %f",
  342. contentsZoom, contentsMinZoom);
  343. [[mapView contents] zoomOutToNextNativeZoomAt:pivotPoint];
  344. contentsZoom = [[mapView contents] zoom];
  345. STAssertEqualsWithAccuracy(contentsZoom, contentsMinZoom, kAccuracyThreshold,
  346. @"map's zoom %f wrong after second zoomOutToNextNativeZoomAt: for minZoom %f",
  347. contentsZoom, contentsMinZoom);
  348. }
  349. @end