Making WordPress.org


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

Events: Port more tests to PHPUnit.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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.' );
Note: See TracChangeset for help on using the changeset viewer.