wordpress-develop/tests/phpunit/tests/rest-api/rest-request.php
Gary Pendergast 8f95800d52 Code is Poetry.
WordPress' code just... wasn't.
This is now dealt with.

Props jrf, pento, netweb, GaryJ, jdgrimes, westonruter, Greg Sherwood from PHPCS, and everyone who's ever contributed to WPCS and PHPCS.
Fixes #41057.



git-svn-id: https://develop.svn.wordpress.org/trunk@42343 602fd350-edb4-49c9-b593-d223f7449a82
2017-11-30 23:09:33 +00:00

661 lines
18 KiB
PHP

<?php
/**
* Unit tests covering WP_REST_Request functionality.
*
* @package WordPress
* @subpackage REST API
*/
/**
* @group restapi
*/
class Tests_REST_Request extends WP_UnitTestCase {
public $request;
public function setUp() {
parent::setUp();
$this->request = new WP_REST_Request();
}
public function test_header() {
$value = 'application/x-wp-example';
$this->request->set_header( 'Content-Type', $value );
$this->assertEquals( $value, $this->request->get_header( 'Content-Type' ) );
}
public function test_header_missing() {
$this->assertNull( $this->request->get_header( 'missing' ) );
$this->assertNull( $this->request->get_header_as_array( 'missing' ) );
}
public function test_remove_header() {
$this->request->add_header( 'Test-Header', 'value' );
$this->assertEquals( 'value', $this->request->get_header( 'Test-Header' ) );
$this->request->remove_header( 'Test-Header' );
$this->assertNull( $this->request->get_header( 'Test-Header' ) );
}
public function test_header_multiple() {
$value1 = 'application/x-wp-example-1';
$value2 = 'application/x-wp-example-2';
$this->request->add_header( 'Accept', $value1 );
$this->request->add_header( 'Accept', $value2 );
$this->assertEquals( $value1 . ',' . $value2, $this->request->get_header( 'Accept' ) );
$this->assertEquals( array( $value1, $value2 ), $this->request->get_header_as_array( 'Accept' ) );
}
public static function header_provider() {
return array(
array( 'Test', 'test' ),
array( 'TEST', 'test' ),
array( 'Test-Header', 'test_header' ),
array( 'test-header', 'test_header' ),
array( 'Test_Header', 'test_header' ),
array( 'test_header', 'test_header' ),
);
}
/**
* @dataProvider header_provider
* @param string $original Original header key.
* @param string $expected Expected canonicalized version.
*/
public function test_header_canonicalization( $original, $expected ) {
$this->assertEquals( $expected, $this->request->canonicalize_header_name( $original ) );
}
public static function content_type_provider() {
return array(
// Check basic parsing.
array( 'application/x-wp-example', 'application/x-wp-example', 'application', 'x-wp-example', '' ),
array( 'application/x-wp-example; charset=utf-8', 'application/x-wp-example', 'application', 'x-wp-example', 'charset=utf-8' ),
// Check case insensitivity.
array( 'APPLICATION/x-WP-Example', 'application/x-wp-example', 'application', 'x-wp-example', '' ),
);
}
/**
* @dataProvider content_type_provider
*
* @param string $header Header value.
* @param string $value Full type value.
* @param string $type Main type (application, text, etc).
* @param string $subtype Subtype (json, etc).
* @param string $parameters Parameters (charset=utf-8, etc).
*/
public function test_content_type_parsing( $header, $value, $type, $subtype, $parameters ) {
// Check we start with nothing.
$this->assertEmpty( $this->request->get_content_type() );
$this->request->set_header( 'Content-Type', $header );
$parsed = $this->request->get_content_type();
$this->assertEquals( $value, $parsed['value'] );
$this->assertEquals( $type, $parsed['type'] );
$this->assertEquals( $subtype, $parsed['subtype'] );
$this->assertEquals( $parameters, $parsed['parameters'] );
}
protected function request_with_parameters() {
$this->request->set_url_params(
array(
'source' => 'url',
'has_url_params' => true,
)
);
$this->request->set_query_params(
array(
'source' => 'query',
'has_query_params' => true,
)
);
$this->request->set_body_params(
array(
'source' => 'body',
'has_body_params' => true,
)
);
$json_data = wp_json_encode(
array(
'source' => 'json',
'has_json_params' => true,
)
);
$this->request->set_body( $json_data );
$this->request->set_default_params(
array(
'source' => 'defaults',
'has_default_params' => true,
)
);
}
public function test_parameter_order() {
$this->request_with_parameters();
$this->request->set_method( 'GET' );
// Check that query takes precedence.
$this->assertEquals( 'query', $this->request->get_param( 'source' ) );
// Check that the correct arguments are parsed (and that falling through
// the stack works).
$this->assertTrue( $this->request->get_param( 'has_url_params' ) );
$this->assertTrue( $this->request->get_param( 'has_query_params' ) );
$this->assertTrue( $this->request->get_param( 'has_default_params' ) );
// POST and JSON parameters shouldn't be parsed.
$this->assertEmpty( $this->request->get_param( 'has_body_params' ) );
$this->assertEmpty( $this->request->get_param( 'has_json_params' ) );
}
public function test_parameter_order_post() {
$this->request_with_parameters();
$this->request->set_method( 'POST' );
$this->request->set_header( 'Content-Type', 'application/x-www-form-urlencoded' );
$this->request->set_attributes( array( 'accept_json' => true ) );
// Check that POST takes precedence.
$this->assertEquals( 'body', $this->request->get_param( 'source' ) );
// Check that the correct arguments are parsed (and that falling through
// the stack works).
$this->assertTrue( $this->request->get_param( 'has_url_params' ) );
$this->assertTrue( $this->request->get_param( 'has_query_params' ) );
$this->assertTrue( $this->request->get_param( 'has_body_params' ) );
$this->assertTrue( $this->request->get_param( 'has_default_params' ) );
// JSON shouldn't be parsed.
$this->assertEmpty( $this->request->get_param( 'has_json_params' ) );
}
public function test_parameter_order_json() {
$this->request_with_parameters();
$this->request->set_method( 'POST' );
$this->request->set_header( 'Content-Type', 'application/json' );
$this->request->set_attributes( array( 'accept_json' => true ) );
// Check that JSON takes precedence.
$this->assertEquals( 'json', $this->request->get_param( 'source' ) );
// Check that the correct arguments are parsed (and that falling through
// the stack works).
$this->assertTrue( $this->request->get_param( 'has_url_params' ) );
$this->assertTrue( $this->request->get_param( 'has_query_params' ) );
$this->assertTrue( $this->request->get_param( 'has_body_params' ) );
$this->assertTrue( $this->request->get_param( 'has_json_params' ) );
$this->assertTrue( $this->request->get_param( 'has_default_params' ) );
}
public function test_parameter_order_json_invalid() {
$this->request_with_parameters();
$this->request->set_method( 'POST' );
$this->request->set_header( 'Content-Type', 'application/json' );
$this->request->set_attributes( array( 'accept_json' => true ) );
// Use invalid JSON data.
$this->request->set_body( '{ this is not json }' );
// Check that JSON is ignored.
$this->assertEquals( 'body', $this->request->get_param( 'source' ) );
// Check that the correct arguments are parsed (and that falling through
// the stack works).
$this->assertTrue( $this->request->get_param( 'has_url_params' ) );
$this->assertTrue( $this->request->get_param( 'has_query_params' ) );
$this->assertTrue( $this->request->get_param( 'has_body_params' ) );
$this->assertTrue( $this->request->get_param( 'has_default_params' ) );
// JSON should be ignored.
$this->assertEmpty( $this->request->get_param( 'has_json_params' ) );
}
public function non_post_http_methods_with_request_body_provider() {
return array(
array( 'PUT' ),
array( 'PATCH' ),
array( 'DELETE' ),
);
}
/**
* Tests that methods supporting request bodies have access to the
* request's body. For POST this is straightforward via `$_POST`; for
* other methods `WP_REST_Request` needs to parse the body for us.
*
* @dataProvider non_post_http_methods_with_request_body_provider
*/
public function test_non_post_body_parameters( $request_method ) {
$data = array(
'foo' => 'bar',
'alot' => array(
'of' => 'parameters',
),
'list' => array(
'of',
'cool',
'stuff',
),
);
$this->request->set_method( $request_method );
$this->request->set_body_params( array() );
$this->request->set_body( http_build_query( $data ) );
foreach ( $data as $key => $expected_value ) {
$this->assertEquals( $expected_value, $this->request->get_param( $key ) );
}
}
public function test_parameters_for_json_put() {
$data = array(
'foo' => 'bar',
'alot' => array(
'of' => 'parameters',
),
'list' => array(
'of',
'cool',
'stuff',
),
);
$this->request->set_method( 'PUT' );
$this->request->add_header( 'content-type', 'application/json' );
$this->request->set_body( wp_json_encode( $data ) );
foreach ( $data as $key => $expected_value ) {
$this->assertEquals( $expected_value, $this->request->get_param( $key ) );
}
}
public function test_parameters_for_json_post() {
$data = array(
'foo' => 'bar',
'alot' => array(
'of' => 'parameters',
),
'list' => array(
'of',
'cool',
'stuff',
),
);
$this->request->set_method( 'POST' );
$this->request->add_header( 'content-type', 'application/json' );
$this->request->set_body( wp_json_encode( $data ) );
foreach ( $data as $key => $expected_value ) {
$this->assertEquals( $expected_value, $this->request->get_param( $key ) );
}
}
public function test_parameter_merging() {
$this->request_with_parameters();
$this->request->set_method( 'POST' );
$expected = array(
'source' => 'body',
'has_url_params' => true,
'has_query_params' => true,
'has_body_params' => true,
'has_default_params' => true,
);
$this->assertEquals( $expected, $this->request->get_params() );
}
public function test_parameter_merging_with_numeric_keys() {
$this->request->set_query_params(
array(
'1' => 'hello',
'2' => 'goodbye',
)
);
$expected = array(
'1' => 'hello',
'2' => 'goodbye',
);
$this->assertEquals( $expected, $this->request->get_params() );
}
public function test_sanitize_params() {
$this->request->set_url_params(
array(
'someinteger' => '123',
'somestring' => 'hello',
)
);
$this->request->set_attributes(
array(
'args' => array(
'someinteger' => array(
'sanitize_callback' => 'absint',
),
'somestring' => array(
'sanitize_callback' => 'absint',
),
),
)
);
$this->request->sanitize_params();
$this->assertEquals( 123, $this->request->get_param( 'someinteger' ) );
$this->assertEquals( 0, $this->request->get_param( 'somestring' ) );
}
public function test_sanitize_params_error() {
$this->request->set_url_params(
array(
'successparam' => '123',
'failparam' => '123',
)
);
$this->request->set_attributes(
array(
'args' => array(
'successparam' => array(
'sanitize_callback' => 'absint',
),
'failparam' => array(
'sanitize_callback' => array( $this, '_return_wp_error_on_validate_callback' ),
),
),
)
);
$valid = $this->request->sanitize_params();
$this->assertWPError( $valid );
$this->assertEquals( 'rest_invalid_param', $valid->get_error_code() );
}
public function test_sanitize_params_with_null_callback() {
$this->request->set_url_params(
array(
'some_email' => '',
)
);
$this->request->set_attributes(
array(
'args' => array(
'some_email' => array(
'type' => 'string',
'format' => 'email',
'sanitize_callback' => null,
),
),
)
);
$this->assertTrue( $this->request->sanitize_params() );
}
public function test_sanitize_params_with_false_callback() {
$this->request->set_url_params(
array(
'some_uri' => 1.23422,
)
);
$this->request->set_attributes(
array(
'args' => array(
'some_uri' => array(
'type' => 'string',
'format' => 'uri',
'sanitize_callback' => false,
),
),
)
);
$this->assertTrue( $this->request->sanitize_params() );
}
public function test_has_valid_params_required_flag() {
$this->request->set_attributes(
array(
'args' => array(
'someinteger' => array(
'required' => true,
),
),
)
);
$valid = $this->request->has_valid_params();
$this->assertWPError( $valid );
$this->assertEquals( 'rest_missing_callback_param', $valid->get_error_code() );
}
public function test_has_valid_params_required_flag_multiple() {
$this->request->set_attributes(
array(
'args' => array(
'someinteger' => array(
'required' => true,
),
'someotherinteger' => array(
'required' => true,
),
),
)
);
$valid = $this->request->has_valid_params();
$this->assertWPError( $valid );
$this->assertEquals( 'rest_missing_callback_param', $valid->get_error_code() );
$data = $valid->get_error_data( 'rest_missing_callback_param' );
$this->assertTrue( in_array( 'someinteger', $data['params'] ) );
$this->assertTrue( in_array( 'someotherinteger', $data['params'] ) );
}
public function test_has_valid_params_validate_callback() {
$this->request->set_url_params(
array(
'someinteger' => '123',
)
);
$this->request->set_attributes(
array(
'args' => array(
'someinteger' => array(
'validate_callback' => '__return_false',
),
),
)
);
$valid = $this->request->has_valid_params();
$this->assertWPError( $valid );
$this->assertEquals( 'rest_invalid_param', $valid->get_error_code() );
}
public function test_has_valid_params_json_error() {
if ( version_compare( PHP_VERSION, '5.3', '<' ) ) {
return $this->markTestSkipped( 'JSON validation is only available for PHP 5.3+' );
}
$this->request->set_header( 'Content-Type', 'application/json' );
$this->request->set_body( '{"invalid": JSON}' );
$valid = $this->request->has_valid_params();
$this->assertWPError( $valid );
$this->assertEquals( 'rest_invalid_json', $valid->get_error_code() );
$data = $valid->get_error_data();
$this->assertEquals( JSON_ERROR_SYNTAX, $data['json_error_code'] );
}
public function test_has_valid_params_empty_json_no_error() {
if ( version_compare( PHP_VERSION, '5.3', '<' ) ) {
return $this->markTestSkipped( 'JSON validation is only available for PHP 5.3+' );
}
$this->request->set_header( 'Content-Type', 'application/json' );
$this->request->set_body( '' );
$valid = $this->request->has_valid_params();
$this->assertNotWPError( $valid );
}
public function test_has_multiple_invalid_params_validate_callback() {
$this->request->set_url_params(
array(
'someinteger' => '123',
'someotherinteger' => '123',
)
);
$this->request->set_attributes(
array(
'args' => array(
'someinteger' => array(
'validate_callback' => '__return_false',
),
'someotherinteger' => array(
'validate_callback' => '__return_false',
),
),
)
);
$valid = $this->request->has_valid_params();
$this->assertWPError( $valid );
$this->assertEquals( 'rest_invalid_param', $valid->get_error_code() );
$data = $valid->get_error_data( 'rest_invalid_param' );
$this->assertArrayHasKey( 'someinteger', $data['params'] );
$this->assertArrayHasKey( 'someotherinteger', $data['params'] );
}
public function test_invalid_params_error_response_format() {
$this->request->set_url_params(
array(
'someinteger' => '123',
'someotherparams' => '123',
)
);
$this->request->set_attributes(
array(
'args' => array(
'someinteger' => array(
'validate_callback' => '__return_false',
),
'someotherparams' => array(
'validate_callback' => array( $this, '_return_wp_error_on_validate_callback' ),
),
),
)
);
$valid = $this->request->has_valid_params();
$this->assertWPError( $valid );
$error_data = $valid->get_error_data();
$this->assertEquals( array( 'someinteger', 'someotherparams' ), array_keys( $error_data['params'] ) );
$this->assertEquals( 'This is not valid!', $error_data['params']['someotherparams'] );
}
public function _return_wp_error_on_validate_callback() {
return new WP_Error( 'some-error', 'This is not valid!' );
}
public function data_from_url() {
return array(
array(
'permalink_structure' => '/%post_name%/',
'original_url' => 'http://' . WP_TESTS_DOMAIN . '/wp-json/wp/v2/posts/1?foo=bar',
),
array(
'permalink_structure' => '',
'original_url' => 'http://' . WP_TESTS_DOMAIN . '/index.php?rest_route=%2Fwp%2Fv2%2Fposts%2F1&foo=bar',
),
);
}
/**
* @dataProvider data_from_url
*/
public function test_from_url( $permalink_structure, $original_url ) {
update_option( 'permalink_structure', $permalink_structure );
$url = add_query_arg( 'foo', 'bar', rest_url( '/wp/v2/posts/1' ) );
$this->assertEquals( $original_url, $url );
$request = WP_REST_Request::from_url( $url );
$this->assertInstanceOf( 'WP_REST_Request', $request );
$this->assertEquals( '/wp/v2/posts/1', $request->get_route() );
$this->assertEqualSets(
array(
'foo' => 'bar',
), $request->get_query_params()
);
}
/**
* @dataProvider data_from_url
*/
public function test_from_url_invalid( $permalink_structure ) {
update_option( 'permalink_structure', $permalink_structure );
$using_site = site_url( '/wp/v2/posts/1' );
$request = WP_REST_Request::from_url( $using_site );
$this->assertFalse( $request );
$using_home = home_url( '/wp/v2/posts/1' );
$request = WP_REST_Request::from_url( $using_home );
$this->assertFalse( $request );
}
public function test_set_param() {
$request = new WP_REST_Request();
$request->set_param( 'param', 'value' );
$this->assertEquals( 'value', $request->get_param( 'param' ) );
}
public function test_set_param_follows_parameter_order() {
$request = new WP_REST_Request();
$request->add_header( 'content-type', 'application/json' );
$request->set_method( 'POST' );
$request->set_body(
wp_json_encode(
array(
'param' => 'value',
)
)
);
$this->assertEquals( 'value', $request->get_param( 'param' ) );
$this->assertEquals(
array( 'param' => 'value' ),
$request->get_json_params()
);
$request->set_param( 'param', 'new_value' );
$this->assertEquals( 'new_value', $request->get_param( 'param' ) );
$this->assertEquals(
array( 'param' => 'new_value' ),
$request->get_json_params()
);
}
}