Skip to content

Commit ed7bdd2

Browse files
author
gziolo
committed
Abilities API: Add coverage for ignored schema validate_callback/sanitize_callback
Add characterization tests documenting that an ability ignores two REST-style schema keywords: * `validate_callback` is never invoked. The REST request layer calls it, but `rest_validate_value_from_schema()` does not. * There is no sanitization pass, so `sanitize_callback` never runs and input reaches the execute callback uncoerced. Custom validation belongs in the `wp_ability_validate_input` / `wp_ability_validate_output` filters. Test-only change. `arg_options` is intentionally not covered here: it is a registration-time helper for `rest_get_endpoint_args_for_schema()` with no runtime meaning for abilities. Follow-up [61032], #64098. See #64955. git-svn-id: https://develop.svn.wordpress.org/trunk@62440 602fd350-edb4-49c9-b593-d223f7449a82
1 parent b2850aa commit ed7bdd2

1 file changed

Lines changed: 117 additions & 0 deletions

File tree

tests/phpunit/tests/abilities-api/wpAbility.php

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1817,4 +1817,121 @@ public function test_ability_invoked_action_fires_on_validation_failure() {
18171817

18181818
$this->assertSame( 1, $action->get_call_count(), 'wp_ability_invoked should fire before input validation failure.' );
18191819
}
1820+
1821+
/**
1822+
* Tests that a `validate_callback` in an input schema is ignored.
1823+
*
1824+
* The REST API invokes a `validate_callback` per request argument, so it is a
1825+
* reasonable thing to expect here too — but abilities do not reuse that
1826+
* request-layer machinery, and a server-only PHP callback could not be honored
1827+
* by the clients that consume the schema anyway. Custom validation belongs in
1828+
* the `wp_ability_validate_input` filter.
1829+
*
1830+
* @ticket 64098
1831+
*/
1832+
public function test_validate_input_ignores_schema_validate_callback() {
1833+
$callback_invoked = false;
1834+
1835+
$args = array_merge(
1836+
self::$test_ability_properties,
1837+
array(
1838+
'input_schema' => array(
1839+
'type' => 'string',
1840+
'validate_callback' => static function () use ( &$callback_invoked ) {
1841+
$callback_invoked = true;
1842+
return new WP_Error( 'should_not_run', 'Schema validate_callback must not be invoked.' );
1843+
},
1844+
),
1845+
)
1846+
);
1847+
1848+
$ability = new WP_Ability( self::$test_ability_name, $args );
1849+
1850+
// 'hello' satisfies the JSON Schema (type string); the validate_callback would
1851+
// reject every value if it were ever invoked.
1852+
$result = $ability->validate_input( 'hello' );
1853+
1854+
$this->assertTrue( $result, 'Input should pass on JSON Schema alone.' );
1855+
$this->assertFalse( $callback_invoked, 'Schema validate_callback must not run during input validation.' );
1856+
}
1857+
1858+
/**
1859+
* Tests that a `validate_callback` in an output schema is ignored.
1860+
*
1861+
* Output is validated the same way as input, so the same reasoning applies: the
1862+
* schema callback never runs. Custom output validation belongs in the
1863+
* `wp_ability_validate_output` filter.
1864+
*
1865+
* @ticket 64098
1866+
*/
1867+
public function test_validate_output_ignores_schema_validate_callback() {
1868+
$callback_invoked = false;
1869+
1870+
$args = array_merge(
1871+
self::$test_ability_properties,
1872+
array(
1873+
'output_schema' => array(
1874+
'type' => 'string',
1875+
'validate_callback' => static function () use ( &$callback_invoked ) {
1876+
$callback_invoked = true;
1877+
return new WP_Error( 'should_not_run', 'Schema validate_callback must not be invoked.' );
1878+
},
1879+
),
1880+
'execute_callback' => static function (): string {
1881+
return 'result';
1882+
},
1883+
)
1884+
);
1885+
1886+
$ability = new WP_Ability( self::$test_ability_name, $args );
1887+
1888+
// The execute callback returns a valid string; the output validate_callback would
1889+
// reject it if it ran, so a returned result proves the callback was ignored.
1890+
$result = $ability->execute();
1891+
1892+
$this->assertSame( 'result', $result, 'Output should pass on JSON Schema alone, so execute() returns the result.' );
1893+
$this->assertFalse( $callback_invoked, 'Schema validate_callback must not run during output validation.' );
1894+
}
1895+
1896+
/**
1897+
* Tests that a `sanitize_callback` is ignored and input is never sanitized.
1898+
*
1899+
* REST cleans and type-coerces arguments in a sanitization step; abilities have
1900+
* no such step, so a `sanitize_callback` never runs and a mistyped value is
1901+
* rejected rather than coerced. This is the easiest REST assumption to carry
1902+
* over by mistake, so it is pinned explicitly.
1903+
*
1904+
* @ticket 64098
1905+
*/
1906+
public function test_execute_ignores_schema_sanitize_callback() {
1907+
$callback_invoked = false;
1908+
1909+
$args = array_merge(
1910+
self::$test_ability_properties,
1911+
array(
1912+
'input_schema' => array(
1913+
'type' => 'string',
1914+
'sanitize_callback' => static function ( $value ) use ( &$callback_invoked ) {
1915+
$callback_invoked = true;
1916+
return 'sanitized';
1917+
},
1918+
),
1919+
'output_schema' => array(
1920+
'type' => 'string',
1921+
),
1922+
'execute_callback' => static function ( $input ): string {
1923+
return $input;
1924+
},
1925+
)
1926+
);
1927+
1928+
$ability = new WP_Ability( self::$test_ability_name, $args );
1929+
1930+
// The execute callback echoes its input, so an unmodified return value proves
1931+
// the sanitize_callback never ran and no sanitization pass took place.
1932+
$result = $ability->execute( 'raw value' );
1933+
1934+
$this->assertSame( 'raw value', $result, 'Input should reach the execute callback unmodified (no sanitization).' );
1935+
$this->assertFalse( $callback_invoked, 'Schema sanitize_callback must not run.' );
1936+
}
18201937
}

0 commit comments

Comments
 (0)