Make WordPress Core


Ignore:
Timestamp:
01/24/2021 04:50:39 PM (4 years ago)
Author:
TimothyBlynJacobs
Message:

REST API: Support type coercion when validating the enum JSON Schema keyword.

Previously, the enum keyword was validated by perform a strict equality check. For string types this is generally ok, but it prevented using alternative types like number when rich type support isn't available.

Now the same level of type coercion/sanitization is applied when validating enum as all other validation checks. This means that a value of "1" will be accepted for an enum of [ 0, 1 ]. Additionally, object types now properly ignore key order when checking for equality.

Props yakimun.
Fixes #51911.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/tests/phpunit/tests/rest-api/rest-schema-validation.php

    r49246 r50010  
    247247        $this->assertTrue( rest_validate_value_from_schema( 'ribs,chicken,', $schema ) );
    248248        $this->assertTrue( rest_validate_value_from_schema( '', $schema ) );
     249    }
     250
     251    /**
     252     * @ticket 51911
     253     *
     254     * @dataProvider data_different_types_of_value_and_enum_elements
     255     *
     256     * @param mixed $value
     257     * @param array $args
     258     * @param bool  $expected
     259     */
     260    public function test_different_types_of_value_and_enum_elements( $value, $args, $expected ) {
     261        $result = rest_validate_value_from_schema( $value, $args );
     262        if ( $expected ) {
     263            $this->assertTrue( $result );
     264        } else {
     265            $this->assertWPError( $result );
     266        }
     267    }
     268
     269    /**
     270     * @return array
     271     */
     272    public function data_different_types_of_value_and_enum_elements() {
     273        return array(
     274            // enum with integers
     275            array(
     276                0,
     277                array(
     278                    'type' => 'integer',
     279                    'enum' => array( 0, 1 ),
     280                ),
     281                true,
     282            ),
     283            array(
     284                0.0,
     285                array(
     286                    'type' => 'integer',
     287                    'enum' => array( 0, 1 ),
     288                ),
     289                true,
     290            ),
     291            array(
     292                '0',
     293                array(
     294                    'type' => 'integer',
     295                    'enum' => array( 0, 1 ),
     296                ),
     297                true,
     298            ),
     299            array(
     300                1,
     301                array(
     302                    'type' => 'integer',
     303                    'enum' => array( 0, 1 ),
     304                ),
     305                true,
     306            ),
     307            array(
     308                1.0,
     309                array(
     310                    'type' => 'integer',
     311                    'enum' => array( 0, 1 ),
     312                ),
     313                true,
     314            ),
     315            array(
     316                '1',
     317                array(
     318                    'type' => 'integer',
     319                    'enum' => array( 0, 1 ),
     320                ),
     321                true,
     322            ),
     323            array(
     324                2,
     325                array(
     326                    'type' => 'integer',
     327                    'enum' => array( 0, 1 ),
     328                ),
     329                false,
     330            ),
     331            array(
     332                2.0,
     333                array(
     334                    'type' => 'integer',
     335                    'enum' => array( 0, 1 ),
     336                ),
     337                false,
     338            ),
     339            array(
     340                '2',
     341                array(
     342                    'type' => 'integer',
     343                    'enum' => array( 0, 1 ),
     344                ),
     345                false,
     346            ),
     347
     348            // enum with floats
     349            array(
     350                0,
     351                array(
     352                    'type' => 'number',
     353                    'enum' => array( 0.0, 1.0 ),
     354                ),
     355                true,
     356            ),
     357            array(
     358                0.0,
     359                array(
     360                    'type' => 'number',
     361                    'enum' => array( 0.0, 1.0 ),
     362                ),
     363                true,
     364            ),
     365            array(
     366                '0',
     367                array(
     368                    'type' => 'number',
     369                    'enum' => array( 0.0, 1.0 ),
     370                ),
     371                true,
     372            ),
     373            array(
     374                1,
     375                array(
     376                    'type' => 'number',
     377                    'enum' => array( 0.0, 1.0 ),
     378                ),
     379                true,
     380            ),
     381            array(
     382                1.0,
     383                array(
     384                    'type' => 'number',
     385                    'enum' => array( 0.0, 1.0 ),
     386                ),
     387                true,
     388            ),
     389            array(
     390                '1',
     391                array(
     392                    'type' => 'number',
     393                    'enum' => array( 0.0, 1.0 ),
     394                ),
     395                true,
     396            ),
     397            array(
     398                2,
     399                array(
     400                    'type' => 'number',
     401                    'enum' => array( 0.0, 1.0 ),
     402                ),
     403                false,
     404            ),
     405            array(
     406                2.0,
     407                array(
     408                    'type' => 'number',
     409                    'enum' => array( 0.0, 1.0 ),
     410                ),
     411                false,
     412            ),
     413            array(
     414                '2',
     415                array(
     416                    'type' => 'number',
     417                    'enum' => array( 0.0, 1.0 ),
     418                ),
     419                false,
     420            ),
     421
     422            // enum with booleans
     423            array(
     424                true,
     425                array(
     426                    'type' => 'boolean',
     427                    'enum' => array( true ),
     428                ),
     429                true,
     430            ),
     431            array(
     432                1,
     433                array(
     434                    'type' => 'boolean',
     435                    'enum' => array( true ),
     436                ),
     437                true,
     438            ),
     439            array(
     440                'true',
     441                array(
     442                    'type' => 'boolean',
     443                    'enum' => array( true ),
     444                ),
     445                true,
     446            ),
     447            array(
     448                false,
     449                array(
     450                    'type' => 'boolean',
     451                    'enum' => array( true ),
     452                ),
     453                false,
     454            ),
     455            array(
     456                0,
     457                array(
     458                    'type' => 'boolean',
     459                    'enum' => array( true ),
     460                ),
     461                false,
     462            ),
     463            array(
     464                'false',
     465                array(
     466                    'type' => 'boolean',
     467                    'enum' => array( true ),
     468                ),
     469                false,
     470            ),
     471            array(
     472                false,
     473                array(
     474                    'type' => 'boolean',
     475                    'enum' => array( false ),
     476                ),
     477                true,
     478            ),
     479            array(
     480                0,
     481                array(
     482                    'type' => 'boolean',
     483                    'enum' => array( false ),
     484                ),
     485                true,
     486            ),
     487            array(
     488                'false',
     489                array(
     490                    'type' => 'boolean',
     491                    'enum' => array( false ),
     492                ),
     493                true,
     494            ),
     495            array(
     496                true,
     497                array(
     498                    'type' => 'boolean',
     499                    'enum' => array( false ),
     500                ),
     501                false,
     502            ),
     503            array(
     504                1,
     505                array(
     506                    'type' => 'boolean',
     507                    'enum' => array( false ),
     508                ),
     509                false,
     510            ),
     511            array(
     512                'true',
     513                array(
     514                    'type' => 'boolean',
     515                    'enum' => array( false ),
     516                ),
     517                false,
     518            ),
     519
     520            // enum with arrays
     521            array(
     522                array( 0, 1 ),
     523                array(
     524                    'type'  => 'array',
     525                    'items' => array( 'type' => 'integer' ),
     526                    'enum'  => array( array( 0, 1 ), array( 1, 2 ) ),
     527                ),
     528                true,
     529            ),
     530            array(
     531                array( '0', 1 ),
     532                array(
     533                    'type'  => 'array',
     534                    'items' => array( 'type' => 'integer' ),
     535                    'enum'  => array( array( 0, 1 ), array( 1, 2 ) ),
     536                ),
     537                true,
     538            ),
     539            array(
     540                array( 0, '1' ),
     541                array(
     542                    'type'  => 'array',
     543                    'items' => array( 'type' => 'integer' ),
     544                    'enum'  => array( array( 0, 1 ), array( 1, 2 ) ),
     545                ),
     546                true,
     547            ),
     548            array(
     549                array( '0', '1' ),
     550                array(
     551                    'type'  => 'array',
     552                    'items' => array( 'type' => 'integer' ),
     553                    'enum'  => array( array( 0, 1 ), array( 1, 2 ) ),
     554                ),
     555                true,
     556            ),
     557            array(
     558                array( 1, 2 ),
     559                array(
     560                    'type'  => 'array',
     561                    'items' => array( 'type' => 'integer' ),
     562                    'enum'  => array( array( 0, 1 ), array( 1, 2 ) ),
     563                ),
     564                true,
     565            ),
     566            array(
     567                array( 2, 3 ),
     568                array(
     569                    'type'  => 'array',
     570                    'items' => array( 'type' => 'integer' ),
     571                    'enum'  => array( array( 0, 1 ), array( 1, 2 ) ),
     572                ),
     573                false,
     574            ),
     575            array(
     576                array( 1, 0 ),
     577                array(
     578                    'type'  => 'array',
     579                    'items' => array( 'type' => 'integer' ),
     580                    'enum'  => array( array( 0, 1 ), array( 1, 2 ) ),
     581                ),
     582                false,
     583            ),
     584
     585            // enum with objects
     586            array(
     587                array(
     588                    'a' => 1,
     589                    'b' => 2,
     590                ),
     591                array(
     592                    'type'                 => 'object',
     593                    'additionalProperties' => array( 'type' => 'integer' ),
     594                    'enum'                 => array(
     595                        array(
     596                            'a' => 1,
     597                            'b' => 2,
     598                        ),
     599                        array(
     600                            'b' => 2,
     601                            'c' => 3,
     602                        ),
     603                    ),
     604                ),
     605                true,
     606            ),
     607            array(
     608                array(
     609                    'a' => '1',
     610                    'b' => 2,
     611                ),
     612                array(
     613                    'type'                 => 'object',
     614                    'additionalProperties' => array( 'type' => 'integer' ),
     615                    'enum'                 => array(
     616                        array(
     617                            'a' => 1,
     618                            'b' => 2,
     619                        ),
     620                        array(
     621                            'b' => 2,
     622                            'c' => 3,
     623                        ),
     624                    ),
     625                ),
     626                true,
     627            ),
     628            array(
     629                array(
     630                    'a' => 1,
     631                    'b' => '2',
     632                ),
     633                array(
     634                    'type'                 => 'object',
     635                    'additionalProperties' => array( 'type' => 'integer' ),
     636                    'enum'                 => array(
     637                        array(
     638                            'a' => 1,
     639                            'b' => 2,
     640                        ),
     641                        array(
     642                            'b' => 2,
     643                            'c' => 3,
     644                        ),
     645                    ),
     646                ),
     647                true,
     648            ),
     649            array(
     650                array(
     651                    'a' => '1',
     652                    'b' => '2',
     653                ),
     654                array(
     655                    'type'                 => 'object',
     656                    'additionalProperties' => array( 'type' => 'integer' ),
     657                    'enum'                 => array(
     658                        array(
     659                            'a' => 1,
     660                            'b' => 2,
     661                        ),
     662                        array(
     663                            'b' => 2,
     664                            'c' => 3,
     665                        ),
     666                    ),
     667                ),
     668                true,
     669            ),
     670            array(
     671                array(
     672                    'b' => 2,
     673                    'a' => 1,
     674                ),
     675                array(
     676                    'type'                 => 'object',
     677                    'additionalProperties' => array( 'type' => 'integer' ),
     678                    'enum'                 => array(
     679                        array(
     680                            'a' => 1,
     681                            'b' => 2,
     682                        ),
     683                        array(
     684                            'b' => 2,
     685                            'c' => 3,
     686                        ),
     687                    ),
     688                ),
     689                true,
     690            ),
     691            array(
     692                array(
     693                    'b' => 2,
     694                    'c' => 3,
     695                ),
     696                array(
     697                    'type'                 => 'object',
     698                    'additionalProperties' => array( 'type' => 'integer' ),
     699                    'enum'                 => array(
     700                        array(
     701                            'a' => 1,
     702                            'b' => 2,
     703                        ),
     704                        array(
     705                            'b' => 2,
     706                            'c' => 3,
     707                        ),
     708                    ),
     709                ),
     710                true,
     711            ),
     712            array(
     713                array(
     714                    'a' => 1,
     715                    'b' => 3,
     716                ),
     717                array(
     718                    'type'                 => 'object',
     719                    'additionalProperties' => array( 'type' => 'integer' ),
     720                    'enum'                 => array(
     721                        array(
     722                            'a' => 1,
     723                            'b' => 2,
     724                        ),
     725                        array(
     726                            'b' => 2,
     727                            'c' => 3,
     728                        ),
     729                    ),
     730                ),
     731                false,
     732            ),
     733            array(
     734                array(
     735                    'c' => 3,
     736                    'd' => 4,
     737                ),
     738                array(
     739                    'type'                 => 'object',
     740                    'additionalProperties' => array( 'type' => 'integer' ),
     741                    'enum'                 => array(
     742                        array(
     743                            'a' => 1,
     744                            'b' => 2,
     745                        ),
     746                        array(
     747                            'b' => 2,
     748                            'c' => 3,
     749                        ),
     750                    ),
     751                ),
     752                false,
     753            ),
     754        );
    249755    }
    250756
Note: See TracChangeset for help on using the changeset viewer.