diff --git a/lib/experimental/fonts/font-library/class-wp-font-collection.php b/lib/experimental/fonts/font-library/class-wp-font-collection.php index 6189da5fa984b1..1ff96b1343b453 100644 --- a/lib/experimental/fonts/font-library/class-wp-font-collection.php +++ b/lib/experimental/fonts/font-library/class-wp-font-collection.php @@ -21,41 +21,128 @@ class WP_Font_Collection { /** - * Font collection configuration. + * The unique slug for the font collection. + * + * @since 6.5.0 + * + * @var string + */ + private $slug; + + /** + * The name of the font collection. + * + * @since 6.5.0 + * + * @var string + */ + private $name; + + /** + * Description of the font collection. + * + * @since 6.5.0 + * + * @var string + */ + private $description; + + /** + * Source of the font collection. + * + * @since 6.5.0 + * + * @var string + */ + private $src; + + /** + * Array of font families in the collection. * * @since 6.5.0 * * @var array */ - private $config; + private $font_families; + + /** + * Categories associated with the font collection. + * + * @since 6.5.0 + * + * @var array + */ + private $categories; + /** * WP_Font_Collection constructor. * * @since 6.5.0 * - * @param array $config Font collection config options. - * See {@see wp_register_font_collection()} for the supported fields. - * @throws Exception If the required parameters are missing. + * @param array $config Font collection config options. { + * @type string $slug The font collection's unique slug. + * @type string $name The font collection's name. + * @type string $description The font collection's description. + * @type string $src The font collection's source. + * @type array $font_families An array of font families in the font collection. + * @type array $categories The font collection's categories. + * } */ public function __construct( $config ) { - if ( empty( $config ) || ! is_array( $config ) ) { - throw new Exception( 'Font Collection config options is required as a non-empty array.' ); - } + $this->is_config_valid( $config ); + + $this->slug = isset( $config['slug'] ) ? $config['slug'] : ''; + $this->name = isset( $config['name'] ) ? $config['name'] : ''; + $this->description = isset( $config['description'] ) ? $config['description'] : ''; + $this->src = isset( $config['src'] ) ? $config['src'] : ''; + $this->font_families = isset( $config['font_families'] ) ? $config['font_families'] : array(); + $this->categories = isset( $config['categories'] ) ? $config['categories'] : array(); + } - if ( empty( $config['slug'] ) || ! is_string( $config['slug'] ) ) { - throw new Exception( 'Font Collection config slug is required as a non-empty string.' ); + /** + * Checks if the font collection config is valid. + * + * @since 6.5.0 + * + * @param array $config Font collection config options. { + * @type string $slug The font collection's unique slug. + * @type string $name The font collection's name. + * @type string $description The font collection's description. + * @type string $src The font collection's source. + * @type array $font_families An array of font families in the font collection. + * @type array $categories The font collection's categories. + * } + * @return bool True if the font collection config is valid and false otherwise. + */ + public static function is_config_valid( $config ) { + if ( empty( $config ) || ! is_array( $config ) ) { + _doing_it_wrong( __METHOD__, __( 'Font Collection config options are required as a non-empty array.', 'gutenberg' ), '6.5.0' ); + return false; } - if ( empty( $config['name'] ) || ! is_string( $config['name'] ) ) { - throw new Exception( 'Font Collection config name is required as a non-empty string.' ); + $required_keys = array( 'slug', 'name' ); + foreach ( $required_keys as $key ) { + if ( empty( $config[ $key ] ) ) { + _doing_it_wrong( + __METHOD__, + // translators: %s: Font collection config key. + sprintf( __( 'Font Collection config %s is required as a non-empty string.', 'gutenberg' ), $key ), + '6.5.0' + ); + return false; + } } - if ( ( empty( $config['src'] ) || ! is_string( $config['src'] ) ) && ( empty( $config['data'] ) ) ) { - throw new Exception( 'Font Collection config "src" option OR "data" option is required.' ); + if ( + ( empty( $config['src'] ) && empty( $config['font_families'] ) ) || + ( ! empty( $config['src'] ) && ! empty( $config['font_families'] ) ) + ) { + _doing_it_wrong( __METHOD__, __( 'Font Collection config "src" option OR "font_families" option are required.', 'gutenberg' ), '6.5.0' ); + return false; } - $this->config = $config; + return true; } /** @@ -73,56 +160,59 @@ public function __construct( $config ) { */ public function get_config() { return array( - 'slug' => $this->config['slug'], - 'name' => $this->config['name'], - 'description' => $this->config['description'] ?? '', + 'slug' => $this->slug, + 'name' => $this->name, + 'description' => $this->description, ); } /** - * Gets the font collection config and data. + * Gets the font collection content. * - * This function returns an array containing the font collection's unique ID, - * name, and its data as a PHP array. + * Load the font collection data from the src if it is not already loaded. * * @since 6.5.0 * - * @return array { - * An array of font collection config and data. + * @return array|WP_Error { + * An array of font collection contents. * - * @type string $slug The font collection's unique ID. - * @type string $name The font collection's name. - * @type string $description The font collection's description. - * @type array $data The font collection's data as a PHP array. + * @type array $font_families The font collection's font families. + * @type string $categories The font collection's categories. * } + * + * A WP_Error object if there was an error loading the font collection data. */ - public function get_config_and_data() { - $config_and_data = $this->get_config(); - $config_and_data['data'] = $this->load_data(); - return $config_and_data; + public function get_content() { + // If the font families are not loaded, and the src is not empty, load the data from the src. + if ( empty( $this->font_families ) && ! empty( $this->src ) ) { + $data = $this->load_contents_from_src(); + if ( is_wp_error( $data ) ) { + return $data; + } + } + + return array( + 'font_families' => $this->font_families, + 'categories' => $this->categories, + ); } /** - * Loads the font collection data. + * Loads the font collection data from the src. * * @since 6.5.0 * * @return array|WP_Error An array containing the list of font families in font-collection.json format on success, * else an instance of WP_Error on failure. */ - public function load_data() { - - if ( ! empty( $this->config['data'] ) ) { - return $this->config['data']; - } - + private function load_contents_from_src() { // If the src is a URL, fetch the data from the URL. - if ( str_contains( $this->config['src'], 'http' ) && str_contains( $this->config['src'], '://' ) ) { - if ( ! wp_http_validate_url( $this->config['src'] ) ) { + if ( preg_match( '#^https?://#', $this->src ) ) { + if ( ! wp_http_validate_url( $this->src ) ) { return new WP_Error( 'font_collection_read_error', __( 'Invalid URL for Font Collection data.', 'gutenberg' ) ); } - $response = wp_remote_get( $this->config['src'] ); + $response = wp_remote_get( $this->src ); if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) { return new WP_Error( 'font_collection_read_error', __( 'Error fetching the Font Collection data from a URL.', 'gutenberg' ) ); } @@ -133,15 +223,22 @@ public function load_data() { } // If the src is a file path, read the data from the file. } else { - if ( ! file_exists( $this->config['src'] ) ) { + if ( ! file_exists( $this->src ) ) { return new WP_Error( 'font_collection_read_error', __( 'Font Collection data JSON file does not exist.', 'gutenberg' ) ); } - $data = wp_json_file_decode( $this->config['src'], array( 'associative' => true ) ); + $data = wp_json_file_decode( $this->src, array( 'associative' => true ) ); if ( empty( $data ) ) { return new WP_Error( 'font_collection_read_error', __( 'Error reading the Font Collection data JSON file contents.', 'gutenberg' ) ); } } + if ( empty( $data['font_families'] ) ) { + return new WP_Error( 'font_collection_contents_error', __( 'Font Collection data JSON file does not contain font families.', 'gutenberg' ) ); + } + + $this->font_families = $data['font_families']; + $this->categories = $data['categories'] ?? array(); + return $data; } } diff --git a/lib/experimental/fonts/font-library/class-wp-font-library.php b/lib/experimental/fonts/font-library/class-wp-font-library.php index fd36f6ba073c4f..51a84b957ea117 100644 --- a/lib/experimental/fonts/font-library/class-wp-font-library.php +++ b/lib/experimental/fonts/font-library/class-wp-font-library.php @@ -62,11 +62,17 @@ public static function get_expected_font_mime_types_per_php_version( $php_versio * @return WP_Font_Collection|WP_Error A font collection is it was registered successfully and a WP_Error otherwise. */ public static function register_font_collection( $config ) { + if ( ! WP_Font_Collection::is_config_valid( $config ) ) { + $error_message = __( 'Font collection config is invalid.', 'gutenberg' ); + return new WP_Error( 'font_collection_registration_error', $error_message ); + } + $new_collection = new WP_Font_Collection( $config ); - if ( self::is_collection_registered( $config['slug'] ) ) { + + if ( self::is_collection_registered( $new_collection->get_config()['slug'] ) ) { $error_message = sprintf( /* translators: %s: Font collection slug. */ - __( 'Font collection with slug: "%s" is already registered.', 'default' ), + __( 'Font collection with slug: "%s" is already registered.', 'gutenberg' ), $config['slug'] ); _doing_it_wrong( @@ -76,7 +82,7 @@ public static function register_font_collection( $config ) { ); return new WP_Error( 'font_collection_registration_error', $error_message ); } - self::$collections[ $config['slug'] ] = $new_collection; + self::$collections[ $new_collection->get_config()['slug'] ] = $new_collection; return $new_collection; } diff --git a/lib/experimental/fonts/font-library/class-wp-rest-font-collections-controller.php b/lib/experimental/fonts/font-library/class-wp-rest-font-collections-controller.php index c7595a56413b9b..51fd14fffaa953 100644 --- a/lib/experimental/fonts/font-library/class-wp-rest-font-collections-controller.php +++ b/lib/experimental/fonts/font-library/class-wp-rest-font-collections-controller.php @@ -42,8 +42,8 @@ public function register_routes() { array( array( 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_font_collections' ), - 'permission_callback' => array( $this, 'update_font_library_permissions_check' ), + 'callback' => array( $this, 'get_items' ), + 'permission_callback' => array( $this, 'get_items_permissions_check' ), ), ) ); @@ -54,13 +54,29 @@ public function register_routes() { array( array( 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_font_collection' ), - 'permission_callback' => array( $this, 'update_font_library_permissions_check' ), + 'callback' => array( $this, 'get_item' ), + 'permission_callback' => array( $this, 'get_items_permissions_check' ), ), ) ); } + /** + * Gets the font collections available. + * + * @since 6.5.0 + * + * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. + */ + public function get_items( $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable + $collections = array(); + foreach ( WP_Font_Library::get_font_collections() as $collection ) { + $collections[] = $collection->get_config(); + } + + return rest_ensure_response( $collections, 200 ); + } + /** * Gets a font collection. * @@ -69,54 +85,42 @@ public function register_routes() { * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ - public function get_font_collection( $request ) { + public function get_item( $request ) { $slug = $request->get_param( 'slug' ); $collection = WP_Font_Library::get_font_collection( $slug ); + // If the collection doesn't exist returns a 404. if ( is_wp_error( $collection ) ) { $collection->add_data( array( 'status' => 404 ) ); return $collection; } - $config_and_data = $collection->get_config_and_data(); - $collection_data = $config_and_data['data']; - // If there was an error getting the collection data, return the error. - if ( is_wp_error( $collection_data ) ) { - $collection_data->add_data( array( 'status' => 500 ) ); - return $collection_data; - } - - return new WP_REST_Response( $config_and_data ); - } + $config = $collection->get_config(); + $contents = $collection->get_content(); - /** - * Gets the font collections available. - * - * @since 6.5.0 - * - * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. - */ - public function get_font_collections() { - $collections = array(); - foreach ( WP_Font_Library::get_font_collections() as $collection ) { - $collections[] = $collection->get_config_and_data(); + // If there was an error getting the collection data, return the error. + if ( is_wp_error( $contents ) ) { + $contents->add_data( array( 'status' => 500 ) ); + return $contents; } - return new WP_REST_Response( $collections, 200 ); + $collection_data = array_merge( $config, $contents ); + return rest_ensure_response( $collection_data ); } /** - * Checks whether the user has permissions to update the Font Library. + * Checks whether the user has permissions to use the Fonts Collections. * * @since 6.5.0 * * @return true|WP_Error True if the request has write access for the item, WP_Error object otherwise. */ - public function update_font_library_permissions_check() { + public function get_items_permissions_check( $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable + if ( ! current_user_can( 'edit_theme_options' ) ) { return new WP_Error( - 'rest_cannot_update_font_library', - __( 'Sorry, you are not allowed to update the Font Library on this site.', 'gutenberg' ), + 'rest_cannot_read', + __( 'Sorry, you are not allowed to use the Font Library on this site.', 'gutenberg' ), array( 'status' => rest_authorization_required_code(), ) diff --git a/lib/experimental/fonts/font-library/font-library.php b/lib/experimental/fonts/font-library/font-library.php index eb76cbab191280..f16c118317eaec 100644 --- a/lib/experimental/fonts/font-library/font-library.php +++ b/lib/experimental/fonts/font-library/font-library.php @@ -134,7 +134,8 @@ function wp_unregister_font_collection( $collection_id ) { 'slug' => 'default-font-collection', 'name' => 'Google Fonts', 'description' => __( 'Add from Google Fonts. Fonts are copied to and served from your site.', 'gutenberg' ), - 'src' => 'https://s.w.org/images/fonts/16.7/collections/google-fonts-with-preview.json', + // TODO: This URL needs to be updated to the wporg hosted one prior to the Gutenberg 17.6 release. + 'src' => 'https://raw.githubusercontent.com/WordPress/google-fonts-to-wordpress-collection/main/releases/gutenberg-17.6/google-fonts.json', ); wp_register_font_collection( $default_font_collection ); diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/context.js b/packages/edit-site/src/components/global-styles/font-library-modal/context.js index 078d11e235c043..c9e51c514104e7 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/context.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/context.js @@ -394,16 +394,16 @@ function FontLibraryProvider( { children } ) { const response = await fetchFontCollections(); setFontCollections( response ); }; - const getFontCollection = async ( id ) => { + const getFontCollection = async ( slug ) => { try { const hasData = !! collections.find( - ( collection ) => collection.id === id - )?.data; + ( collection ) => collection.slug === slug + )?.font_families; if ( hasData ) return; - const response = await fetchFontCollection( id ); + const response = await fetchFontCollection( slug ); const updatedCollections = collections.map( ( collection ) => - collection.id === id - ? { ...collection, data: { ...response?.data } } + collection.slug === slug + ? { ...collection, ...response } : collection ); setFontCollections( updatedCollections ); diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/font-collection.js b/packages/edit-site/src/components/global-styles/font-library-modal/font-collection.js index 5b6eeb2481e7a4..793ca9c753f337 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/font-collection.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/font-collection.js @@ -36,8 +36,8 @@ const DEFAULT_CATEGORY = { id: 'all', name: __( 'All' ), }; -function FontCollection( { id } ) { - const requiresPermission = id === 'default-font-collection'; +function FontCollection( { slug } ) { + const requiresPermission = slug === 'default-font-collection'; const getGoogleFontsPermissionFromStorage = () => { return ( @@ -57,7 +57,7 @@ function FontCollection( { id } ) { const { collections, getFontCollection, installFont } = useContext( FontLibraryContext ); const selectedCollection = collections.find( - ( collection ) => collection.id === id + ( collection ) => collection.slug === slug ); useEffect( () => { @@ -69,12 +69,12 @@ function FontCollection( { id } ) { handleStorage(); window.addEventListener( 'storage', handleStorage ); return () => window.removeEventListener( 'storage', handleStorage ); - }, [ id, requiresPermission ] ); + }, [ slug, requiresPermission ] ); useEffect( () => { const fetchFontCollection = async () => { try { - await getFontCollection( id ); + await getFontCollection( slug ); resetFilters(); } catch ( e ) { setNotice( { @@ -85,12 +85,12 @@ function FontCollection( { id } ) { } }; fetchFontCollection(); - }, [ id, getFontCollection ] ); + }, [ slug, getFontCollection ] ); useEffect( () => { setSelectedFont( null ); setNotice( null ); - }, [ id ] ); + }, [ slug ] ); useEffect( () => { // If the selected fonts change, reset the selected fonts to install @@ -108,10 +108,10 @@ function FontCollection( { id } ) { }, [ notice ] ); const collectionFonts = useMemo( - () => selectedCollection?.data?.fontFamilies ?? [], + () => selectedCollection?.font_families ?? [], [ selectedCollection ] ); - const collectionCategories = selectedCollection?.data?.categories ?? []; + const collectionCategories = selectedCollection?.categories ?? []; const categories = [ DEFAULT_CATEGORY, ...collectionCategories ]; @@ -277,11 +277,11 @@ function FontCollection( { id } ) { { ! renderConfirmDialog && - ! selectedCollection?.data?.fontFamilies && + ! selectedCollection?.font_families && ! notice && } { ! renderConfirmDialog && - !! selectedCollection?.data?.fontFamilies?.length && + !! selectedCollection?.font_families?.length && ! fonts.length && ( { __( @@ -302,10 +302,10 @@ function FontCollection( { id } ) { { fonts.map( ( font ) => ( { - setSelectedFont( font ); + setSelectedFont( font.font_family_settings ); } } /> ) ) } diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/index.js b/packages/edit-site/src/components/global-styles/font-library-modal/index.js index 65a284560687cc..a68c42ec010413 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/index.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/index.js @@ -31,10 +31,10 @@ const DEFAULT_TABS = [ ]; const tabsFromCollections = ( collections ) => - collections.map( ( { id, name } ) => ( { - id, + collections.map( ( { slug, name } ) => ( { + id: slug, title: - collections.length === 1 && id === 'default-font-collection' + collections.length === 1 && slug === 'default-font-collection' ? __( 'Install Fonts' ) : name, } ) ); @@ -76,7 +76,7 @@ function FontLibraryModal( { contents = ; break; default: - contents = ; + contents = ; } return ( setAccessible( true ); + $slug = new ReflectionProperty( WP_Font_Collection::class, 'slug' ); + $slug->setAccessible( true ); - $config = array( + $name = new ReflectionProperty( WP_Font_Collection::class, 'name' ); + $name->setAccessible( true ); + + $description = new ReflectionProperty( WP_Font_Collection::class, 'description' ); + $description->setAccessible( true ); + + $src = new ReflectionProperty( WP_Font_Collection::class, 'src' ); + $src->setAccessible( true ); + + $config = array( 'slug' => 'my-collection', 'name' => 'My Collection', 'description' => 'My collection description', 'src' => 'my-collection-data.json', ); - $font_collection = new WP_Font_Collection( $config ); + $collection = new WP_Font_Collection( $config ); - $actual = $property->getValue( $font_collection ); - $property->setAccessible( false ); + $actual_slug = $slug->getValue( $collection ); + $this->assertSame( 'my-collection', $actual_slug, 'Provided slug and initialized slug should match.' ); + $slug->setAccessible( false ); - $this->assertSame( $config, $actual ); + $actual_name = $name->getValue( $collection ); + $this->assertSame( 'My Collection', $actual_name, 'Provided name and initialized name should match.' ); + $name->setAccessible( false ); + + $actual_description = $description->getValue( $collection ); + $this->assertSame( 'My collection description', $actual_description, 'Provided description and initialized description should match.' ); + $description->setAccessible( false ); + + $actual_src = $src->getValue( $collection ); + $this->assertSame( 'my-collection-data.json', $actual_src, 'Provided src and initialized src should match.' ); + $src->setAccessible( false ); } /** - * @dataProvider data_should_throw_exception + * @dataProvider data_should_do_ti_wrong * * @param mixed $config Config of the font collection. - * @param string $expected_exception_message Expected exception message. */ - public function test_should_throw_exception( $config, $expected_exception_message ) { - $this->expectException( 'Exception' ); - $this->expectExceptionMessage( $expected_exception_message ); + public function test_should_do_ti_wrong( $config ) { + $this->setExpectedIncorrectUsage( 'WP_Font_Collection::is_config_valid' ); new WP_Font_Collection( $config ); } @@ -47,7 +65,7 @@ public function test_should_throw_exception( $config, $expected_exception_messag * * @return array */ - public function data_should_throw_exception() { + public function data_should_do_ti_wrong() { return array( 'no id' => array( array( @@ -55,27 +73,22 @@ public function data_should_throw_exception() { 'description' => 'My collection description', 'src' => 'my-collection-data.json', ), - 'Font Collection config slug is required as a non-empty string.', ), 'no config' => array( '', - 'Font Collection config options is required as a non-empty array.', ), 'empty array' => array( array(), - 'Font Collection config options is required as a non-empty array.', ), 'boolean instead of config array' => array( false, - 'Font Collection config options is required as a non-empty array.', ), 'null instead of config array' => array( null, - 'Font Collection config options is required as a non-empty array.', ), 'missing src' => array( @@ -84,9 +97,7 @@ public function data_should_throw_exception() { 'name' => 'My Collection', 'description' => 'My collection description', ), - 'Font Collection config "src" option OR "data" option is required.', ), - ); } } diff --git a/phpunit/tests/fonts/font-library/wpFontCollection/getConfig.php b/phpunit/tests/fonts/font-library/wpFontCollection/getConfig.php index 5f1f082297d418..393de7d22614da 100644 --- a/phpunit/tests/fonts/font-library/wpFontCollection/getConfig.php +++ b/phpunit/tests/fonts/font-library/wpFontCollection/getConfig.php @@ -32,7 +32,7 @@ public function data_should_get_config() { file_put_contents( $mock_file, '{"this is mock data":true}' ); return array( - 'with a file' => array( + 'with a file' => array( 'config' => array( 'slug' => 'my-collection', 'name' => 'My Collection', @@ -45,7 +45,7 @@ public function data_should_get_config() { 'description' => 'My collection description', ), ), - 'with a url' => array( + 'with a url' => array( 'config' => array( 'slug' => 'my-collection-with-url', 'name' => 'My Collection with URL', @@ -58,12 +58,12 @@ public function data_should_get_config() { 'description' => 'My collection description', ), ), - 'with data' => array( + 'with font_families' => array( 'config' => array( - 'slug' => 'my-collection', - 'name' => 'My Collection', - 'description' => 'My collection description', - 'data' => array( 'this is mock data' => true ), + 'slug' => 'my-collection', + 'name' => 'My Collection', + 'description' => 'My collection description', + 'font_families' => array( array() ), ), 'expected_data' => array( 'slug' => 'my-collection', diff --git a/phpunit/tests/fonts/font-library/wpFontCollection/getConfigAndData.php b/phpunit/tests/fonts/font-library/wpFontCollection/getContent.php similarity index 52% rename from phpunit/tests/fonts/font-library/wpFontCollection/getConfigAndData.php rename to phpunit/tests/fonts/font-library/wpFontCollection/getContent.php index 885b0a0b9036cb..ab0e87cde000e7 100644 --- a/phpunit/tests/fonts/font-library/wpFontCollection/getConfigAndData.php +++ b/phpunit/tests/fonts/font-library/wpFontCollection/getContent.php @@ -1,6 +1,6 @@ 'mock', - 'categories' => 'mock', + 'font_families' => array( 'mock' ), + 'categories' => array( 'mock' ), ); return array( @@ -47,14 +47,14 @@ public function mock_request( $preempt, $args, $url ) { } /** - * @dataProvider data_should_get_config_and_data + * @dataProvider data_should_get_content * * @param array $config Font collection config options. - * @param array $expected_data Expected data. + * @param array $expected_data Expected output data. */ - public function test_should_get_config_and_data( $config, $expected_data ) { + public function test_should_get_content( $config, $expected_data ) { $collection = new WP_Font_Collection( $config ); - $this->assertSame( $expected_data, $collection->get_config_and_data() ); + $this->assertSame( $expected_data, $collection->get_content() ); } /** @@ -62,12 +62,12 @@ public function test_should_get_config_and_data( $config, $expected_data ) { * * @return array[] */ - public function data_should_get_config_and_data() { + public function data_should_get_content() { $mock_file = wp_tempnam( 'my-collection-data-' ); - file_put_contents( $mock_file, '{"this is mock data":true}' ); + file_put_contents( $mock_file, '{"font_families":[ "mock" ], "categories":[ "mock" ] }' ); return array( - 'with a file' => array( + 'with a file' => array( 'config' => array( 'slug' => 'my-collection', 'name' => 'My Collection', @@ -75,13 +75,11 @@ public function data_should_get_config_and_data() { 'src' => $mock_file, ), 'expected_data' => array( - 'slug' => 'my-collection', - 'name' => 'My Collection', - 'description' => 'My collection description', - 'data' => array( 'this is mock data' => true ), + 'font_families' => array( 'mock' ), + 'categories' => array( 'mock' ), ), ), - 'with a url' => array( + 'with a url' => array( 'config' => array( 'slug' => 'my-collection-with-url', 'name' => 'My Collection with URL', @@ -89,27 +87,33 @@ public function data_should_get_config_and_data() { 'src' => 'https://localhost/fonts/mock-font-collection.json', ), 'expected_data' => array( - 'slug' => 'my-collection-with-url', - 'name' => 'My Collection with URL', - 'description' => 'My collection description', - 'data' => array( - 'fontFamilies' => 'mock', - 'categories' => 'mock', - ), + 'font_families' => array( 'mock' ), + 'categories' => array( 'mock' ), ), ), - 'with data' => array( + 'with font_families and categories' => array( 'config' => array( - 'slug' => 'my-collection', - 'name' => 'My Collection', - 'description' => 'My collection description', - 'data' => array( 'this is mock data' => true ), + 'slug' => 'my-collection', + 'name' => 'My Collection', + 'description' => 'My collection description', + 'font_families' => array( 'mock' ), + 'categories' => array( 'mock' ), ), 'expected_data' => array( - 'slug' => 'my-collection', - 'name' => 'My Collection', - 'description' => 'My collection description', - 'data' => array( 'this is mock data' => true ), + 'font_families' => array( 'mock' ), + 'categories' => array( 'mock' ), + ), + ), + 'with font_families without categories' => array( + 'config' => array( + 'slug' => 'my-collection', + 'name' => 'My Collection', + 'description' => 'My collection description', + 'font_families' => array( 'mock' ), + ), + 'expected_data' => array( + 'font_families' => array( 'mock' ), + 'categories' => array(), ), ), ); diff --git a/phpunit/tests/fonts/font-library/wpFontCollection/isConfigValid.php b/phpunit/tests/fonts/font-library/wpFontCollection/isConfigValid.php new file mode 100644 index 00000000000000..7cfdfc829ab863 --- /dev/null +++ b/phpunit/tests/fonts/font-library/wpFontCollection/isConfigValid.php @@ -0,0 +1,103 @@ +assertTrue( WP_Font_Collection::is_config_valid( $config ) ); + } + + public function data_is_config_valid() { + return array( + 'with src' => array( + 'config' => array( + 'slug' => 'my-collection', + 'name' => 'My Collection', + 'description' => 'My collection description', + 'src' => 'my-collection-data.json', + ), + ), + 'with font families' => array( + 'config' => array( + 'slug' => 'my-collection', + 'name' => 'My Collection', + 'description' => 'My collection description', + 'font_families' => array( 'mock' ), + ), + ), + + ); + } + + /** + * @dataProvider data_is_config_valid_should_call_doing_ti_wrong + * + * @param mixed $config Config of the font collection. + */ + public function test_is_config_valid_should_call_doing_ti_wrong( $config ) { + $this->setExpectedIncorrectUsage( 'WP_Font_Collection::is_config_valid', 'Should call _doing_it_wrong if the config is not valid.' ); + $this->assertFalse( WP_Font_Collection::is_config_valid( $config ), 'Should return false if the config is not valid.' ); + } + + public function data_is_config_valid_should_call_doing_ti_wrong() { + return array( + 'with missing slug' => array( + 'config' => array( + 'name' => 'My Collection', + 'description' => 'My collection description', + 'src' => 'my-collection-data.json', + ), + ), + 'with missing name' => array( + 'config' => array( + 'slug' => 'my-collection', + 'description' => 'My collection description', + 'src' => 'my-collection-data.json', + ), + ), + 'with missing src' => array( + 'config' => array( + 'slug' => 'my-collection', + 'name' => 'My Collection', + 'description' => 'My collection description', + ), + ), + 'with both src and font_families' => array( + 'config' => array( + 'slug' => 'my-collection', + 'name' => 'My Collection', + 'description' => 'My collection description', + 'src' => 'my-collection-data.json', + 'font_families' => array( 'mock' ), + ), + ), + 'without src or font_families' => array( + 'config' => array( + 'slug' => 'my-collection', + 'name' => 'My Collection', + 'description' => 'My collection description', + ), + ), + 'with empty config' => array( + 'config' => array(), + ), + 'without an array' => array( + 'config' => 'not an array', + ), + ); + } +} diff --git a/phpunit/tests/fonts/font-library/wpFontFamily/__construct.php b/phpunit/tests/fonts/font-library/wpFontFamily/__construct.php index 3a1e387c3651b2..cee0628dad3103 100644 --- a/phpunit/tests/fonts/font-library/wpFontFamily/__construct.php +++ b/phpunit/tests/fonts/font-library/wpFontFamily/__construct.php @@ -30,11 +30,11 @@ public function test_should_initialize_data() { } /** - * @dataProvider data_should_throw_exception + * @dataProvider data_should_do_it_wrong * * @param mixed $font_data Data to test. */ - public function test_should_throw_exception( $font_data ) { + public function test_should_do_it_wrong( $font_data ) { $this->expectException( 'Exception' ); $this->expectExceptionMessage( 'Font family data is missing the slug.' ); @@ -46,7 +46,7 @@ public function test_should_throw_exception( $font_data ) { * * @return array */ - public function data_should_throw_exception() { + public function data_should_do_it_wrong() { return array( 'no slug' => array( array( diff --git a/phpunit/tests/fonts/font-library/wpFontLibrary/registerFontCollection.php b/phpunit/tests/fonts/font-library/wpFontLibrary/registerFontCollection.php index a7ea2870957e9d..b06ae3c8d53548 100644 --- a/phpunit/tests/fonts/font-library/wpFontLibrary/registerFontCollection.php +++ b/phpunit/tests/fonts/font-library/wpFontLibrary/registerFontCollection.php @@ -29,9 +29,9 @@ public function test_should_return_error_if_slug_is_missing() { 'description' => 'My Collection Description', 'src' => 'my-collection-data.json', ); - $this->expectException( 'Exception' ); - $this->expectExceptionMessage( 'Font Collection config slug is required as a non-empty string.' ); - WP_Font_Library::register_font_collection( $config ); + $this->setExpectedIncorrectUsage( 'WP_Font_Collection::is_config_valid' ); + $collection = WP_Font_Library::register_font_collection( $config ); + $this->assertWPError( $collection, 'A WP_Error should be returned.' ); } public function test_should_return_error_if_name_is_missing() { @@ -40,16 +40,16 @@ public function test_should_return_error_if_name_is_missing() { 'description' => 'My Collection Description', 'src' => 'my-collection-data.json', ); - $this->expectException( 'Exception' ); - $this->expectExceptionMessage( 'Font Collection config name is required as a non-empty string.' ); - WP_Font_Library::register_font_collection( $config ); + $this->setExpectedIncorrectUsage( 'WP_Font_Collection::is_config_valid' ); + $collection = WP_Font_Library::register_font_collection( $config ); + $this->assertWPError( $collection, 'A WP_Error should be returned.' ); } public function test_should_return_error_if_config_is_empty() { $config = array(); - $this->expectException( 'Exception' ); - $this->expectExceptionMessage( 'Font Collection config options is required as a non-empty array.' ); - WP_Font_Library::register_font_collection( $config ); + $this->setExpectedIncorrectUsage( 'WP_Font_Collection::is_config_valid' ); + $collection = WP_Font_Library::register_font_collection( $config ); + $this->assertWPError( $collection, 'A WP_Error should be returned.' ); } public function test_should_return_error_if_slug_is_repeated() { diff --git a/phpunit/tests/fonts/font-library/wpRestFontCollectionsController.php b/phpunit/tests/fonts/font-library/wpRestFontCollectionsController.php new file mode 100644 index 00000000000000..164f88f3f7b4b2 --- /dev/null +++ b/phpunit/tests/fonts/font-library/wpRestFontCollectionsController.php @@ -0,0 +1,163 @@ +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, '{"font_families": [ "mock" ], "categories": [ "mock" ] }' ); + + wp_register_font_collection( + array( + 'name' => 'My Collection', + 'slug' => 'mock-col-slug', + 'src' => $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->assertCount( 1, $routes['/wp/v2/font-collections'], 'Rest server has not the collections path initialized.' ); + $this->assertCount( 1, $routes['/wp/v2/font-collections/(?P[\/\w-]+)'], 'Rest server has not the collection path initialized.' ); + + $this->assertArrayHasKey( 'GET', $routes['/wp/v2/font-collections'][0]['methods'], 'Rest server has not the GET method for collections intialized.' ); + $this->assertArrayHasKey( 'GET', $routes['/wp/v2/font-collections/(?P[\/\w-]+)'][0]['methods'], 'Rest server has not the GET method for collection intialized.' ); + } + + /** + * @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->assertEquals( 200, $response->get_status() ); + } + + /** + * @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->assertEquals( 200, $response->get_status(), 'Response code is not 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( 'font_collection_not_found', $response, 404 ); + } + + /** + * @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, 'Response code 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, 'Response code 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(). + } + + /** + * @doesNotPerformAssertions + */ + public function test_get_item_schema() { + // Controller does not use test_get_item_schema(). + } +} diff --git a/phpunit/tests/fonts/font-library/wpRestFontCollectionsController/base.php b/phpunit/tests/fonts/font-library/wpRestFontCollectionsController/base.php deleted file mode 100644 index 2469d71dc79ce8..00000000000000 --- a/phpunit/tests/fonts/font-library/wpRestFontCollectionsController/base.php +++ /dev/null @@ -1,42 +0,0 @@ -factory->user->create( - array( - 'role' => 'administrator', - ) - ); - wp_set_current_user( $admin_id ); - } - - /** - * Tear down each test method. - */ - public function tear_down() { - parent::tear_down(); - - // Reset $collections static property of WP_Font_Library class. - $reflection = new ReflectionClass( 'WP_Font_Library' ); - $property = $reflection->getProperty( 'collections' ); - $property->setAccessible( true ); - $property->setValue( null, array() ); - } -} diff --git a/phpunit/tests/fonts/font-library/wpRestFontCollectionsController/getFontCollection.php b/phpunit/tests/fonts/font-library/wpRestFontCollectionsController/getFontCollection.php deleted file mode 100644 index c9d003389997b4..00000000000000 --- a/phpunit/tests/fonts/font-library/wpRestFontCollectionsController/getFontCollection.php +++ /dev/null @@ -1,126 +0,0 @@ - 'one-collection', - 'name' => 'One Font Collection', - 'description' => 'Demo about how to a font collection to your WordPress Font Library.', - 'src' => $mock_file, - ); - wp_register_font_collection( $config_with_file ); - - $config_with_url = array( - 'slug' => 'collection-with-url', - 'name' => 'Another Font Collection', - 'description' => 'Demo about how to a font collection to your WordPress Font Library.', - 'src' => 'https://wordpress.org/fonts/mock-font-collection.json', - ); - - wp_register_font_collection( $config_with_url ); - - $config_with_non_existing_file = array( - 'slug' => 'collection-with-non-existing-file', - 'name' => 'Another Font Collection', - 'description' => 'Demo about how to a font collection to your WordPress Font Library.', - 'src' => '/home/non-existing-file.json', - ); - - wp_register_font_collection( $config_with_non_existing_file ); - - $config_with_non_existing_url = array( - 'slug' => 'collection-with-non-existing-url', - 'name' => 'Another Font Collection', - 'description' => 'Demo about how to a font collection to your WordPress Font Library.', - 'src' => 'https://non-existing-url-1234x.com.ar/fake-path/missing-file.json', - ); - - wp_register_font_collection( $config_with_non_existing_url ); - } - - public function mock_request( $preempt, $args, $url ) { - // Check if it's the URL you want to mock. - if ( 'https://wordpress.org/fonts/mock-font-collection.json' === $url ) { - - // Mock the response body. - $mock_collection_data = array( - 'fontFamilies' => 'mock', - 'categories' => 'mock', - ); - - return array( - 'body' => json_encode( $mock_collection_data ), - 'response' => array( - 'code' => 200, - ), - ); - } - - // For any other URL, return false which ensures the request is made as usual (or you can return other mock data). - return false; - } - - public function tear_down() { - // Remove the mock to not affect other tests. - remove_filter( 'pre_http_request', array( $this, 'mock_request' ) ); - - parent::tear_down(); - } - - public function test_get_font_collection_from_file() { - $request = new WP_REST_Request( 'GET', '/wp/v2/font-collections/one-collection' ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - $this->assertSame( 200, $response->get_status(), 'The response status is not 200.' ); - $this->assertArrayHasKey( 'data', $data, 'The response data does not have the key with the file data.' ); - $this->assertSame( array( 'this is mock data' => true ), $data['data'], 'The response data does not have the expected file data.' ); - } - - public function test_get_font_collection_from_url() { - $request = new WP_REST_Request( 'GET', '/wp/v2/font-collections/collection-with-url' ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - $this->assertSame( 200, $response->get_status(), 'The response status is not 200.' ); - $this->assertArrayHasKey( 'data', $data, 'The response data does not have the key with the file data.' ); - } - - public function test_get_non_existing_collection_should_return_404() { - $request = new WP_REST_Request( 'GET', '/wp/v2/font-collections/non-existing-collection-id' ); - $response = rest_get_server()->dispatch( $request ); - $this->assertSame( 404, $response->get_status() ); - } - - public function test_get_non_existing_file_should_return_500() { - $request = new WP_REST_Request( 'GET', '/wp/v2/font-collections/collection-with-non-existing-file' ); - $response = rest_get_server()->dispatch( $request ); - $this->assertSame( 500, $response->get_status() ); - } - - public function test_get_non_existing_url_should_return_500() { - $request = new WP_REST_Request( 'GET', '/wp/v2/font-collections/collection-with-non-existing-url' ); - $response = rest_get_server()->dispatch( $request ); - $this->assertSame( 500, $response->get_status() ); - } -} diff --git a/phpunit/tests/fonts/font-library/wpRestFontCollectionsController/getFontCollections.php b/phpunit/tests/fonts/font-library/wpRestFontCollectionsController/getFontCollections.php deleted file mode 100644 index 0a8d24e8f392ba..00000000000000 --- a/phpunit/tests/fonts/font-library/wpRestFontCollectionsController/getFontCollections.php +++ /dev/null @@ -1,45 +0,0 @@ -dispatch( $request ); - $this->assertSame( 200, $response->get_status() ); - $this->assertSame( array(), $response->get_data() ); - } - - public function test_get_font_collections() { - // Mock font collection data file. - $mock_file = wp_tempnam( 'my-collection-data-' ); - file_put_contents( $mock_file, '{"this is mock data":true}' ); - - // Add a font collection. - $config = array( - 'slug' => 'my-font-collection', - 'name' => 'My Font Collection', - 'description' => 'Demo about how to a font collection to your WordPress Font Library.', - 'src' => $mock_file, - ); - wp_register_font_collection( $config ); - - $request = new WP_REST_Request( 'GET', '/wp/v2/font-collections' ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - $this->assertSame( 200, $response->get_status(), 'The response status is not 200.' ); - $this->assertCount( 1, $data, 'The response data is not an array with one element.' ); - $this->assertArrayHasKey( 'slug', $data[0], 'The response data does not have the key with the collection slug.' ); - $this->assertArrayHasKey( 'name', $data[0], 'The response data does not have the key with the collection name.' ); - } -} diff --git a/phpunit/tests/fonts/font-library/wpRestFontCollectionsController/registerRoutes.php b/phpunit/tests/fonts/font-library/wpRestFontCollectionsController/registerRoutes.php deleted file mode 100644 index fb100a400fb4cf..00000000000000 --- a/phpunit/tests/fonts/font-library/wpRestFontCollectionsController/registerRoutes.php +++ /dev/null @@ -1,24 +0,0 @@ -get_routes(); - $this->assertCount( 1, $routes['/wp/v2/font-collections'], 'Rest server has not the collections path initialized.' ); - $this->assertCount( 1, $routes['/wp/v2/font-collections/(?P[\/\w-]+)'], 'Rest server has not the collection path initialized.' ); - - $this->assertArrayHasKey( 'GET', $routes['/wp/v2/font-collections'][0]['methods'], 'Rest server has not the GET method for collections intialized.' ); - $this->assertArrayHasKey( 'GET', $routes['/wp/v2/font-collections/(?P[\/\w-]+)'][0]['methods'], 'Rest server has not the GET method for collection intialized.' ); - } -}