浏览代码

i18n and exceptions for geocoding

euromark 13 年之前
父节点
当前提交
52c5f52d92
共有 3 个文件被更改,包括 229 次插入188 次删除
  1. 76 38
      Lib/GeocodeLib.php
  2. 84 97
      Lib/MyCakeTestCase.php
  3. 69 53
      Test/Case/Lib/GeocodeLibTest.php

+ 76 - 38
Lib/GeocodeLib.php

@@ -4,10 +4,14 @@ App::uses('Xml', 'Utility');
 App::uses('HttpSocketLib', 'Tools.Lib');
 
 /**
- * geocode via google (UPDATE: api3)
+ * Geocode via google (UPDATE: api3)
  * @see DEPRECATED api2: http://code.google.com/intl/de-DE/apis/maps/articles/phpsqlgeocode.html
  * @see http://code.google.com/intl/de/apis/maps/documentation/geocoding/#Types
  * 
+ * TODOS (since 1.2):
+ * - Work with exceptions in 2.x
+ * - Rewrite in a cleaner 2.x way
+ * 
  * @author Mark Scherer
  * @cakephp 2.x
  * @licence MIT
@@ -29,9 +33,26 @@ class GeocodeLib {
 	const ACC_INTERSEC = 8;
 	const ACC_STREET = 9;
 	
+	const UNIT_KM = 'K';
+	const UNIT_NAUTICAL = 'N';
+	const UNIT_FEET = 'F';
+	const UNIT_INCHES = 'I';
+	const UNIT_MILES = 'M';
+	
 	# First tries with curl, then cake, then php
-	public $use = array('curl' => true, 'cake'=> true, 'php' => true);
-	public $units = array('K' => 1.609344, 'N' => 0.868976242, 'F' => 5280, 'I' => 63360, 'M' => 1);
+	public $use = array(
+		'curl' => true, 
+		'cake'=> true, 
+		'php' => true
+	);
+	
+	public $units = array(
+		self::UNIT_KM => 1.609344, 
+		self::UNIT_NAUTICAL => 0.868976242, 
+		self::UNIT_FEET => 5280, 
+		self::UNIT_INCHES => 63360, 
+		self::UNIT_MILES => 1
+	);
 
 	/**
 	 * validation and retrieval options
@@ -59,12 +80,12 @@ class GeocodeLib {
 	 */
 	protected $params = array(
 		'address' => '', # either address or latlng required!
-		'latlng' => '',
-		'region' => '', # country tlds
+		'latlng' => '', # The textual latitude/longitude value for which you wish to obtain the closest, human-readable address
+		'region' => '', # The region code, specified as a ccTLD ("top-level domain") two-character
 		'language' => 'de',
 		'bounds' => '',
 		'sensor' => 'false', # device with gps module sensor
-		//'key' => '' # not neccessary anymore
+		//'key' => '' # not necessary anymore
  	);
 
 	protected $error = array();
@@ -116,7 +137,10 @@ class GeocodeLib {
 		$this->setOptions($options);
 	}
 
-
+	/**
+	 * @param array $params
+	 * @return void
+	 */
 	public function setParams($params) {
 		foreach ($params as $key => $value) {
 			if ($key == 'sensor' && $value != 'false' && $value != 'true') {
@@ -126,13 +150,17 @@ class GeocodeLib {
 		}
 	}
 
+	/**
+	 * @param array $options
+	 * @return void
+	 */
 	public function setOptions($options) {
 		foreach ($options as $key => $value) {
 			if ($key == 'output' && $value != 'xml' && $value != 'json') {
-				continue;
+				throw new CakeException('Invalid output format');
 			}
 			if ($key == 'host' && !array_key_exists($value, $this->hosts)) {
-				continue;
+				throw new CakeException('Invalid host');
 			}
 			$this->options[$key] = $value;
 		}
@@ -179,10 +207,12 @@ class GeocodeLib {
 				$params[] = $key.'='.$value;
 			}
 		}
-		return $url.implode('&', $params);
+		return $url . implode('&', $params);
 	}
 
-
+	/**
+	 * @return bool $isInconclusive (or null if no query has been run yet)
+	 */
 	public function isInconclusive() {
 		if ($this->result === null) {
 			return null;
@@ -229,8 +259,8 @@ class GeocodeLib {
 	 */
 	public function reverseGeocode($lat, $lng, $settings = array()) {
 		$this->reset(false);
-		$latlng = $lat.','.$lng;
-		$this->setParams(array_merge($settings, array('latlng'=>$latlng)));
+		$latlng = $lat . ',' . $lng;
+		$this->setParams(array_merge($settings, array('latlng' => $latlng)));
 		
 		$count = 0;
 		$request_url = $this->url();
@@ -238,7 +268,7 @@ class GeocodeLib {
 			$result = $this->_fetch($request_url);
 			if ($result === false || $result === null) {
 				$this->setError('Could not retrieve url');
-				CakeLog::write('geocode', 'Geocoder could not retrieve url with \''.$latlng.'\'');
+				CakeLog::write('geocode', __('Could not retrieve url with \'%s\'', $latlng));
 				return false;
 			}
 
@@ -250,7 +280,7 @@ class GeocodeLib {
 
 			if (!is_object($res)) {
 				$this->setError('XML parsing failed');
-				CakeLog::write('geocode', 'Geocoder failed with XML parsing of \''.$latlng.'\'');
+				CakeLog::write('geocode', __('Failed with XML parsing of \'%s\'', $latlng));
 				return false;
 			}
 
@@ -262,7 +292,7 @@ class GeocodeLib {
 
 				# validate
 				if (isset($xmlArray['result'][0]) && !$this->options['allow_inconclusive']) {
-					$this->setError('Inconclusive result (total of '.count($xmlArray['result']).')');
+					$this->setError(__('Inconclusive result (total of %s)', count($xmlArray['result'])));
 					$this->result = $xmlArray['result'];
 					return false;
 				}
@@ -275,7 +305,9 @@ class GeocodeLib {
 				}
 
 				if ($this->_isNotAccurateEnough($accuracy)) {
-					$this->setError('Accuracy not good enough ('.implode(', ', (array)$accuracy).' instead of at least '.$this->accuracyTypes[$this->options['min_accuracy']].')');
+					$accuracy = implode(', ', (array)$accuracy);
+					$minAccuracy = $this->accuracyTypes[$this->options['min_accuracy']]; 
+					$this->setError(__('Accuracy not good enough (%s instead of at least %s)', $accuracy, $minAccuracy));
 					$this->result = $xmlArray['result'];
 					return false;
 				}
@@ -283,31 +315,31 @@ class GeocodeLib {
 
 				# save Result
 				if ($this->options['log']) {
-					CakeLog::write('geocode', 'Address \''.$latlng.'\' has been geocoded');
+					CakeLog::write('geocode', __('Address \'%s\' has been geocoded', $latlng));
 				}
 				break;
 
 			} elseif ($status == self::CODE_TOO_MANY_QUERIES) {
 				// sent geocodes too fast, delay +0.1 seconds
 				if ($this->options['log']) {
-					CakeLog::write('geocode', 'Delay neccessary for \''.$latlng.'\'');
+					CakeLog::write('geocode', __('Delay necessary for \'%s\'', $latlng));
 				}
 				$count++;
+				
 			} else {
-
 				# something went wrong
 				$this->setError('Error '.$status.(isset($this->statusCodes[$status]) ? ' ('.$this->statusCodes[$status].')' : ''));
 
 				if ($this->options['log']) {
-					CakeLog::write('geocode', 'Geocoder could not geocode \''.$latlng.'\'');
+					CakeLog::write('geocode', __('Could not geocode \'%s\'', $latlng));
 				}
 				return false; # for now...
 			}
 			if ($count > 5) {
 				if ($this->options['log']) {
-					CakeLog::write('geocode', 'Geocoder aborted after too many trials with \''.$latlng.'\'');
+					CakeLog::write('geocode', __('Aborted after too many trials with \'%s\'', $latlng));
 				}
-				$this->setError('Too many trials - abort');
+				$this->setError(__('Too many trials - abort'));
 				return false;
 			}
 			$this->pause(true);
@@ -319,6 +351,7 @@ class GeocodeLib {
 
 	/**
 	 * trying to avoid "TOO_MANY_QUERIES" error
+	 * @param bool $raise If the pause length should be raised
 	 * 2010-06-29 ms
 	 */
 	public function pause($raise = false) {
@@ -341,7 +374,7 @@ class GeocodeLib {
 		$this->reset(false);
 		$this->setParams(array_merge($settings, array('address'=>$address)));
 		if ($this->options['allow_inconclusive']) {
-			# only host working with this setting
+			# only host working with this setting?
 			//$this->options['host'] = self::DEFAULT_HOST;
 		}
 
@@ -357,6 +390,7 @@ class GeocodeLib {
 			}
 
 			if ($this->options['output'] == 'json') {
+				//TODO? necessary?
 				//$res = json_decode($result);
 			} else {
 				try {
@@ -369,7 +403,7 @@ class GeocodeLib {
 
 			if (!is_object($res)) {
 				$this->setError('XML parsing failed');
-				CakeLog::write('geocode', 'Geocoder failed with XML parsing of \''.$address.'\'');
+				CakeLog::write('geocode', __('Failed with XML parsing of \'%s\'', $address));
 				return false;
 			}
 
@@ -380,7 +414,7 @@ class GeocodeLib {
 			if ($status == self::CODE_SUCCESS) {
 				# validate
 				if (isset($xmlArray['result'][0]) && !$this->options['allow_inconclusive']) {
-					$this->setError('Inconclusive result (total of '.count($xmlArray['result']).')');
+					$this->setError(__('Inconclusive result (total of %s)', count($xmlArray['result'])));
 					$this->result = $xmlArray['result'];
 					return false;
 				}
@@ -393,7 +427,9 @@ class GeocodeLib {
 				//echo returns($accuracy);
 
 				if ($this->_isNotAccurateEnough($accuracy)) {
-					$this->setError('Accuracy not good enough ('.implode(', ', (array)$accuracy).' instead of at least '.$this->accuracyTypes[$this->options['min_accuracy']].')');
+					$accuracy = implode(', ', (array)$accuracy);
+					$minAccuracy = $this->accuracyTypes[$this->options['min_accuracy']];
+					$this->setError(__('Accuracy not good enough (%s instead of at least %s)', $accuracy, $minAccuracy));
 					$this->result = $xmlArray['result'];
 					return false;
 				}
@@ -409,7 +445,7 @@ class GeocodeLib {
 						}
 					}
 					if (!$validExpectation) {
-						$this->setError('Expectation not good reached ('.$accuracy.' instead of '.implode(', ', (array)$this->options['expect']).')');
+						$this->setError(__('Expectation not reached (%s instead of at least %s)', $accuracy, implode(', ', (array)$this->options['expect'])));
 						$this->result = $xmlArray['result'];
 						return false;
 					}
@@ -418,14 +454,14 @@ class GeocodeLib {
 
 				# save Result
 				if ($this->options['log']) {
-					CakeLog::write('geocode', 'Address \''.$address.'\' has been geocoded');
+					CakeLog::write('geocode', __('Address \'%s\' has been geocoded', $address));
 				}
 				break;
 
 			} elseif ($status == self::CODE_TOO_MANY_QUERIES) {
 				// sent geocodes too fast, delay +0.1 seconds
 				if ($this->options['log']) {
-					CakeLog::write('geocode', 'Delay neccessary for \''.$address.'\'');
+					CakeLog::write('geocode', __('Delay necessary for address \'%s\'', $address));
 				}
 				$count++;
 			} else {
@@ -434,13 +470,13 @@ class GeocodeLib {
 				$this->setError('Error '.$status.(isset($this->statusCodes[$status]) ? ' ('.$this->statusCodes[$status].')' : ''));
 
 				if ($this->options['log']) {
-					CakeLog::write('geocode', 'Geocoder could not geocode \''.$address.'\'');
+					CakeLog::write('geocode', __('Could not geocode \'%s\'', $address));
 				}
 				return false; # for now...
 			}
 			if ($count > 5) {
 				if ($this->options['log']) {
-					CakeLog::write('geocode', 'Geocoder aborted after too many trials with \''.$address.'\'');
+					CakeLog::write('geocode', __('Aborted after too many trials with \'%s\'', $address));
 				}
 				$this->setError('Too many trials - abort');
 				return false;
@@ -667,10 +703,13 @@ class GeocodeLib {
 		return ceil($res);
 	}
 
-
+	/**
+	 * @throws CakeException
+	 * @return float $converterValue
+	 */
 	public function convert($value, $fromUnit, $toUnit) {
 		if (!isset($this->units[($fromUnit = strtoupper($fromUnit))]) || !isset($this->units[($toUnit = strtoupper($toUnit))])) {
-			return false;
+			throw new CakeException(__('Invalid Unit'));
 		}
 		if ($fromUnit == 'M') {
 			$value *= $this->units[$toUnit];
@@ -696,6 +735,8 @@ class GeocodeLib {
 	 * - 3:
 	 * - 4:
 	 * - 5:
+	 * @throws CakeException
+	 * @return float $coord
 	 * 2011-03-16 ms
 	 */
 	public static function blur($coord, $level = 0) {
@@ -715,9 +756,7 @@ class GeocodeLib {
 			case 5:
 				break;
 			default:
-				# wrong level, return value
-				trigger_error('Invalid level \''.h($level).'\'');
-				return $coord;
+				throw new CakeException(__('Invalid level \'%s\'', $level));
 		}
 		$scrambleVal = 0.000001 * mt_rand(1000,2000) * (mt_rand(0,1) === 0 ? 1 : -1);
 
@@ -726,7 +765,6 @@ class GeocodeLib {
 		//$scrambleVal *= (mt_rand(0,1) === 0 ? 1 : 2);
 		//$scrambleVal *= (float)(2^$level);
 
-		//die($scrambleVal.' '.$coord);
 		# TODO: + - by chance!!!
 		return $coord + $scrambleVal;
 	}

+ 84 - 97
Lib/MyCakeTestCase.php

@@ -2,19 +2,46 @@
 
 abstract class MyCakeTestCase extends CakeTestCase {
 
+
+/*** assert mods ***/
+
+/** enhanced **/
+
+	protected static function assertNotWithinMargin($result, $expected, $margin, $message = '') {
+		$upper = $result + $margin;
+		$lower = $result - $margin;
+		return self::assertFalse((($expected <= $upper) && ($expected >= $lower)), $message);
+	}
+
+	//deprecated?
+	public function assertIsNull($is, $title = null, $value = null, $message = '', $options = array()) {
+		$expectation = 'NULL';
+		self::_printTitle($expectation, $title, $options);
+		self::_printResult($is, $value, $options);
+		return $this->assertNull($is, $message);
+	}
+
+	//deprecated?
+	public function assertIsNotNull($is, $title = null, $value = null, $message = '', $options = array()) {
+		$expectation = 'NOT NULL';
+		self::_printTitle($expectation, $title, $options);
+		self::_printResult($is, $value, $options);
+		return $this->assertNotNull($is, $message);
+	}
+	
 /*** time needed ***/
 
 	protected static $startTime = null;
 
-	public function _microtime($precision = 8) {
+	protected function _microtime($precision = 8) {
 		return round(microtime(true), $precision);
 	}
 
-	public function _startClock($precision = 8) {
+	protected function _startClock($precision = 8) {
 		self::$startTime = self::_microtime();
 	}
 
-	public function _elapsedTime($precision = 8, $restart = false) {
+	protected function _elapsedTime($precision = 8, $restart = false) {
 		$elapsed = self::_microtime() - self::$startTime;
 		if ($restart) {
 			self::_startClock();
@@ -22,23 +49,6 @@ abstract class MyCakeTestCase extends CakeTestCase {
 		return round($elapsed, $precision);
 	}
 
-	public function _header($title) {
-		if (strpos($title, 'test') === 0) {
-			$title = substr($title, 4);
-			$title = Inflector::humanize(Inflector::underscore($title));
-		}
-		return '<h3>'.$title.'</h3>';
-	}
-
-	/**
-	 * without trailing slash!?
-	 * //TODO: test
-	 * 2011-04-03 ms
-	 */
-	public function _baseurl() {
-		return current(split("webroot", $_SERVER['PHP_SELF']));
-	}
-
 /*
 # cakephp2 phpunit wrapper
 	public function assertEquals($expected, $actual, $title = null, $value = null, $message = '', $options = array()) {
@@ -55,9 +65,31 @@ abstract class MyCakeTestCase extends CakeTestCase {
 	}
 */
 
-# helper methods
+/*** Helper Functions **/
+
 
-	public function _basePath($full = false) {
+	/**
+	 * outputs debug information during a web tester (browser) test case
+	 * since PHPUnit>=3.6 swallowes all output by default 
+	 * this is a convenience output handler since debug() or pr() have no effect
+	 * @param mixed $data
+	 * @param bool $pre should a pre tag be enclosed around the output
+	 * @return void
+	 * 2011-12-04 ms
+	 */
+	public function out($data, $pre = true) {
+		if ($pre) {
+			$data = pre($data);
+		}
+		echo $data;
+		if (empty($_SERVER['HTTP_HOST'])) {
+			# cli mode / shell access: use the --debug modifier if you are using the CLI interface
+			return;
+		}
+		ob_flush();
+	}
+	
+	protected function _basePath($full = false) {
 		$phpSelf = $_SERVER['PHP_SELF'];
 		if (strpos($phpSelf, 'webroot/test.php') !== false) {
 			$pieces = explode('webroot/test.php', $phpSelf, 2);
@@ -71,6 +103,23 @@ abstract class MyCakeTestCase extends CakeTestCase {
 		}
 		return $url;
 	}
+	
+	protected function _header($title) {
+		if (strpos($title, 'test') === 0) {
+			$title = substr($title, 4);
+			$title = Inflector::humanize(Inflector::underscore($title));
+		}
+		return '<h3>'.$title.'</h3>';
+	}
+
+	/**
+	 * without trailing slash!?
+	 * //TODO: test
+	 * 2011-04-03 ms
+	 */
+	protected function _baseurl() {
+		return current(split("webroot", $_SERVER['PHP_SELF']));
+	}
 
 	/**
 	 * @param float $time
@@ -78,7 +127,7 @@ abstract class MyCakeTestCase extends CakeTestCase {
 	 * @param bool $secs: usually in milliseconds (for long times set it to 'true')
 	 * 2009-07-20 ms
 	 */
-	public function _printElapsedTime($time = null, $precision = 8, $secs = false) {
+	protected function _printElapsedTime($time = null, $precision = 8, $secs = false) {
 		if ($time === null) {
 			$time = self::_elapsedTime($precision);
 		}
@@ -95,59 +144,7 @@ abstract class MyCakeTestCase extends CakeTestCase {
 		pr('elapsedTime: '.number_format($time, $precision, ',', '.').' '.$unit);
 	}
 
-
-/*** assert mods ***/
-
-/** enhanced **/
-
-	public static function assertNull($is, $title = null, $value = null, $message = '', $options = array()) {
-		$expectation = 'NULL';
-		self::_printTitle($expectation, $title, $options);
-		self::_printResult($is, $value, $options);
-		return parent::assertNull($is, $message);
-	}
-
-	public static function assertNotNull($is, $title = null, $value = null, $message = '', $options = array()) {
-		$expectation = 'NOT NULL';
-		self::_printTitle($expectation, $title, $options);
-		self::_printResult($is, $value, $options);
-		return parent::assertNotNull($is, $message);
-	}
-
-	/**
-	 * own function: notEmpty
-	 * FAIL on: array(), NULL, '', false, 0
-	 * 2009-07-09 ms
-	 */
-
-	//deprecated
-	public static function assertNotEmpty($is, $title = null, $value = null, $message = '') {
-		$expectation = 'NOT EMPTY';
-		self::_printTitle($expectation, $title);
-		self::_printResult($is, $value);
-		return parent::assertTrue(!empty($is), $message);
-	}
-
-	//deprecated
-	public static function assertIsTrue($is, $title = null, $value = null, $message = '') {
-		$expectation = 'TRUE';
-		echo self::_title($expectation, $title);
-		self::_printResult($is, $value);
-		return parent::assertTrue($is, $message);
-	}
-
-	//deprecated
-	public static function assertIsFalse($is, $title = null, $value = null, $message = '') {
-		$expectation = 'FALSE';
-		echo self::_title($expectation, $title);
-		self::_printResult($is, $value);
-		return parent::assertFalse($is, $message);
-	}
-
-
-/*** Helper Functions **/
-
-	public function _title($expectation, $title = null) {
+	protected function _title($expectation, $title = null) {
 		$eTitle = '{expects: '.$expectation.'}';
 		if (!empty($title)) {
 			$eTitle = $title.' '.$eTitle;
@@ -155,14 +152,14 @@ abstract class MyCakeTestCase extends CakeTestCase {
 		return BR.BR.'<b>'.$eTitle.'</b>'.BR;
 	}
 
-	public function _printTitle($expectation, $title = null) {
+	protected function _printTitle($expectation, $title = null) {
 		if (empty($_SERVER['HTTP_HOST']) || !isset($_GET['show_passes']) || !$_GET['show_passes']) {
 			return false;
 		}
 		echo self::_title($expectation, $title);
 	}
 
-	public function _printResults($expected, $is, $pre = null, $status = false) {
+	protected function _printResults($expected, $is, $pre = null, $status = false) {
 		if (empty($_SERVER['HTTP_HOST']) || !isset($_GET['show_passes']) || !$_GET['show_passes']) {
 			return false;
 		}
@@ -179,7 +176,7 @@ abstract class MyCakeTestCase extends CakeTestCase {
 		}
 	}
 
-	public function _printResult($is, $pre = null, $status = false) {
+	protected function _printResult($is, $pre = null, $status = false) {
 		if (empty($_SERVER['HTTP_HOST']) || !isset($_GET['show_passes']) || !$_GET['show_passes']) {
 			return false;
 		}
@@ -191,27 +188,17 @@ abstract class MyCakeTestCase extends CakeTestCase {
 		echo 'result is:';
 		pr($is);
 	}
-
+	
 	/**
-	 * outputs debug information during a web tester (browser) test case
-	 * since PHPUnit>=3.6 swallowes all output by default 
-	 * this is a convenience output handler since debug() or pr() have no effect
-	 * @param mixed $data
-	 * @param bool $pre should a pre tag be enclosed around the output
-	 * @return void
-	 * 2011-12-04 ms
+	 * osFix method
+	 *
+	 * @param string $string
+	 * @return string
 	 */
-	public function out($data, $pre = true) {
-		if ($pre) {
-			$data = pre($data);
-		}
-		echo $data;
-		if (empty($_SERVER['HTTP_HOST'])) {
-			# cli mode / shell access: use the --debug modifier if you are using the CLI interface
-			return;
-		}
-		ob_flush();
+	protected function _osFix($string) {
+		return str_replace(array("\r\n", "\r"), "\n", $string);
 	}
 
+
 }
 

+ 69 - 53
Test/Case/Lib/GeocodeLibTest.php

@@ -1,6 +1,7 @@
 <?php
 
 App::uses('GeocodeLib', 'Tools.Lib');
+App::uses('MyCakeTestCase', 'Tools.Lib');
 
 # google maps
 Configure::write('Google', array(
@@ -12,19 +13,19 @@ Configure::write('Google', array(
 	'type' => 'G_NORMAL_MAP'
 ));
 
-class GeocodeLibTest extends CakeTestCase {
+class GeocodeLibTest extends MyCakeTestCase {
 
 	public function setUp() {
-		$this->GeocodeLib = new GeocodeLib();
+		$this->Geocode = new GeocodeLib();
 	}
 
 	public function TearDown() {
-		unset($this->GeocodeLib);
+		unset($this->Geocode);
 	}
 	
 	public function testObject() {
-		$this->assertTrue(is_object($this->GeocodeLib));
-		$this->assertTrue(is_a($this->GeocodeLib, 'GeocodeLib'));
+		$this->assertTrue(is_object($this->Geocode));
+		$this->assertTrue(is_a($this->Geocode, 'GeocodeLib'));
 	}
 
 
@@ -36,7 +37,7 @@ class GeocodeLibTest extends CakeTestCase {
 		);
 
 		foreach ($coords as $coord) {
-			$is = $this->GeocodeLib->distance($coord['x'], $coord['y']);
+			$is = $this->Geocode->distance($coord['x'], $coord['y']);
 			echo $coord['name'].':';
 			pr('is: '.$is.' - expected: '.$coord['d']);
 			$this->assertEquals($coord['d'], $is);
@@ -44,6 +45,20 @@ class GeocodeLibTest extends CakeTestCase {
 
 	}
 
+
+	public function testBlur() {
+		$coords = array(
+			array(48.1391, 1, 0.002), //'y'=>array('lat'=>48.8934, 'lng'=>8.70492), 'd'=>228),
+			array(11.5802, 1, 0.002),
+		);
+		foreach ($coords as $coord) {
+			$is = $this->Geocode->blur($coord[0], $coord[1]);
+			//pr('is: '.$is.' - expected: '.$coord[0].' +- '.$coord[2]); ob_flush();
+			$this->assertWithinMargin($is, $coord[0], $coord[2]);
+			$this->assertNotWithinMargin($is, $coord[0], $coord[2] / 4);
+		}
+	}
+
 	public function testConvert() {
 		$values = array(
 			array(3, 'M', 'K', 4.828032),
@@ -51,7 +66,7 @@ class GeocodeLibTest extends CakeTestCase {
 			array(100000, 'I', 'K', 2.54),
 		);
 		foreach ($values as $value) {
-			$is = $this->GeocodeLib->convert($value[0], $value[1], $value[2]);
+			$is = $this->Geocode->convert($value[0], $value[1], $value[2]);
 			echo $value[0].$value[1].' in '.$value[2].':';
 			pr('is: '.returns($is).' - expected: '.$value[3]);
 			$this->assertEquals($value[3], round($is, 8));
@@ -60,7 +75,7 @@ class GeocodeLibTest extends CakeTestCase {
 
 
 	public function testUrl() {
-		$is = $this->GeocodeLib->url();
+		$is = $this->Geocode->url();
 		pr($is);
 		$this->assertTrue(!empty($is) && startsWith($is, 'http://maps.google.de/maps/api/geocode/xml?'));
 	}
@@ -69,13 +84,13 @@ class GeocodeLibTest extends CakeTestCase {
 	// not possible with protected method
 	public function _testFetch() {
 		$url = 'http://maps.google.com/maps/api/geocode/xml?sensor=false&address=74523';
-		$is = $this->GeocodeLib->_fetch($url);
+		$is = $this->Geocode->_fetch($url);
 		//echo returns($is);
 
 		$this->assertTrue(!empty($is) && substr($is, 0, 38) == '<?xml version="1.0" encoding="UTF-8"?>');
 
 		$url = 'http://maps.google.com/maps/api/geocode/json?sensor=false&address=74523';
-		$is = $this->GeocodeLib->_fetch($url);
+		$is = $this->Geocode->_fetch($url);
 		//echo returns($is);
 		$this->assertTrue(!empty($is) && substr($is, 0, 1) == '{');
 
@@ -87,67 +102,69 @@ class GeocodeLibTest extends CakeTestCase {
 
 
 	public function testSetOptions() {
-		$this->GeocodeLib->setOptions(array('host'=>'xx'));
-		# should remain ".com"
-		$res = $this->GeocodeLib->url();
-		pr($res);
-
-		$this->GeocodeLib->setOptions(array('host'=>'de'));
-		# should now be ".de"
-		$res = $this->GeocodeLib->url();
-		pr($res);
-
-		# now DE
-
+		# should be the default
+		$res = $this->Geocode->url();
+		$this->assertTextContains('maps.google.de', $res);
+
+		$this->Geocode->setOptions(array('host'=>'it'));
+		# should now be ".it"
+		$res = $this->Geocode->url();
+		$this->assertTextContains('maps.google.it', $res);
 	}
 
+	/**
+	 * @expectedException CakeException
+	 */
+	public function testSetInvalidOptions() {
+		$this->Geocode->setOptions(array('host'=>'xx'));
+	}
 
 	public function testGeocode() {
 		$address = '74523 Deutschland';
 		echo '<h2>'.$address.'</h2>';
-		$is = $this->GeocodeLib->geocode($address);
+		$is = $this->Geocode->geocode($address);
 		echo returns($is);
 		$this->assertTrue($is);
 
-		$is = $this->GeocodeLib->getResult();
+		$is = $this->Geocode->getResult();
 		echo returns($is);
 		$this->assertTrue(!empty($is));
 
-		$is = $this->GeocodeLib->error();
+		$is = $this->Geocode->error();
 		echo returns($is);
 		$this->assertTrue(empty($is));
 
 
 		$address = 'Leopoldstraße 100, München';
 		echo '<h2>'.$address.'</h2>';
-		$is = $this->GeocodeLib->geocode($address);
+		$is = $this->Geocode->geocode($address);
 		echo returns($is);
 		$this->assertTrue($is);
 
-		pr($this->GeocodeLib->debug());
+		pr($this->Geocode->debug());
 
-		$is = $this->GeocodeLib->getResult();
+		$is = $this->Geocode->getResult();
 		echo returns($is);
 		$this->assertTrue(!empty($is));
 
-		$is = $this->GeocodeLib->error();
+		$is = $this->Geocode->error();
 		echo returns($is);
 		$this->assertTrue(empty($is));
 
 
 		$address = 'Oranienburger Straße 87, 10178 Berlin, Deutschland';
 		echo '<h2>'.$address.'</h2>';
-		$is = $this->GeocodeLib->geocode($address);
+		$is = $this->Geocode->geocode($address);
 		echo returns($is);
 		$this->assertTrue($is);
 
-		pr($this->GeocodeLib->debug());
+		pr($this->Geocode->debug());
 
-		$is = $this->GeocodeLib->getResult();
+		$is = $this->Geocode->getResult();
 		echo returns($is);
 		$this->assertTrue(!empty($is));
 
-		$is = $this->GeocodeLib->error();
+		$is = $this->Geocode->error();
 		echo returns($is);
 		$this->assertTrue(empty($is));
 
@@ -156,13 +173,13 @@ class GeocodeLibTest extends CakeTestCase {
 	public function testGeocodeInvalid() {
 		$address = 'Hjfjosdfhosj, 78878 Mdfkufsdfk';
 		echo '<h2>'.$address.'</h2>';
-		$is = $this->GeocodeLib->geocode($address);
+		$is = $this->Geocode->geocode($address);
 		echo returns($is);
 		$this->assertFalse($is);
 
-		pr($this->GeocodeLib->debug());
+		pr($this->Geocode->debug());
 
-		$is = $this->GeocodeLib->error();
+		$is = $this->Geocode->error();
 		echo returns($is);
 		$this->assertTrue(!empty($is));
 	}
@@ -171,12 +188,12 @@ class GeocodeLibTest extends CakeTestCase {
 	public function testGeocodeMinAcc() {
 		$address = 'Deutschland';
 		echo '<h2>'.$address.'</h2>';
-		$this->GeocodeLib->setOptions(array('min_accuracy'=>3));
-		$is = $this->GeocodeLib->geocode($address);
+		$this->Geocode->setOptions(array('min_accuracy'=>3));
+		$is = $this->Geocode->geocode($address);
 		echo returns($is);
 		$this->assertFalse($is);
 
-		$is = $this->GeocodeLib->error();
+		$is = $this->Geocode->error();
 		echo returns($is);
 		$this->assertTrue(!empty($is));
 	}
@@ -190,28 +207,28 @@ class GeocodeLibTest extends CakeTestCase {
 		echo '<h2>'.$address.'</h2>';
 
 		# allow_inconclusive = TRUE
-		$this->GeocodeLib->setOptions(array('allow_inconclusive'=>true));
-		$is = $this->GeocodeLib->geocode($address);
+		$this->Geocode->setOptions(array('allow_inconclusive'=>true));
+		$is = $this->Geocode->geocode($address);
 		echo 'debug:';
-		pr($this->GeocodeLib->debug());
+		pr($this->Geocode->debug());
 		echo 'debug end';
 		$this->assertTrue($is);
 
-		$res = $this->GeocodeLib->getResult();
+		$res = $this->Geocode->getResult();
 		pr($res);
 		$this->assertTrue(count($res) > 4);
 
-		$is = $this->GeocodeLib->isInconclusive();
+		$is = $this->Geocode->isInconclusive();
 		$this->assertTrue($is);
 
 
 		# allow_inconclusive = FALSE
-		$this->GeocodeLib->setOptions(array('allow_inconclusive'=>false));
-		$is = $this->GeocodeLib->geocode($address);
+		$this->Geocode->setOptions(array('allow_inconclusive'=>false));
+		$is = $this->Geocode->geocode($address);
 		echo returns($is);
 		$this->assertFalse($is);
 
-		$is = $this->GeocodeLib->error();
+		$is = $this->Geocode->error();
 		echo returns($is);
 		$this->assertTrue(!empty($is));
 
@@ -220,20 +237,19 @@ class GeocodeLibTest extends CakeTestCase {
 
 	public function testReverseGeocode() {
 		$coords = array(
-			array(-34.594445, -58.37446, 'Florida 1134-1200, Buenos Aires, Capital Federal, Argentinien'),
+			array(-34.594445, -58.37446, 'Calle Florida 1134-1200, Buenos Aires'),
 			array(48.8934, 8.70492, 'B294, 75175 Pforzheim, Deutschland')
 		);
 
 		foreach ($coords as $coord) {
-			$is = $this->GeocodeLib->reverseGeocode($coord[0], $coord[1]);
-			echo returns($is);
+			$is = $this->Geocode->reverseGeocode($coord[0], $coord[1]);
 			$this->assertTrue($is);
 
-			$is = $this->GeocodeLib->getResult();
+			$is = $this->Geocode->getResult();
 			$this->assertTrue(!empty($is));
-			echo returns($is);
+			//echo returns($is); ob_flush();
 			$address = isset($is[0]) ? $is[0]['formatted_address'] : $is['formatted_address'];
-			$this->assertEquals($coord[2], $address);
+			$this->assertTextContains($coord[2], $address);
 		}
 
 	}