use blib; use Test::More; use strict; use warnings; use Data::Dumper; use_ok( "Geo::StreetAddress::US" ); my %address = ( "1005 Gravenstein Hwy 95472" => { 'number' => '1005', 'street' => 'Gravenstein', 'zip' => '95472', 'type' => 'Hwy', }, "1005 Gravenstein Hwy, 95472" => { 'number' => '1005', 'street' => 'Gravenstein', 'zip' => '95472', 'type' => 'Hwy', }, "1005 Gravenstein Hwy N, 95472" => { 'number' => '1005', 'street' => 'Gravenstein', 'zip' => '95472', 'suffix' => 'N', 'type' => 'Hwy', }, "1005 Gravenstein Highway North, 95472" => { 'number' => '1005', 'street' => 'Gravenstein', 'zip' => '95472', 'suffix' => 'N', 'type' => 'Hwy', }, "1005 N Gravenstein Highway, Sebastopol, CA" => { 'number' => '1005', 'street' => 'Gravenstein', 'state' => 'CA', 'city' => 'Sebastopol', 'type' => 'Hwy', 'prefix' => 'N' }, "1005 N Gravenstein Highway, Suite 500, Sebastopol, CA" => { 'number' => '1005', 'street' => 'Gravenstein', 'state' => 'CA', 'city' => 'Sebastopol', 'type' => 'Hwy', 'prefix' => 'N', 'sec_unit_type' => 'Suite', 'sec_unit_num' => '500', }, "1005 N Gravenstein Hwy Suite 500 Sebastopol, CA" => { 'number' => '1005', 'street' => 'Gravenstein', 'state' => 'CA', 'city' => 'Sebastopol', 'type' => 'Hwy', 'prefix' => 'N', 'sec_unit_type' => 'Suite', 'sec_unit_num' => '500', }, "1005 N Gravenstein Highway, Sebastopol, CA, 95472" => { 'number' => '1005', 'street' => 'Gravenstein', 'state' => 'CA', 'city' => 'Sebastopol', 'zip' => '95472', 'type' => 'Hwy', 'prefix' => 'N' }, "1005 N Gravenstein Highway Sebastopol CA 95472" => { 'number' => '1005', 'street' => 'Gravenstein', 'state' => 'CA', 'city' => 'Sebastopol', 'zip' => '95472', 'type' => 'Hwy', 'prefix' => 'N' }, "1005 Gravenstein Hwy N Sebastopol CA" => { 'number' => '1005', 'street' => 'Gravenstein', 'state' => 'CA', 'city' => 'Sebastopol', 'suffix' => 'N', 'type' => 'Hwy', }, "1005 Gravenstein Hwy N, Sebastopol CA" => { 'number' => '1005', 'street' => 'Gravenstein', 'state' => 'CA', 'city' => 'Sebastopol', 'suffix' => 'N', 'type' => 'Hwy', }, "1005 Gravenstein Hwy, N Sebastopol CA" => { 'number' => '1005', 'street' => 'Gravenstein', 'state' => 'CA', 'city' => 'North Sebastopol', 'type' => 'Hwy', }, "1005 Gravenstein Hwy, North Sebastopol CA" => { 'number' => '1005', 'street' => 'Gravenstein', 'state' => 'CA', 'city' => 'North Sebastopol', 'type' => 'Hwy', }, "1005 Gravenstein Hwy Sebastopol CA" => { 'number' => '1005', 'street' => 'Gravenstein', 'state' => 'CA', 'city' => 'Sebastopol', 'type' => 'Hwy', }, "115 Broadway San Francisco CA" => { 'type' => '', 'number' => '115', 'street' => 'Broadway', 'state' => 'CA', 'city' => 'San Francisco', }, "7800 Mill Station Rd, Sebastopol, CA 95472" => { 'number' => '7800', 'street' => 'Mill Station', 'state' => 'CA', 'city' => 'Sebastopol', 'zip' => '95472', 'type' => 'Rd', }, "7800 Mill Station Rd Sebastopol CA 95472" => { 'number' => '7800', 'street' => 'Mill Station', 'state' => 'CA', 'city' => 'Sebastopol', 'zip' => '95472', 'type' => 'Rd', }, "1005 State Highway 116 Sebastopol CA 95472" => { 'number' => '1005', 'street' => 'State Highway 116', 'state' => 'CA', 'city' => 'Sebastopol', 'zip' => '95472', 'type' => 'Hwy', }, "1600 Pennsylvania Ave. Washington DC" => { 'number' => '1600', 'street' => 'Pennsylvania', 'state' => 'DC', 'city' => 'Washington', 'type' => 'Ave', }, "1600 Pennsylvania Avenue Washington DC" => { 'number' => '1600', 'street' => 'Pennsylvania', 'state' => 'DC', 'city' => 'Washington', 'type' => 'Ave', }, "48S 400E, Salt Lake City UT" => { 'type' => '', 'number' => '48', 'street' => '400', 'state' => 'UT', 'city' => 'Salt Lake City', 'suffix' => 'E', 'prefix' => 'S' }, "550 S 400 E #3206, Salt Lake City UT 84111" => { 'number' => '550', 'street' => '400', 'state' => 'UT', 'sec_unit_num' => '3206', 'zip' => '84111', 'city' => 'Salt Lake City', 'suffix' => 'E', 'type' => '', 'sec_unit_type' => '#', 'prefix' => 'S' }, "6641 N 2200 W Apt D304 Park City, UT 84098" => { 'number' => '6641', 'street' => '2200', 'state' => 'UT', 'sec_unit_num' => 'D304', 'zip' => '84098', 'city' => 'Park City', 'suffix' => 'W', 'type' => '', 'sec_unit_type' => 'Apt', 'prefix' => 'N' }, "100 South St, Philadelphia, PA" => { 'number' => '100', 'street' => 'South', 'state' => 'PA', 'city' => 'Philadelphia', 'type' => 'St', }, "100 S.E. Washington Ave, Minneapolis, MN" => { 'number' => '100', 'street' => 'Washington', 'state' => 'MN', 'city' => 'Minneapolis', 'type' => 'Ave', 'prefix' => 'SE' }, "3813 1/2 Some Road, Los Angeles, CA" => { 'number' => '3813', 'street' => 'Some', 'state' => 'CA', 'city' => 'Los Angeles', 'type' => 'Rd', }, "Mission & Valencia San Francisco CA" => { 'type1' => '', 'type2' => '', 'street1' => 'Mission', 'state' => 'CA', 'city' => 'San Francisco', 'street2' => 'Valencia' }, "Mission & Valencia, San Francisco CA" => { 'type1' => '', 'type2' => '', 'street1' => 'Mission', 'state' => 'CA', 'city' => 'San Francisco', 'street2' => 'Valencia' }, "Mission St and Valencia St San Francisco CA" => { 'type1' => 'St', 'type2' => 'St', 'street1' => 'Mission', 'state' => 'CA', 'city' => 'San Francisco', 'street2' => 'Valencia' }, "Mission St & Valencia St San Francisco CA" => { 'type1' => 'St', 'type2' => 'St', 'street1' => 'Mission', 'state' => 'CA', 'city' => 'San Francisco', 'street2' => 'Valencia' }, "Mission and Valencia Sts San Francisco CA" => { 'type1' => 'St', 'type2' => 'St', 'street1' => 'Mission', 'state' => 'CA', 'city' => 'San Francisco', 'street2' => 'Valencia' }, "Mission & Valencia Sts. San Francisco CA" => { 'type1' => 'St', 'type2' => 'St', 'street1' => 'Mission', 'state' => 'CA', 'city' => 'San Francisco', 'street2' => 'Valencia' }, "Mission & Valencia Streets San Francisco CA" => { 'type1' => 'St', 'type2' => 'St', 'street1' => 'Mission', 'state' => 'CA', 'city' => 'San Francisco', 'street2' => 'Valencia' }, "Mission Avenue and Valencia Street San Francisco CA" => { 'type1' => 'Ave', 'type2' => 'St', 'street1' => 'Mission', 'state' => 'CA', 'city' => 'San Francisco', 'street2' => 'Valencia' }, "1 First St, e San Jose CA" => { # lower case city direction 'number' => '1', 'street' => 'First', 'state' => 'CA', 'city' => 'East San Jose', 'type' => 'St', }, "123 Maple Rochester, New York" => { # space in state name 'type' => '', 'number' => '123', 'street' => 'Maple', 'state' => 'NY', 'city' => 'Rochester', }, "233 S Wacker Dr 60606-6306" => { # zip+4 with hyphen 'number' => '233', 'street' => 'Wacker', 'zip' => '60606', 'type' => 'Dr', 'prefix' => 'S' }, "233 S Wacker Dr 606066306" => { # zip+4 without hyphen 'number' => '233', 'street' => 'Wacker', 'zip' => '60606', 'type' => 'Dr', 'prefix' => 'S' }, "233 S Wacker Dr lobby 60606" => { # unnumbered secondary unit type 'number' => '233', 'street' => 'Wacker', 'zip' => '60606', 'type' => 'Dr', 'prefix' => 'S', 'sec_unit_type' => 'lobby', }, "(233 S Wacker Dr lobby 60606)" => { # surrounding punctuation 'number' => '233', 'street' => 'Wacker', 'zip' => '60606', 'type' => 'Dr', 'prefix' => 'S', 'sec_unit_type' => 'lobby', }, "#42 233 S Wacker Dr 60606" => { # leading numbered secondary unit type 'sec_unit_num' => '42', 'zip' => '60606', 'number' => '233', 'street' => 'Wacker', 'sec_unit_type' => '#', 'type' => 'Dr', 'prefix' => 'S' }, "lt42 99 Some Road, Some City LA" => { # no space before sec_unit_num 'sec_unit_num' => '42', 'city' => 'Some City', 'number' => '99', 'street' => 'Some', 'sec_unit_type' => 'lt', 'type' => 'Rd', 'state' => 'LA' }, "36401 County Road 43, Eaton, CO 80615" => { # numbered County Road 'city' => 'Eaton', 'zip' => '80615', 'number' => '36401', 'street' => 'County Road 43', 'type' => 'Rd', 'state' => 'CO' }, "1234 COUNTY HWY 60E, Town, CO 12345" => { 'city' => 'Town', 'zip' => '12345', 'number' => '1234', 'street' => 'COUNTY HWY 60', 'suffix' => 'E', 'type' => '', # ? 'state' => 'CO' }, ); while (my ($addr, $expected) = each %address) { my $parse = Geo::StreetAddress::US->parse_location( $addr ); is_deeply( $parse, $expected, "can parse $addr" ) or warn "Got: ".Dumper($parse); } my @failures = ( "1005 N Gravenstein Hwy Sebastopol", "1005 N Gravenstein Hwy Sebastopol CZ", "Gravenstein Hwy 95472", "E1005 Gravenstein Hwy 95472", "1005E Gravenstein Hwy 95472", ); for my $fail (@failures) { my $parse = Geo::StreetAddress::US->parse_location( $fail ); ok( !$parse || !defined($parse->{state}), "can't parse $fail" ); } ok not Geo::StreetAddress::US->avoid_redundant_street_type; Geo::StreetAddress::US->avoid_redundant_street_type(1); ok Geo::StreetAddress::US->avoid_redundant_street_type; is_deeply Geo::StreetAddress::US->parse_location("36401 County Road 43, Eaton, CO 80615"), { 'city' => 'Eaton', 'zip' => '80615', 'number' => '36401', 'street' => 'County Road 43', 'type' => undef, # 'state' => 'CO' }, 'type should be undef for Country Road 43 with avoid_redundant_street_type'; # XXX TODO: a suffix like "COUNTY HWY 60E" breaks this logic # but not very badly, suffix='E', street='COUNTY HWY 60' and type='' (not undef) is_deeply Geo::StreetAddress::US->parse_location("1234 COUNTY HWY 60, Town, CO 12345"), { 'city' => 'Town', 'zip' => '12345', 'number' => '1234', 'street' => 'COUNTY HWY 60', 'type' => undef, 'state' => 'CO' }, 'type should be undef for COUNTY HWY 60 with avoid_redundant_street_type'; done_testing();