The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
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();