Making WordPress.org

Changeset 10546


Ignore:
Timestamp:
12/23/2020 09:33:48 PM (5 years ago)
Author:
iandunn
Message:

Events: Port more tests to PHPUnit.

Location:
sites/trunk/api.wordpress.org/public_html/events/1.0
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • sites/trunk/api.wordpress.org/public_html/events/1.0/index.php

    r10544 r10546  
    163163        /*
    164164         * In local development environments, the IP sent by the Events widget will typically be
    165          * private. In those cases, we can use the web server's IP address, which is the user's
    166          * actual public address.
     165         * private. In those cases, we can use the web server's IP address, which should be the same
     166         * as the dev's browser IP.
    167167         */
    168168        $public_ip = filter_var(
  • sites/trunk/api.wordpress.org/public_html/events/1.0/tests/test-index-phpunit.php

    r10544 r10546  
    33namespace Dotorg\API\Events\Tests;
    44use PHPUnit\Framework\TestCase;
    5 use function Dotorg\API\Events\{ get_events };
     5use function Dotorg\API\Events\{ get_events, get_location, build_response, is_client_core };
    66
    77/**
     
    116116    }
    117117
     118    /**
     119     * @covers ::get_location
     120     *
     121     * @group unit
     122     *
     123     * @dataProvider data_get_location
     124     */
     125    public function test_get_location( array $input, $expected ) : void {
     126        $actual_result = get_location( $input );
     127
     128        // Normalize to lowercase to account for inconsistency in the IP database
     129        if ( isset( $actual_result['description'] ) && is_string( $actual_result['description'] ) ) {
     130            $actual_result['description'] = strtolower( $actual_result['description'] );
     131        }
     132
     133        /*
     134         * Normalize coordinates to account for minor differences in the databases.
     135         *
     136         * Rounding to three decimal places means that we're still accurate within about 110 meters, which is
     137         * good enough for our purposes.
     138         *
     139         * @link https://gis.stackexchange.com/a/8674/49125.
     140         */
     141        if ( isset( $actual_result['latitude'], $actual_result['longitude'] ) ) {
     142            $actual_result['latitude']  = number_format( round( $actual_result['latitude'],  3 ), 3 );
     143            $actual_result['longitude'] = number_format( round( $actual_result['longitude'], 3 ), 3 );
     144        }
     145
     146        $this->assertSame( $expected, $actual_result );
     147    }
     148
     149    public function data_get_location() : array {
     150        $cases = array(
     151            /*
     152             * Only the country code is given
     153             */
     154            'country-code-australia' => array(
     155                'input' => array(
     156                    'country' => 'AU',
     157                    'restrict_by_country' => true,
     158                ),
     159                'expected' => array(
     160                    'country' => 'AU',
     161                ),
     162            ),
     163
     164
     165            /*
     166             * The country name, locale, and timezone are given
     167             */
     168            'country-exonym-1-word' => array(
     169                'input' => array(
     170                    'location_name' => 'Indonesia',
     171                    'locale'        => 'id_ID',
     172                    'timezone'      => 'Asia/Jakarta',
     173                ),
     174                'expected' => array(
     175                    'country'     => 'ID',
     176                    'description' => 'indonesia',
     177                ),
     178            ),
     179
     180            'country-exonym-2-words' => array(
     181                'input' => array(
     182                    'location_name' => 'Bosnia and Herzegovina',
     183                    'locale'        => 'bs_BA',
     184                    'timezone'      => 'Europe/Sarajevo',
     185                ),
     186                'expected' => array(
     187                    'country'     => 'BA',
     188                    'description' => 'bosnia and herzegovina',
     189                ),
     190            ),
     191
     192            /*
     193             * A location couldn't be found
     194             */
     195            'city-invalid-private-ip' => array(
     196                'input' => array(
     197                    'location_name' => 'InvalidCity',
     198                    'ip'            => '127.0.0.1',
     199                ),
     200                'expected' => false,
     201            ),
     202
     203            /*
     204             * No input was provided
     205             */
     206            'input-empty' => array(
     207                'input'    => array(),
     208                'expected' => array(),
     209            ),
     210
     211
     212            /*
     213             * The English city exonym, locale, and timezone are given
     214             */
     215            'city-africa' => array(
     216                'input' => array(
     217                    'location_name' => 'Nairobi',
     218                    'locale'        => 'en_GB',
     219                    'timezone'      => 'Africa/Nairobi',
     220                ),
     221                'expected' => array(
     222                    'description' => 'nairobi',
     223                    'latitude'    => '-1.283',
     224                    'longitude'   => '36.817',
     225                    'country'     => 'KE',
     226                ),
     227            ),
     228
     229            'city-asia' => array(
     230                'input' => array(
     231                    'location_name' => 'Tokyo',
     232                    'locale'        => 'ja',
     233                    'timezone'      => 'Asia/Tokyo',
     234                ),
     235                'expected' => array(
     236                    'description' => 'tokyo',
     237                    'latitude'    => '35.690',
     238                    'longitude'   => '139.692',
     239                    'country'     => 'JP',
     240                ),
     241            ),
     242
     243            'city-europe' => array(
     244                'input' => array(
     245                    'location_name' => 'Berlin',
     246                    'locale'        => 'de_DE',
     247                    'timezone'      => 'Europe/Berlin',
     248                ),
     249                'expected' => array(
     250                    'description' => 'berlin',
     251                    'latitude'    => '52.524',
     252                    'longitude'   => '13.411',
     253                    'country'     => 'DE',
     254                ),
     255            ),
     256
     257            'city-north-america' => array(
     258                'input' => array(
     259                    'location_name' => 'Vancouver',
     260                    'locale'        => 'en_CA',
     261                    'timezone'      => 'America/Vancouver',
     262                ),
     263                'expected' => array(
     264                    'description' => 'vancouver',
     265                    'latitude'    => '49.250',
     266                    'longitude'   => '-123.119',
     267                    'country'     => 'CA',
     268                ),
     269            ),
     270
     271            'city-oceania' => array(
     272                'input' => array(
     273                    'location_name' => 'Brisbane',
     274                    'locale'        => 'en_AU',
     275                    'timezone'      => 'Australia/Brisbane',
     276                ),
     277                'expected' => array(
     278                    'description' => 'brisbane',
     279                    'latitude'    => '-27.468',
     280                    'longitude'   => '153.028',
     281                    'country'     => 'AU',
     282                ),
     283            ),
     284
     285            // Many users never change the default `en_US` locale in Core
     286            'city-oceania-with-en_US' => array(
     287                'input' => array(
     288                    'location_name' => 'Sydney',
     289                    'locale'        => 'en_US',
     290                    'timezone'      => 'Australia/Sydney',
     291                ),
     292                'expected' => array(
     293                    'description' => 'sydney',
     294                    'latitude'    => '-33.868',
     295                    'longitude'   => '151.207',
     296                    'country'     => 'AU',
     297                ),
     298            ),
     299
     300            'city-south-america' => array(
     301                'input' => array(
     302                    'location_name' => 'Sao Paulo',
     303                    'locale'        => 'pt_BR',
     304                    'timezone'      => 'America/Sao_Paulo',
     305                ),
     306                'expected' => array(
     307                    'description' => 'sao paulo',
     308                    'latitude'    => '-23.548',
     309                    'longitude'   => '-46.636',
     310                    'country'     => 'BR',
     311                ),
     312            ),
     313
     314            // Users will often type them without the dash, bypassing an exact match
     315            'city-with-dashes-in-formal-name' => array(
     316                'input' => array(
     317                    'location_name' => 'Osakashi',
     318                    'locale'        => 'ja',
     319                    'timezone'      => 'Asia/Tokyo',
     320                ),
     321                'expected' => array(
     322                    'description' => 'osakashi',
     323                    'latitude'    => '34.694',
     324                    'longitude'   => '135.502',
     325                    'country'     => 'JP',
     326                ),
     327            ),
     328
     329            // If a location is provided, the fallback search should be attempted before an IP search
     330            'fallback-with-public-ip' => array(
     331                'input' => array(
     332                    'location_name' => 'Osakashi',
     333                    'locale'        => 'ja',
     334                    'timezone'      => 'Asia/Tokyo',
     335                    'ip'            => '153.163.68.148', // Tokyo
     336                ),
     337                'expected' => array(
     338                    'description' => 'osakashi',
     339                    'latitude'    => '34.694',
     340                    'longitude'   => '135.502',
     341                    'country'     => 'JP',
     342                ),
     343            ),
     344
     345            'city-with-apostrophe-in-formal-name' => array(
     346                'input' => array(
     347                    'location_name' => "Coeur d'Alene",
     348                    'locale'        => 'en_US',
     349                    'timezone'      => 'America/Los_Angeles',
     350                ),
     351                'expected' => array(
     352                    'description' => "coeur d'alene",
     353                    'latitude'    => '47.678',
     354                    'longitude'   => '-116.780',
     355                    'country'     => 'US',
     356                ),
     357            ),
     358
     359            'city-with-diacritics-in-query' => array(
     360                'input' => array(
     361                    'location_name' => 'Doña Ana',
     362                    'locale'        => 'en_US',
     363                    'timezone'      => 'America/Denver',
     364                ),
     365                'expected' => array(
     366                    'description' => 'doña ana',
     367                    'latitude'    => '32.390',
     368                    'longitude'   => '-106.814',
     369                    'country'     => 'US',
     370                ),
     371            ),
     372
     373            'city-with-diacritics-in-formal-name-but-not-in-query' => array(
     374                'input' => array(
     375                    'location_name' => 'Dona Ana',
     376                    'locale'        => 'en_US',
     377                    'timezone'      => 'America/Denver',
     378                ),
     379                'expected' => array(
     380                    'description' => 'dona ana',
     381                    'latitude'    => '32.390',
     382                    'longitude'   => '-106.814',
     383                    'country'     => 'US',
     384                ),
     385            ),
     386
     387            'city-with-period-in-query' => array(
     388                'input' => array(
     389                    'location_name' => 'St. Louis',
     390                    'locale'        => 'en_US',
     391                    'timezone'      => 'America/Chicago',
     392                ),
     393                'expected' => array(
     394                    'description' => 'st. louis',
     395                    'latitude'    => '38.627',
     396                    'longitude'   => '-90.198',
     397                    'country'     => 'US',
     398                ),
     399            ),
     400
     401            'city-with-period-in-formal-name-but-not-in-query' => array(
     402                'input' => array(
     403                    'location_name' => 'St Louis',
     404                    'locale'        => 'en_US',
     405                    'timezone'      => 'America/Chicago',
     406                ),
     407                'expected' => array(
     408                    'description' => 'st louis',
     409                    'latitude'    => '38.627',
     410                    'longitude'   => '-90.198',
     411                    'country'     => 'US',
     412                ),
     413            ),
     414
     415            /*
     416             * The city endonym, locale, and timezone are given
     417             */
     418            'city-endonym-accents-africa' => array(
     419                'input' => array(
     420                    'location_name' => 'Yaoundé',
     421                    'locale'        => 'fr_FR',
     422                    'timezone'      => 'Africa/Douala',
     423                ),
     424                'expected' => array(
     425                    'description' => 'yaoundé',
     426                    'latitude'    => '3.867',
     427                    'longitude'   => '11.517',
     428                    'country'     => 'CM',
     429                ),
     430            ),
     431
     432            'city-endonym-non-latin-africa' => array(
     433                'input' => array(
     434                    'location_name' => 'አዲስ አበ',
     435                    'locale'        => 'am',
     436                    'timezone'      => 'Africa/Addis_Ababa',
     437                ),
     438                'expected' => array(
     439                    'description' => 'አዲስ አበባ',
     440                    'latitude'    => '9.025',
     441                    'longitude'   => '38.747',
     442                    'country'     => 'ET',
     443                ),
     444            ),
     445
     446            'city-endonym-ideographic-asia1' => array(
     447                'input' => array(
     448                    'location_name' => '白浜町宇佐崎南',
     449                    'locale'        => 'ja',
     450                    'timezone'      => 'Asia/Tokyo',
     451                ),
     452                'expected' => array(
     453                    'description' => '白浜町宇佐崎南',
     454                    'latitude'    => '34.783',
     455                    'longitude'   => '134.717',
     456                    'country'     => 'JP',
     457                ),
     458            ),
     459
     460            'city-endonym-ideographic-asia2' => array(
     461                'input' => array(
     462                    'location_name' => 'تهران',
     463                    'locale'        => 'fa_IR',
     464                    'timezone'      => 'Asia/Tehran',
     465                ),
     466                'expected' => array(
     467                    'description' => 'تهران',
     468                    'latitude'    => '35.694',
     469                    'longitude'   => '51.422',
     470                    'country'     => 'IR',
     471                ),
     472            ),
     473
     474            'city-endonym-ideographic-asia3' => array(
     475                'input' => array(
     476                    'location_name' => 'كراچى',
     477                    'locale'        => 'ur',
     478                    'timezone'      => 'Asia/Karachi',
     479                ),
     480                'expected' => array(
     481                    'description' => 'كراچى',
     482                    'latitude'    => '24.861',
     483                    'longitude'   => '67.010',
     484                    'country'     => 'PK',
     485                ),
     486            ),
     487
     488            'city-endonym-ideographic-asia4' => array(
     489                'input' => array(
     490                    'location_name' => '京都',
     491                    'locale'        => 'ja',
     492                    'timezone'      => 'Asia/Tokyo',
     493                ),
     494                'expected' => array(
     495                    'description' => '京都',
     496                    'latitude'    => '35.021',
     497                    'longitude'   => '135.754',
     498                    'country'     => 'JP',
     499                ),
     500            ),
     501
     502            'city-endonym-ideographic-asia5' => array(
     503                'input' => array(
     504                    'location_name' => '東京',
     505                    'locale'        => 'ja',
     506                    'timezone'      => 'Asia/Tokyo',
     507                ),
     508                'expected' => array(
     509                    'description' => '東京',
     510                    'latitude'    => '35.690',
     511                    'longitude'   => '139.692',
     512                    'country'     => 'JP',
     513                ),
     514            ),
     515
     516            'city-endonym-ideographic-municipal-unit-asia' => array(
     517                'input' => array(
     518                    'location_name' => '大阪',
     519                    'locale'        => 'ja',
     520                    'timezone'      => 'Asia/Tokyo',
     521                ),
     522                'expected' => array(
     523                    'description' => '大阪',
     524                    'latitude'    => '34.694',
     525                    'longitude'   => '135.502',
     526                    'country'     => 'JP',
     527                ),
     528            ),
     529
     530            'city-endonym-europe' => array(
     531                'input' => array(
     532                    'location_name' => 'Wien',
     533                    'locale'        => 'de_DE',
     534                    'timezone'      => 'Europe/Berlin',
     535                ),
     536                'expected' => array(
     537                    'description' => 'wien',
     538                    'latitude'    => '48.208',
     539                    'longitude'   => '16.372',
     540                    'country'     => 'AT',
     541                ),
     542            ),
     543
     544            'city-endonym-europe2' => array(
     545                'input' => array(
     546                    'location_name' => 'Москва',
     547                    'locale'        => 'ru_RU',
     548                    'timezone'      => 'Europe/Moscow',
     549                ),
     550                'expected' => array(
     551                    'description' => 'Москва',
     552                    'latitude'    => '55.752',
     553                    'longitude'   => '37.616',
     554                    'country'     => 'RU',
     555                ),
     556            ),
     557
     558            // https://meta.trac.wordpress.org/ticket/3295
     559            'city-endonym-europe3-uppercase' => array(
     560                'input' => array(
     561                    'location_name' => 'Санкт-Петербург',
     562                    'locale'        => 'ru_RU',
     563                    'timezone'      => 'Europe/Moscow',
     564                ),
     565                'expected' => array(
     566                    'description' => 'Санкт-Петербург',
     567                    'latitude'    => '59.939',
     568                    'longitude'   => '30.314',
     569                    'country'     => 'RU',
     570                ),
     571            ),
     572
     573            // https://meta.trac.wordpress.org/ticket/3295
     574            'city-endonym-europe3-lowercase' => array(
     575                'input' => array(
     576                    'location_name' => 'санкт-петербург',
     577                    'locale'        => 'ru_RU',
     578                    'timezone'      => 'Europe/Moscow',
     579                ),
     580                'expected' => array(
     581                    'description' => 'Санкт-Петербург',
     582                    'latitude'    => '59.939',
     583                    'longitude'   => '30.314',
     584                    'country'     => 'RU',
     585                ),
     586            ),
     587
     588            'city-endonym-accents-north-america' => array(
     589                'input' => array(
     590                    'location_name' => 'Ciudad de México',
     591                    'locale'        => 'en_MX',
     592                    'timezone'      => 'America/Mexico_City',
     593                ),
     594                'expected' => array(
     595                    'description' => 'ciudad de méxico',
     596                    'latitude'    => '19.428',
     597                    'longitude'   => '-99.128',
     598                    'country'     => 'MX',
     599                ),
     600            ),
     601
     602            'city-endonym-accents-oceania' => array(
     603                'input' => array(
     604                    'location_name' => 'Hagåtña',
     605                    'locale'        => 'en_US',
     606                    'timezone'      => 'Pacific/Guam',
     607                ),
     608                'expected' => array(
     609                    'description' => 'hagåtña',
     610                    'latitude'    => '13.476',
     611                    'longitude'   => '144.749',
     612                    'country'     => 'GU',
     613                ),
     614            ),
     615
     616            'city-endonym-south-america' => array(
     617                'input' => array(
     618                    'location_name' => 'Bogotá',
     619                    'locale'        => 'es_CO',
     620                    'timezone'      => 'America/Bogota',
     621                ),
     622                'expected' => array(
     623                    'description' => 'bogotá',
     624                    'latitude'    => '4.610',
     625                    'longitude'   => '-74.082',
     626                    'country'     => 'CO',
     627                ),
     628            ),
     629
     630            // https://meta.trac.wordpress.org/ticket/3367
     631            // The following tests ensure that West/East portlands return correctly with inversed timezones.
     632            'usa-city-disambiguation' => array(
     633                'input' => array(
     634                    'location_name' => 'Portland',
     635                    'locale'        => 'en_US',
     636                    'timezone'      => 'America/Los_Angeles',
     637                ),
     638                'expected' => array(
     639                    'description' => 'portland',
     640                    'latitude'    => '45.523',
     641                    'longitude'   => '-122.676',
     642                    'country'     => 'US',
     643                ),
     644            ),
     645            'usa-city-disambiguation-2' => array(
     646                'input' => array(
     647                    'location_name' => 'Portland, OR',
     648                    'locale'        => 'en_US',
     649                    'timezone'      => 'America/New_York',
     650                ),
     651                'expected' => array(
     652                    'description' => 'portland, or',
     653                    'latitude'    => '45.523',
     654                    'longitude'   => '-122.676',
     655                    'country'     => 'US',
     656                ),
     657            ),
     658            'usa-city-disambiguation-3' => array(
     659                'input' => array(
     660                    'location_name' => 'Portland',
     661                    'locale'        => 'en_US',
     662                    'timezone'      => 'America/New_York',
     663                ),
     664                'expected' => array(
     665                    'description' => 'portland',
     666                    'latitude'    => '43.657',
     667                    'longitude'   => '-70.259',
     668                    'country'     => 'US',
     669                ),
     670            ),
     671            'usa-city-disambiguation-4' => array(
     672                'input' => array(
     673                    'location_name' => 'Portland, ME',
     674                    'locale'        => 'en_US',
     675                    'timezone'      => 'America/Los_Angeles',
     676                ),
     677                'expected' => array(
     678                    'description' => 'portland, me',
     679                    'latitude'    => '43.657',
     680                    'longitude'   => '-70.259',
     681                    'country'     => 'US',
     682                ),
     683            ),
     684
     685            /*
     686             * A combination of city, region, and country are given, along with the locale and timezone
     687             *
     688             * InvalidCity is used in tests that want to bypass the guess_location_from_city() tests and only test the country
     689             */
     690            '1-word-city-region' => array(
     691                'input' => array(
     692                    'location_name' => 'Portland Maine',
     693                    'locale'        => 'en_US',
     694                    'timezone'      => 'America/New_York',
     695                ),
     696                'expected' => array(
     697                    'description' => 'portland',
     698                    'latitude'    => '43.657',
     699                    'longitude'   => '-70.259',
     700                    'country'     => 'US',
     701                ),
     702            ),
     703
     704            '2-word-city-region' => array(
     705                'input' => array(
     706                    'location_name' => 'São Paulo Brazil',
     707                    'locale'        => 'pt_BR',
     708                    'timezone'      => 'America/Sao_Paulo',
     709                ),
     710                'expected' => array(
     711                    'description' => 'são paulo',
     712                    'latitude'    => '-23.548',
     713                    'longitude'   => '-46.636',
     714                    'country'     => 'BR',
     715                ),
     716            ),
     717
     718            'city-1-word-country' => array(
     719                'input' => array(
     720                    'location_name' => 'InvalidCity Canada',
     721                    'locale'        => 'en_CA',
     722                    'timezone'      => 'America/Vancouver',
     723                ),
     724                'expected' => array(
     725                    'country'     => 'CA',
     726                    'description' => 'canada',
     727                ),
     728            ),
     729
     730            'city-2-word-country' => array(
     731                'input' => array(
     732                    'location_name' => 'InvalidCity Dominican Republic',
     733                    'locale'        => 'es_ES',
     734                    'timezone'      => 'America/Santo_Domingo',
     735                ),
     736                'expected' => array(
     737                    'country'     => 'DO',
     738                    'description' => 'dominican republic',
     739                ),
     740            ),
     741
     742            'city-3-word-country' => array(
     743                'input' => array(
     744                    'location_name' => 'InvalidCity Central African Republic',
     745                    'locale'        => 'fr_FR',
     746                    'timezone'      => 'Africa/Bangui',
     747                ),
     748                'expected' => array(
     749                    'country'     => 'CF',
     750                    'description' => 'central african republic',
     751                ),
     752            ),
     753
     754            'country-code' => array(
     755                'input' => array(
     756                    'location_name' => 'GB',
     757                    'locale'        => 'en_GB',
     758                    'timezone'      => 'Europe/London',
     759                ),
     760                'expected' => array(
     761                    'country'     => 'GB',
     762                    'description' => 'united kingdom',
     763                ),
     764            ),
     765
     766            'city-country-code' => array(
     767                'input' => array(
     768                    'location_name' => 'InvalidCity BI',
     769                    'locale'        => 'fr_FR',
     770                    'timezone'      => 'Africa/Bujumbura',
     771                ),
     772                'expected' => array(
     773                    'country'     => 'BI',
     774                    'description' => 'burundi',
     775                ),
     776            ),
     777
     778            /*
     779             * Coordinates should take precedence over IP addresses
     780             */
     781            'coordinates-over-ip-us' => array(
     782                'input' => array(
     783                    'latitude'  => '47.6062100',
     784                    'longitude' => '-122.3320700',
     785                    'ip'        => '192.0.70.251',  // San Francisco, USA
     786                    'timezone'  => 'America/Los_Angeles',
     787                    'locale'    => 'en_US',
     788                ),
     789                'expected' => array(
     790                    'description' => false,
     791                    'latitude'    => '47.606',
     792                    'longitude'   => '-122.332',
     793                ),
     794            ),
     795
     796            'coordinates-over-ip-africa' => array(
     797                'input' => array(
     798                    'latitude'  => '-19.634233',
     799                    'longitude' => '17.331767',
     800                    'ip'        => '41.190.96.5',   // Tsumeb, Namibia
     801                    'timezone'  => 'Africa/Windhoek',
     802                    'locale'    => 'af',
     803                ),
     804                'expected' => array(
     805                    'description' => false,
     806                    'latitude'    => '-19.634',
     807                    'longitude'   => '17.332',
     808                ),
     809            ),
     810
     811            /*
     812             * Only the IPv4 address is given.
     813             *
     814             * Note that IP locations change frequently, so some of these expected results will inevitably become outdated
     815             * and cause tests to fail.
     816             *
     817             * See https://awebanalysis.com/en/ipv4-directory/
     818             */
     819            'ip-africa' => array(
     820                'input' => array( 'ip' => '41.191.232.22' ),
     821                'expected' => array(
     822                    'description' => 'harare',
     823                    'latitude'    => '-17.829',
     824                    'longitude'   => '31.054',
     825                    'country'     => 'ZW',
     826                    'internal'    => true,
     827                ),
     828            ),
     829
     830            'ip-asia' => array(
     831                'input' => array( 'ip' => '86.108.55.28' ),
     832                'expected' => array(
     833                    'description' => 'amman',
     834                    'latitude'    => '31.955',
     835                    'longitude'   => '35.945',
     836                    'country'     => 'JO',
     837                    'internal'    => true,
     838                ),
     839            ),
     840
     841            'ip-europe' => array(
     842                'input' => array( 'ip' => '80.95.186.144' ),
     843                'expected' => array(
     844                    'description' => 'belfast',
     845                    'latitude'    => '54.583',
     846                    'longitude'   => '-5.933',
     847                    'country'     => 'GB',
     848                    'internal'    => true,
     849                ),
     850            ),
     851
     852            'ip-north-america' => array(
     853                'input' => array( 'ip' => '189.147.186.0' ),
     854                'expected' => array(
     855                    'description' => 'mexico city',
     856                    'latitude'    => '19.428',
     857                    'longitude'   => '-99.128',
     858                    'country'     => 'MX',
     859                    'internal'    => true,
     860                ),
     861            ),
     862
     863            'ip-oceania' => array(
     864                'input' => array( 'ip' => '116.12.57.122' ),
     865                'expected' => array(
     866                    'description' => 'auckland',
     867                    'latitude'    => '-36.867',
     868                    'longitude'   => '174.767',
     869                    'country'     => 'NZ',
     870                    'internal'    => true,
     871                ),
     872            ),
     873
     874            'ip-south-america' => array(
     875                'input' => array( 'ip' => '181.66.32.136' ),
     876                'expected' => array(
     877                    'description' => 'lima',
     878                    'latitude'    => '-12.043',
     879                    'longitude'   => '-77.028',
     880                    'country'     => 'PE',
     881                    'internal'    => true,
     882                ),
     883            ),
     884
     885            /*
     886             * Only an IPv6 address is given.
     887             *
     888             * Note that IP locations change frequently, so some of these expected results will inevitably become outdated
     889             * and cause tests to fail.
     890             *
     891             * See https://www.google.com/intl/en/ipv6/statistics.html#tab=per-country-ipv6-adoption&tab=per-country-ipv6-adoption
     892             * See https://awebanalysis.com/en/ipv6-directory/
     893             * See https://www.google.com/search?q=australia+site%3Ahttps%3A%2F%2Fawebanalysis.com%2Fen%2Fipv6-directory%2F
     894             */
     895            'ipv6-africa' => array(
     896                'input'    => array( 'ip' => '2c0f:f8f0:ffff:ffff:ffff:ffff:ffff:ffff' ),
     897                'expected' => array(
     898                    'description' => 'harare',
     899                    'latitude'    => '-17.829',
     900                    'longitude'   => '31.054',
     901                    'country'     => 'ZW',
     902                    'internal'    => true,
     903                ),
     904            ),
     905
     906            'ipv6-asia-anonymized' => array(
     907                'input'    => array( 'ip' => '2405:200:1000::' ),
     908                'expected' => array(
     909                    'description' => 'mumbai',
     910                    'latitude'    => '19.014',
     911                    'longitude'   => '72.848',
     912                    'country'     => 'IN',
     913                    'internal'    => true,
     914                ),
     915            ),
     916
     917            'ipv6-europe-anonymized' => array(
     918                'input'    => array( 'ip' => '2a02:578:1000::' ),
     919                'expected' => array(
     920                    'description' => 'sint-niklaas',
     921                    'latitude'    => '51.165',
     922                    'longitude'   => '4.144',
     923                    'country'     => 'BE',
     924                    'internal'    => true,
     925                ),
     926            ),
     927
     928            'ipv6-north-america-anonymized' => array(
     929                'input'    => array( 'ip' => '2605:a600::' ),
     930                'expected' => array(
     931                    'description' => 'mountain view',
     932                    'latitude'    => '37.386',
     933                    'longitude'   => '-122.084',
     934                    'country'     => 'US',
     935                    'internal'    => true,
     936                ),
     937            ),
     938
     939            'ipv6-oceania-collapsed-prefix' => array(
     940                'input'    => array( 'ip' => '::ffff:0190:c500' ),
     941                'expected' => array(
     942                    'description' => 'perth',
     943                    'latitude'    => '-31.952',
     944                    'longitude'   => '115.861',
     945                    'country'     => 'AU',
     946                    'internal'    => true,
     947                ),
     948            ),
     949
     950            'ipv6-south-america' => array(
     951                'input'    => array( 'ip' => '2001:1388:6643:2736:10f1:897c:428c:1b3b' ),
     952                'expected' => array(
     953                    'description' => 'lima',
     954                    'latitude'    => '-12.043',
     955                    'longitude'   => '-77.028',
     956                    'country'     => 'PE',
     957                    'internal'    => true,
     958                ),
     959            ),
     960        );
     961
     962        return $cases;
     963    }
     964
     965    /**
     966     * @covers ::build_response
     967     *
     968     * @todo It might be better to do more abstracted tests of `main()`, or e2e tests, rather than coupling to the
     969     * internals of `build_request()`.
     970     *
     971     * @group unit
     972     *
     973     * @dataProvider data_build_response
     974     */
     975    function test_build_response( array $input, array $expected ) : void {
     976        $actual_result = build_response( $input['location'], $input['location_args'] );
     977
     978        $this->assertSame( $expected['location'], $actual_result['location'] );
     979        $this->assertSame( isset( $expected['error'] ), isset( $actual_result['error'] ) );
     980
     981        if ( $expected['events'] ) {
     982            $this->assertNotEmpty( $actual_result['events'] );
     983            $this->assertNotEmpty( $actual_result['events'][0]['url'] );
     984            $this->assertGreaterThan( time() - ( 2 * 24 * 60 * 60 ), strtotime( $actual_result['events'][0]['date'] ) );
     985        }
     986
     987        if ( isset( $expected['error'] ) ) {
     988            $this->assertSame( $expected['error'], $actual_result['error'] );
     989        }
     990    }
     991
     992    function data_build_response() : array {
     993        return array(
     994            'utrecht-ip' => array(
     995                'input' => array(
     996                    'location' => array(
     997                        'latitude'  => '52.090284',
     998                        'longitude' => '5.124719',
     999                        'internal'  => true,
     1000                    ),
     1001                    'location_args' => array( 'ip' => '84.31.177.21' ),
     1002                ),
     1003                'expected' => array(
     1004                    'location' => array(
     1005                        'ip' => '84.31.177.21',
     1006                    ),
     1007                    'events' => true,
     1008                ),
     1009            ),
     1010
     1011            'canada-country' => array(
     1012                'input' => array(
     1013                    'location' => array(
     1014                        'country' => 'CA',
     1015                    ),
     1016                    'location_args' => array(
     1017                        'restrict_by_country' => true,
     1018                    ),
     1019                ),
     1020                'expected' => array(
     1021                    'location' => array(
     1022                        'country' => 'CA',
     1023                    ),
     1024                    'events' => true,
     1025                ),
     1026            ),
     1027
     1028            'throttled' => array(
     1029                'input' => array(
     1030                    'location' => 'temp-request-throttled',
     1031                ),
     1032                'expected' => array(
     1033                    'location' => array(),
     1034                    'error'    => 'temp-request-throttled',
     1035                    'events'   => false,
     1036                ),
     1037            ),
     1038
     1039            'no-location' => array(
     1040                'input' => array(
     1041                    'location' => array(),
     1042                ),
     1043                'expected' => array(
     1044                    'location' => array(),
     1045                    'error'    => 'no_location_available',
     1046                    'events'   => false,
     1047                ),
     1048            ),
     1049        );
     1050    }
     1051
     1052    /**
     1053     * @covers ::is_client_core
     1054     *
     1055     * @group unit
     1056     *
     1057     * @dataProvider data_is_client_core
     1058     */
     1059    function test_is_client_core( string $user_agent, bool $expected_result ) : void {
     1060        $actual_result = is_client_core( $user_agent );
     1061
     1062        $this->assertSame( $expected_result, $actual_result );
     1063    }
     1064
     1065    public function data_is_client_core() : array {
     1066        return array(
     1067            'Empty string'                    => array( '', false ),
     1068            'Mentions WP but not Core format' => array( 'Contains WordPress but no slash', false ),
     1069            'Core old version'                => array( 'WordPress/4.9; https://example.org', true ),
     1070            'Core future version, no URL'     => array( 'WordPress/10.0', true ),
     1071        );
     1072    }
     1073
    1181074    function test_port_remaining_tests() {
    1191075        $this->markTestIncomplete( 'Not all of the tests from ./test-index.php have been ported to PHPUnit yet. See the notes in that file.' );
  • sites/trunk/api.wordpress.org/public_html/events/1.0/tests/test-index.php

    r10544 r10546  
    3333
    3434    $tests_failed  = 0;
    35     $tests_failed += test_get_location();
    3635    $tests_failed += test_maybe_add_regional_wordcamps();
    3736    $tests_failed += test_maybe_add_wp15_promo();
    38     $tests_failed += test_build_response();
    39     $tests_failed += test_is_client_core();
    4037    $tests_failed += test_get_iso_3166_2_country_codes();
    4138    $tests_failed += test_remove_duplicate_events();
     
    10299        }
    103100    }
    104 }
    105 
    106 /**
    107  * Test `get_location()`
    108  *
    109  * @return bool The number of failures
    110  */
    111 function test_get_location() {
    112     $failed = 0;
    113     $cases  = get_location_test_cases();
    114 
    115     printf( "\nRunning %d location tests", count( $cases ) );
    116 
    117     foreach ( $cases as $case_id => $case ) {
    118         $actual_result = get_location( $case['input'] );
    119 
    120         // Normalize to lowercase to account for inconsistency in the IP database
    121         if ( isset( $actual_result['description'] ) && is_string( $actual_result['description'] ) ) {
    122             $actual_result['description'] = strtolower( $actual_result['description'] );
    123         }
    124 
    125         /*
    126          * Normalize coordinates to account for minor differences in the databases
    127          *
    128          * Rounding to three decimal places means that we're still accurate within about 110 meters, which is
    129          * good enough for our purposes.
    130          *
    131          * See https://gis.stackexchange.com/a/8674/49125
    132          */
    133         if ( isset( $actual_result['latitude'], $actual_result['longitude'] ) ) {
    134             $actual_result['latitude']  = number_format( round( $actual_result['latitude'],  3 ), 3 );
    135             $actual_result['longitude'] = number_format( round( $actual_result['longitude'], 3 ), 3 );
    136         }
    137 
    138         $passed = $case['expected'] === $actual_result;
    139 
    140         output_results( $case_id, $passed, $case['expected'], $actual_result );
    141 
    142         if ( ! $passed ) {
    143             $failed++;
    144         }
    145     }
    146 
    147     return $failed;
    148 }
    149 
    150 /**
    151  * Get the cases for testing `get_location()`
    152  *
    153  * @return array
    154  */
    155 function get_location_test_cases() {
    156     $cases = array(
    157         /*
    158          * Only the country code is given
    159          */
    160         'country-code-australia' => array(
    161             'input' => array(
    162                 'country' => 'AU',
    163                 'restrict_by_country' => true,
    164             ),
    165             'expected' => array(
    166                 'country' => 'AU',
    167             ),
    168         ),
    169 
    170 
    171         /*
    172          * The country name, locale, and timezone are given
    173          */
    174         'country-exonym-1-word' => array(
    175             'input' => array(
    176                 'location_name' => 'Indonesia',
    177                 'locale'        => 'id_ID',
    178                 'timezone'      => 'Asia/Jakarta',
    179             ),
    180             'expected' => array(
    181                 'country'     => 'ID',
    182                 'description' => 'indonesia',
    183             ),
    184         ),
    185 
    186         'country-exonym-2-words' => array(
    187             'input' => array(
    188                 'location_name' => 'Bosnia and Herzegovina',
    189                 'locale'        => 'bs_BA',
    190                 'timezone'      => 'Europe/Sarajevo',
    191             ),
    192             'expected' => array(
    193                 'country'     => 'BA',
    194                 'description' => 'bosnia and herzegovina',
    195             ),
    196         ),
    197 
    198         /*
    199          * A location couldn't be found
    200          */
    201         'city-invalid-private-ip' => array(
    202             'input' => array(
    203                 'location_name' => 'InvalidCity',
    204                 'ip'            => '127.0.0.1',
    205             ),
    206             'expected' => false,
    207         ),
    208 
    209         /*
    210          * No input was provided
    211          */
    212         'input-empty' => array(
    213             'input'    => array(),
    214             'expected' => array(),
    215         ),
    216 
    217 
    218         /*
    219          * The English city exonym, locale, and timezone are given
    220          */
    221         'city-africa' => array(
    222             'input' => array(
    223                 'location_name' => 'Nairobi',
    224                 'locale'        => 'en_GB',
    225                 'timezone'      => 'Africa/Nairobi',
    226             ),
    227             'expected' => array(
    228                 'description' => 'nairobi',
    229                 'latitude'    => '-1.283',
    230                 'longitude'   => '36.817',
    231                 'country'     => 'KE',
    232             ),
    233         ),
    234 
    235         'city-asia' => array(
    236             'input' => array(
    237                 'location_name' => 'Tokyo',
    238                 'locale'        => 'ja',
    239                 'timezone'      => 'Asia/Tokyo',
    240             ),
    241             'expected' => array(
    242                 'description' => 'tokyo',
    243                 'latitude'    => '35.690',
    244                 'longitude'   => '139.692',
    245                 'country'     => 'JP',
    246             ),
    247         ),
    248 
    249         'city-europe' => array(
    250             'input' => array(
    251                 'location_name' => 'Berlin',
    252                 'locale'        => 'de_DE',
    253                 'timezone'      => 'Europe/Berlin',
    254             ),
    255             'expected' => array(
    256                 'description' => 'berlin',
    257                 'latitude'    => '52.524',
    258                 'longitude'   => '13.411',
    259                 'country'     => 'DE',
    260             ),
    261         ),
    262 
    263         'city-north-america' => array(
    264             'input' => array(
    265                 'location_name' => 'Vancouver',
    266                 'locale'        => 'en_CA',
    267                 'timezone'      => 'America/Vancouver',
    268             ),
    269             'expected' => array(
    270                 'description' => 'vancouver',
    271                 'latitude'    => '49.250',
    272                 'longitude'   => '-123.119',
    273                 'country'     => 'CA',
    274             ),
    275         ),
    276 
    277         'city-oceania' => array(
    278             'input' => array(
    279                 'location_name' => 'Brisbane',
    280                 'locale'        => 'en_AU',
    281                 'timezone'      => 'Australia/Brisbane',
    282             ),
    283             'expected' => array(
    284                 'description' => 'brisbane',
    285                 'latitude'    => '-27.468',
    286                 'longitude'   => '153.028',
    287                 'country'     => 'AU',
    288             ),
    289         ),
    290 
    291         // Many users never change the default `en_US` locale in Core
    292         'city-oceania-with-en_US' => array(
    293             'input' => array(
    294                 'location_name' => 'Sydney',
    295                 'locale'        => 'en_US',
    296                 'timezone'      => 'Australia/Sydney',
    297             ),
    298             'expected' => array(
    299                 'description' => 'sydney',
    300                 'latitude'    => '-33.868',
    301                 'longitude'   => '151.207',
    302                 'country'     => 'AU',
    303             ),
    304         ),
    305 
    306         'city-south-america' => array(
    307             'input' => array(
    308                 'location_name' => 'Sao Paulo',
    309                 'locale'        => 'pt_BR',
    310                 'timezone'      => 'America/Sao_Paulo',
    311             ),
    312             'expected' => array(
    313                 'description' => 'sao paulo',
    314                 'latitude'    => '-23.548',
    315                 'longitude'   => '-46.636',
    316                 'country'     => 'BR',
    317             ),
    318         ),
    319 
    320         // Users will often type them without the dash, bypassing an exact match
    321         'city-with-dashes-in-formal-name' => array(
    322             'input' => array(
    323                 'location_name' => 'Osakashi',
    324                 'locale'        => 'ja',
    325                 'timezone'      => 'Asia/Tokyo',
    326             ),
    327             'expected' => array(
    328                 'description' => 'osakashi',
    329                 'latitude'    => '34.694',
    330                 'longitude'   => '135.502',
    331                 'country'     => 'JP',
    332             ),
    333         ),
    334 
    335         // If a location is provided, the fallback search should be attempted before an IP search
    336         'fallback-with-public-ip' => array(
    337             'input' => array(
    338                 'location_name' => 'Osakashi',
    339                 'locale'        => 'ja',
    340                 'timezone'      => 'Asia/Tokyo',
    341                 'ip'            => '153.163.68.148', // Tokyo
    342             ),
    343             'expected' => array(
    344                 'description' => 'osakashi',
    345                 'latitude'    => '34.694',
    346                 'longitude'   => '135.502',
    347                 'country'     => 'JP',
    348             ),
    349         ),
    350 
    351         'city-with-apostrophe-in-formal-name' => array(
    352             'input' => array(
    353                 'location_name' => "Coeur d'Alene",
    354                 'locale'        => 'en_US',
    355                 'timezone'      => 'America/Los_Angeles',
    356             ),
    357             'expected' => array(
    358                 'description' => "coeur d'alene",
    359                 'latitude'    => '47.678',
    360                 'longitude'   => '-116.780',
    361                 'country'     => 'US',
    362             ),
    363         ),
    364 
    365         'city-with-diacritics-in-query' => array(
    366             'input' => array(
    367                 'location_name' => 'Doña Ana',
    368                 'locale'        => 'en_US',
    369                 'timezone'      => 'America/Denver',
    370             ),
    371             'expected' => array(
    372                 'description' => 'doña ana',
    373                 'latitude'    => '32.390',
    374                 'longitude'   => '-106.814',
    375                 'country'     => 'US',
    376             ),
    377         ),
    378 
    379         'city-with-diacritics-in-formal-name-but-not-in-query' => array(
    380             'input' => array(
    381                 'location_name' => 'Dona Ana',
    382                 'locale'        => 'en_US',
    383                 'timezone'      => 'America/Denver',
    384             ),
    385             'expected' => array(
    386                 'description' => 'dona ana',
    387                 'latitude'    => '32.390',
    388                 'longitude'   => '-106.814',
    389                 'country'     => 'US',
    390             ),
    391         ),
    392 
    393         'city-with-period-in-query' => array(
    394             'input' => array(
    395                 'location_name' => 'St. Louis',
    396                 'locale'        => 'en_US',
    397                 'timezone'      => 'America/Chicago',
    398             ),
    399             'expected' => array(
    400                 'description' => 'st. louis',
    401                 'latitude'    => '38.627',
    402                 'longitude'   => '-90.198',
    403                 'country'     => 'US',
    404             ),
    405         ),
    406 
    407         'city-with-period-in-formal-name-but-not-in-query' => array(
    408             'input' => array(
    409                 'location_name' => 'St Louis',
    410                 'locale'        => 'en_US',
    411                 'timezone'      => 'America/Chicago',
    412             ),
    413             'expected' => array(
    414                 'description' => 'st louis',
    415                 'latitude'    => '38.627',
    416                 'longitude'   => '-90.198',
    417                 'country'     => 'US',
    418             ),
    419         ),
    420 
    421         /*
    422          * The city endonym, locale, and timezone are given
    423          */
    424         'city-endonym-accents-africa' => array(
    425             'input' => array(
    426                 'location_name' => 'Yaoundé',
    427                 'locale'        => 'fr_FR',
    428                 'timezone'      => 'Africa/Douala',
    429             ),
    430             'expected' => array(
    431                 'description' => 'yaoundé',
    432                 'latitude'    => '3.867',
    433                 'longitude'   => '11.517',
    434                 'country'     => 'CM',
    435             ),
    436         ),
    437 
    438         'city-endonym-non-latin-africa' => array(
    439             'input' => array(
    440                 'location_name' => 'አዲስ አበ',
    441                 'locale'        => 'am',
    442                 'timezone'      => 'Africa/Addis_Ababa',
    443             ),
    444             'expected' => array(
    445                 'description' => 'አዲስ አበባ',
    446                 'latitude'    => '9.025',
    447                 'longitude'   => '38.747',
    448                 'country'     => 'ET',
    449             ),
    450         ),
    451 
    452         'city-endonym-ideographic-asia1' => array(
    453             'input' => array(
    454                 'location_name' => '白浜町宇佐崎南',
    455                 'locale'        => 'ja',
    456                 'timezone'      => 'Asia/Tokyo',
    457             ),
    458             'expected' => array(
    459                 'description' => '白浜町宇佐崎南',
    460                 'latitude'    => '34.783',
    461                 'longitude'   => '134.717',
    462                 'country'     => 'JP',
    463             ),
    464         ),
    465 
    466         'city-endonym-ideographic-asia2' => array(
    467             'input' => array(
    468                 'location_name' => 'تهران',
    469                 'locale'        => 'fa_IR',
    470                 'timezone'      => 'Asia/Tehran',
    471             ),
    472             'expected' => array(
    473                 'description' => 'تهران',
    474                 'latitude'    => '35.694',
    475                 'longitude'   => '51.422',
    476                 'country'     => 'IR',
    477             ),
    478         ),
    479 
    480         'city-endonym-ideographic-asia3' => array(
    481             'input' => array(
    482                 'location_name' => 'كراچى',
    483                 'locale'        => 'ur',
    484                 'timezone'      => 'Asia/Karachi',
    485             ),
    486             'expected' => array(
    487                 'description' => 'كراچى',
    488                 'latitude'    => '24.861',
    489                 'longitude'   => '67.010',
    490                 'country'     => 'PK',
    491             ),
    492         ),
    493 
    494         'city-endonym-ideographic-asia4' => array(
    495             'input' => array(
    496                 'location_name' => '京都',
    497                 'locale'        => 'ja',
    498                 'timezone'      => 'Asia/Tokyo',
    499             ),
    500             'expected' => array(
    501                 'description' => '京都',
    502                 'latitude'    => '35.021',
    503                 'longitude'   => '135.754',
    504                 'country'     => 'JP',
    505             ),
    506         ),
    507 
    508         'city-endonym-ideographic-asia5' => array(
    509             'input' => array(
    510                 'location_name' => '東京',
    511                 'locale'        => 'ja',
    512                 'timezone'      => 'Asia/Tokyo',
    513             ),
    514             'expected' => array(
    515                 'description' => '東京',
    516                 'latitude'    => '35.690',
    517                 'longitude'   => '139.692',
    518                 'country'     => 'JP',
    519             ),
    520         ),
    521 
    522         'city-endonym-ideographic-municipal-unit-asia' => array(
    523             'input' => array(
    524                 'location_name' => '大阪',
    525                 'locale'        => 'ja',
    526                 'timezone'      => 'Asia/Tokyo',
    527             ),
    528             'expected' => array(
    529                 'description' => '大阪',
    530                 'latitude'    => '34.694',
    531                 'longitude'   => '135.502',
    532                 'country'     => 'JP',
    533             ),
    534         ),
    535 
    536         'city-endonym-europe' => array(
    537             'input' => array(
    538                 'location_name' => 'Wien',
    539                 'locale'        => 'de_DE',
    540                 'timezone'      => 'Europe/Berlin',
    541             ),
    542             'expected' => array(
    543                 'description' => 'wien',
    544                 'latitude'    => '48.208',
    545                 'longitude'   => '16.372',
    546                 'country'     => 'AT',
    547             ),
    548         ),
    549 
    550         'city-endonym-europe2' => array(
    551             'input' => array(
    552                 'location_name' => 'Москва',
    553                 'locale'        => 'ru_RU',
    554                 'timezone'      => 'Europe/Moscow',
    555             ),
    556             'expected' => array(
    557                 'description' => 'Москва',
    558                 'latitude'    => '55.752',
    559                 'longitude'   => '37.616',
    560                 'country'     => 'RU',
    561             ),
    562         ),
    563 
    564         // https://meta.trac.wordpress.org/ticket/3295
    565         'city-endonym-europe3-uppercase' => array(
    566             'input' => array(
    567                 'location_name' => 'Санкт-Петербург',
    568                 'locale'        => 'ru_RU',
    569                 'timezone'      => 'Europe/Moscow',
    570             ),
    571             'expected' => array(
    572                 'description' => 'Санкт-Петербург',
    573                 'latitude'    => '59.939',
    574                 'longitude'   => '30.314',
    575                 'country'     => 'RU',
    576             ),
    577         ),
    578 
    579         // https://meta.trac.wordpress.org/ticket/3295
    580         'city-endonym-europe3-lowercase' => array(
    581             'input' => array(
    582                 'location_name' => 'санкт-петербург',
    583                 'locale'        => 'ru_RU',
    584                 'timezone'      => 'Europe/Moscow',
    585             ),
    586             'expected' => array(
    587                 'description' => 'Санкт-Петербург',
    588                 'latitude'    => '59.939',
    589                 'longitude'   => '30.314',
    590                 'country'     => 'RU',
    591             ),
    592         ),
    593 
    594         'city-endonym-accents-north-america' => array(
    595             'input' => array(
    596                 'location_name' => 'Ciudad de México',
    597                 'locale'        => 'en_MX',
    598                 'timezone'      => 'America/Mexico_City',
    599             ),
    600             'expected' => array(
    601                 'description' => 'ciudad de méxico',
    602                 'latitude'    => '19.428',
    603                 'longitude'   => '-99.128',
    604                 'country'     => 'MX',
    605             ),
    606         ),
    607 
    608         'city-endonym-accents-oceania' => array(
    609             'input' => array(
    610                 'location_name' => 'Hagåtña',
    611                 'locale'        => 'en_US',
    612                 'timezone'      => 'Pacific/Guam',
    613             ),
    614             'expected' => array(
    615                 'description' => 'hagåtña',
    616                 'latitude'    => '13.476',
    617                 'longitude'   => '144.749',
    618                 'country'     => 'GU',
    619             ),
    620         ),
    621 
    622         'city-endonym-south-america' => array(
    623             'input' => array(
    624                 'location_name' => 'Bogotá',
    625                 'locale'        => 'es_CO',
    626                 'timezone'      => 'America/Bogota',
    627             ),
    628             'expected' => array(
    629                 'description' => 'bogotá',
    630                 'latitude'    => '4.610',
    631                 'longitude'   => '-74.082',
    632                 'country'     => 'CO',
    633             ),
    634         ),
    635 
    636         // https://meta.trac.wordpress.org/ticket/3367
    637         // The following tests ensure that West/East portlands return correctly with inversed timezones.
    638         'usa-city-disambiguation' => array(
    639             'input' => array(
    640                 'location_name' => 'Portland',
    641                 'locale'        => 'en_US',
    642                 'timezone'      => 'America/Los_Angeles',
    643             ),
    644             'expected' => array(
    645                 'description' => 'portland',
    646                 'latitude'    => '45.523',
    647                 'longitude'   => '-122.676',
    648                 'country'     => 'US',
    649             ),
    650         ),
    651         'usa-city-disambiguation-2' => array(
    652             'input' => array(
    653                 'location_name' => 'Portland, OR',
    654                 'locale'        => 'en_US',
    655                 'timezone'      => 'America/New_York',
    656             ),
    657             'expected' => array(
    658                 'description' => 'portland, or',
    659                 'latitude'    => '45.523',
    660                 'longitude'   => '-122.676',
    661                 'country'     => 'US',
    662             ),
    663         ),
    664         'usa-city-disambiguation-3' => array(
    665             'input' => array(
    666                 'location_name' => 'Portland',
    667                 'locale'        => 'en_US',
    668                 'timezone'      => 'America/New_York',
    669             ),
    670             'expected' => array(
    671                 'description' => 'portland',
    672                 'latitude'    => '43.657',
    673                 'longitude'   => '-70.259',
    674                 'country'     => 'US',
    675             ),
    676         ),
    677         'usa-city-disambiguation-4' => array(
    678             'input' => array(
    679                 'location_name' => 'Portland, ME',
    680                 'locale'        => 'en_US',
    681                 'timezone'      => 'America/Los_Angeles',
    682             ),
    683             'expected' => array(
    684                 'description' => 'portland, me',
    685                 'latitude'    => '43.657',
    686                 'longitude'   => '-70.259',
    687                 'country'     => 'US',
    688             ),
    689         ),
    690 
    691         /*
    692          * A combination of city, region, and country are given, along with the locale and timezone
    693          *
    694          * InvalidCity is used in tests that want to bypass the guess_location_from_city() tests and only test the country
    695          */
    696         '1-word-city-region' => array(
    697             'input' => array(
    698                 'location_name' => 'Portland Maine',
    699                 'locale'        => 'en_US',
    700                 'timezone'      => 'America/New_York',
    701             ),
    702             'expected' => array(
    703                 'description' => 'portland',
    704                 'latitude'    => '43.657',
    705                 'longitude'   => '-70.259',
    706                 'country'     => 'US',
    707             ),
    708         ),
    709 
    710         '2-word-city-region' => array(
    711             'input' => array(
    712                 'location_name' => 'São Paulo Brazil',
    713                 'locale'        => 'pt_BR',
    714                 'timezone'      => 'America/Sao_Paulo',
    715             ),
    716             'expected' => array(
    717                 'description' => 'são paulo',
    718                 'latitude'    => '-23.548',
    719                 'longitude'   => '-46.636',
    720                 'country'     => 'BR',
    721             ),
    722         ),
    723 
    724         'city-1-word-country' => array(
    725             'input' => array(
    726                 'location_name' => 'InvalidCity Canada',
    727                 'locale'        => 'en_CA',
    728                 'timezone'      => 'America/Vancouver',
    729             ),
    730             'expected' => array(
    731                 'country'     => 'CA',
    732                 'description' => 'canada',
    733             ),
    734         ),
    735 
    736         'city-2-word-country' => array(
    737             'input' => array(
    738                 'location_name' => 'InvalidCity Dominican Republic',
    739                 'locale'        => 'es_ES',
    740                 'timezone'      => 'America/Santo_Domingo',
    741             ),
    742             'expected' => array(
    743                 'country'     => 'DO',
    744                 'description' => 'dominican republic',
    745             ),
    746         ),
    747 
    748         'city-3-word-country' => array(
    749             'input' => array(
    750                 'location_name' => 'InvalidCity Central African Republic',
    751                 'locale'        => 'fr_FR',
    752                 'timezone'      => 'Africa/Bangui',
    753             ),
    754             'expected' => array(
    755                 'country'     => 'CF',
    756                 'description' => 'central african republic',
    757             ),
    758         ),
    759 
    760         'country-code' => array(
    761             'input' => array(
    762                 'location_name' => 'GB',
    763                 'locale'        => 'en_GB',
    764                 'timezone'      => 'Europe/London',
    765             ),
    766             'expected' => array(
    767                 'country'     => 'GB',
    768                 'description' => 'united kingdom',
    769             ),
    770         ),
    771 
    772         'city-country-code' => array(
    773             'input' => array(
    774                 'location_name' => 'InvalidCity BI',
    775                 'locale'        => 'fr_FR',
    776                 'timezone'      => 'Africa/Bujumbura',
    777             ),
    778             'expected' => array(
    779                 'country'     => 'BI',
    780                 'description' => 'burundi',
    781             ),
    782         ),
    783 
    784         /*
    785          * Coordinates should take precedence over IP addresses
    786          */
    787         'coordinates-over-ip-us' => array(
    788             'input' => array(
    789                 'latitude'  => '47.6062100',
    790                 'longitude' => '-122.3320700',
    791                 'ip'        => '192.0.70.251',  // San Francisco, USA
    792                 'timezone'  => 'America/Los_Angeles',
    793                 'locale'    => 'en_US',
    794             ),
    795             'expected' => array(
    796                 'description' => false,
    797                 'latitude'    => '47.606',
    798                 'longitude'   => '-122.332',
    799             ),
    800         ),
    801 
    802         'coordinates-over-ip-africa' => array(
    803             'input' => array(
    804                 'latitude'  => '-19.634233',
    805                 'longitude' => '17.331767',
    806                 'ip'        => '41.190.96.5',   // Tsumeb, Namibia
    807                 'timezone'  => 'Africa/Windhoek',
    808                 'locale'    => 'af',
    809             ),
    810             'expected' => array(
    811                 'description' => false,
    812                 'latitude'    => '-19.634',
    813                 'longitude'   => '17.332',
    814             ),
    815         ),
    816 
    817         /*
    818          * Only the IPv4 address is given.
    819          *
    820          * Note that IP locations change frequently, so some of these expected results will inevitably become outdated
    821          * and cause tests to fail.
    822          *
    823          * See https://awebanalysis.com/en/ipv4-directory/
    824          */
    825         'ip-africa' => array(
    826             'input' => array( 'ip' => '41.191.232.22' ),
    827             'expected' => array(
    828                 'description' => 'harare',
    829                 'latitude'    => '-17.829',
    830                 'longitude'   => '31.054',
    831                 'country'     => 'ZW',
    832                 'internal'    => true,
    833             ),
    834         ),
    835 
    836         'ip-asia' => array(
    837             'input' => array( 'ip' => '86.108.55.28' ),
    838             'expected' => array(
    839                 'description' => 'amman',
    840                 'latitude'    => '31.955',
    841                 'longitude'   => '35.945',
    842                 'country'     => 'JO',
    843                 'internal'    => true,
    844             ),
    845         ),
    846 
    847         'ip-europe' => array(
    848             'input' => array( 'ip' => '80.95.186.144' ),
    849             'expected' => array(
    850                 'description' => 'belfast',
    851                 'latitude'    => '54.583',
    852                 'longitude'   => '-5.933',
    853                 'country'     => 'GB',
    854                 'internal'    => true,
    855             ),
    856         ),
    857 
    858         'ip-north-america' => array(
    859             'input' => array( 'ip' => '189.147.186.0' ),
    860             'expected' => array(
    861                 'description' => 'mexico city',
    862                 'latitude'    => '19.428',
    863                 'longitude'   => '-99.128',
    864                 'country'     => 'MX',
    865                 'internal'    => true,
    866             ),
    867         ),
    868 
    869         'ip-oceania' => array(
    870             'input' => array( 'ip' => '116.12.57.122' ),
    871             'expected' => array(
    872                 'description' => 'auckland',
    873                 'latitude'    => '-36.867',
    874                 'longitude'   => '174.767',
    875                 'country'     => 'NZ',
    876                 'internal'    => true,
    877             ),
    878         ),
    879 
    880         'ip-south-america' => array(
    881             'input' => array( 'ip' => '181.66.32.136' ),
    882             'expected' => array(
    883                 'description' => 'lima',
    884                 'latitude'    => '-12.043',
    885                 'longitude'   => '-77.028',
    886                 'country'     => 'PE',
    887                 'internal'    => true,
    888             ),
    889         ),
    890 
    891         /*
    892          * Only an IPv6 address is given.
    893          *
    894          * Note that IP locations change frequently, so some of these expected results will inevitably become outdated
    895          * and cause tests to fail.
    896          *
    897          * See https://www.google.com/intl/en/ipv6/statistics.html#tab=per-country-ipv6-adoption&tab=per-country-ipv6-adoption
    898          * See https://awebanalysis.com/en/ipv6-directory/
    899          * See https://www.google.com/search?q=australia+site%3Ahttps%3A%2F%2Fawebanalysis.com%2Fen%2Fipv6-directory%2F
    900          */
    901         'ipv6-africa' => array(
    902             'input'    => array( 'ip' => '2c0f:f8f0:ffff:ffff:ffff:ffff:ffff:ffff' ),
    903             'expected' => array(
    904                 'description' => 'harare',
    905                 'latitude'    => '-17.829',
    906                 'longitude'   => '31.054',
    907                 'country'     => 'ZW',
    908                 'internal'    => true,
    909             ),
    910         ),
    911 
    912         'ipv6-asia-anonymized' => array(
    913             'input'    => array( 'ip' => '2405:200:1000::' ),
    914             'expected' => array(
    915                 'description' => 'mumbai',
    916                 'latitude'    => '19.014',
    917                 'longitude'   => '72.848',
    918                 'country'     => 'IN',
    919                 'internal'    => true,
    920             ),
    921         ),
    922 
    923         'ipv6-europe-anonymized' => array(
    924             'input'    => array( 'ip' => '2a02:578:1000::' ),
    925             'expected' => array(
    926                 'description' => 'sint-niklaas',
    927                 'latitude'    => '51.165',
    928                 'longitude'   => '4.144',
    929                 'country'     => 'BE',
    930                 'internal'    => true,
    931             ),
    932         ),
    933 
    934         'ipv6-north-america-anonymized' => array(
    935             'input'    => array( 'ip' => '2605:a600::' ),
    936             'expected' => array(
    937                 'description' => 'mountain view',
    938                 'latitude'    => '37.386',
    939                 'longitude'   => '-122.084',
    940                 'country'     => 'US',
    941                 'internal'    => true,
    942             ),
    943         ),
    944 
    945         'ipv6-oceania-collapsed-prefix' => array(
    946             'input'    => array( 'ip' => '::ffff:0190:c500' ),
    947             'expected' => array(
    948                 'description' => 'perth',
    949                 'latitude'    => '-31.952',
    950                 'longitude'   => '115.861',
    951                 'country'     => 'AU',
    952                 'internal'    => true,
    953             ),
    954         ),
    955 
    956         'ipv6-south-america' => array(
    957             'input'    => array( 'ip' => '2001:1388:6643:2736:10f1:897c:428c:1b3b' ),
    958             'expected' => array(
    959                 'description' => 'lima',
    960                 'latitude'    => '-12.043',
    961                 'longitude'   => '-77.028',
    962                 'country'     => 'PE',
    963                 'internal'    => true,
    964             ),
    965         ),
    966     );
    967 
    968     return $cases;
    969 }
    970 
    971 /**
    972  * Test `build_response()`
    973  *
    974  * @todo It might be better to do more abstracted tests of `main()`, rather than coupling to the
    975  *       internals of `build_request()`.
    976  *
    977  * @return bool The number of failures
    978  */
    979 function test_build_response() {
    980     $failed = 0;
    981     $cases  = build_response_test_cases();
    982 
    983     printf( "\nRunning %d build_response() tests", count( $cases ) );
    984 
    985     foreach ( $cases as $case_id => $case ) {
    986         $actual_result = build_response( $case['input']['location'], $case['input']['location_args'] );
    987 
    988         $passed = $case['expected']['location']       === $actual_result['location'] &&
    989                   isset( $case['expected']['error'] ) === isset( $actual_result['error'] );
    990 
    991         if ( $passed && $case['expected']['events'] ) {
    992             $passed = ! empty( $actual_result['events'] ) &&
    993                       ! empty( $actual_result['events'][0]['url'] ) &&
    994                       strtotime( $actual_result['events'][0]['date'] ) > time() - ( 2 * 24 * 60 * 60 );
    995         }
    996 
    997         if ( $passed && isset( $case['expected']['error'] ) ) {
    998             $passed = $case['expected']['error'] === $actual_result['error'];
    999         }
    1000 
    1001         output_results( $case_id, $passed, $case['expected'], $actual_result );
    1002 
    1003         if ( ! $passed ) {
    1004             $failed++;
    1005         }
    1006     }
    1007 
    1008     return $failed;
    1009 }
    1010 
    1011 /**
    1012  * Get the cases for testing `build_response()`
    1013  *
    1014  * @return array
    1015  */
    1016 function build_response_test_cases() {
    1017     $cases = array(
    1018         'utrecht-ip' => array(
    1019             'input' => array(
    1020                 'location' => array(
    1021                     'latitude'  => '52.090284',
    1022                     'longitude' => '5.124719',
    1023                     'internal'  => true,
    1024                 ),
    1025                 'location_args' => array( 'ip' => '84.31.177.21' ),
    1026             ),
    1027             'expected' => array(
    1028                 'location' => array(
    1029                     'ip' => '84.31.177.21',
    1030                 ),
    1031                 'events' => true,
    1032             ),
    1033         ),
    1034 
    1035         'canada-country' => array(
    1036             'input' => array(
    1037                 'location' => array(
    1038                     'country' => 'CA',
    1039                 ),
    1040                 'location_args' => array(
    1041                     'restrict_by_country' => true,
    1042                 ),
    1043             ),
    1044             'expected' => array(
    1045                 'location' => array(
    1046                     'country' => 'CA',
    1047                 ),
    1048                 'events' => true,
    1049             ),
    1050         ),
    1051 
    1052         'throttled' => array(
    1053             'input' => array(
    1054                 'location' => 'temp-request-throttled',
    1055             ),
    1056             'expected' => array(
    1057                 'location' => array(),
    1058                 'error'    => 'temp-request-throttled',
    1059                 'events'   => false,
    1060             ),
    1061         ),
    1062 
    1063         'no-location' => array(
    1064             'input' => array(
    1065                 'location' => array(),
    1066             ),
    1067             'expected' => array(
    1068                 'location' => array(),
    1069                 'error'    => 'no_location_available',
    1070                 'events'   => false,
    1071             ),
    1072         ),
    1073     );
    1074 
    1075     return $cases;
    1076 }
    1077 
    1078 /**
    1079  * Test `is_client_core()`.
    1080  *
    1081  * @return int
    1082  */
    1083 function test_is_client_core() {
    1084     $failed = 0;
    1085     $cases  = array(
    1086         ''                                   => false,
    1087         'Contains WordPress but no slash'    => false,
    1088         'WordPress/4.9; https://example.org' => true,
    1089         'WordPress/10.0'                     => true,
    1090     );
    1091 
    1092     printf( "\nRunning %d is_client_core() tests", count( $cases ) );
    1093 
    1094     foreach ( $cases as $user_agent => $expected_result ) {
    1095         $actual_result = is_client_core( $user_agent );
    1096         $passed        = $expected_result === $actual_result;
    1097 
    1098         output_results( $user_agent, $passed, $expected_result, $actual_result );
    1099 
    1100         if ( ! $passed ) {
    1101             $failed++;
    1102         }
    1103     }
    1104 
    1105     return $failed;
    1106101}
    1107102
Note: See TracChangeset for help on using the changeset viewer.