Location: PHPKode > scripts > Geocoder > geocoder/GeocoderTests.php
<?php
require_once ('lib/simpletest/unit_tester.php');
require_once ('lib/simpletest/reporter.php');

require_once ('USGeocoder.inc');
require_once ('WorldGeocoder.inc');
require_once ('GoogleGeocoder.inc');
require_once ('MathUtils.inc');

class GeocoderTest extends UnitTestCase {

    protected function testResult ($actual, $expect, $label='')
    {
        //print_array($expect, 'expect');
        //print_array($actual, 'actual');
        $lat = $actual["latitude"] ;
        $lon = $actual["longitude"] ;
        $err = $actual["error"] ;
        list($expectLat,$expectLon,$expectErr) = $expect ;

        $this->assertTrue (abs($lat - $expect[0]) < 0.05, $label." with $lat != $expectLat") ; // we should check that difference < delta..
        $this->assertTrue (abs($lon - $expect[1]) < 0.05, $label." with $lon != $expectLon") ;
        $this->assertEqual ($err, $expect[2], $label." with $err != $expectErr") ;
    }

}

class USGeoCoderTest extends GeocoderTest {

    //
    // Validate US Geocoder
    //
    public function testZIP ()
    {
        // The zipcode of Sunnyvale, headquarters of Yahoo...
        $test = new USGeocoder ("US", "94089-1019") ;
        $result = $test->submit() ;
        $this->testResult($result, array("37.402414", "-122.008017", null)) ;

        $test = new USGeocoder ("US", "89883") ;
        $result = $test->submit() ;
        $this->testResult($result, array("40.735472", "-114.065667", null)) ;
    }

    public function testCityState ()
    {
        // headquarters of Yahoo...
        $test = new USGeocoder ("US", null, "Sunnyvale", "CA") ;
        $result = $test->submit() ;
        $this->testResult($result, array("37.371612", "-122.038258", null)) ;
    }

    public function testInvalidZip ()
    {
        $test = new USGeocoder ("US", "99999") ;
        $result = $test->submit() ;
        $this->testResult($result, array(null, null, "Could not geocode ,US")) ;
    }

    public function testCityWithSpace ()
    {
        $test = new USGeocoder ("US", null, "san francisco", "ca") ;
        $result = $test->submit() ;
        $this->testResult($result, array("37.779160", "-122.420049", null)) ;
    }

    public function testNulls ()
    {
        $test = new USGeocoder ("US", null, null, null) ;
        $result = $test->submit() ;
        $this->testResult($result, array(null, null, "Could not geocode ,US")) ;
    }

    //
    // Validate the US Geocoder parser
    //

    public function testLimitReached ()
    {
        $input = <<<TESTXML
					<Error xmlns="urn:yahoo:api"
				xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
				xsi:noNamespaceSchemaLocation="http://api.yahoo.com/Api/V1/error.xsd">
				The following errors were detected:
				<Message>limit exceeded</Message>
				</Error>
TESTXML;
        $test = new USGeocoder (null, null, null) ;
        $result = $test->parseResult ($input) ;
        $this->assertNull ($result) ;
    }

    public function testDoubleInfo ()
    {
        $input = <<<TESTXML
					<?xml version="1.0" encoding="UTF-8"?>
				<ResultSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:yahoo:maps" xsi:schemaLocation="urn:yahoo:maps http://api.local.yahoo.com/MapsService/V1/GeocodeResponse.xsd">
				<Result precision="address">
				<Latitude>37.416384</Latitude>
				<Latitude>99</Latitude>
				<Longitude>-122.024853</Longitude>
				<Address>701 FIRST AVE</Address>
				<City>SUNNYVALE</City>
				<State>CA</State>
				<Zip>94089-1019</Zip>
				<Country>US</Country>
				</Result>
				</ResultSet>
TESTXML;
        $test = new USGeocoder (null, null, null) ;
        $result = $test->parseResult (trim($input)) ;
        $this->assertNull ($result) ;
    }

    public function testDoubleInfo2 ()
    {
        $input = <<<TESTXML
					<?xml version="1.0" encoding="UTF-8"?>
				<ResultSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:yahoo:maps" xsi:schemaLocation="urn:yahoo:maps http://api.local.yahoo.com/MapsService/V1/GeocodeResponse.xsd">
				<Result precision="address">
				<Latitude>37.416384</Latitude>
				<Longitude>-122.024853</Longitude>
				<Longitude>99</Longitude>
				<Address>701 FIRST AVE</Address>
				<City>SUNNYVALE</City>
				<State>CA</State>
				<Zip>94089-1019</Zip>
				<Country>US</Country>
				</Result>
				</ResultSet>
TESTXML;
        $test = new USGeocoder (null, null, null) ;
        $result = $test->parseResult (trim($input)) ;
        $this->assertNull ($result) ;
    }

    public function testNoInfo ()
    {
        $input = <<<TESTXML
					<?xml version="1.0" encoding="UTF-8"?>
				<ResultSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:yahoo:maps" xsi:schemaLocation="urn:yahoo:maps http://api.local.yahoo.com/MapsService/V1/GeocodeResponse.xsd">
				<Result precision="address">
				<Longitude>-122.024853</Longitude>
				<Address>701 FIRST AVE</Address>
				<City>SUNNYVALE</City>
				<State>CA</State>
				<Zip>94089-1019</Zip>
				<Country>US</Country>
				</Result>
				</ResultSet>
TESTXML;
        $test = new USGeocoder (null, null, null) ;
        $result = $test->parseResult (trim($input)) ;
        $this->assertNull ($result) ;
    }

    public function testNoInfo2 ()
    {
        $input = <<<TESTXML
					<?xml version="1.0" encoding="UTF-8"?>
				<ResultSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:yahoo:maps" xsi:schemaLocation="urn:yahoo:maps http://api.local.yahoo.com/MapsService/V1/GeocodeResponse.xsd">
				<Result precision="address">
				<Latitude>37.416384</Latitude>
				<Address>701 FIRST AVE</Address>
				<City>SUNNYVALE</City>
				<State>CA</State>
				<Zip>94089-1019</Zip>
				<Country>US</Country>
				</Result>
				</ResultSet>
TESTXML;
        $test = new USGeocoder (null, null, null) ;
        $result = $test->parseResult (trim($input)) ;
        $this->assertNull ($result) ;
    }
}

class WorldGeoCoderTest extends GeocoderTest {

    // Validate World Geocoder
    public function testWorldZIP ()
    {
        // The zipcode of Sunnyvale, headquarters of Yahoo...
        $test = new WorldGeocoder ("US", "94089-1019") ;
        $result = $test->submit() ;
        $this->testResult($result, array("37.189396", "-121.705327", null)) ;
    }

    public function testWorldZIP2 ()
    {
        // The zipcode of Sunnyvale, headquarters of Yahoo...
        // idem, but with 5 char zipcode
        $test = new WorldGeocoder ("US", "94089") ;
        $result = $test->submit() ;
        $this->testResult($result, array("37.189396", "-121.705327", null)) ;
    }

    public function testWorldCity ()
    {
        $test = new WorldGeocoder ("US", NULL, "San Francisco", "CA") ;
        $result = $test->submit() ;
        $this->testResult($result, array("37.784827", "-122.727802", null)) ;

        // put the state inside the city
        $test = new WorldGeocoder ("US", NULL, "San Francisco, ca") ;
        $result = $test->submit() ;
        $this->testResult($result, array("37.784827", "-122.727802", null)) ;

        // canada cities can also have a state
        $test = new WorldGeocoder ("CA", NULL, "Toronto, ON") ;
        $result = $test->submit() ;
        //print_array($result);
        //$this->testResult($result, array("37.784827", "-122.727802", null)) ;
    }

    public function testGeoCode () {
        $result = WorldGeocoder::geoCode('US', "94089", "Sunnyvale, ca") ;
        $this->testResult($result, array("37.189396", "-121.705327", null)) ;

        $result = WorldGeocoder::geoCode('US', '99999', "Sunnyvale, ca") ;
        $this->testResult($result, array("37.189396", "-121.705327", null)) ;
    }

    public function testWorldCity2 ()
    {
        $test = new WorldGeocoder ("BE", NULL, "Mechelen", NULL) ;
        $result = $test->submit() ;
        $this->testResult($result, array("51.0333333", "4.4666667", null)) ;
    }

    public function testWorldCity3 ()
    {// test with accented characters
        $test = new WorldGeocoder ("BE", NULL, html_entity_decode("La Louvi&egrave;re", NULL, 'UTF-8'), NULL) ;
        $result = $test->submit() ;
        $this->testResult($result, array("50.4666667", "4.1833333", null)) ;
    }

    public function testWorldInvalidCity ()
    {
        // invalid city no zip
        $test = new WorldGeocoder ("BE", NULL, "Tiznoland", NULL) ;
        $result = $test->submit() ;
        //print_array ($result) ;
        $this->testResult($result, array(NULL, NULL, "no_geocode")) ;

        // valid zip invalid city
        $test = new WorldGeocoder ("BE", "2800", "Tiznoland", NULL) ;
        $result = $test->submit() ;
        //print_array ($result) ;
        $this->testResult($result, array(NULL, NULL, "no_geocode")) ;

        $test = new WorldGeocoder ("UK", NULL, "PRESCOTT, MERSEYSIDE", NULL) ;
        $result = $test->submit() ;
        //print_array ($result) ;
        $this->testResult($result, array(NULL, NULL, "no_geocode")) ;
    }

    public function testWorldInvalidZIP ()
    {
        $test = new WorldGeocoder ("US", "99999", NULL, NULL) ;
        $result = $test->submit() ;
        $this->testResult($result, array(NULL, NULL, "no_geocode")) ;

        // cityname has precedence over invalid zip...
        $test = new WorldGeocoder ("BE", "28888", "Mechelen", NULL) ;
        $result = $test->submit() ;
        $this->testResult($result, array("51.0333333", "4.4666667", NULL)) ;
    }

    public function testWorldAllNull ()
    {
        $test = new WorldGeocoder (NULL, NULL, NULL, NULL) ;
        $result = $test->submit() ;
        $this->testResult($result, array(NULL, NULL, 'Could not geocode ,')) ;
    }

    public function testWorldBad () {
        // the input is wrong because of input error, hence all input shifts...
        $test = new WorldGeocoder ("BEAUMONT,TX", "www.artstudio.org", 77701) ;
        $result = $test->submit() ;
        //print_array($result);
        $this->testResult($result, array(NULL, NULL, 'no_geocode')) ;
    }

    //
    // Validate the World Geocoder parser
    //

    public function testWorldParser ()
    {
        $input = <<<TESTXML
					<rdf:RDF>
				<geo:Point>
				<geo:long>-0.15</geo:long>
				<geo:lat>50.8333333</geo:lat>
				</geo:Point>
				</rdf:RDF>
TESTXML;
        $test = new WorldGeocoder (null, null, null, null) ;
        $result = $test->parseResult ($input) ;
        $this->testResult($result, array("50.8333333", "-0.15", null)) ;
    }

}

class GoogleGeoCoderTest extends GeocoderTest {

    public function testGoogleCity ()
    {
        $testList = array (
        array ('US', 'San Francisco', "37.775000", "-122.418333"),
        array ('US', 'San Francisco, ca', "37.775000", "-122.418333"),
        array ('US', 'West Wendover,NV', "40.739167", "-114.072500"),
        array ('US', ' Molena,ga', "33.011944", "-84.500278"),
        array ('CA', 'Toronto,ON', "43.670233", "-79.392486"),
        array ('BE', 'Mechelen', "51.029998", "4.469999"),
        array ('GM', 'Koln', "50.940664",  "6.959911"),
        array ('BE', 'La Louvi&egrave;re', "50.490001", "4.230000")
        ) ;

        foreach ($testList as $oneTest) {
            list ($country,$city,$lat,$lon) = $oneTest ;
            $city = html_entity_decode($city, NULL, 'UTF-8') ;

            $test = new GoogleGeocoder ($country, NULL, $city) ;
            $result = $test->submit() ;
            //print_array($result);
            $this->testResult($result, array($lat, $lon, null)) ;
        }
    }

    public function testGoogleZipCode () {
        $testList = array (
        array ('94089', "Sunnyvale, ca", "37.398255", "-122.000637", null),
        //array ('99999', "Sunnyvale, ca", NULL, NULL, 'no_geocode'),
        array ('94089', NULL, "37.398255", "-122.000637", null),
        array ('94089', "Sunnyvale", "37.398255", "-122.000637", null),
        array ('89883', NULL, "40.878962", "-114.154526", null),
        ) ;

        foreach ($testList as $oneTest) {
            list($zip, $city, $expectLat, $expectLon, $expectErr) = $oneTest ;
            sleep(1) ;
            $test = new GoogleGeocoder('US', $zip, $city) ;
            $result = $test->submit() ;
            //print_array($result);
            $this->testResult($result, array($expectLat, $expectLon, $expectErr)) ;
        }
    }

    public function testGoogleZipCode2 () {
        $testList = array (

        array ('2018', 'Antwerpen', 'BE', 0, 0),
        array ('2030', 'Antwerpen', 'BE', 0, 0),
        // array ('NW1 8AB', 'London', 'UK', 0, 0),   UK not yet supported in Google
        array ('75020', 'Paris', 'FR', 0, 0),
        array ('75009', 'Paris', 'FR', 0, 0),
        array (NULL, 'K&ouml;ln', 'GM', 0, 0),   // '51063'
        array ('50674', 'K&ouml;ln', 'GM', 0, 0),
        array ('28914', 'Madrid', 'SP', 0, 0),
        array ('1030', 'Wien', 'AU', 0, 0),
        array ('1110', 'Wien', 'AU', 0, 0),
        array (NULL, 'Z&uuml;rich', 'SZ', 0, 0), // '8050'
        array ('8022', 'Z&uuml;rich', 'SZ', 0, 0),
        array (NULL, 'Montr&eacute;al,QC', 'CA', 0, 0), // 'H2R2W1'
        array ('H2X 3K2', 'Montr&eacute;al,QC', 'CA', 0, 0),
        array ('1101 DS', 'Amsterdam', 'NL', 0, 0),
        array ('1071 LN', 'Amsterdam', 'NL', 0, 0),
        array ('1000', 'K&oslash;benhavn',  'DA', 0, 0),
        array ('1369', 'K&oslash;benhavn',  'DA', 0, 0),
        array ('2300', 'K&oslash;benhavn', 'DA', 0, 0),

        ) ;

        foreach ($testList as $oneTest) {
            sleep (1) ;

            list ($zip,$city,$country,$lon,$lat) = $oneTest ;
            $city = html_entity_decode($city, NULL, 'UTF-8');
            $test = new GoogleGeocoder($country, $zip, $city) ;
            $result = $test->submit() ;
            //print_array($result);

            $verify = new GoogleGeocoder($country, NULL, $city) ;
            $expect = $verify->submit() ;

            //echo("<hr>$city");
            //print_array($result); print_array($expect);
            $distance = distance($result['latitude'], $result['longitude'], $expect['latitude'], $expect['longitude'], 'km') ;
            //echo("$distance<br>");
            $this->assertTrue ($distance < 15, "Distance $distance with $city, $country") ;
        }

    }

    public function testGoogleInvalidCity ()
    {
        // invalid city no zip
        $test = new GoogleGeocoder ("BE", NULL, "Tiznoland", NULL) ;
        $result = $test->submit() ;
        //print_array ($result) ;
        $this->testResult($result, array(NULL, NULL, "no_geocode")) ;

        // valid zip invalid city
        $test = new GoogleGeocoder ("BE", "2800", "Tiznoland", NULL) ;
        $result = $test->submit() ;
        //print_array ($result) ;
        $this->testResult($result, array(NULL, NULL, "no_geocode")) ;
    }

    public function testGoogleAllNull ()
    {
        $test = new GoogleGeocoder (NULL, NULL, NULL, NULL) ;
        $result = $test->submit() ;
        $this->testResult($result, array(NULL, NULL, 'no_geocode')) ;
    }

    public function testGeocoderGeocode () {
        $testList = array (
        array ('US', 'San Francisco',       '94115', "37.775000", "-122.418333"), // no WorldGeocoder as no state
        array ('BE', 'La Louvi&egrave;re',  '7100',  "50.4666667", "4.1833333"),
        array ("FI", "Jyv&auml;skyl&auml;", '40100', "62.2333333", "25.7333333"),
        array ("SP", "Bergara",             NULL,    "43.118217",   "-2.413358"),   // WorldGeo doesn't know city
        array ("GM", "K&ouml;ln",           '51063', "50.9333333", "6.95"),
        array ('NZ', 'Motueka',             NULL,   "-41.110107", "173.011121"),
        array ('NL', 'Amsterdam',           '1017 PH', "52.35", "4.9166667"),
        array ('NL', 'Amsterdam',           '9999XX', "52.35", "4.9166667"),  // illegal zip, fall back on city+country..
        ) ;

        foreach ($testList as $oneTest) {
            list ($country,$city,$zip, $lat,$lon) = $oneTest ;
            $city = html_entity_decode($city, NULL, 'UTF-8');

            $result = Geocoder::geoCode($country, NULL, $city) ;
            //print_array($result);
            $this->testResult($result, array($lat, $lon, null)) ;

            // now try again with zip code. Distance from old geocode should be less than 10km..
            $result1 = Geocoder::geoCode($country, $zip, $city) ;

            $distance = distance($result['latitude'], $result['longitude'], $result1['latitude'], $result1['longitude'], 'km') ;
            //print_array($result1, $city.$zip);
            $this->assertTrue ($distance < 10.0) ;
        }

        $result = Geocoder::geoCode('BE', NULL, 'Tiznoland') ;

        $this->testResult($result, array(NULL, NULL, 'no_geocode')) ;
    }

    public function testCheckValidPlace () {
        $this->assertTrue (Geocoder::checkValidPlace('Nijmegen', 'NL')) ;
        $this->assertTrue (Geocoder::checkValidPlace('Jena', 'GM')) ;
        $this->assertTrue (Geocoder::checkValidPlace('London', 'UK')) ;

        $this->assertFalse (Geocoder::checkValidPlace('Nijmegen', 'DK')) ;
        $this->assertFalse (Geocoder::checkValidPlace('Kiekeboe', 'BE')) ;

        // not-strict: there seems to be an Antwerpen in NL according to Google
        $this->assertTrue (Geocoder::checkValidPlace('Antwerpen', 'NL')) ;

        // but if we believe only WorldGeocoder, then not
        $this->assertFalse (Geocoder::checkValidPlace('Antwerpen', 'NL', true)) ;
    }

}

//--------------------------------------------------------------------------------



$testList = array (
'GeocoderTest' => new GeocoderTest(),
'USGeoCoderTest' => new USGeoCoderTest(),
'GoogleGeoCoderTest' => new GoogleGeoCoderTest(),
) ;

foreach ($testList as $oneName => $oneTest) {
    $tester = new GroupTest($oneName) ;
    $tester->addTestCase ($oneTest) ;
    $tester->run(new HtmlReporter("UTF-8")) ;
}

?>
Return current item: Geocoder