Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Adds additional tests
  • Loading branch information
creativecoder committed Jan 11, 2024
commit 0b572b15bebfdd2a32965dc042ce03a9e33c2c66
Original file line number Diff line number Diff line change
Expand Up @@ -141,14 +141,14 @@ public function get_font_faces_permissions_check() {
}

public function validate_create_font_face_settings( $value, $request ) {
// decoded font_face_settings matches schema
$settings = json_decode( $value, true );
$schema = $this->get_item_schema()['properties']['font_face_settings'];

// Check that the font face settings match the theme.json schema.
$valid_settings = rest_validate_value_from_schema( $settings, $schema, 'font_face_settings' );

// Some properties, like fontWeight, validate as multiple "oneOf" types and trigger an error, but are still valid.
// e.g. a fontWeight of "400" validates as both a string and an integer due to loose type checking.
// Some properties trigger a multiple "oneOf" types error that we ignore, because they are still valid.
// e.g. a fontWeight of "400" validates as both a string and an integer due to is_numeric type checking.
if ( is_wp_error( $valid_settings ) && $valid_settings->get_error_code() !== 'rest_one_of_multiple_matches' ) {
$valid_settings->add_data( array( 'status' => 400 ) );
return $valid_settings;
Expand All @@ -157,19 +157,29 @@ public function validate_create_font_face_settings( $value, $request ) {
$srcs = is_array( $settings['src'] ) ? $settings['src'] : array( $settings['src'] );
$files = $request->get_file_params();

foreach ( $srcs as $src ) {
$src_valid_url = wp_http_validate_url( $src );
$src_valid_file_key = in_array( $src, array_keys( $files ), true );

if ( ! $src_valid_url && ! $src_valid_file_key ) {
// Check that each file in the request references a src in the settings.
foreach ( array_keys( $files ) as $file ) {
if ( ! in_array( $file, $srcs, true ) ) {
return new WP_Error(
'rest_invalid_param',
/* translators: %s: A URL. */
__( 'The src setting must be a valid url or file key.', 'gutenberg' ),
__( 'Every file uploaded must be used as a font face src.', 'gutenberg' ),
array( 'status' => 400 )
);
}
}

// Check that src strings are non-empty.
foreach ( $srcs as $src ) {
if ( ! $src ) {
return new WP_Error(
'rest_invalid_param',
__( 'Font face src values must be non-empty strings.', 'gutenberg' ),
array( 'status' => 400 )
);
}
}

return true;
}

Expand Down Expand Up @@ -232,6 +242,7 @@ public function get_item( $request ) {
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
*/
public function create_item( $request ) {
// Settings arrive as stringified JSON, since this is a multipart/form-data request.
$settings = json_decode( $request->get_param( 'font_face_settings' ), true );
$file_params = $request->get_file_params();

Expand All @@ -255,6 +266,7 @@ public function create_item( $request ) {
$processed_srcs = array();

foreach ( $srcs as $src ) {
// If src not a file reference, use it as is.
if ( ! isset( $file_params[ $src ] ) ) {
$processed_srcs[] = $src;
continue;
Expand All @@ -278,10 +290,11 @@ public function create_item( $request ) {

$settings['src'] = count( $processed_srcs ) === 1 ? $processed_srcs[0] : $processed_srcs;

// Ensure that $settings data is slashed, so values with quotes are escaped.
wp_update_post(
array(
'ID' => $font_face_id,
'post_content' => wp_json_encode( $settings ),
'post_content' => wp_json_encode( wp_slash( $settings ) ),
)
);

Expand Down
Binary file added phpunit/data/fonts/OpenSans-Regular.otf
Binary file not shown.
Binary file modified phpunit/data/fonts/OpenSans-Regular.ttf
Binary file not shown.
Binary file added phpunit/data/fonts/OpenSans-Regular.woff
Binary file not shown.
198 changes: 104 additions & 94 deletions phpunit/tests/fonts/font-library/wpRestFontFacesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,31 +78,10 @@ public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
}

public static function wpTearDownAfterClass() {
if ( file_exists( self::$font_file_ttf ) ) {
unlink( self::$font_file_ttf );
}
if ( file_exists( self::$font_file_woff2 ) ) {
unlink( self::$font_file_woff2 );
}

self::delete_user( self::$admin_id );
self::delete_user( self::$editor_id );
}

public function set_up() {
parent::set_up();

// @core-merge Use `DIR_TESTDATA` instead of `GUTENBERG_DIR_TESTDATA`.
$font_file_ttf = GUTENBERG_DIR_TESTDATA . 'fonts/OpenSans-Regular.ttf';
self::$font_file_ttf = wp_tempnam( 'OpenSans-Regular.ttf' );
copy( $font_file_ttf, self::$font_file_ttf );

// @core-merge Use `DIR_TESTDATA` instead of `GUTENBERG_DIR_TESTDATA`.
$font_file_woff2 = GUTENBERG_DIR_TESTDATA . 'fonts/OpenSans-Regular.woff2';
self::$font_file_woff2 = wp_tempnam( 'OpenSans-Regular.woff2' );
copy( $font_file_woff2, self::$font_file_woff2 );
}

/**
* @covers WP_REST_Font_Faces_Controller::register_routes
*/
Expand Down Expand Up @@ -257,6 +236,8 @@ public function test_get_item_invalid_parent_id() {
*/
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', 2 );
$request->set_param(
Expand All @@ -266,29 +247,29 @@ public function test_create_item() {
'fontFamily' => 'Open Sans',
'fontWeight' => '400',
'fontStyle' => 'normal',
'src' => 'file-0',
'src' => array_keys( $files )[0],
)
)
);
$request->set_file_params(
array(
'file-0' => array(
'name' => 'OpenSans-Regular.ttf',
'full_path' => 'OpenSans-Regular.ttf',
'type' => 'font/ttf',
'tmp_name' => self::$font_file_ttf,
'error' => 0,
'size' => filesize( self::$font_file_ttf ),
),
)
);
$request->set_file_params( $files );

$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();

$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(
$settings,
array(
'fontFamily' => 'Open Sans',
'fontWeight' => '400',
'fontStyle' => 'normal',
)
);

$this->assertSame( self::$font_family_id, $data['parent'], 'The returned parent id should match the font family id.' );

wp_delete_post( $data['id'], true );
Expand All @@ -299,6 +280,8 @@ public function test_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', 2 );
$request->set_param(
Expand All @@ -308,37 +291,21 @@ public function test_create_item_with_multiple_font_files() {
'fontFamily' => 'Open Sans',
'fontWeight' => '400',
'fontStyle' => 'normal',
'src' => array( 'file-0', 'file-1' ),
'src' => array_keys( $files ),
)
)
);
$request->set_file_params(
array(
'file-0' => array(
'name' => 'OpenSans-Regular.ttf',
'full_path' => 'OpenSans-Regular.ttf',
'type' => 'font/ttf',
'tmp_name' => self::$font_file_ttf,
'error' => 0,
'size' => filesize( self::$font_file_ttf ),
),
'file-1' => array(
'name' => 'OpenSans-Regular.woff2',
'full_path' => 'OpenSans-Regular.woff2',
'type' => 'font/woff2',
'tmp_name' => self::$font_file_woff2,
'error' => 0,
'size' => filesize( self::$font_file_woff2 ),
),
)
);
$request->set_file_params( $files );

$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();

$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'] );

wp_delete_post( $data['id'], true );
}

Expand All @@ -365,6 +332,67 @@ public function test_create_item_with_url_src() {
$data = $response->get_data();

$this->check_font_face_data( $data, $data['id'], $response->get_links() );

wp_delete_post( $data['id'], true );
}

/**
* @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', 2 );
$request->set_param( 'font_face_settings', wp_json_encode( $properties ) );

$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();

$this->assertArrayHasKey( 'font_face_settings', $data );
$this->assertSame( $properties, $data['font_face_settings'] );

wp_delete_post( $data['id'], true );
}

/**
* @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',
'src' => 'https://fonts.gstatic.com/s/open-sans/v30/KFOkCnqEu92Fr1MmgWxPKTM1K9nz.ttf',
)
)
);

$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();

$this->assertSame( 2, $data['theme_json_version'], 'The default theme.json version should be 2.' );
}

/**
Expand Down Expand Up @@ -416,7 +444,7 @@ public function data_create_item_invalid_settings() {
'Invalid src' => array(
'settings' => array(
'fontFamily' => 'Open Sans',
'src' => 'invalid',
'src' => '',
),
),
'Missing fontFamily' => array(
Expand All @@ -435,44 +463,6 @@ public function data_create_item_invalid_settings() {
),
);
}
/**
* @dataProvider data_create_item_default_params
*
* @covers WP_REST_Font_Faces_Controller::validate_create_font_face_request
*/
// public function test_create_item_default_params( $theme_json_version, $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( 'theme_json_version', 2 );
// $request->set_param(
// 'font_face_settings',
// wp_json_encode( $settings )
// );

// $response = rest_get_server()->dispatch( $request );
// $data = $response->get_data();

// foreach ( $expected as $key => $value ) {
// $this->assertSame( $value, $data[ $key ], "The returned $key should match the expected default value." );
// }
// }

public function data_create_item_default_params() {
$default_settings = array(
'fontFamily' => 'Open Sans',
'src' => 'https://fonts.gstatic.com/s/open-sans/v30/KFOkCnqEu92Fr1MmgWxPKTM1K9nz.ttf',
);

return array(
'Default theme_json_version' => array(
'theme_json_version' => null,
'settings' => $default_settings,
'expected' => array(
'theme_json_version' => 2,
),
),
);
}

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 );
Expand Down Expand Up @@ -600,4 +590,24 @@ protected function check_file_meta( $font_face_id, $srcs ) {
$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 ) {
$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;
}
}