diff --git a/phpunit/tests/fonts/font-library/wpRestFontCollectionsController.php b/phpunit/tests/fonts/font-library/wpRestFontCollectionsController.php deleted file mode 100644 index bd511c8150e23f..00000000000000 --- a/phpunit/tests/fonts/font-library/wpRestFontCollectionsController.php +++ /dev/null @@ -1,207 +0,0 @@ -get_font_collections(); - foreach ( $collections as $slug => $collection ) { - WP_Font_Library::get_instance()->unregister_font_collection( $slug ); - } - - self::$admin_id = $factory->user->create( - array( - 'role' => 'administrator', - ) - ); - self::$editor_id = $factory->user->create( - array( - 'role' => 'editor', - ) - ); - $mock_file = wp_tempnam( 'my-collection-data-' ); - file_put_contents( $mock_file, '{"name": "Mock Collection", "font_families": [ "mock" ], "categories": [ "mock" ] }' ); - - wp_register_font_collection( 'mock-col-slug', $mock_file ); - } - - public static function wpTearDownAfterClass() { - self::delete_user( self::$admin_id ); - self::delete_user( self::$editor_id ); - wp_unregister_font_collection( 'mock-col-slug' ); - } - - /** - * @covers WP_REST_Font_Collections_Controller::register_routes - */ - public function test_register_routes() { - $routes = rest_get_server()->get_routes(); - - $this->assertArrayHasKey( 'GET', $routes['/wp/v2/font-collections'][0]['methods'], 'Rest server has not the GET method for collections initialized.' ); - $this->assertArrayHasKey( 'GET', $routes['/wp/v2/font-collections/(?P[\/\w-]+)'][0]['methods'], 'Rest server has not the GET method for collection initialized.' ); - } - - /** - * @covers WP_REST_Font_Collections_Controller::get_items - */ - public function test_get_items() { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'GET', '/wp/v2/font-collections' ); - $response = rest_get_server()->dispatch( $request ); - $content = $response->get_data(); - $this->assertIsArray( $content ); - $this->assertSame( 200, $response->get_status() ); - } - - /** - * @covers WP_REST_Font_Collections_Controller::get_items - */ - public function test_get_items_should_only_return_valid_collections() { - $this->setExpectedIncorrectUsage( 'WP_Font_Collection::load_from_json' ); - - wp_set_current_user( self::$admin_id ); - wp_register_font_collection( 'invalid-collection', 'invalid-collection-file' ); - - $request = new WP_REST_Request( 'GET', '/wp/v2/font-collections' ); - $response = rest_get_server()->dispatch( $request ); - $content = $response->get_data(); - - wp_unregister_font_collection( 'invalid-collection' ); - - $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' ); - $this->assertCount( 1, $content, 'The response should only contain valid collections.' ); - } - - /** - * @covers WP_REST_Font_Collections_Controller::get_item - */ - public function test_get_item() { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'GET', '/wp/v2/font-collections/mock-col-slug' ); - $response = rest_get_server()->dispatch( $request ); - $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' ); - - $response_data = $response->get_data(); - $this->assertArrayHasKey( 'name', $response_data, 'Response data does not have the name key.' ); - $this->assertArrayHasKey( 'slug', $response_data, 'Response data does not have the slug key.' ); - $this->assertArrayHasKey( 'description', $response_data, 'Response data does not have the description key.' ); - $this->assertArrayHasKey( 'font_families', $response_data, 'Response data does not have the font_families key.' ); - $this->assertArrayHasKey( 'categories', $response_data, 'Response data does not have the categories key.' ); - - $this->assertIsString( $response_data['name'], 'name is not a string.' ); - $this->assertIsString( $response_data['slug'], 'slug is not a string.' ); - $this->assertIsString( $response_data['description'], 'description is not a string.' ); - - $this->assertIsArray( $response_data['font_families'], 'font_families is not an array.' ); - $this->assertIsArray( $response_data['categories'], 'categories is not an array.' ); - } - - /** - * @covers WP_REST_Font_Collections_Controller::get_item - */ - public function test_get_item_invalid_slug() { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'GET', '/wp/v2/font-collections/non-existing-collection' ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_font_collection_not_found', $response, 404 ); - } - - /** - * @covers WP_REST_Font_Collections_Controller::get_item - */ - public function test_get_item_invalid_collection() { - $this->setExpectedIncorrectUsage( 'WP_Font_Collection::load_from_json' ); - - wp_set_current_user( self::$admin_id ); - $slug = 'invalid-collection'; - wp_register_font_collection( $slug, 'invalid-collection-file' ); - - $request = new WP_REST_Request( 'GET', '/wp/v2/font-collections/' . $slug ); - $response = rest_get_server()->dispatch( $request ); - - wp_unregister_font_collection( $slug ); - - $this->assertErrorResponse( 'font_collection_json_missing', $response, 500, 'When the collection json file is invalid, the response should return an error for "font_collection_json_missing" with 500 status.' ); - } - - /** - * @covers WP_REST_Font_Collections_Controller::get_item - */ - public function test_get_item_invalid_id_permission() { - $request = new WP_REST_Request( 'GET', '/wp/v2/font-collections/mock-col-slug' ); - - wp_set_current_user( 0 ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_cannot_read', $response, 401, 'The response status should be 401 for non-authenticated users.' ); - - wp_set_current_user( self::$editor_id ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_cannot_read', $response, 403, 'The response status should be 403 for users without the right permissions.' ); - } - - /** - * @doesNotPerformAssertions - */ - public function test_context_param() { - // Controller does not use get_context_param(). - } - - /** - * @doesNotPerformAssertions - */ - public function test_create_item() { - // Controller does not use test_create_item(). - } - - /** - * @doesNotPerformAssertions - */ - public function test_update_item() { - // Controller does not use test_update_item(). - } - - /** - * @doesNotPerformAssertions - */ - public function test_delete_item() { - // Controller does not use test_delete_item(). - } - - /** - * @doesNotPerformAssertions - */ - public function test_prepare_item() { - // Controller does not use test_prepare_item(). - } - - public function test_get_item_schema() { - $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/font-collections' ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - - $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' ); - $properties = $data['schema']['properties']; - $this->assertCount( 5, $properties, 'There should be 5 properties in the response data schema.' ); - $this->assertArrayHasKey( 'slug', $properties, 'The slug property should exist in the response data schema.' ); - $this->assertArrayHasKey( 'name', $properties, 'The name property should exist in the response data schema.' ); - $this->assertArrayHasKey( 'description', $properties, 'The description property should exist in the response data schema.' ); - $this->assertArrayHasKey( 'font_families', $properties, 'The slug font_families should exist in the response data schema.' ); - $this->assertArrayHasKey( 'categories', $properties, 'The categories property should exist in the response data schema.' ); - } -} diff --git a/phpunit/tests/fonts/font-library/wpRestFontFacesController.php b/phpunit/tests/fonts/font-library/wpRestFontFacesController.php deleted file mode 100644 index 2312ca6dabc6fd..00000000000000 --- a/phpunit/tests/fonts/font-library/wpRestFontFacesController.php +++ /dev/null @@ -1,1080 +0,0 @@ - '"Open Sans"', - 'fontWeight' => '400', - 'fontStyle' => 'normal', - 'src' => 'https://fonts.gstatic.com/s/open-sans/v30/KFOkCnqEu92Fr1MmgWxPKTM1K9nz.ttf', - ); - - public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) { - self::$font_family_id = Tests_REST_WpRestFontFamiliesController::create_font_family_post(); - self::$other_font_family_id = Tests_REST_WpRestFontFamiliesController::create_font_family_post(); - - self::$font_face_id1 = self::create_font_face_post( - self::$font_family_id, - array( - 'fontFamily' => '"Open Sans"', - 'fontWeight' => '400', - 'fontStyle' => 'normal', - 'src' => home_url( '/wp-content/fonts/open-sans-medium.ttf' ), - ) - ); - self::$font_face_id2 = self::create_font_face_post( - self::$font_family_id, - array( - 'fontFamily' => '"Open Sans"', - 'fontWeight' => '900', - 'fontStyle' => 'normal', - 'src' => home_url( '/wp-content/fonts/open-sans-bold.ttf' ), - ) - ); - - self::$admin_id = $factory->user->create( - array( - 'role' => 'administrator', - ) - ); - self::$editor_id = $factory->user->create( - array( - 'role' => 'editor', - ) - ); - - self::$post_ids_for_cleanup = array(); - } - - public static function wpTearDownAfterClass() { - self::delete_user( self::$admin_id ); - self::delete_user( self::$editor_id ); - - wp_delete_post( self::$font_family_id, true ); - wp_delete_post( self::$other_font_family_id, true ); - wp_delete_post( self::$font_face_id1, true ); - wp_delete_post( self::$font_face_id2, true ); - } - - public function tear_down() { - foreach ( self::$post_ids_for_cleanup as $post_id ) { - wp_delete_post( $post_id, true ); - } - self::$post_ids_for_cleanup = array(); - parent::tear_down(); - } - - public static function create_font_face_post( $parent_id, $settings = array() ) { - $settings = array_merge( self::$default_settings, $settings ); - $title = WP_Font_Utils::get_font_face_slug( $settings ); - $post_id = self::factory()->post->create( - wp_slash( - array( - 'post_type' => 'wp_font_face', - 'post_status' => 'publish', - 'post_title' => $title, - 'post_name' => sanitize_title( $title ), - 'post_content' => wp_json_encode( $settings ), - 'post_parent' => $parent_id, - ) - ) - ); - - self::$post_ids_for_cleanup[] = $post_id; - - return $post_id; - } - - /** - * @covers WP_REST_Font_Faces_Controller::register_routes - */ - public function test_register_routes() { - $routes = rest_get_server()->get_routes(); - $this->assertArrayHasKey( - '/wp/v2/font-families/(?P[\d]+)/font-faces', - $routes, - 'Font faces collection for the given font family does not exist' - ); - $this->assertCount( - 2, - $routes['/wp/v2/font-families/(?P[\d]+)/font-faces'], - 'Font faces collection for the given font family does not have exactly two elements' - ); - $this->assertArrayHasKey( - '/wp/v2/font-families/(?P[\d]+)/font-faces/(?P[\d]+)', - $routes, - 'Single font face route for the given font family does not exist' - ); - $this->assertCount( - 2, - $routes['/wp/v2/font-families/(?P[\d]+)/font-faces/(?P[\d]+)'], - 'Font faces collection for the given font family does not have exactly two elements' - ); - } - - public function test_font_faces_no_autosave_routes() { - // @core-merge: Enable this test. - $this->markTestSkipped( 'This test only works with WP 6.4 and above. Enable it once 6.5 is released.' ); - $routes = rest_get_server()->get_routes(); - $this->assertArrayNotHasKey( - '/wp/v2/font-families/(?P[\d]+)/font-faces/(?P[\d]+)/autosaves', - $routes, - 'Font faces autosaves route exists.' - ); - $this->assertArrayNotHasKey( - '/wp/v2/font-families/(?P[\d]+)/font-faces/(?P[\d]+)/autosaves/(?P[\d]+)', - $routes, - 'Font faces autosaves by id route exists.' - ); - } - - /** - * @doesNotPerformAssertions - */ - public function test_context_param() { - // See test_get_context_param(). - } - - /** - * @dataProvider data_get_context_param - * - * @covers WP_REST_Font_Faces_Controller::get_context_param - * - * @param bool $single_route Whether to test a single route. - */ - public function test_get_context_param( $single_route ) { - $route = '/wp/v2/font-families/' . self::$font_family_id . '/font-faces'; - if ( $single_route ) { - $route .= '/' . self::$font_face_id1; - } - - $request = new WP_REST_Request( 'OPTIONS', $route ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - - $endpoint_data = $data['endpoints'][0]; - $this->assertArrayNotHasKey( 'allow_batch', $endpoint_data, 'The allow_batch property should not exist in the endpoint data.' ); - $this->assertSame( 'view', $endpoint_data['args']['context']['default'], 'The endpoint\'s args::context::default should be set to view.' ); - $this->assertSame( array( 'view', 'embed', 'edit' ), $endpoint_data['args']['context']['enum'], 'The endpoint\'s args::context::enum should be set to [ view, embed, edit ].' ); - } - - /** - * Data provider. - * - * @return array - */ - public function data_get_context_param() { - return array( - 'Collection' => array( false ), - 'Single' => array( true ), - ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::get_items - */ - public function test_get_items() { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - - $this->assertSame( 200, $response->get_status(), 'The response status should be 200' ); - $this->assertCount( 2, $data, 'There should be 2 properties in the response data.' ); - $this->assertArrayHasKey( '_links', $data[0], 'The _links property should exist in the response data 0.' ); - $this->check_font_face_data( $data[0], self::$font_face_id2, $data[0]['_links'] ); - $this->assertArrayHasKey( '_links', $data[1], 'The _links property should exist in the response data 1.' ); - $this->check_font_face_data( $data[1], self::$font_face_id1, $data[1]['_links'] ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::get_items - */ - public function test_get_items_no_permission() { - wp_set_current_user( 0 ); - $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_cannot_read', $response, 401, 'The response should return an error with a "rest_cannot_read" code and 401 status.' ); - - wp_set_current_user( self::$editor_id ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_cannot_read', $response, 403, 'The response should return an error with a "rest_cannot_read" code and 403 status.' ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::get_items - */ - public function test_get_items_missing_parent() { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . REST_TESTS_IMPOSSIBLY_HIGH_NUMBER . '/font-faces' ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_post_invalid_parent', $response, 404 ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::get_item - */ - public function test_get_item() { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces/' . self::$font_face_id1 ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - - $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' ); - $this->check_font_face_data( $data, self::$font_face_id1, $response->get_links() ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::prepare_item_for_response - */ - public function test_get_item_removes_extra_settings() { - $font_face_id = self::create_font_face_post( self::$font_family_id, array( 'extra' => array() ) ); - - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces/' . $font_face_id ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - - $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' ); - $this->assertArrayHasKey( 'font_face_settings', $data, 'The font_face_settings property should exist in the response data.' ); - $this->assertArrayNotHasKey( 'extra', $data['font_face_settings'], 'The extra property should exist in the font_face_settings data.' ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::prepare_item_for_response - */ - public function test_get_item_malformed_post_content_returns_empty_settings() { - $font_face_id = wp_insert_post( - array( - 'post_type' => 'wp_font_face', - 'post_parent' => self::$font_family_id, - 'post_status' => 'publish', - 'post_content' => 'invalid', - ) - ); - - self::$post_ids_for_cleanup[] = $font_face_id; - - $empty_settings = array( - 'fontFamily' => '', - 'src' => array(), - ); - - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces/' . $font_face_id ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - - $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' ); - $this->assertArrayHasKey( 'font_face_settings', $data, 'The font_face_settings property should exist in the response data.' ); - $this->assertSame( $empty_settings, $data['font_face_settings'], 'The empty settings should exist in the font_face_settings data.' ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::get_item - */ - public function test_get_item_invalid_font_face_id() { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces/' . REST_TESTS_IMPOSSIBLY_HIGH_NUMBER ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_post_invalid_id', $response, 404 ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::get_item - */ - public function test_get_item_no_permission() { - wp_set_current_user( 0 ); - $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces/' . self::$font_face_id1 ); - - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_cannot_read', $response, 401, 'The response should return an error with a "rest_cannot_read" code and 401 status.' ); - - wp_set_current_user( self::$editor_id ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_cannot_read', $response, 403, 'The response should return an error with a "rest_cannot_read" code and 403 status.' ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::get_item - */ - public function test_get_item_missing_parent() { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . REST_TESTS_IMPOSSIBLY_HIGH_NUMBER . '/font-faces/' . self::$font_face_id1 ); - $response = rest_get_server()->dispatch( $request ); - - $this->assertErrorResponse( 'rest_post_invalid_parent', $response, 404 ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::get_item - */ - public function test_get_item_valid_parent_id() { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces/' . self::$font_face_id1 ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - - $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' ); - $this->assertSame( self::$font_family_id, $data['parent'], 'The returned parent id should match the font family id.' ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::get_item - */ - public function test_get_item_invalid_parent_id() { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . self::$other_font_family_id . '/font-faces/' . self::$font_face_id1 ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_font_face_parent_id_mismatch', $response, 404 ); - - $expected_message = 'The font face does not belong to the specified font family with id of "' . self::$other_font_family_id . '".'; - $this->assertSame( $expected_message, $response->as_error()->get_error_messages()[0], 'The message must contain the correct parent ID.' ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::create_item - */ - public function test_create_item() { - wp_set_current_user( self::$admin_id ); - $files = $this->setup_font_file_upload( array( 'woff2' ) ); - - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' ); - $request->set_param( 'theme_json_version', WP_REST_Font_Faces_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED ); - $request->set_param( - 'font_face_settings', - wp_json_encode( - array( - 'fontFamily' => '"Open Sans"', - 'fontWeight' => '200', - 'fontStyle' => 'normal', - 'src' => array_keys( $files )[0], - ) - ) - ); - $request->set_file_params( $files ); - - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - - $this->assertSame( 201, $response->get_status(), 'The response status should be 201.' ); - $this->check_font_face_data( $data, $data['id'], $response->get_links() ); - $this->check_file_meta( $data['id'], array( $data['font_face_settings']['src'] ) ); - - $settings = $data['font_face_settings']; - unset( $settings['src'] ); - $this->assertSame( - array( - 'fontFamily' => '"Open Sans"', - 'fontWeight' => '200', - 'fontStyle' => 'normal', - ), - $settings, - 'The font_face_settings data should match the expected data.' - ); - - $this->assertSame( self::$font_family_id, $data['parent'], 'The returned parent id should match the font family id.' ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::create_item - */ - public function test_create_item_with_multiple_font_files() { - wp_set_current_user( self::$admin_id ); - $files = $this->setup_font_file_upload( array( 'ttf', 'otf', 'woff', 'woff2' ) ); - - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' ); - $request->set_param( 'theme_json_version', WP_REST_Font_Faces_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED ); - $request->set_param( - 'font_face_settings', - wp_json_encode( - array( - 'fontFamily' => '"Open Sans"', - 'fontWeight' => '200', - 'fontStyle' => 'normal', - 'src' => array_keys( $files ), - ) - ) - ); - $request->set_file_params( $files ); - - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - - $this->assertSame( 201, $response->get_status(), 'The response status should be 201.' ); - $this->check_font_face_data( $data, $data['id'], $response->get_links() ); - $this->check_file_meta( $data['id'], $data['font_face_settings']['src'] ); - - $settings = $data['font_face_settings']; - $this->assertCount( 4, $settings['src'], 'There should be 4 items in the font_face_settings::src data.' ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::create_item - */ - public function test_create_item_invalid_file_type() { - $image_file = DIR_TESTDATA . '/images/canola.jpg'; - $image_path = wp_tempnam( 'canola.jpg' ); - copy( $image_file, $image_path ); - - $files = array( - 'file-0' => array( - 'name' => 'canola.jpg', - 'full_path' => 'canola.jpg', - 'type' => 'font/woff2', - 'tmp_name' => $image_path, - 'error' => 0, - 'size' => filesize( $image_path ), - ), - ); - - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' ); - $request->set_param( 'theme_json_version', WP_REST_Font_Faces_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED ); - $request->set_param( - 'font_face_settings', - wp_json_encode( - array_merge( - self::$default_settings, - array( - 'fontWeight' => '200', - 'src' => array_keys( $files )[0], - ) - ) - ) - ); - $request->set_file_params( $files ); - - $response = rest_get_server()->dispatch( $request ); - - $this->assertErrorResponse( 'rest_font_upload_invalid_file_type', $response, 400 ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::create_item - */ - public function test_create_item_with_url_src() { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' ); - $request->set_param( 'theme_json_version', WP_REST_Font_Faces_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED ); - $request->set_param( - 'font_face_settings', - wp_json_encode( - array( - 'fontFamily' => '"Open Sans"', - 'fontWeight' => '200', - 'fontStyle' => 'normal', - 'src' => 'https://fonts.gstatic.com/s/open-sans/v30/KFOkCnqEu92Fr1MmgWxPKTM1K9nz.ttf', - ) - ) - ); - - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - - $this->assertSame( 201, $response->get_status(), 'The response status should be 201.' ); - $this->check_font_face_data( $data, $data['id'], $response->get_links() ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::create_item - */ - public function test_create_item_with_all_properties() { - wp_set_current_user( self::$admin_id ); - - $properties = array( - 'fontFamily' => '"Open Sans"', - 'fontWeight' => '300 500', - 'fontStyle' => 'oblique 30deg 50deg', - 'fontDisplay' => 'swap', - 'fontStretch' => 'expanded', - 'ascentOverride' => '70%', - 'descentOverride' => '30%', - 'fontVariant' => 'normal', - 'fontFeatureSettings' => '"swsh" 2', - 'fontVariationSettings' => '"xhgt" 0.7', - 'lineGapOverride' => '10%', - 'sizeAdjust' => '90%', - 'unicodeRange' => 'U+0025-00FF, U+4??', - 'preview' => 'https://s.w.org/images/fonts/16.7/previews/open-sans/open-sans-400-normal.svg', - 'src' => 'https://fonts.gstatic.com/s/open-sans/v30/KFOkCnqEu92Fr1MmgWxPKTM1K9nz.ttf', - ); - - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' ); - $request->set_param( 'theme_json_version', WP_REST_Font_Faces_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED ); - $request->set_param( 'font_face_settings', wp_json_encode( $properties ) ); - - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - wp_delete_post( $data['id'], true ); - - $this->assertSame( 201, $response->get_status(), 'The response status should be 201.' ); - $this->assertArrayHasKey( 'font_face_settings', $data, 'The font_face_settings property should exist in the response data.' ); - $this->assertSame( $properties, $data['font_face_settings'], 'The font_face_settings should match the expected properties.' ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::create_item - */ - public function test_create_item_missing_parent() { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . REST_TESTS_IMPOSSIBLY_HIGH_NUMBER . '/font-faces' ); - $request->set_param( - 'font_face_settings', - wp_json_encode( array_merge( self::$default_settings, array( 'fontWeight' => '100' ) ) ) - ); - $response = rest_get_server()->dispatch( $request ); - - $this->assertErrorResponse( 'rest_post_invalid_parent', $response, 404 ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::create_item - */ - public function test_create_item_with_duplicate_properties() { - $settings = array( - 'fontFamily' => '"Open Sans"', - 'fontWeight' => '200', - 'fontStyle' => 'italic', - 'src' => home_url( '/wp-content/fonts/open-sans-italic-light.ttf' ), - ); - self::create_font_face_post( self::$font_family_id, $settings ); - - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' ); - $request->set_param( 'font_face_settings', wp_json_encode( $settings ) ); - - $response = rest_get_server()->dispatch( $request ); - - $this->assertErrorResponse( 'rest_duplicate_font_face', $response, 400, 'The response should return an error for "rest_duplicate_font_face" with 400 status.' ); - $expected_message = 'A font face matching those settings already exists.'; - $message = $response->as_error()->get_error_messages()[0]; - $this->assertSame( $expected_message, $message, 'The response error message should match.' ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::validate_create_font_face_request - */ - public function test_create_item_default_theme_json_version() { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' ); - $request->set_param( - 'font_face_settings', - wp_json_encode( - array( - 'fontFamily' => '"Open Sans"', - 'fontWeight' => '200', - 'src' => 'https://fonts.gstatic.com/s/open-sans/v30/KFOkCnqEu92Fr1MmgWxPKTM1K9nz.ttf', - ) - ) - ); - - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - wp_delete_post( $data['id'], true ); - - $this->assertSame( 201, $response->get_status(), 'The response status should be 201.' ); - $this->assertArrayHasKey( 'theme_json_version', $data, 'The theme_json_version property should exist in the response data.' ); - $this->assertSame( WP_REST_Font_Faces_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED, $data['theme_json_version'], 'The default theme.json version should match the latest version supported by the controller.' ); - } - - /** - * @dataProvider data_create_item_invalid_theme_json_version - * - * @covers WP_REST_Font_Faces_Controller::create_item - * - * @param int $theme_json_version Version input to test. - */ - public function test_create_item_invalid_theme_json_version( $theme_json_version ) { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' ); - $request->set_param( 'theme_json_version', $theme_json_version ); - $request->set_param( 'font_face_settings', '' ); - - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_invalid_param', $response, 400 ); - } - - /** - * Data provider. - * - * @return array - */ - public function data_create_item_invalid_theme_json_version() { - return array( - array( 1 ), - array( 3 ), - ); - } - - /** - * @dataProvider data_create_item_invalid_settings - * - * @covers WP_REST_Font_Faces_Controller::validate_create_font_face_settings - * - * @param mixed $settings Settings to test. - */ - public function test_create_item_invalid_settings( $settings ) { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' ); - $request->set_param( 'theme_json_version', WP_REST_Font_Faces_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED ); - $request->set_param( 'font_face_settings', wp_json_encode( $settings ) ); - - $response = rest_get_server()->dispatch( $request ); - - $this->assertErrorResponse( 'rest_invalid_param', $response, 400 ); - } - - /** - * Data provider. - * - * @return array - */ - public function data_create_item_invalid_settings() { - return array( - 'Missing fontFamily' => array( - 'settings' => array_diff_key( self::$default_settings, array( 'fontFamily' => '' ) ), - ), - 'Empty fontFamily' => array( - 'settings' => array_merge( self::$default_settings, array( 'fontFamily' => '' ) ), - ), - 'Wrong fontFamily type' => array( - 'settings' => array_merge( self::$default_settings, array( 'fontFamily' => 1234 ) ), - ), - 'Invalid fontDisplay' => array( - 'settings' => array_merge( self::$default_settings, array( 'fontDisplay' => 'invalid' ) ), - ), - 'Missing src' => array( - 'settings' => array_diff_key( self::$default_settings, array( 'src' => '' ) ), - ), - 'Empty src string' => array( - 'settings' => array_merge( self::$default_settings, array( 'src' => '' ) ), - ), - 'Empty src array' => array( - 'settings' => array_merge( self::$default_settings, array( 'src' => array() ) ), - ), - 'Empty src array values' => array( - 'settings' => array_merge( self::$default_settings, array( '', '' ) ), - ), - 'Wrong src type' => array( - 'settings' => array_merge( self::$default_settings, array( 'src' => 1234 ) ), - ), - 'Wrong src array types' => array( - 'settings' => array_merge( self::$default_settings, array( 'src' => array( 1234, 5678 ) ) ), - ), - ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::validate_create_font_face_settings - */ - public function test_create_item_invalid_settings_json() { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' ); - $request->set_param( 'theme_json_version', WP_REST_Font_Faces_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED ); - $request->set_param( 'font_face_settings', 'invalid' ); - - $response = rest_get_server()->dispatch( $request ); - - $this->assertErrorResponse( 'rest_invalid_param', $response, 400, 'The response should return an error for "rest_invalid_param" with 400 status.' ); - $expected_message = 'font_face_settings parameter must be a valid JSON string.'; - $message = $response->as_error()->get_all_error_data()[0]['params']['font_face_settings']; - $this->assertSame( $expected_message, $message, 'The response error message should match.' ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::validate_create_font_face_settings - */ - public function test_create_item_invalid_file_src() { - $files = $this->setup_font_file_upload( array( 'woff2' ) ); - - wp_set_current_user( self::$admin_id ); - $src = 'invalid'; - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' ); - $request->set_param( 'theme_json_version', WP_REST_Font_Faces_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED ); - $request->set_param( - 'font_face_settings', - wp_json_encode( - array_merge( self::$default_settings, array( 'src' => $src ) ) - ) - ); - $request->set_file_params( $files ); - - $response = rest_get_server()->dispatch( $request ); - - $this->assertErrorResponse( 'rest_invalid_param', $response, 400, 'The response should return an error for "rest_invalid_param" with 400 status.' ); - $expected_message = 'font_face_settings[src] value "' . $src . '" must be a valid URL or file reference.'; - $message = $response->as_error()->get_all_error_data()[0]['params']['font_face_settings']; - $this->assertSame( $expected_message, $message, 'The response error message should match.' ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::validate_create_font_face_settings - */ - public function test_create_item_missing_file_src() { - $files = $this->setup_font_file_upload( array( 'woff2', 'woff' ) ); - - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' ); - $request->set_param( 'theme_json_version', WP_REST_Font_Faces_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED ); - $request->set_param( - 'font_face_settings', - wp_json_encode( - array_merge( self::$default_settings, array( 'src' => array( array_keys( $files )[0] ) ) ) - ) - ); - $request->set_file_params( $files ); - - $response = rest_get_server()->dispatch( $request ); - - $this->assertErrorResponse( 'rest_invalid_param', $response, 400, 'The response should return an error for "rest_invalid_param" with 400 status.' ); - $expected_message = 'File ' . array_keys( $files )[1] . ' must be used in font_face_settings[src].'; - $message = $response->as_error()->get_all_error_data()[0]['params']['font_face_settings']; - $this->assertSame( $expected_message, $message, 'The response error message should match.' ); - } - - /** - * @dataProvider data_sanitize_font_face_settings - * - * @covers WP_REST_Font_Face_Controller::sanitize_font_face_settings - * - * @param string $settings Settings to test. - * @param string $expected Expected settings result. - */ - public function test_create_item_sanitize_font_face_settings( $settings, $expected ) { - $settings = array_merge( self::$default_settings, $settings ); - $expected = array_merge( self::$default_settings, $expected ); - - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' ); - $request->set_param( 'font_face_settings', wp_json_encode( $settings ) ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - wp_delete_post( $data['id'], true ); - - $this->assertSame( 201, $response->get_status(), 'The response status should be 201.' ); - $this->assertSame( $expected, $data['font_face_settings'], 'The response font_face_settings should match.' ); - } - - /** - * Data provider. - * - * @return array - */ - public function data_sanitize_font_face_settings() { - return array( - 'settings with tags, extra whitespace, new lines' => array( - 'settings' => array( - 'fontFamily' => " Open Sans\n ", - 'fontStyle' => " oblique 20deg 50deg\n ", - 'fontWeight' => " 200\n ", - 'src' => " https://example.com/ ", - 'fontStretch' => " expanded\n ", - 'ascentOverride' => " 70%\n ", - 'descentOverride' => " 30%\n ", - 'fontVariant' => " normal\n ", - 'fontFeatureSettings' => " \"swsh\" 2\n ", - 'fontVariationSettings' => " \"xhgt\" 0.7\n ", - 'lineGapOverride' => " 10%\n ", - 'sizeAdjust' => " 90%\n ", - 'unicodeRange' => " U+0025-00FF, U+4??\n ", - 'preview' => " https://example.com/ ", - ), - 'expected' => array( - 'fontFamily' => '"Open Sans"', - 'fontStyle' => 'oblique 20deg 50deg', - 'fontWeight' => '200', - 'src' => 'https://example.com//stylescriptalert(\'XSS\');/script%20%20%20%20%20%20', - 'fontStretch' => 'expanded', - 'ascentOverride' => '70%', - 'descentOverride' => '30%', - 'fontVariant' => 'normal', - 'fontFeatureSettings' => '"swsh" 2', - 'fontVariationSettings' => '"xhgt" 0.7', - 'lineGapOverride' => '10%', - 'sizeAdjust' => '90%', - 'unicodeRange' => 'U+0025-00FF, U+4??', - 'preview' => 'https://example.com//stylescriptalert(\'XSS\');/script%20%20%20%20%20%20', - ), - ), - 'multiword font family name with integer' => array( - 'settings' => array( - 'fontFamily' => 'Libre Barcode 128 Text', - ), - 'expected' => array( - 'fontFamily' => '"Libre Barcode 128 Text"', - ), - ), - 'multiword font family name' => array( - 'settings' => array( - 'fontFamily' => 'B612 Mono', - ), - 'expected' => array( - 'fontFamily' => '"B612 Mono"', - ), - ), - 'comma-separated font family names' => array( - 'settings' => array( - 'fontFamily' => 'Open Sans, Noto Sans, sans-serif', - ), - 'expected' => array( - 'fontFamily' => '"Open Sans", "Noto Sans", sans-serif', - ), - ), - ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::create_item - */ - // public function test_create_item_no_permission() {} - - /** - * @covers WP_REST_Font_Faces_Controller::update_item - */ - public function test_update_item() { - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces/' . self::$font_face_id1 ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_no_route', $response, 404 ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::delete_item - */ - public function test_delete_item() { - wp_set_current_user( self::$admin_id ); - $font_face_id = self::create_font_face_post( self::$font_family_id ); - $request = new WP_REST_Request( 'DELETE', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces/' . $font_face_id ); - $request->set_param( 'force', true ); - $response = rest_get_server()->dispatch( $request ); - - $this->assertSame( 200, $response->get_status(), 'The response status should be 201.' ); - $this->assertNull( get_post( $font_face_id ), 'The deleted post should not exist.' ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::delete_item - */ - public function test_delete_item_no_trash() { - wp_set_current_user( self::$admin_id ); - $font_face_id = self::create_font_face_post( self::$font_family_id ); - - // Attempt trashing. - $request = new WP_REST_Request( 'DELETE', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces/' . $font_face_id ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_trash_not_supported', $response, 501, 'The response should return an error for "rest_trash_not_supported" with 501 status.' ); - - $request->set_param( 'force', 'false' ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_trash_not_supported', $response, 501, 'When "force" is false, the response should return an error for "rest_trash_not_supported" with 501 status.' ); - - // Ensure the post still exists. - $post = get_post( $font_face_id ); - $this->assertNotEmpty( $post, 'The post should still exists.' ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::delete_item - */ - public function test_delete_item_invalid_font_face_id() { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'DELETE', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces/' . REST_TESTS_IMPOSSIBLY_HIGH_NUMBER ); - $request->set_param( 'force', true ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_post_invalid_id', $response, 404 ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::delete - */ - public function test_delete_item_missing_parent() { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'DELETE', '/wp/v2/font-families/' . REST_TESTS_IMPOSSIBLY_HIGH_NUMBER . '/font-faces/' . self::$font_face_id1 ); - $request->set_param( 'force', true ); - $response = rest_get_server()->dispatch( $request ); - - $this->assertErrorResponse( 'rest_post_invalid_parent', $response, 404 ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::get_item - */ - public function test_delete_item_invalid_parent_id() { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'DELETE', '/wp/v2/font-families/' . self::$other_font_family_id . '/font-faces/' . self::$font_face_id1 ); - $request->set_param( 'force', true ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_font_face_parent_id_mismatch', $response, 404, 'The response should return an error for "rest_font_face_parent_id_mismatch" with 404 status.' ); - - $expected_message = 'The font face does not belong to the specified font family with id of "' . self::$other_font_family_id . '".'; - $this->assertSame( $expected_message, $response->as_error()->get_error_messages()[0], 'The message must contain the correct parent ID.' ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::delete_item - */ - public function test_delete_item_no_permissions() { - $font_face_id = $this->create_font_face_post( self::$font_family_id ); - - wp_set_current_user( 0 ); - $request = new WP_REST_Request( 'DELETE', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces/' . $font_face_id ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_cannot_delete', $response, 401, 'The response should return an error for "rest_cannot_delete" with 401 status for an invalid user.' ); - - wp_set_current_user( self::$editor_id ); - $request = new WP_REST_Request( 'DELETE', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces/' . $font_face_id ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_cannot_delete', $response, 403, 'The response should return an error for "rest_cannot_delete" with 403 status for a user without permission.' ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::prepare_item_for_response - */ - public function test_prepare_item() { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces/' . self::$font_face_id2 ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - - $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' ); - $this->check_font_face_data( $data, self::$font_face_id2, $response->get_links() ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::get_item_schema - */ - public function test_get_item_schema() { - $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - - $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' ); - $properties = $data['schema']['properties']; - $this->assertCount( 4, $properties, 'There should be 4 properties in the schema::properties data.' ); - $this->assertArrayHasKey( 'id', $properties, 'The id property should exist in the schema::properties data.' ); - $this->assertArrayHasKey( 'theme_json_version', $properties, 'The theme_json_version property should exist in the schema::properties data.' ); - $this->assertArrayHasKey( 'parent', $properties, 'The parent property should exist in the schema::properties data.' ); - $this->assertArrayHasKey( 'font_face_settings', $properties, 'The font_face_settings property should exist in the schema::properties data.' ); - } - - /** - * @covers WP_REST_Font_Faces_Controller::get_item_schema - */ - public function test_get_item_schema_font_face_settings_should_all_have_sanitize_callbacks() { - $schema = ( new WP_REST_Font_Faces_Controller( 'wp_font_face' ) )->get_item_schema(); - $font_face_settings_schema = $schema['properties']['font_face_settings']; - - $this->assertArrayHasKey( 'properties', $font_face_settings_schema, 'font_face_settings schema is missing properties.' ); - $this->assertIsArray( $font_face_settings_schema['properties'], 'font_face_settings properties should be an array.' ); - - // arg_options should be removed for each setting property. - foreach ( $font_face_settings_schema['properties'] as $property ) { - $this->assertArrayHasKey( 'arg_options', $property, 'Setting schema should have arg_options.' ); - $this->assertArrayHasKey( 'sanitize_callback', $property['arg_options'], 'Setting schema should have a sanitize_callback.' ); - $this->assertIsCallable( $property['arg_options']['sanitize_callback'], 'The sanitize_callback value should be callable.' ); - } - } - - /** - * @covers WP_REST_Font_Faces_Controller::get_public_item_schema - */ - public function test_get_public_item_schema_should_not_have_arg_options() { - $schema = ( new WP_REST_Font_Faces_Controller( 'wp_font_face' ) )->get_public_item_schema(); - $font_face_settings_schema = $schema['properties']['font_face_settings']; - - $this->assertArrayHasKey( 'properties', $font_face_settings_schema, 'font_face_settings schema is missing properties.' ); - $this->assertIsArray( $font_face_settings_schema['properties'], 'font_face_settings properties should be an array.' ); - - // arg_options should be removed for each setting property. - foreach ( $font_face_settings_schema['properties'] as $property ) { - $this->assertArrayNotHasKey( 'arg_options', $property, 'arg_options should be removed from the schema for each setting.' ); - } - } - - - /** - * If WP_Theme_JSON::LATEST_SCHEMA is changed, the controller should be updated to handle any differences - * in `fontFace` structure to ensure support for the latest theme.json schema, and backwards compatibility - * for existing wp_font_face posts. - */ - public function test_controller_supports_latest_theme_json_version() { - $this->assertSame( WP_Theme_JSON::LATEST_SCHEMA, WP_REST_Font_Faces_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED ); - } - - protected function check_font_face_data( $data, $post_id, $links ) { - self::$post_ids_for_cleanup[] = $post_id; - $post = get_post( $post_id ); - - $this->assertArrayHasKey( 'id', $data, 'The id property should exist in response data.' ); - $this->assertSame( $post->ID, $data['id'], 'The "id" from the response data should match the post ID.' ); - - $this->assertArrayHasKey( 'parent', $data, 'The parent property should exist in response data.' ); - $this->assertSame( $post->post_parent, $data['parent'], 'The "parent" from the response data should match the post parent.' ); - - $this->assertArrayHasKey( 'theme_json_version', $data, 'The theme_json_version property should exist in response data.' ); - $this->assertSame( WP_REST_Font_Faces_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED, $data['theme_json_version'], 'The "theme_json_version" from the response data should match the latest version supported by the controller.' ); - - $this->assertArrayHasKey( 'font_face_settings', $data, 'The font_face_settings property should exist in response data.' ); - $this->assertSame( $post->post_content, wp_json_encode( $data['font_face_settings'] ), 'The encoded "font_face_settings" from the response data should match the post content.' ); - - $this->assertNotEmpty( $links, 'The links should not be empty in the response data.' ); - $expected = rest_url( 'wp/v2/font-families/' . $post->post_parent . '/font-faces/' . $post->ID ); - $this->assertSame( $expected, $links['self'][0]['href'], 'The links URL from the response data should match the post\'s REST endpoint.' ); - $expected = rest_url( 'wp/v2/font-families/' . $post->post_parent . '/font-faces' ); - $this->assertSame( $expected, $links['collection'][0]['href'], 'The links collection URL from the response data should match the REST endpoint.' ); - $expected = rest_url( 'wp/v2/font-families/' . $post->post_parent ); - $this->assertSame( $expected, $links['parent'][0]['href'], 'The links for a parent URL from the response data should match the parent\'s REST endpoint.' ); - } - - protected function check_file_meta( $font_face_id, $src_attributes ) { - $file_meta = get_post_meta( $font_face_id, '_wp_font_face_file' ); - - foreach ( $src_attributes as $src_attribute ) { - $file_name = basename( $src_attribute ); - $this->assertContains( $file_name, $file_meta, 'The uploaded font file path should be saved in the post meta.' ); - } - } - - protected function setup_font_file_upload( $formats ) { - $files = array(); - foreach ( $formats as $format ) { - // @core-merge Use `DIR_TESTDATA` instead of `GUTENBERG_DIR_TESTDATA`. - $font_file = GUTENBERG_DIR_TESTDATA . 'fonts/OpenSans-Regular.' . $format; - $font_path = wp_tempnam( 'OpenSans-Regular.' . $format ); - copy( $font_file, $font_path ); - - $files[ 'file-' . count( $files ) ] = array( - 'name' => 'OpenSans-Regular.' . $format, - 'full_path' => 'OpenSans-Regular.' . $format, - 'type' => 'font/' . $format, - 'tmp_name' => $font_path, - 'error' => 0, - 'size' => filesize( $font_path ), - ); - } - - return $files; - } -} diff --git a/phpunit/tests/fonts/font-library/wpRestFontFamiliesController.php b/phpunit/tests/fonts/font-library/wpRestFontFamiliesController.php deleted file mode 100644 index 300be122f14c1f..00000000000000 --- a/phpunit/tests/fonts/font-library/wpRestFontFamiliesController.php +++ /dev/null @@ -1,1059 +0,0 @@ - 'Open Sans', - 'slug' => 'open-sans', - 'fontFamily' => '"Open Sans", sans-serif', - 'preview' => 'https://s.w.org/images/fonts/16.7/previews/open-sans/open-sans-400-normal.svg', - ); - - public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) { - self::$admin_id = $factory->user->create( - array( - 'role' => 'administrator', - ) - ); - self::$editor_id = $factory->user->create( - array( - 'role' => 'editor', - ) - ); - - self::$font_family_id1 = self::create_font_family_post( - array( - 'name' => 'Open Sans', - 'slug' => 'open-sans', - 'fontFamily' => '"Open Sans", sans-serif', - 'preview' => 'https://s.w.org/images/fonts/16.7/previews/open-sans/open-sans-400-normal.svg', - ) - ); - self::$font_family_id2 = self::create_font_family_post( - array( - 'name' => 'Helvetica', - 'slug' => 'helvetica', - 'fontFamily' => 'Helvetica, Arial, sans-serif', - ) - ); - self::$font_face_id1 = Tests_REST_WpRestFontFacesController::create_font_face_post( - self::$font_family_id1, - array( - 'fontFamily' => '"Open Sans"', - 'fontWeight' => '400', - 'fontStyle' => 'normal', - 'src' => home_url( '/wp-content/fonts/open-sans-medium.ttf' ), - ) - ); - self::$font_face_id2 = Tests_REST_WpRestFontFacesController::create_font_face_post( - self::$font_family_id1, - array( - 'fontFamily' => '"Open Sans"', - 'fontWeight' => '900', - 'fontStyle' => 'normal', - 'src' => home_url( '/wp-content/fonts/open-sans-bold.ttf' ), - ) - ); - - static::$post_ids_to_cleanup = array(); - } - - public static function wpTearDownAfterClass() { - self::delete_user( self::$admin_id ); - self::delete_user( self::$editor_id ); - - wp_delete_post( self::$font_family_id1 ); - wp_delete_post( self::$font_family_id2 ); - wp_delete_post( self::$font_face_id1 ); - wp_delete_post( self::$font_face_id2 ); - } - - public function tear_down() { - foreach ( static::$post_ids_to_cleanup as $post_id ) { - wp_delete_post( $post_id, true ); - } - static::$post_ids_to_cleanup = array(); - - parent::tear_down(); - } - - public static function create_font_family_post( $settings = array() ) { - $settings = array_merge( self::$default_settings, $settings ); - $post_id = self::factory()->post->create( - wp_slash( - array( - 'post_type' => 'wp_font_family', - 'post_status' => 'publish', - 'post_title' => $settings['name'], - 'post_name' => $settings['slug'], - 'post_content' => wp_json_encode( - array( - 'fontFamily' => $settings['fontFamily'], - 'preview' => $settings['preview'], - ) - ), - ) - ) - ); - - static::$post_ids_to_cleanup[] = $post_id; - - return $post_id; - } - - /** - * @covers WP_REST_Font_Families_Controller::register_routes - */ - public function test_register_routes() { - $routes = rest_get_server()->get_routes(); - $this->assertArrayHasKey( - '/wp/v2/font-families', - $routes, - 'Font faces collection for the given font family does not exist' - ); - $this->assertCount( - 2, - $routes['/wp/v2/font-families'], - 'Font faces collection for the given font family does not have exactly two elements' - ); - $this->assertArrayHasKey( - '/wp/v2/font-families/(?P[\d]+)', - $routes, - 'Single font face route for the given font family does not exist' - ); - $this->assertCount( - 3, - $routes['/wp/v2/font-families/(?P[\d]+)'], - 'Font faces collection for the given font family does not have exactly two elements' - ); - } - - public function test_font_families_no_autosave_routes() { - // @core-merge: Enable this test. - $this->markTestSkipped( 'This test only works with WP 6.4 and above. Enable it once 6.5 is released.' ); - $routes = rest_get_server()->get_routes(); - $this->assertArrayNotHasKey( - '/wp/v2/font-families/(?P[\d]+)/autosaves', - $routes, - 'Font families autosaves route exists.' - ); - $this->assertArrayNotHasKey( - '/wp/v2/font-families/(?P[\d]+)/autosaves/(?P[\d]+)', - $routes, - 'Font families autosaves by id route exists.' - ); - } - - /** - * @doesNotPerformAssertions - */ - public function test_context_param() { - // See test_get_context_param(). - } - - /** - * @dataProvider data_get_context_param - * - * @covers WP_REST_Font_Families_Controller::get_context_param - * - * @param bool $single_route Whether to test a single route. - */ - public function test_get_context_param( $single_route ) { - $route = '/wp/v2/font-families'; - if ( $single_route ) { - $route .= '/' . self::$font_family_id1; - } - - $request = new WP_REST_Request( 'OPTIONS', $route ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - - $endpoint_data = $data['endpoints'][0]; - $this->assertArrayNotHasKey( 'allow_batch', $endpoint_data, 'The allow_batch property should not exist in the endpoint data.' ); - $this->assertSame( 'view', $endpoint_data['args']['context']['default'], 'The endpoint\'s args::context::default should be set to view.' ); - $this->assertSame( array( 'view', 'embed', 'edit' ), $endpoint_data['args']['context']['enum'], 'The endpoint\'s args::context::enum should be set to [ view, embed, edit ].' ); - } - - /** - * Data provider. - * - * @return array - */ - public function data_get_context_param() { - return array( - 'Collection' => array( false ), - 'Single' => array( true ), - ); - } - - /** - * @covers WP_REST_Font_Families_Controller::get_items - */ - public function test_get_items() { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'GET', '/wp/v2/font-families' ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - - $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' ); - $this->assertCount( 2, $data, 'There should be 2 properties in the response data.' ); - $this->assertArrayHasKey( '_links', $data[0], 'The _links property should exist in the response data 0.' ); - $this->check_font_family_data( $data[0], self::$font_family_id2, $data[0]['_links'] ); - $this->assertArrayHasKey( '_links', $data[1], 'The _links property should exist in the response data 1.' ); - $this->check_font_family_data( $data[1], self::$font_family_id1, $data[1]['_links'] ); - } - - /** - * @covers WP_REST_Font_Families_Controller::get_items - */ - public function test_get_items_by_slug() { - $font_family = get_post( self::$font_family_id2 ); - - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'GET', '/wp/v2/font-families' ); - $request->set_param( 'slug', $font_family->post_name ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - - $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' ); - $this->assertCount( 1, $data, 'There should be 2 properties in the response data.' ); - $this->assertArrayHasKey( 'id', $data[0], 'The id property should exist in the response data.' ); - $this->assertSame( $font_family->ID, $data[0]['id'], 'The id should match the expected ID in the response data.' ); - } - - /** - * @covers WP_REST_Font_Families_Controller::get_items - */ - public function test_get_items_no_permission() { - wp_set_current_user( 0 ); - $request = new WP_REST_Request( 'GET', '/wp/v2/font-families' ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_cannot_read', $response, 401, 'The response should return an error with a "rest_cannot_read" code and 401 status.' ); - - wp_set_current_user( self::$editor_id ); - $request = new WP_REST_Request( 'GET', '/wp/v2/font-families' ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_cannot_read', $response, 403, 'The response should return an error with a "rest_cannot_read" code and 403 status.' ); - } - - /** - * @covers WP_REST_Font_Families_Controller::get_item - */ - public function test_get_item() { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . self::$font_family_id1 ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - - $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' ); - $this->check_font_family_data( $data, self::$font_family_id1, $response->get_links() ); - } - - /** - * @covers WP_REST_Font_Families_Controller::prepare_item_for_response - */ - public function test_get_item_embedded_font_faces() { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . self::$font_family_id1 ); - $request->set_param( '_embed', true ); - $response = rest_get_server()->dispatch( $request ); - $data = rest_get_server()->response_to_data( $response, true ); - - $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' ); - $this->assertArrayHasKey( '_embedded', $data, 'The _embedded property should exist in the response data.' ); - $this->assertArrayHasKey( 'font_faces', $data['_embedded'], 'The font_faces property should exist in _embedded data.' ); - $this->assertCount( 2, $data['_embedded']['font_faces'], 'There should be 2 font_faces in the _embedded data.' ); - - foreach ( $data['_embedded']['font_faces'] as $font_face ) { - $this->assertArrayHasKey( 'id', $font_face, 'The id property should exist in the _embedded font_face data.' ); - - $font_face_request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . self::$font_family_id1 . '/font-faces/' . $font_face['id'] ); - $font_face_response = rest_get_server()->dispatch( $font_face_request ); - $font_face_data = rest_get_server()->response_to_data( $font_face_response, true ); - - $this->assertSame( $font_face_data, $font_face, 'The embedded font_face data should match when the data from a single request.' ); - } - } - - /** - * @covers WP_REST_Font_Families_Controller::get_item - */ - public function test_get_item_removes_extra_settings() { - $font_family_id = self::create_font_family_post( array( 'fontFace' => array() ) ); - - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . $font_family_id ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - - $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' ); - $this->assertArrayNotHasKey( 'fontFace', $data['font_family_settings'], 'The fontFace property should not exist in the font_family_settings data.' ); - } - - /** - * @covers WP_REST_Font_Families_Controller::prepare_item_for_response - */ - public function test_get_item_malformed_post_content_returns_empty_settings() { - $font_family_id = wp_insert_post( - array( - 'post_type' => 'wp_font_family', - 'post_status' => 'publish', - 'post_content' => 'invalid', - ) - ); - - static::$post_ids_to_cleanup[] = $font_family_id; - - $empty_settings = array( - 'name' => '', - // Slug will default to the post id. - 'slug' => (string) $font_family_id, - 'fontFamily' => '', - 'preview' => '', - ); - - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . $font_family_id ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - - $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' ); - $this->assertSame( $empty_settings, $data['font_family_settings'], 'The empty settings should exist in the font_family_settings data.' ); - } - - /** - * @covers WP_REST_Font_Families_Controller::get_item - */ - public function test_get_item_invalid_font_family_id() { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . REST_TESTS_IMPOSSIBLY_HIGH_NUMBER ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_post_invalid_id', $response, 404 ); - } - - /** - * @covers WP_REST_Font_Families_Controller::get_item - */ - public function test_get_item_no_permission() { - wp_set_current_user( 0 ); - $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . self::$font_family_id1 ); - - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_cannot_read', $response, 401, 'The response should return an error with a "rest_cannot_read" code and 401 status.' ); - - wp_set_current_user( self::$editor_id ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_cannot_read', $response, 403, 'The response should return an error with a "rest_cannot_read" code and 403 status.' ); - } - - /** - * @covers WP_REST_Font_Families_Controller::create_item - */ - public function test_create_item() { - $settings = array_merge( self::$default_settings, array( 'slug' => 'open-sans-2' ) ); - - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families' ); - $request->set_param( 'theme_json_version', WP_REST_Font_Families_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED ); - $request->set_param( 'font_family_settings', wp_json_encode( $settings ) ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - - $this->assertSame( 201, $response->get_status(), 'The response status should be 201.' ); - $this->check_font_family_data( $data, $data['id'], $response->get_links() ); - - $reponse_settings = $data['font_family_settings']; - $this->assertSame( $settings, $reponse_settings, 'The expected settings should exist in the font_family_settings data.' ); - $this->assertEmpty( $data['font_faces'], 'The font_faces should be empty or not exist in the response data.' ); - } - - /** - * @covers WP_REST_Font_Families_Controller::validate_create_font_face_request - */ - public function test_create_item_default_theme_json_version() { - $settings = array_merge( self::$default_settings, array( 'slug' => 'open-sans-2' ) ); - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families' ); - $request->set_param( 'font_family_settings', wp_json_encode( $settings ) ); - - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - - static::$post_ids_to_cleanup[] = $data['id']; - - $this->assertSame( 201, $response->get_status(), 'The response status should be 201.' ); - $this->assertArrayHasKey( 'theme_json_version', $data, 'The theme_json_version property should exist in the response data.' ); - $this->assertSame( WP_REST_Font_Families_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED, $data['theme_json_version'], 'The default theme.json version should match the latest version supported by the controller.' ); - } - - /** - * @dataProvider data_create_item_invalid_theme_json_version - * - * @covers WP_REST_Font_Families_Controller::create_item - * - * @param int $theme_json_version Version to test. - */ - public function test_create_item_invalid_theme_json_version( $theme_json_version ) { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families' ); - $request->set_param( 'theme_json_version', $theme_json_version ); - $request->set_param( 'font_family_settings', wp_json_encode( self::$default_settings ) ); - - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_invalid_param', $response, 400 ); - } - - /** - * Data provider. - * - * @return array - */ - public function data_create_item_invalid_theme_json_version() { - return array( - array( 1 ), - array( 3 ), - ); - } - - /** - * @dataProvider data_create_item_with_default_preview - * - * @covers WP_REST_Font_Families_Controller::sanitize_font_family_settings - * - * @param array $settings Settings to test. - */ - public function test_create_item_with_default_preview( $settings ) { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families' ); - $request->set_param( 'theme_json_version', WP_REST_Font_Families_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED ); - $request->set_param( 'font_family_settings', wp_json_encode( $settings ) ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - - static::$post_ids_to_cleanup[] = $data['id']; - - $this->assertSame( 201, $response->get_status(), 'The response status should be 201.' ); - $response_settings = $data['font_family_settings']; - $this->assertArrayHasKey( 'preview', $response_settings, 'The preview property should exist in the font_family_settings data.' ); - $this->assertSame( '', $response_settings['preview'], 'The preview data should be an empty string.' ); - } - - /** - * Data provider. - * - * @return array - */ - public function data_create_item_with_default_preview() { - $default_settings = array( - 'name' => 'Open Sans', - 'slug' => 'open-sans-2', - 'fontFamily' => '"Open Sans", sans-serif', - ); - return array( - 'No preview param' => array( - 'settings' => $default_settings, - ), - 'Empty preview' => array( - 'settings' => array_merge( $default_settings, array( 'preview' => '' ) ), - ), - ); - } - - /** - * @dataProvider data_sanitize_font_family_settings - * - * @covers WP_REST_Font_Families_Controller::sanitize_font_family_settings - * - * @param string $settings Font family settings to test. - * @param string $expected Expected settings result. - */ - public function test_create_item_santize_font_family_settings( $settings, $expected ) { - $settings = array_merge( self::$default_settings, $settings ); - $expected = array_merge( self::$default_settings, $expected ); - - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families' ); - $request->set_param( 'font_family_settings', wp_json_encode( $settings ) ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - - static::$post_ids_to_cleanup[] = $data['id']; - - $this->assertSame( 201, $response->get_status(), 'The response status should be 201.' ); - $this->assertSame( $expected, $data['font_family_settings'], 'The response font_family_settings should match.' ); - } - - /** - * Data provider. - * - * @return array - */ - public function data_sanitize_font_family_settings() { - return array( - 'settings with tags, extra whitespace, new lines' => array( - 'settings' => array( - 'name' => " Opening Sans\n ", - 'slug' => " OPENing SanS \n ", - 'fontFamily' => " Opening Sans\n ", - 'preview' => " https://example.com/ ", - ), - 'expected' => array( - 'name' => 'Opening Sans', - 'slug' => 'opening-sans-alertxss', - 'fontFamily' => '"Opening Sans"', - 'preview' => "https://example.com//stylescriptalert('XSS');/script%20%20%20%20%20%20", - ), - ), - 'multiword font family name with integer' => array( - 'settings' => array( - 'slug' => 'libre-barcode-128-text', - 'fontFamily' => 'Libre Barcode 128 Text', - ), - 'expected' => array( - 'slug' => 'libre-barcode-128-text', - 'fontFamily' => '"Libre Barcode 128 Text"', - ), - ), - 'multiword font family name' => array( - 'settings' => array( - 'slug' => 'b612-mono', - 'fontFamily' => 'B612 Mono', - ), - 'expected' => array( - 'slug' => 'b612-mono', - 'fontFamily' => '"B612 Mono"', - ), - ), - 'comma-separated font family names' => array( - 'settings' => array( - 'slug' => 'open-sans-noto-sans', - 'fontFamily' => 'Open Sans, Noto Sans, sans-serif', - ), - 'expected' => array( - 'slug' => 'open-sans-noto-sans', - 'fontFamily' => '"Open Sans", "Noto Sans", sans-serif', - ), - ), - ); - } - - /** - * @dataProvider data_create_item_invalid_settings - * - * @covers WP_REST_Font_Families_Controller::validate_create_font_face_settings - * - * @param array $settings Settings to test. - */ - public function test_create_item_invalid_settings( $settings ) { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families' ); - $request->set_param( 'theme_json_version', WP_REST_Font_Families_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED ); - $request->set_param( 'font_family_settings', wp_json_encode( $settings ) ); - - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_invalid_param', $response, 400 ); - } - - /** - * Data provider. - * - * @return array - */ - public function data_create_item_invalid_settings() { - return array( - 'Missing name' => array( - 'settings' => array_diff_key( self::$default_settings, array( 'name' => '' ) ), - ), - 'Empty name' => array( - 'settings' => array_merge( self::$default_settings, array( 'name' => '' ) ), - ), - 'Wrong name type' => array( - 'settings' => array_merge( self::$default_settings, array( 'name' => 1234 ) ), - ), - 'Missing slug' => array( - 'settings' => array_diff_key( self::$default_settings, array( 'slug' => '' ) ), - ), - 'Empty slug' => array( - 'settings' => array_merge( self::$default_settings, array( 'slug' => '' ) ), - ), - 'Wrong slug type' => array( - 'settings' => array_merge( self::$default_settings, array( 'slug' => 1234 ) ), - ), - 'Missing fontFamily' => array( - 'settings' => array_diff_key( self::$default_settings, array( 'fontFamily' => '' ) ), - ), - 'Empty fontFamily' => array( - 'settings' => array_merge( self::$default_settings, array( 'fontFamily' => '' ) ), - ), - 'Wrong fontFamily type' => array( - 'settings' => array_merge( self::$default_settings, array( 'fontFamily' => 1234 ) ), - ), - ); - } - - /** - * @covers WP_REST_Font_Family_Controller::validate_font_family_settings - */ - public function test_create_item_invalid_settings_json() { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families' ); - $request->set_param( 'theme_json_version', WP_REST_Font_Families_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED ); - $request->set_param( 'font_family_settings', 'invalid' ); - - $response = rest_get_server()->dispatch( $request ); - - $this->assertErrorResponse( 'rest_invalid_param', $response, 400, 'The response should return an error for "rest_invalid_param" with 400 status.' ); - $expected_message = 'font_family_settings parameter must be a valid JSON string.'; - $message = $response->as_error()->get_all_error_data()[0]['params']['font_family_settings']; - $this->assertSame( $expected_message, $message, 'The response error message should match.' ); - } - - /** - * @covers WP_REST_Font_Family_Controller::create_item - */ - public function test_create_item_with_duplicate_slug() { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families' ); - $request->set_param( 'theme_json_version', WP_REST_Font_Families_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED ); - $request->set_param( 'font_family_settings', wp_json_encode( array_merge( self::$default_settings, array( 'slug' => 'helvetica' ) ) ) ); - - $response = rest_get_server()->dispatch( $request ); - - $this->assertErrorResponse( 'rest_duplicate_font_family', $response, 400, 'The response should return an error for "rest_duplicate_font_family" with 400 status.' ); - $expected_message = 'A font family with slug "helvetica" already exists.'; - $message = $response->as_error()->get_error_messages()[0]; - $this->assertSame( $expected_message, $message, 'The response error message should match.' ); - } - - /** - * @covers WP_REST_Font_Families_Controller::create_item - */ - public function test_create_item_no_permission() { - $settings = array_merge( self::$default_settings, array( 'slug' => 'open-sans-2' ) ); - wp_set_current_user( 0 ); - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families' ); - $request->set_param( 'font_family_settings', wp_json_encode( $settings ) ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_cannot_create', $response, 401, 'The response should return an error for "rest_cannot_create" with 401 status.' ); - - wp_set_current_user( self::$editor_id ); - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families' ); - $request->set_param( - 'font_family_settings', - wp_json_encode( - array( - 'name' => 'Open Sans', - 'slug' => 'open-sans', - 'fontFamily' => '"Open Sans", sans-serif', - 'preview' => 'https://s.w.org/images/fonts/16.7/previews/open-sans/open-sans-400-normal.svg', - ) - ) - ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_cannot_create', $response, 403, 'The response should return an error for "rest_cannot_create" with 403 status.' ); - } - - /** - * @covers WP_REST_Font_Families_Controller::update_item - */ - public function test_update_item() { - wp_set_current_user( self::$admin_id ); - - $settings = array( - 'name' => 'Open Sans', - 'fontFamily' => '"Open Sans, "Noto Sans", sans-serif', - 'preview' => 'https://s.w.org/images/fonts/16.9/previews/open-sans/open-sans-400-normal.svg', - ); - - $font_family_id = self::create_font_family_post( array( 'slug' => 'open-sans-2' ) ); - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . $font_family_id ); - $request->set_param( - 'font_family_settings', - wp_json_encode( $settings ) - ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - - $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' ); - $this->check_font_family_data( $data, $font_family_id, $response->get_links() ); - - $expected_settings = array( - 'name' => $settings['name'], - 'slug' => 'open-sans-2', - 'fontFamily' => $settings['fontFamily'], - 'preview' => $settings['preview'], - ); - $this->assertSame( $expected_settings, $data['font_family_settings'], 'The response font_family_settings should match expected settings.' ); - } - - /** - * @dataProvider data_update_item_individual_settings - * - * @covers WP_REST_Font_Families_Controller::update_item - * - * @param array $settings Settings to test. - */ - public function test_update_item_individual_settings( $settings ) { - wp_set_current_user( self::$admin_id ); - - $font_family_id = self::create_font_family_post(); - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . $font_family_id ); - $request->set_param( 'font_family_settings', wp_json_encode( $settings ) ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - - $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' ); - $key = key( $settings ); - $value = current( $settings ); - $this->assertArrayHasKey( $key, $data['font_family_settings'], 'The expected key should exist in the font_family_settings data.' ); - $this->assertSame( $value, $data['font_family_settings'][ $key ], 'The font_family_settings data should match.' ); - } - - /** - * Data provider. - * - * @return array - */ - public function data_update_item_individual_settings() { - return array( - array( array( 'name' => 'Opened Sans' ) ), - array( array( 'fontFamily' => '"Opened Sans", sans-serif' ) ), - array( array( 'preview' => 'https://s.w.org/images/fonts/16.7/previews/opened-sans/opened-sans-400-normal.svg' ) ), - // Empty preview is allowed. - array( array( 'preview' => '' ) ), - ); - } - - /** - * @dataProvider data_sanitize_font_family_settings - * - * @covers WP_REST_Font_Families_Controller::sanitize_font_family_settings - * - * @param string $settings Font family settings to test. - * @param string $expected Expected settings result. - */ - public function test_update_item_santize_font_family_settings( $settings, $expected ) { - // Unset/modify slug from the data provider, since we're updating rather than creating. - unset( $settings['slug'] ); - $initial_settings = array( 'slug' => 'open-sans-update' ); - $expected = array_merge( self::$default_settings, $expected, $initial_settings ); - - wp_set_current_user( self::$admin_id ); - $font_family_id = self::create_font_family_post( $initial_settings ); - static::$post_ids_to_cleanup[] = $font_family_id; - - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . $font_family_id ); - $request->set_param( 'font_family_settings', wp_json_encode( $settings ) ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - - $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' ); - $this->assertSame( $expected, $data['font_family_settings'], 'The response font_family_settings should match.' ); - } - - /** - * @dataProvider data_update_item_invalid_settings - * - * @covers WP_REST_Font_Families_Controller::update_item - * - * @param array $settings Settings to test. - */ - public function test_update_item_empty_settings( $settings ) { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id1 ); - $request->set_param( - 'font_family_settings', - wp_json_encode( $settings ) - ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_invalid_param', $response, 400 ); - } - - /** - * Data provider. - * - * @return array - */ - public function data_update_item_invalid_settings() { - return array( - 'Empty name' => array( - array( 'name' => '' ), - ), - 'Wrong name type' => array( - array( 'name' => 1234 ), - ), - 'Empty fontFamily' => array( - array( 'fontFamily' => '' ), - ), - 'Wrong fontFamily type' => array( - array( 'fontFamily' => 1234 ), - ), - ); - } - - /** - * @covers WP_REST_Font_Families_Controller::update_item - */ - public function test_update_item_update_slug_not_allowed() { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id1 ); - $request->set_param( - 'font_family_settings', - wp_json_encode( array( 'slug' => 'new-slug' ) ) - ); - $response = rest_get_server()->dispatch( $request ); - - $this->assertErrorResponse( 'rest_invalid_param', $response, 400, 'The response should return an error for "rest_invalid_param" with 400 status.' ); - $expected_message = 'font_family_settings[slug] cannot be updated.'; - $message = $response->as_error()->get_all_error_data()[0]['params']['font_family_settings']; - $this->assertSame( $expected_message, $message, 'The response error message should match.' ); - } - - /** - * @covers WP_REST_Font_Families_Controller::update_item - */ - public function test_update_item_invalid_font_family_id() { - $settings = array_diff_key( self::$default_settings, array( 'slug' => '' ) ); - - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . REST_TESTS_IMPOSSIBLY_HIGH_NUMBER ); - $request->set_param( 'font_family_settings', wp_json_encode( $settings ) ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_post_invalid_id', $response, 404, 'The response should return an error for "rest_post_invalid_id" with 404 status.' ); - } - - /** - * @covers WP_REST_Font_Families_Controller::update_item - */ - public function test_update_item_no_permission() { - $settings = array_diff_key( self::$default_settings, array( 'slug' => '' ) ); - - wp_set_current_user( 0 ); - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id1 ); - $request->set_param( 'font_family_settings', wp_json_encode( $settings ) ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_cannot_edit', $response, 401, 'The response should return an error for "rest_cannot_edit" with 401 status for an invalid user.' ); - - wp_set_current_user( self::$editor_id ); - $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id1 ); - $request->set_param( 'font_family_settings', wp_json_encode( $settings ) ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_cannot_edit', $response, 403, 'The response should return an error for "rest_cannot_edit" with 403 status for a user without permission.' ); - } - - - /** - * @covers WP_REST_Font_Families_Controller::delete_item - */ - public function test_delete_item() { - wp_set_current_user( self::$admin_id ); - $font_family_id = self::create_font_family_post(); - $request = new WP_REST_Request( 'DELETE', '/wp/v2/font-families/' . $font_family_id ); - $request['force'] = true; - $response = rest_get_server()->dispatch( $request ); - - $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' ); - $this->assertNull( get_post( $font_family_id ), 'The post should not exist after deleting.' ); - } - - /** - * @covers WP_REST_Font_Families_Controller::delete_item - */ - public function test_delete_item_no_trash() { - wp_set_current_user( self::$admin_id ); - $font_family_id = self::create_font_family_post(); - - // Attempt trashing. - $request = new WP_REST_Request( 'DELETE', '/wp/v2/font-families/' . $font_family_id ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_trash_not_supported', $response, 501, 'The response should return an error for "rest_trash_not_supported" with 501 status.' ); - - $request->set_param( 'force', 'false' ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_trash_not_supported', $response, 501, 'When "force" is false, the response should return an error for "rest_trash_not_supported" with 501 status.' ); - - // Ensure the post still exists. - $post = get_post( $font_family_id ); - $this->assertNotEmpty( $post, 'The post should still exist.' ); - } - - /** - * @covers WP_REST_Font_Families_Controller::delete_item - */ - public function test_delete_item_invalid_font_family_id() { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'DELETE', '/wp/v2/font-families/' . REST_TESTS_IMPOSSIBLY_HIGH_NUMBER ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_post_invalid_id', $response, 404 ); - } - - /** - * @covers WP_REST_Font_Families_Controller::delete_item - */ - public function test_delete_item_no_permissions() { - $font_family_id = self::create_font_family_post(); - - wp_set_current_user( 0 ); - $request = new WP_REST_Request( 'DELETE', '/wp/v2/font-families/' . $font_family_id ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_cannot_delete', $response, 401, 'The response should return an error for "rest_cannot_delete" with 401 status for an invalid user.' ); - - wp_set_current_user( self::$editor_id ); - $request = new WP_REST_Request( 'DELETE', '/wp/v2/font-families/' . $font_family_id ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_cannot_delete', $response, 403, 'The response should return an error for "rest_cannot_delete" with 403 status for a user without permission.' ); - } - - /** - * @covers WP_REST_Font_Families_Controller::prepare_item_for_response - */ - public function test_prepare_item() { - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . self::$font_family_id2 ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - - $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' ); - $this->check_font_family_data( $data, self::$font_family_id2, $response->get_links() ); - } - - /** - * @covers WP_REST_Font_Families_Controller::get_item_schema - */ - public function test_get_item_schema() { - $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/font-families' ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - - $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' ); - $properties = $data['schema']['properties']; - $this->assertCount( 4, $properties, 'There should be 4 properties in the schema::properties data.' ); - $this->assertArrayHasKey( 'id', $properties, 'The id property should exist in the schema::properties data.' ); - $this->assertArrayHasKey( 'theme_json_version', $properties, 'The theme_json_version property should exist in the schema::properties data.' ); - $this->assertArrayHasKey( 'font_faces', $properties, 'The font_faces property should exist in the schema::properties data.' ); - $this->assertArrayHasKey( 'font_family_settings', $properties, 'The font_family_settings property should exist in the schema::properties data.' ); - } - - /** - * @covers WP_REST_Font_Families_Controller::get_item_schema - */ - public function test_get_item_schema_font_family_settings_should_all_have_sanitize_callbacks() { - $schema = ( new WP_REST_Font_Families_Controller( 'wp_font_family' ) )->get_item_schema(); - $font_family_settings_schema = $schema['properties']['font_family_settings']; - - $this->assertArrayHasKey( 'properties', $font_family_settings_schema, 'font_family_settings schema is missing properties.' ); - $this->assertIsArray( $font_family_settings_schema['properties'], 'font_family_settings properties should be an array.' ); - - // arg_options should be removed for each setting property. - foreach ( $font_family_settings_schema['properties'] as $property ) { - $this->assertArrayHasKey( 'arg_options', $property, 'Setting schema should have arg_options.' ); - $this->assertArrayHasKey( 'sanitize_callback', $property['arg_options'], 'Setting schema should have a sanitize_callback.' ); - $this->assertIsCallable( $property['arg_options']['sanitize_callback'], 'That sanitize_callback value should be callable.' ); - } - } - - /** - * @covers WP_REST_Font_Families_Controller::get_public_item_schema - */ - public function test_get_public_item_schema_should_not_have_arg_options() { - $schema = ( new WP_REST_Font_Families_Controller( 'wp_font_family' ) )->get_public_item_schema(); - $font_family_settings_schema = $schema['properties']['font_family_settings']; - - $this->assertArrayHasKey( 'properties', $font_family_settings_schema, 'font_family_settings schema is missing properties.' ); - $this->assertIsArray( $font_family_settings_schema['properties'], 'font_family_settings properties should be an array.' ); - - // arg_options should be removed for each setting property. - foreach ( $font_family_settings_schema['properties'] as $property ) { - $this->assertArrayNotHasKey( 'arg_options', $property, 'arg_options should be removed from the schema for each setting.' ); - } - } - - /** - * If WP_Theme_JSON::LATEST_SCHEMA is changed, the controller should be updated to handle any differences - * in `fontFamilies` structure to ensure support for the latest theme.json schema, and backwards compatibility - * for existing wp_font_family posts. - */ - public function test_controller_supports_latest_theme_json_version() { - $this->assertSame( WP_Theme_JSON::LATEST_SCHEMA, WP_REST_Font_Families_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED ); - } - - protected function check_font_family_data( $data, $post_id, $links ) { - static::$post_ids_to_cleanup[] = $post_id; - $post = get_post( $post_id ); - - $this->assertArrayHasKey( 'id', $data, 'The id property should exist in response data.' ); - $this->assertSame( $post->ID, $data['id'], 'The "id" from the response data should match the post ID.' ); - - $this->assertArrayHasKey( 'theme_json_version', $data, 'The theme_json_version property should exist in response data.' ); - $this->assertSame( WP_REST_Font_Families_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED, $data['theme_json_version'], 'The "theme_json_version" from the response data should match the latest version supported by the controller.' ); - - $font_face_ids = get_children( - array( - 'fields' => 'ids', - 'post_parent' => $post_id, - 'post_type' => 'wp_font_face', - 'order' => 'ASC', - 'orderby' => 'ID', - ) - ); - $this->assertArrayHasKey( 'font_faces', $data, 'The font_faces property should exist in the response data.' ); - - foreach ( $font_face_ids as $font_face_id ) { - $this->assertContains( $font_face_id, $data['font_faces'], 'The ID is in the font_faces data.' ); - } - - $this->assertArrayHasKey( 'font_family_settings', $data, 'The font_family_settings property should exist in the response data.' ); - $settings = $data['font_family_settings']; - $expected_settings = array( - 'name' => $post->post_title, - 'slug' => $post->post_name, - 'fontFamily' => $settings['fontFamily'], - 'preview' => $settings['preview'], - ); - $this->assertSame( $expected_settings, $settings, 'The font_family_settings should match.' ); - - $this->assertNotEmpty( $links, 'The links should not be empty in the response data.' ); - $expected = rest_url( 'wp/v2/font-families/' . $post->ID ); - $this->assertSame( $expected, $links['self'][0]['href'], 'The links URL from the response data should match the post\'s REST endpoint.' ); - $expected = rest_url( 'wp/v2/font-families' ); - $this->assertSame( $expected, $links['collection'][0]['href'], 'The links collection URL from the response data should match the REST endpoint.' ); - - if ( ! $font_face_ids ) { - return; - } - - // Check font_face links, if present. - $this->assertArrayHasKey( 'font_faces', $links ); - foreach ( $links['font_faces'] as $index => $link ) { - $expected = rest_url( 'wp/v2/font-families/' . $post->ID . '/font-faces/' . $font_face_ids[ $index ] ); - $this->assertSame( $expected, $link['href'], 'The links for a font faces URL from the response data should match the REST endpoint.' ); - - $embeddable = isset( $link['attributes']['embeddable'] ) - ? $link['attributes']['embeddable'] - : $link['embeddable']; - $this->assertTrue( $embeddable, 'The embeddable should be true.' ); - } - } -}