wordpress-develop/tests/phpunit/tests/image/functions.php
Adam Silverstein 575ce15b5d Media: enable AVIF support.
Add support for uploading, editing and saving AVIF images when supported by the server.

Add 'image/avif' to supported mime types. Correctly identify AVIF images and sizes even when PHP doesn't support AVIF. Resize uploaded AVIF files (when supported) and use for front end markup.

Props adamsilverstein, lukefiretoss, ayeshrajans, navjotjsingh, Tyrannous, jb510, gregbenz, nickpagz, JavierCasares, mukesh27, yguyon, swissspidy.
Fixes #51228.



git-svn-id: https://develop.svn.wordpress.org/trunk@57524 602fd350-edb4-49c9-b593-d223f7449a82
2024-02-02 17:46:50 +00:00

1156 lines
32 KiB
PHP

<?php
/**
* @group image
* @group media
* @group upload
*/
class Tests_Image_Functions extends WP_UnitTestCase {
/**
* Includes the required files.
*/
public function set_up() {
parent::set_up();
require_once ABSPATH . WPINC . '/class-wp-image-editor.php';
require_once ABSPATH . WPINC . '/class-wp-image-editor-gd.php';
require_once ABSPATH . WPINC . '/class-wp-image-editor-imagick.php';
require_once DIR_TESTDATA . '/../includes/mock-image-editor.php';
// Ensure no legacy / failed tests detritus.
$folder = get_temp_dir() . 'wordpress-gsoc-flyer*.*';
foreach ( glob( $folder ) as $file ) {
unlink( $file );
}
}
/**
* Gets the available image editor engine classes.
*
* @return string[] Available image editor classes; empty array when none are available.
*/
private function get_image_editor_engine_classes() {
$classes = array( 'WP_Image_Editor_GD', 'WP_Image_Editor_Imagick' );
foreach ( $classes as $key => $class ) {
if ( ! call_user_func( array( $class, 'test' ) ) ) {
// If the image editor isn't available, skip it.
unset( $classes[ $key ] );
}
}
return $classes;
}
/**
* Data provider with the available image editor engine classes.
*
* @return array
*/
public function data_image_editor_engine_classes() {
return $this->text_array_to_dataprovider( $this->get_image_editor_engine_classes() );
}
/**
* Gets the MIME type of a file.
*
* @param string $filename
* @return string
*/
protected function get_mime_type( $filename ) {
$mime_type = '';
if ( extension_loaded( 'fileinfo' ) ) {
$finfo = new finfo();
$mime_type = $finfo->file( $filename, FILEINFO_MIME );
}
if ( false !== strpos( $mime_type, ';' ) ) {
list( $mime_type, $charset ) = explode( ';', $mime_type, 2 );
}
return $mime_type;
}
/**
* @dataProvider data_file_is_valid_image_positive
*
* @covers ::file_is_valid_image
* @covers ::wp_getimagesize
*
* @param string $file File name.
*/
public function test_file_is_valid_image_positive( $file ) {
$this->assertTrue(
file_is_valid_image( DIR_TESTDATA . '/images/' . $file ),
"file_is_valid_image( '$file' ) should return true."
);
}
/**
* Data provider.
*
* @return array
*/
public function data_file_is_valid_image_positive() {
// These are all image files recognized by PHP.
$files = array(
'test-image-cmyk.jpg',
'test-image-grayscale.jpg',
'test-image.bmp',
'test-image.gif',
'test-image.png',
'test-image.tiff',
'test-image-lzw.tiff',
'test-image.jp2',
'test-image.psd',
'test-image-zip.tiff',
'test-image.jpg',
'test-image.ico',
'webp-animated.webp',
'webp-lossless.webp',
'webp-lossy.webp',
'webp-transparent.webp',
'avif-animated.avif',
'avif-lossless.avif',
'avif-lossy.avif',
'avif-transparent.avif',
);
return $this->text_array_to_dataprovider( $files );
}
/**
* @dataProvider data_file_is_valid_image_negative
*
* @covers ::file_is_valid_image
* @covers ::wp_getimagesize
*
* @param string $file File name.
*/
public function test_file_is_valid_image_negative( $file ) {
$this->assertFalse(
file_is_valid_image( DIR_TESTDATA . '/images/' . $file ),
"file_is_valid_image( '$file' ) should return false."
);
}
/**
* Data provider.
*
* @return array
*/
public function data_file_is_valid_image_negative() {
// These are actually image files but aren't recognized or usable by PHP.
$files = array(
'test-image.pct',
'test-image.tga',
'test-image.sgi',
);
return $this->text_array_to_dataprovider( $files );
}
/**
* @dataProvider data_file_is_displayable_image_positive
*
* @covers ::file_is_displayable_image
*
* @param string $file File name.
*/
public function test_file_is_displayable_image_positive( $file ) {
$this->assertTrue(
file_is_displayable_image( DIR_TESTDATA . '/images/' . $file ),
"file_is_displayable_image( '$file' ) should return true."
);
}
/**
* Data provider.
*
* @return array
*/
public function data_file_is_displayable_image_positive() {
// These are all usable in typical web browsers.
$files = array(
'test-image.gif',
'test-image.png',
'test-image.jpg',
'test-image.ico',
);
// Add WebP images if the image editor supports them.
$file = DIR_TESTDATA . '/images/test-image.webp';
$editor = wp_get_image_editor( $file );
if ( ! is_wp_error( $editor ) && $editor->supports_mime_type( 'image/webp' ) ) {
$files[] = 'webp-animated.webp';
$files[] = 'webp-lossless.webp';
$files[] = 'webp-lossy.webp';
$files[] = 'webp-transparent.webp';
}
// Add AVIF images if the image editor supports them.
$file = DIR_TESTDATA . '/images/avif-lossless.avif';
$editor = wp_get_image_editor( $file );
if ( ! is_wp_error( $editor ) && $editor->supports_mime_type( 'image/avif' ) ) {
$files[] = 'avif-animated.avif';
$files[] = 'avif-lossless.avif';
$files[] = 'avif-lossy.avif';
$files[] = 'avif-transparent.avif';
}
return $this->text_array_to_dataprovider( $files );
}
/**
* @dataProvider data_file_is_displayable_image_negative
*
* @covers ::file_is_displayable_image
*
* @param string $file File name.
*/
public function test_file_is_displayable_image_negative( $file ) {
$this->assertFalse(
file_is_displayable_image( DIR_TESTDATA . '/images/' . $file ),
"file_is_displayable_image( '$file' ) should return false."
);
}
/**
* Data provider.
*
* @return array
*/
public function data_file_is_displayable_image_negative() {
// These are image files but aren't suitable for web pages because of compatibility or size issues.
$files = array(
// 'test-image-cmyk.jpg', Allowed in r9727.
// 'test-image-grayscale.jpg', Allowed in r9727.
// 'test-image.bmp', Allowed in r28589.
'test-image.pct',
'test-image.tga',
'test-image.sgi',
'test-image.tiff',
'test-image-lzw.tiff',
'test-image.jp2',
'test-image.psd',
'test-image-zip.tiff',
);
return $this->text_array_to_dataprovider( $files );
}
/**
* @ticket 50833
* @requires extension gd
*/
public function test_is_gd_image_valid_types() {
$this->assertTrue( is_gd_image( imagecreate( 5, 5 ) ) );
}
/**
* @ticket 50833
*/
public function test_is_gd_image_invalid_types() {
$this->assertFalse( is_gd_image( new stdClass() ) );
$this->assertFalse( is_gd_image( array() ) );
$this->assertFalse( is_gd_image( null ) );
$handle = fopen( __FILE__, 'r' );
$this->assertFalse( is_gd_image( $handle ) );
fclose( $handle );
}
/**
* Tests wp_save_image_file() and mime types.
*
* @dataProvider data_wp_save_image_file
*
* @ticket 6821
* @covers ::wp_save_image_file
* @requires extension fileinfo
*
* @param string $class_name Name of the image editor engine class to be tested.
* @param string $mime_type The mime type to test.
*/
public function test_wp_save_image_file( $class_name, $mime_type ) {
require_once ABSPATH . 'wp-admin/includes/image-edit.php';
$img = new $class_name( DIR_TESTDATA . '/images/canola.jpg' );
$loaded = $img->load();
$this->assertNotWPError( $loaded, 'Image failed to load - WP_Error returned.' );
if ( ! $img->supports_mime_type( $mime_type ) ) {
$this->markTestSkipped(
sprintf(
'The %s mime type is not supported by the %s engine.',
$mime_type,
str_replace( 'WP_Image_Editor_', '', $class_name )
)
);
}
// Save the file.
$file = wp_tempnam();
$ret = wp_save_image_file( $file, $img, $mime_type, 1 );
// Make assertions.
$this->assertNotWPError( $ret, 'Image failed to save - WP_Error returned.' );
$this->assertIsArray( $ret, 'Image failed to save - non-array response returned.' );
$this->assertSame( $mime_type, $this->get_mime_type( $ret['path'] ), 'Mime type of the saved image does not match.' );
// Clean up.
unlink( $file );
unlink( $ret['path'] );
unset( $img );
}
/**
* Data provider.
*
* @return array
*/
public function data_wp_save_image_file() {
$classes = $this->get_image_editor_engine_classes();
// Mime types.
$mime_types = array(
'image/jpeg',
'image/gif',
'image/png',
);
// Include WebP in tests when platform supports it.
if ( function_exists( 'imagewebp' ) ) {
$mime_types[] = 'image/webp';
}
$data = array();
foreach ( $classes as $class ) {
foreach ( $mime_types as $mime_type ) {
$data[ $class . '; ' . $mime_type ] = array(
'class_name' => $class,
'mime_type' => $mime_type,
);
}
}
return $data;
}
/**
* Tests that wp_save_image_file() throws a deprecated argument notice when passed a GD resource.
*
* @ticket 6821
* @expectedDeprecated wp_save_image_file
* @requires function imagejpeg
*
* @covers ::wp_save_image_file
*/
public function test_wp_save_image_file_deprecated_argument_with_gd_resource() {
require_once ABSPATH . 'wp-admin/includes/image-edit.php';
// Call wp_save_image_file().
$file = wp_tempnam();
$img = imagecreatefromjpeg( DIR_TESTDATA . '/images/canola.jpg' );
$ret = wp_save_image_file( $file, $img, 'image/jpeg', 1 );
imagedestroy( $img );
unlink( $file );
$this->assertTrue( $ret, 'Image failed to save.' );
}
/**
* Tests that `wp_image_editor()` applies 'image_edit_thumbnails_separately' filters.
*
* @ticket 53161
*
* @covers ::wp_image_editor
*/
public function test_wp_image_editor_should_apply_image_edit_thumbnails_separately_filters() {
require_once ABSPATH . 'wp-admin/includes/image-edit.php';
$filename = DIR_TESTDATA . '/images/canola.jpg';
$contents = file_get_contents( $filename );
$upload = wp_upload_bits( wp_basename( $filename ), null, $contents );
$id = $this->_make_attachment( $upload );
$filter = new MockAction();
add_filter( 'image_edit_thumbnails_separately', array( &$filter, 'filter' ) );
ob_start();
wp_image_editor( $id );
ob_end_clean();
$this->assertSame( 1, $filter->get_call_count() );
}
/**
* Tests that `wp_image_editor()` conditionally outputs markup for editing thumbnails separately
* based on the result of applying 'image_edit_thumbnails_separately' filters.
*
* @ticket 53161
*
* @covers ::wp_image_editor
*
* @dataProvider data_wp_image_editor_should_respect_image_edit_thumbnails_separately_filters
*
* @param string $callback The name of the callback for the 'image_edit_thumbnails_separately' hook.
* @param bool $expected Whether the markup should be output.
*/
public function test_wp_image_editor_should_respect_image_edit_thumbnails_separately_filters( $callback, $expected ) {
require_once ABSPATH . 'wp-admin/includes/image-edit.php';
$filename = DIR_TESTDATA . '/images/canola.jpg';
$contents = file_get_contents( $filename );
$upload = wp_upload_bits( wp_basename( $filename ), null, $contents );
$id = $this->_make_attachment( $upload );
add_filter( 'image_edit_thumbnails_separately', $callback );
ob_start();
wp_image_editor( $id );
$actual = ob_get_clean();
if ( $expected ) {
$this->assertStringContainsString(
'imgedit-applyto',
$actual,
'The markup should have been output.'
);
} else {
$this->assertStringNotContainsString(
'imgedit-applyto',
$actual,
'The markup should not have been output.'
);
}
}
/**
* Data provider.
*
* @return array[]
*/
public function data_wp_image_editor_should_respect_image_edit_thumbnails_separately_filters() {
return array(
'true' => array(
'callback' => '__return_true',
'expected' => true,
),
'false' => array(
'callback' => '__return_false',
'expected' => false,
),
);
}
/**
* Tests that a passed mime type overrides the extension in the filename when saving an image.
*
* @dataProvider data_image_editor_engine_classes
*
* @ticket 6821
* @covers WP_Image_Editor::get_mime_type
* @covers WP_Image_Editor::get_output_format
* @requires extension fileinfo
*
* @param string $class_name Name of the image editor engine class to be tested.
*/
public function test_mime_overrides_filename_when_saving_an_image( $class_name ) {
$img = new $class_name( DIR_TESTDATA . '/images/canola.jpg' );
$loaded = $img->load();
$this->assertNotWPError( $loaded, 'Image failed to load - WP_Error returned.' );
// Save the file.
$mime_type = 'image/gif';
$file = wp_tempnam( 'tmp.jpg' );
$ret = $img->save( $file, $mime_type );
// Make assertions.
$this->assertNotWPError( $ret, 'Image failed to save - WP_Error returned.' );
$this->assertIsArray( $ret, 'Image failed to save - non-array response returned.' );
$this->assertSame( $mime_type, $this->get_mime_type( $ret['path'] ), 'Mime type of the saved image did not override file name.' );
// Clean up.
unlink( $file );
unlink( $ret['path'] );
unset( $img );
}
/**
* Tests that mime types are correctly inferred from file extensions when saving an image.
*
* @dataProvider data_inferred_mime_types_when_saving_an_image
*
* @ticket 6821
* @covers WP_Image_Editor::get_mime_type
* @covers WP_Image_Editor::get_output_format
* @requires extension fileinfo
*
* @param string $class_name Name of the image editor engine class to be tested.
* @param string $extension File extension.
* @param string $mime_type The mime type to test.
*/
public function test_inferred_mime_types_when_saving_an_image( $class_name, $extension, $mime_type ) {
$img = new $class_name( DIR_TESTDATA . '/images/canola.jpg' );
$loaded = $img->load();
$this->assertNotWPError( $loaded, 'Image failed to load - WP_Error returned.' );
if ( ! $img->supports_mime_type( $mime_type ) ) {
$this->markTestSkipped(
sprintf(
'The %s mime type is not supported by the %s engine.',
$mime_type,
str_replace( 'WP_Image_Editor_', '', $class_name )
)
);
}
// Save the file.
$temp = get_temp_dir();
$file = wp_unique_filename( $temp, uniqid() . ".$extension" );
$ret = $img->save( trailingslashit( $temp ) . $file );
// Make assertions.
$this->assertNotWPError( $ret, 'Image failed to save - WP Error returned.' );
$this->assertIsArray( $ret, 'Image failed to save - non-array response returned.' );
$this->assertSame( $mime_type, $this->get_mime_type( $ret['path'] ), 'Mime type of the saved image was not inferred correctly.' );
// Clean up.
unlink( $ret['path'] );
unset( $img );
}
/**
* Data provider.
*
* @return array
*/
public function data_inferred_mime_types_when_saving_an_image() {
$classes = $this->get_image_editor_engine_classes();
// Mime types.
$mime_types = array(
'jpg' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'jpe' => 'image/jpeg',
'gif' => 'image/gif',
'png' => 'image/png',
'webp' => 'image/webp',
'unk' => 'image/jpeg', // Default, unknown.
);
$data = array();
foreach ( $classes as $class ) {
foreach ( $mime_types as $ext => $mime_type ) {
$data[ $class . '; Extension: ' . $ext . '; Mime type: ' . $mime_type ] = array(
'class_name' => $class,
'extension' => $ext,
'mime_type' => $mime_type,
);
}
}
return $data;
}
/**
* Tests that the deprecated wp_load_image() function fails when loading a directory.
*
* @ticket 17814
* @covers ::wp_load_image
* @expectedDeprecated wp_load_image
*/
public function test_wp_load_image_should_fail_with_error_message_when_loading_a_directory() {
$editor = wp_load_image( DIR_TESTDATA );
$this->assertIsString( $editor );
}
/**
* Tests that the wp_get_image_editor() function fails when loading a directory.
*
* @ticket 17814
* @covers ::wp_get_image_editor
*/
public function test_wp_get_image_editor_should_fail_with_wp_error_object_when_loading_a_directory() {
$editor = wp_get_image_editor( DIR_TESTDATA );
$this->assertInstanceOf( 'WP_Error', $editor );
}
/**
* Tests that the load() method in an image editor class fails when loading a directory.
*
* @dataProvider data_image_editor_engine_classes
*
* @ticket 17814
* @covers WP_Image_Editor_GD::load
* @covers WP_Image_Editor_Imagick::load
*
* @param string $class_name Name of the image editor engine class to be tested.
*/
public function test_image_editor_classes_should_fail_with_wp_error_object_when_loading_a_directory( $class_name ) {
$editor = new $class_name( DIR_TESTDATA );
$loaded = $editor->load();
$this->assertInstanceOf( 'WP_Error', $loaded, 'Loading a directory did not result in a WP_Error.' );
$this->assertSame( 'error_loading_image', $loaded->get_error_code(), 'Error code from WP_Error did not match expectation.' );
}
/**
* @covers ::wp_crop_image
* @requires function imagejpeg
*/
public function test_wp_crop_image_with_file() {
$file = wp_crop_image(
DIR_TESTDATA . '/images/canola.jpg',
0,
0,
100,
100,
100,
100
);
$this->assertNotWPError( $file, 'Cropping the image resulted in a WP_Error.' );
$this->assertFileExists( $file, "The file $file does not exist." );
$image = wp_get_image_editor( $file );
$size = $image->get_size();
$this->assertSame( 100, $size['height'], 'Cropped image height does not match expectation.' );
$this->assertSame( 100, $size['width'], 'Cropped image width does not match expectation.' );
unlink( $file );
}
/**
* @covers ::wp_crop_image
* @requires function imagejpeg
* @requires extension openssl
*/
public function test_wp_crop_image_with_url() {
$file = wp_crop_image(
'https://asdftestblog1.files.wordpress.com/2008/04/canola.jpg',
0,
0,
100,
100,
100,
100,
false,
DIR_TESTDATA . '/images/' . __FUNCTION__ . '.jpg'
);
if ( is_wp_error( $file ) && $file->get_error_code() === 'invalid_image' ) {
$this->markTestSkipped( 'Tests_Image_Functions::test_wp_crop_image_url() cannot access remote image.' );
}
$this->assertNotWPError( $file, 'Cropping the image resulted in a WP_Error.' );
$this->assertFileExists( $file, "The file $file does not exist." );
$image = wp_get_image_editor( $file );
$size = $image->get_size();
$this->assertSame( 100, $size['height'], 'Cropped image height does not match expectation.' );
$this->assertSame( 100, $size['width'], 'Cropped image width does not match expectation.' );
unlink( $file );
}
/**
* @covers ::wp_crop_image
*/
public function test_wp_crop_image_should_fail_with_wp_error_object_if_file_does_not_exist() {
$file = wp_crop_image(
DIR_TESTDATA . '/images/canoladoesnotexist.jpg',
0,
0,
100,
100,
100,
100
);
$this->assertInstanceOf( 'WP_Error', $file );
}
/**
* @covers ::wp_crop_image
* @requires extension openssl
*/
public function test_wp_crop_image_should_fail_with_wp_error_object_if_url_does_not_exist() {
$file = wp_crop_image(
'https://asdftestblog1.files.wordpress.com/2008/04/canoladoesnotexist.jpg',
0,
0,
100,
100,
100,
100
);
$this->assertInstanceOf( 'WP_Error', $file );
}
/**
* @ticket 23325
* @covers ::wp_crop_image
*/
public function test_wp_crop_image_should_fail_with_wp_error_object_if_there_was_an_error_on_saving() {
WP_Image_Editor_Mock::$save_return = new WP_Error();
add_filter(
'wp_image_editors',
static function ( $editors ) {
return array( 'WP_Image_Editor_Mock' );
}
);
$file = wp_crop_image(
DIR_TESTDATA . '/images/canola.jpg',
0,
0,
100,
100,
100,
100
);
$this->assertInstanceOf( 'WP_Error', $file );
WP_Image_Editor_Mock::$save_return = array();
}
/**
* @ticket 55403
* @covers ::wp_crop_image
*/
public function test_wp_crop_image_should_return_correct_file_extension_if_output_format_was_modified() {
add_filter(
'image_editor_output_format',
static function () {
return array_fill_keys( array( 'image/jpg', 'image/jpeg', 'image/png' ), 'image/webp' );
}
);
$file = wp_crop_image(
DIR_TESTDATA . '/images/canola.jpg',
0,
0,
100,
100,
100,
100
);
$this->assertNotWPError( $file, 'Cropping the image resulted in a WP_Error.' );
$this->assertFileExists( $file, "The file $file does not exist." );
unlink( $file );
}
/**
* @ticket 31050
*/
public function test_wp_generate_attachment_metadata_pdf() {
if ( ! wp_image_editor_supports( array( 'mime_type' => 'application/pdf' ) ) ) {
$this->markTestSkipped( 'Rendering PDFs is not supported on this system.' );
}
$orig_file = DIR_TESTDATA . '/images/wordpress-gsoc-flyer.pdf';
$test_file = get_temp_dir() . 'wordpress-gsoc-flyer.pdf';
copy( $orig_file, $test_file );
$editor = wp_get_image_editor( $test_file );
if ( is_wp_error( $editor ) ) {
$this->markTestSkipped( $editor->get_error_message() );
}
$attachment_id = self::factory()->attachment->create_object(
$test_file,
0,
array(
'post_mime_type' => 'application/pdf',
)
);
$this->assertNotWPError( $attachment_id, 'Could not create attachment - WP_Error returned.' );
$this->assertIsInt( $attachment_id, 'Could not create attachment - non-integer response returned.' );
$temp_dir = get_temp_dir();
$metadata = wp_generate_attachment_metadata( $attachment_id, $test_file );
$expected = array(
'sizes' => array(
'full' => array(
'file' => 'wordpress-gsoc-flyer-pdf.jpg',
'width' => 1088,
'height' => 1408,
'mime-type' => 'image/jpeg',
'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf.jpg' ),
),
'medium' => array(
'file' => 'wordpress-gsoc-flyer-pdf-232x300.jpg',
'width' => 232,
'height' => 300,
'mime-type' => 'image/jpeg',
'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-232x300.jpg' ),
),
'large' => array(
'file' => 'wordpress-gsoc-flyer-pdf-791x1024.jpg',
'width' => 791,
'height' => 1024,
'mime-type' => 'image/jpeg',
'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-791x1024.jpg' ),
),
'thumbnail' => array(
'file' => 'wordpress-gsoc-flyer-pdf-116x150.jpg',
'width' => 116,
'height' => 150,
'mime-type' => 'image/jpeg',
'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-116x150.jpg' ),
),
),
'filesize' => wp_filesize( $test_file ),
);
$this->assertSame( $expected, $metadata );
unlink( $test_file );
foreach ( $metadata['sizes'] as $size ) {
unlink( $temp_dir . $size['file'] );
}
}
/**
* Tests crop setting for PDF.
*
* @ticket 43226
*/
public function test_crop_setting_for_pdf() {
if ( ! wp_image_editor_supports( array( 'mime_type' => 'application/pdf' ) ) ) {
$this->markTestSkipped( 'Rendering PDFs is not supported on this system.' );
}
update_option( 'medium_crop', 1 );
$orig_file = DIR_TESTDATA . '/images/wordpress-gsoc-flyer.pdf';
$test_file = get_temp_dir() . 'wordpress-gsoc-flyer.pdf';
copy( $orig_file, $test_file );
$editor = wp_get_image_editor( $test_file );
if ( is_wp_error( $editor ) ) {
$this->markTestSkipped( $editor->get_error_message() );
}
$attachment_id = self::factory()->attachment->create_object(
$test_file,
0,
array(
'post_mime_type' => 'application/pdf',
)
);
$this->assertNotWPError( $attachment_id, 'Could not create attachment - WP_Error returned.' );
$this->assertIsInt( $attachment_id, 'Could not create attachment - non-integer response returned.' );
$temp_dir = get_temp_dir();
$metadata = wp_generate_attachment_metadata( $attachment_id, $test_file );
$expected = array(
'sizes' => array(
'full' => array(
'file' => 'wordpress-gsoc-flyer-pdf.jpg',
'width' => 1088,
'height' => 1408,
'mime-type' => 'image/jpeg',
'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf.jpg' ),
),
'medium' => array(
'file' => 'wordpress-gsoc-flyer-pdf-300x300.jpg',
'width' => 300,
'height' => 300,
'mime-type' => 'image/jpeg',
'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-300x300.jpg' ),
),
'large' => array(
'file' => 'wordpress-gsoc-flyer-pdf-791x1024.jpg',
'width' => 791,
'height' => 1024,
'mime-type' => 'image/jpeg',
'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-791x1024.jpg' ),
),
'thumbnail' => array(
'file' => 'wordpress-gsoc-flyer-pdf-116x150.jpg',
'width' => 116,
'height' => 150,
'mime-type' => 'image/jpeg',
'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-116x150.jpg' ),
),
),
'filesize' => wp_filesize( $test_file ),
);
$this->assertSame( $expected, $metadata );
unlink( $test_file );
foreach ( $metadata['sizes'] as $size ) {
unlink( $temp_dir . $size['file'] );
}
}
/**
* @ticket 39231
*/
public function test_fallback_intermediate_image_sizes() {
if ( ! wp_image_editor_supports( array( 'mime_type' => 'application/pdf' ) ) ) {
$this->markTestSkipped( 'Rendering PDFs is not supported on this system.' );
}
$orig_file = DIR_TESTDATA . '/images/wordpress-gsoc-flyer.pdf';
$test_file = get_temp_dir() . 'wordpress-gsoc-flyer.pdf';
copy( $orig_file, $test_file );
$editor = wp_get_image_editor( $test_file );
if ( is_wp_error( $editor ) ) {
$this->markTestSkipped( $editor->get_error_message() );
}
$attachment_id = self::factory()->attachment->create_object(
$test_file,
0,
array(
'post_mime_type' => 'application/pdf',
)
);
$this->assertNotWPError( $attachment_id, 'Could not create attachment - WP_Error returned.' );
$this->assertIsInt( $attachment_id, 'Could not create attachment - non-integer response returned.' );
add_image_size( 'test-size', 100, 100 );
add_filter( 'fallback_intermediate_image_sizes', array( $this, 'filter_fallback_intermediate_image_sizes' ), 10, 2 );
$metadata = wp_generate_attachment_metadata( $attachment_id, $test_file );
$temp_dir = get_temp_dir();
$expected = array(
'file' => 'wordpress-gsoc-flyer-pdf-77x100.jpg',
'width' => 77,
'height' => 100,
'mime-type' => 'image/jpeg',
'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-77x100.jpg' ),
);
// Different environments produce slightly different filesize results.
$this->assertSame( $metadata['sizes']['test-size'], $expected );
$this->assertArrayHasKey( 'test-size', $metadata['sizes'], 'The `test-size` was not added to the metadata.' );
$this->assertSame( $expected, $metadata['sizes']['test-size'] );
remove_image_size( 'test-size' );
remove_filter( 'fallback_intermediate_image_sizes', array( $this, 'filter_fallback_intermediate_image_sizes' ), 10 );
unlink( $test_file );
foreach ( $metadata['sizes'] as $size ) {
unlink( $temp_dir . $size['file'] );
}
}
public function filter_fallback_intermediate_image_sizes( $fallback_sizes, $metadata ) {
// Add the 'test-size' to the list of fallback sizes.
$fallback_sizes[] = 'test-size';
return $fallback_sizes;
}
/**
* Tests that PDF preview does not overwrite existing JPEG.
*
* @ticket 39875
*/
public function test_pdf_preview_doesnt_overwrite_existing_jpeg() {
if ( ! wp_image_editor_supports( array( 'mime_type' => 'application/pdf' ) ) ) {
$this->markTestSkipped( 'Rendering PDFs is not supported on this system.' );
}
$temp_dir = get_temp_dir();
// Dummy JPEGs.
$jpg1_path = $temp_dir . 'test.jpg'; // Straight.
file_put_contents( $jpg1_path, 'asdf' );
$jpg2_path = $temp_dir . 'test-pdf.jpg'; // With PDF marker.
file_put_contents( $jpg2_path, 'fdsa' );
// PDF with same name as JPEG.
$pdf_path = $temp_dir . 'test.pdf';
copy( DIR_TESTDATA . '/images/wordpress-gsoc-flyer.pdf', $pdf_path );
$editor = wp_get_image_editor( $pdf_path );
if ( is_wp_error( $editor ) ) {
$this->markTestSkipped( $editor->get_error_message() );
}
$attachment_id = self::factory()->attachment->create_object(
$pdf_path,
0,
array(
'post_mime_type' => 'application/pdf',
)
);
$metadata = wp_generate_attachment_metadata( $attachment_id, $pdf_path );
$preview_path = $temp_dir . $metadata['sizes']['full']['file'];
// PDF preview didn't overwrite PDF.
$this->assertNotEquals( $pdf_path, $preview_path );
// PDF preview didn't overwrite JPG with same name.
$this->assertNotEquals( $jpg1_path, $preview_path );
$this->assertSame( 'asdf', file_get_contents( $jpg1_path ) );
// PDF preview didn't overwrite PDF preview with same name.
$this->assertNotEquals( $jpg2_path, $preview_path );
$this->assertSame( 'fdsa', file_get_contents( $jpg2_path ) );
// Cleanup.
unlink( $jpg1_path );
unlink( $jpg2_path );
unlink( $pdf_path );
foreach ( $metadata['sizes'] as $size ) {
unlink( $temp_dir . $size['file'] );
}
}
/**
* Tests that wp_exif_frac2dec() properly handles edge cases
* and always returns an int or float, or 0 for failures.
*
* @param mixed $fraction The fraction to convert.
* @param int|float $expect The expected result.
*
* @ticket 54385
* @dataProvider data_wp_exif_frac2dec
*
* @covers ::wp_exif_frac2dec
*/
public function test_wp_exif_frac2dec( $fraction, $expect ) {
$this->assertSame( $expect, wp_exif_frac2dec( $fraction ) );
}
/**
* Data provider for testing `wp_exif_frac2dec()`.
*
* @return array
*/
public function data_wp_exif_frac2dec() {
return array(
'invalid input: null' => array(
'fraction' => null,
'expect' => 0,
),
'invalid input: boolean true' => array(
'fraction' => null,
'expect' => 0,
),
'invalid input: empty array value' => array(
'fraction' => array(),
'expect' => 0,
),
'input is already integer' => array(
'fraction' => 12,
'expect' => 12,
),
'input is already float' => array(
'fraction' => 10.123,
'expect' => 10.123,
),
'string input is not a fraction - no slash, not numeric' => array(
'fraction' => '123notafraction',
'expect' => 0,
),
'string input is not a fraction - no slash, numeric integer' => array(
'fraction' => '48',
'expect' => 48.0,
),
'string input is not a fraction - no slash, numeric integer (integer 0)' => array(
'fraction' => '0',
'expect' => 0.0,
),
'string input is not a fraction - no slash, octal numeric integer' => array(
'fraction' => '010',
'expect' => 10.0,
),
'string input is not a fraction - no slash, numeric float (float 0)' => array(
'fraction' => '0.0',
'expect' => 0.0,
),
'string input is not a fraction - no slash, numeric float (typical fnumber)' => array(
'fraction' => '4.8',
'expect' => 4.8,
),
'string input is not a fraction - more than 1 slash with text' => array(
'fraction' => 'path/to/file',
'expect' => 0,
),
'string input is not a fraction - more than 1 slash with numbers' => array(
'fraction' => '1/2/3',
'expect' => 0,
),
'string input is not a fraction - only a slash' => array(
'fraction' => '/',
'expect' => 0,
),
'string input is not a fraction - only slashes' => array(
'fraction' => '///',
'expect' => 0,
),
'string input is not a fraction - left/right is not numeric' => array(
'fraction' => 'path/to',
'expect' => 0,
),
'string input is not a fraction - left is not numeric' => array(
'fraction' => 'path/10',
'expect' => 0,
),
'string input is not a fraction - right is not numeric' => array(
'fraction' => '0/abc',
'expect' => 0,
),
'division by zero is prevented 1' => array(
'fraction' => '0/0',
'expect' => 0,
),
'division by zero is prevented 2' => array(
'fraction' => '100/0.0',
'expect' => 0,
),
'typical focal length' => array(
'fraction' => '37 mm',
'expect' => 0,
),
'typical exposure time' => array(
'fraction' => '1/350',
'expect' => 0.002857142857142857,
),
'valid fraction 1' => array(
'fraction' => '50/100',
'expect' => 0.5,
),
'valid fraction 2' => array(
'fraction' => '25/100',
'expect' => .25,
),
'valid fraction 3' => array(
'fraction' => '4/2',
'expect' => 2,
),
);
}
}