Make WordPress Core

Changeset 61363


Ignore:
Timestamp:
12/09/2025 06:32:27 PM (4 days ago)
Author:
jorgefilipecosta
Message:

Add: Unit test to validate core abilities schemas only include valid properties.

On https://github.com/WordPress/wordpress-develop/pull/10508 we fixed an issue where some core abilties used invalid schema-04 properties.
This commit adds a unit test to make all the properties used are valid, so the same issue does not happen in the future.

Props jorgefilipecosta, westonruter.
Fixes: #64384

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/tests/phpunit/tests/abilities-api/wpRegisterCoreAbilities.php

    r61069 r61363  
    175175        $this->assertSame( $environment, $ability_data['environment'] );
    176176    }
     177
     178    /**
     179     * Tests that all core ability schemas only use valid JSON Schema keywords.
     180     *
     181     * This prevents regressions where invalid keywords like 'examples' are used
     182     * in schema properties (not valid in JSON Schema draft-04 used by WordPress).
     183     *
     184     * @ticket 64384
     185     */
     186    public function test_core_abilities_schemas_use_only_valid_keywords(): void {
     187        $allowed_keywords = rest_get_allowed_schema_keywords();
     188        // Add 'required' which is valid at the property level for draft-04.
     189        $allowed_keywords[] = 'required';
     190
     191        $abilities = wp_get_abilities();
     192
     193        $this->assertNotEmpty( $abilities, 'Core abilities should be registered.' );
     194
     195        foreach ( $abilities as $ability ) {
     196            $this->assert_schema_uses_valid_keywords(
     197                $ability->get_input_schema(),
     198                $allowed_keywords,
     199                $ability->get_name() . ' input_schema'
     200            );
     201            $this->assert_schema_uses_valid_keywords(
     202                $ability->get_output_schema(),
     203                $allowed_keywords,
     204                $ability->get_name() . ' output_schema'
     205            );
     206        }
     207    }
     208
     209    /**
     210     * Recursively validates that a schema only uses allowed keywords.
     211     *
     212     * @param array|null $schema           The schema to validate.
     213     * @param string[]   $allowed_keywords List of allowed schema keywords.
     214     * @param string     $context          Context for error messages.
     215     */
     216    private function assert_schema_uses_valid_keywords( ?array $schema, array $allowed_keywords, string $context ): void {
     217        if ( null === $schema ) {
     218            return;
     219        }
     220
     221        foreach ( $schema as $key => $value ) {
     222            // Skip integer keys (array indices).
     223            if ( is_int( $key ) ) {
     224                continue;
     225            }
     226
     227            // These keywords contain nested schemas that we recurse into.
     228            $nesting_keywords = array( 'properties', 'items', 'additionalProperties', 'patternProperties', 'anyOf', 'oneOf' );
     229
     230            if ( ! in_array( $key, $nesting_keywords, true ) && ! in_array( $key, $allowed_keywords, true ) ) {
     231                $this->fail( "Invalid schema keyword '{$key}' found in {$context}. Valid keywords are: " . implode( ', ', $allowed_keywords ) );
     232            }
     233
     234            // Recursively check nested schemas.
     235            if ( 'properties' === $key && is_array( $value ) ) {
     236                foreach ( $value as $prop_name => $prop_schema ) {
     237                    $this->assert_schema_uses_valid_keywords(
     238                        $prop_schema,
     239                        $allowed_keywords,
     240                        "{$context}.properties.{$prop_name}"
     241                    );
     242                }
     243            } elseif ( 'items' === $key && is_array( $value ) ) {
     244                $this->assert_schema_uses_valid_keywords(
     245                    $value,
     246                    $allowed_keywords,
     247                    "{$context}.items"
     248                );
     249            } elseif ( ( 'anyOf' === $key || 'oneOf' === $key ) && is_array( $value ) ) {
     250                foreach ( $value as $index => $sub_schema ) {
     251                    $this->assert_schema_uses_valid_keywords(
     252                        $sub_schema,
     253                        $allowed_keywords,
     254                        "{$context}.{$key}[{$index}]"
     255                    );
     256                }
     257            } elseif ( 'additionalProperties' === $key && is_array( $value ) ) {
     258                $this->assert_schema_uses_valid_keywords(
     259                    $value,
     260                    $allowed_keywords,
     261                    "{$context}.additionalProperties"
     262                );
     263            }
     264        }
     265    }
    177266}
Note: See TracChangeset for help on using the changeset viewer.