Skip to content

Instantly share code, notes, and snippets.

@pbiron
Last active June 7, 2018 19:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pbiron/6a5284805165bf1118e88723f39c2f42 to your computer and use it in GitHub Desktop.
Save pbiron/6a5284805165bf1118e88723f39c2f42 to your computer and use it in GitHub Desktop.
proposed WP unit tests for testing `_wp_attachment_backup_sizes` meta for ajax media editing
<?php
/**
* Admin ajax functions to be tested
*/
require_once( ABSPATH . 'wp-admin/includes/ajax-actions.php' );
/**
* Testing `_wp_attachment_backup_sizes` meta for ajax media editing
*
* Does NOT test that the edits made are correct
* ONLY tests the creation/modification of the `_wp_attachment_backup_sizes` meta
*
* @package WordPress
* @subpackage UnitTests
* @since x.y.z
* @group ajax
*
* @todo I've tagged all these tests with {@ticket 44127} because I decided they
* were needed while I was working on that ticket. However, I'm now thinking
* I should open a new ticket specifically stating the need for these tests,
* independent of that ticket. Opinions?
* @todo Are tests needed for flip & rotate as well as crop? I don't think so
* because I don't think the actual edit operation affects what is
* stored in _wp_attachment_backup_sizes, but need confirmation of that.
* @todo As far as I can tell, the tests that depend on IMAGE_EDIT_OVERWRITE
* must be at the end of the file. Is there any way to avoid this?
*/
class Tests_Ajax_MediaEditBackupSizes extends WP_Ajax_UnitTestCase {
/**
* The attachment ID
*
* @var int
*/
public $attachment_id;
/**
* Uploaded file bits.
*
* Keys are filenames and values are the result of calling `wp_upload_bits()` for those files.
*
* @var array
*/
public $uploaded_bits = array();
/**
* Setup the test fixture.
*/
public function setUp() {
parent::setUp();
require_once( ABSPATH . 'wp-admin/includes/image-edit.php' );
}
/**
* Tear down the test fixture.
*/
public function tearDown() {
// Cleanup
$this->remove_added_uploads();
parent::tearDown();
}
/**
* Upload an image.
*
* @param string $file
* @return int
*/
public function _insert_attachment( $file ) {
if ( ! isset( $this->uploaded_bits[ $file ] ) ) {
// only upload a given file once, regardless of how many tests it's used in
$filename = DIR_TESTDATA . '/images/' . $file;
$contents = file_get_contents( $filename );
$this->uploaded_bits[ $file ] = wp_upload_bits( basename( $filename ), null, $contents );
}
$this->attachment_id = $this->_make_attachment( $this->uploaded_bits[ $file ] );
}
/**
* Setup the `$_REQUEST` array for wp_save_image()
*
* @param array $args
*/
public function _setUpRequest( $args ) {
$defaults = array(
'action' => 'image-editor',
'context' => 'edit-attachment',
'postid' => $this->attachment_id,
);
$args = wp_parse_args( $args, $defaults );
foreach ( $args as $arg => $value ) {
$_REQUEST[$arg] = $value;
}
}
/**
* @ticket 44127
*/
public function testScaleImage() {
if ( defined( 'IMAGE_EDIT_OVERWRITE' ) && IMAGE_EDIT_OVERWRITE ) {
// skip test
$this->markTestSkipped( 'testScaleImage() skipped because IMAGE_EDIT_OVERWRITE is defined and is true' );
}
$file = '33772.jpg';
$this->_insert_attachment( $file );
// setup the expected backup sizes
$orig_metadata = wp_get_attachment_metadata( $this->attachment_id );
$expected = array(
'full-orig' => array(
'width' => $orig_metadata['width'],
'height' => $orig_metadata['height'],
'file' => $file,
),
);
$this->_setUpRequest( array( 'do' => 'scale', 'fwidth' => '1200', 'fheight' => '675' ) );
$ret = wp_save_image( $this->attachment_id );
$actual = get_post_meta( $this->attachment_id, '_wp_attachment_backup_sizes', true );
$this->assertEquals( $expected, $actual );
}
/**
* @ticket 44127
*/
public function testMultipleScaleImage() {
if ( defined( 'IMAGE_EDIT_OVERWRITE' ) && IMAGE_EDIT_OVERWRITE ) {
// skip test
$this->markTestSkipped( 'testMultipleScaleImage() skipped because IMAGE_EDIT_OVERWRITE is defined and is true' );
}
$file = '33772.jpg';
$this->_insert_attachment( $file );
// setup the initial expected backup sizes, we'll append to this
// each time thru the loop below
$orig_metadata = wp_get_attachment_metadata( $this->attachment_id );
$expected = array(
'full-orig' => array(
'width' => $orig_metadata['width'],
'height' => $orig_metadata['height'],
'file' => $file,
),
);
// save basename for the suffix hash
$basename = basename( $file, '.jpg' ) . '-e';
$scaled_sizes = array(
array( 'width' => '1200', 'height' => '675' ),
array( 'width' => '800', 'height' => '450' ),
array( 'width' => '400', 'height' => '225' ),
array( 'width' => '300', 'height' => '169' ),// same size as 'medium' size
);
// loop thru all the scaled_sizes and scale the image to each
foreach ( $scaled_sizes as $idx => $size ) {
$this->_setUpRequest( array( 'do' => 'scale', 'fwidth' => $size['width'], 'fheight' => $size['height'] ) );
$ret = wp_save_image( $this->attachment_id );
$metadata = wp_get_attachment_metadata( $this->attachment_id );
if ( 0 !== $idx ) {
// get the filename hash
$suffix = str_replace( $basename, '', basename( $metadata['file'], '.jpg' ) );
// append to the expected backup size
$expected['full-' . $suffix] = array(
'width' => $previous_size['width'],
'height' => $previous_size['height'],
'file' => $previous_filename,
);
}
// save these for the expected value the next time through the loop
$previous_filename = basename( $metadata['file'] );
$previous_size = $size;
}
$actual = get_post_meta( $this->attachment_id, '_wp_attachment_backup_sizes', true );
$this->assertEquals( $expected, $actual );
}
/**
* @ticket 44127
*/
public function testCropImageAll() {
$file = '33772.jpg';
$this->_insert_attachment( $file );
// setup the expected backup sizes
$orig_metadata = wp_get_attachment_metadata( $this->attachment_id );
$expected = array(
'full-orig' => array(
'width' => $orig_metadata['width'],
'height' => $orig_metadata['height'],
'file' => $file,
),
);
foreach ( $orig_metadata['sizes'] as $size => $data ) {
$expected[$size . '-orig'] = $data;
}
$this->_setUpRequest( array( 'do' => 'save', 'target' => 'all', 'history' => '[{\"c\":{\"x\":35,\"y\":23,\"w\":345,\"h\":186}}]' ) );
$ret = wp_save_image( $this->attachment_id );
$actual = get_post_meta( $this->attachment_id, '_wp_attachment_backup_sizes', true );
$this->assertEquals( $expected, $actual );
}
/**
* @ticket 44127
*/
public function testCropImageThumbnail() {
$file = '33772.jpg';
$this->_insert_attachment( $file );
// setup the expected backup sizes
$orig_metadata = wp_get_attachment_metadata( $this->attachment_id );
$expected = array(
'thumbnail-orig' => $orig_metadata['sizes']['thumbnail'],
);
$this->_setUpRequest( array( 'do' => 'save', 'target' => 'thumbnail', 'history' => '[{\"c\":{\"x\":35,\"y\":23,\"w\":345,\"h\":186}}]' ) );
$ret = wp_save_image( $this->attachment_id );
$actual = get_post_meta( $this->attachment_id, '_wp_attachment_backup_sizes', true );
$this->assertEquals( $expected, $actual );
}
/**
* @ticket 44127
*/
public function testCropImageNoThumbnail() {
$file = '33772.jpg';
$this->_insert_attachment( $file );
// setup the expected backup sizes
$orig_metadata = wp_get_attachment_metadata( $this->attachment_id );
$expected = array(
'full-orig' => array(
'width' => $orig_metadata['width'],
'height' => $orig_metadata['height'],
'file' => $file,
),
);
foreach ( $orig_metadata['sizes'] as $size => $data ) {
if ( 'thumbnail' !== $size ) {
$expected[$size . '-orig'] = $data;
}
}
$this->_setUpRequest( array( 'do' => 'save', 'target' => 'nothumb', 'history' => '[{\"c\":{\"x\":35,\"y\":23,\"w\":345,\"h\":186}}]' ) );
$ret = wp_save_image( $this->attachment_id );
$actual = get_post_meta( $this->attachment_id, '_wp_attachment_backup_sizes', true );
$this->assertEquals( $expected, $actual );
}
/**
* @ticket 44127
*/
public function testScaleImageImageEditOverwrite() {
if ( ! defined( 'IMAGE_EDIT_OVERWRITE' ) || ! IMAGE_EDIT_OVERWRITE ) {
// skip test
$this->markTestSkipped( 'testScaleImageImageEditOverwrite() skipped because IMAGE_EDIT_OVERWRITE is not defined or is false' );
}
$file = '33772.jpg';
$this->_insert_attachment( $file );
// setup the expected backup sizes
$orig_metadata = wp_get_attachment_metadata( $this->attachment_id );
$expected = array(
'full-orig' => array(
'width' => $orig_metadata['width'],
'height' => $orig_metadata['height'],
'file' => $file,
),
);
foreach ( $orig_metadata['sizes'] as $size => $data ) {
// @todo why isn't thumbnail-orig added to the backup sizes when IMAGE_EDIT_OVERWRITE is true?
// is that a bug in wp_save_image()?
// Note: this is NOT the same as skipping 'thumbnail-orig in testCropImageNoThumbnail(),
// which is expected
if ( 'thumbnail' !== $size ) {
$expected[$size . '-orig'] = $data;
}
}
$this->_setUpRequest( array( 'do' => 'scale', 'fwidth' => '1200', 'fheight' => '675' ) );
$ret = wp_save_image( $this->attachment_id );
$actual = get_post_meta( $this->attachment_id, '_wp_attachment_backup_sizes', true );
$this->assertEquals( $expected, $actual );
}
/**
* @ticket 44127
*/
public function testMultipleScaleImageImageEditOverwrite() {
if ( ! defined( 'IMAGE_EDIT_OVERWRITE' ) || ! IMAGE_EDIT_OVERWRITE ) {
// skip test
$this->markTestSkipped( 'testMultipleScaleImageImageEditOverwrite() skipped because IMAGE_EDIT_OVERWRITE is not defined or is false' );
}
$file = '33772.jpg';
$this->_insert_attachment( $file );
// setup the expected backup sizes
$orig_metadata = wp_get_attachment_metadata( $this->attachment_id );
$expected = array(
'full-orig' => array(
'width' => $orig_metadata['width'],
'height' => $orig_metadata['height'],
'file' => $file,
),
);
foreach ( $orig_metadata['sizes'] as $size => $data ) {
// @todo why isn't thumbnail-orig added to the backup sizes when IMAGE_EDIT_OVERWRITE is true?
// is that a bug in wp_save_image()?
// Note: this is NOT the same as skipping 'thumbnail-orig in testCropImageNoThumbnail(),
// which is expected
if ( 'thumbnail' !== $size ) {
$expected[$size . '-orig'] = $data;
}
}
// save basename for the suffix hash
$basename = basename( $file, '.jpg' ) . '-e';
$scaled_sizes = array(
array( 'width' => '1200', 'height' => '675' ),
array( 'width' => '800', 'height' => '450' ),
array( 'width' => '400', 'height' => '225' ),
array( 'width' => '300', 'height' => '169' ),// same size as 'medium' size
);
// loop thru all the scaled_sizes and scale the image to each
foreach ( $scaled_sizes as $idx => $size ) {
$this->_setUpRequest( array( 'do' => 'scale', 'fwidth' => $size['width'], 'fheight' => $size['height'] ) );
$ret = wp_save_image( $this->attachment_id );
$metadata = wp_get_attachment_metadata( $this->attachment_id );
}
$actual = get_post_meta( $this->attachment_id, '_wp_attachment_backup_sizes', true );
$this->assertEquals( $expected, $actual );
}
}
<phpunit
bootstrap="includes/bootstrap.php"
backupGlobals="false"
colors="true"
beStrictAboutTestsThatDoNotTestAnything="true"
>
<testsuites>
<!-- Default test suite to run all tests, modified from multiste.xml -->
<testsuite>
<directory suffix=".php">tests</directory>
<exclude>tests/phpunit/tests/actions/closures.php</exclude>
<exclude>tests/phpunit/tests/image/editor.php</exclude>
<exclude>tests/phpunit/tests/image/editorGd.php</exclude>
<exclude>tests/phpunit/tests/image/editorImagick.php</exclude>
<file phpVersion="5.3.0">tests/phpunit/tests/actions/closures.php</file>
<file phpVersion="5.3.0">tests/phpunit/tests/image/editor.php</file>
<file phpVersion="5.3.0">tests/phpunit/tests/image/editorGd.php</file>
<file phpVersion="5.3.0">tests/phpunit/tests/image/editorImagick.php</file>
</testsuite>
</testsuites>
<php>
<const name="WP_RUN_CORE_TESTS" value="1" />
</php>
<groups>
<include>
<group>44127</group>
</include>
</groups>
</phpunit>
<phpunit
bootstrap="includes/bootstrap.php"
backupGlobals="false"
colors="true"
beStrictAboutTestsThatDoNotTestAnything="true"
>
<testsuites>
<!-- Default test suite to run all tests, modified from multiste.xml -->
<testsuite>
<directory suffix=".php">tests</directory>
<exclude>tests/phpunit/tests/actions/closures.php</exclude>
<exclude>tests/phpunit/tests/image/editor.php</exclude>
<exclude>tests/phpunit/tests/image/editorGd.php</exclude>
<exclude>tests/phpunit/tests/image/editorImagick.php</exclude>
<file phpVersion="5.3.0">tests/phpunit/tests/actions/closures.php</file>
<file phpVersion="5.3.0">tests/phpunit/tests/image/editor.php</file>
<file phpVersion="5.3.0">tests/phpunit/tests/image/editorGd.php</file>
<file phpVersion="5.3.0">tests/phpunit/tests/image/editorImagick.php</file>
</testsuite>
</testsuites>
<php>
<const name="WP_RUN_CORE_TESTS" value="1" />
<const name="IMAGE_EDIT_OVERWRITE" value="1" />
</php>
<groups>
<include>
<group>44127</group>
</include>
</groups>
</phpunit>
@joemcgill
Copy link

Hey Paul, this is looking pretty good I think. There are a few places where I could see adding some efficiencies, like for example, you could probably avoid uploading the same file each time by abstracting out the wp_upload_bits() part and saving the result as a property of the test class and reusing it when creating specific attachments. Also whenever you're looping through sizes, you call get_post_meta() to get the value of the actual backup sizes array, but really you only need to do so once after the whole loop has completed in most cases.

I think it's worth getting this up as a patch on the ticket once you've made those adjustments so it's easier for others to test and leave feedback in one same place. Nice work!

@pbiron
Copy link
Author

pbiron commented Jun 7, 2018

thanx for the reply.

DId you notice the @todo at the top of the file?

@todo I've tagged all these tests with {@ticket 44127} because I decided they
were needed while I was working on that ticket. However, I'm now thinking
I should open a new ticket specifically stating the need for these tests,
independent of that ticket. Opinions?

Do you think it's worthwhile adding a separate ticket just for these unit tests and then referencing that ticket in 44127?

@pbiron
Copy link
Author

pbiron commented Jun 7, 2018

you could probably avoid uploading the same file each time by abstracting out the wp_upload_bits() part and saving the result as a property of the test class and reusing it when creating specific attachments.

Good idea.

Also whenever you're looping through sizes, you call get_post_meta() to get the value of the actual backup sizes array, but really you only need to do so once after the whole loop has completed in most cases.

Good catch...that's actually a holdover from a previous version of the test where I thought I needed within each loop to set things up for the next iteration...and I just forgot to remove it.

I've updated this gist with those changes and will now add them to the trac ticket.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment