Make WordPress Core

Ticket #42663: imagick.5.diff

File imagick.5.diff, 12.9 KB (added by calin, 5 years ago)

Fix testing names

  • src/wp-includes/class-wp-image-editor-imagick.php

    diff --git a/src/wp-includes/class-wp-image-editor-imagick.php b/src/wp-includes/class-wp-image-editor-imagick.php
    index 9f6a0f3b52..9d2115c391 100644
    a b class WP_Image_Editor_Imagick extends WP_Image_Editor { 
    2121         */
    2222        protected $image;
    2323
     24        /**
     25         * Generated temporary files
     26         *
     27         * @var array
     28         */
     29        private $_tmp;
     30
    2431        public function __destruct() {
    2532                if ( $this->image instanceof Imagick ) {
    2633                        // we don't need the original in memory anymore
    2734                        $this->image->clear();
    2835                        $this->image->destroy();
    2936                }
     37                // if we have processed files from stream wrappers remove the local copies
     38                if ( is_array( $this->_tmp ) ) {
     39                        foreach ( $this->_tmp as $tmpfile ) {
     40                                @unlink( $tmpfile );
     41                        }
     42                }
    3043        }
    3144
    3245        /**
    class WP_Image_Editor_Imagick extends WP_Image_Editor { 
    133146                if ( ! is_file( $this->file ) && ! preg_match( '|^https?://|', $this->file ) )
    134147                        return new WP_Error( 'error_loading_image', __('File doesn’t exist?'), $this->file );
    135148
     149                $local_file = $this->file;
     150                if ( wp_is_stream( $this->file ) ) {
     151                        $local_file = wp_tempnam();
     152
     153                        if ( empty( $this->_tmp ) ) {
     154                                $this->_tmp = array();
     155                        }
     156                        $this->_tmp[] = $local_file;
     157
     158                        if ( false === @copy( $this->file, $local_file ) ) {
     159                                return new WP_Error( 'error_loading_image', __( 'File doesn’t exist?' ), error_get_last() );
     160                        }
     161                }
     162
    136163                /*
    137164                 * Even though Imagick uses less PHP memory than GD, set higher limit
    138165                 * for users that have low PHP.ini limits.
    class WP_Image_Editor_Imagick extends WP_Image_Editor { 
    142169                try {
    143170                        $this->image = new Imagick();
    144171                        $file_extension = strtolower( pathinfo( $this->file, PATHINFO_EXTENSION ) );
    145                         $filename = $this->file;
     172                        $filename = $local_file;
    146173
    147174                        if ( 'pdf' == $file_extension ) {
    148                                 $filename = $this->pdf_setup();
     175                                $filename = $this->pdf_setup( $local_file );
    149176                        }
    150177
    151178                        // Reading image after Imagick instantiation because `setResolution`
    class WP_Image_Editor_Imagick extends WP_Image_Editor { 
    735762         *
    736763         * @return string|WP_Error File to load or WP_Error on failure.
    737764         */
    738         protected function pdf_setup() {
     765        protected function pdf_setup( $local_file ) {
    739766                try {
    740767                        // By default, PDFs are rendered in a very low resolution.
    741768                        // We want the thumbnail to be readable, so increase the rendering DPI.
    742769                        $this->image->setResolution( 128, 128 );
    743770
    744771                        // Only load the first page.
    745                         return $this->file . '[0]';
     772                        return $local_file . '[0]';
    746773                }
    747774                catch ( Exception $e ) {
    748775                        return new WP_Error( 'pdf_setup_failed', $e->getMessage(), $this->file );
    749776                }
    750777        }
    751778
     779        /**
     780         * Either calls editor's save function or handles file as a stream.
     781         *
     782         * @param string|stream $filename
     783         * @param callable $function
     784         * @param array $arguments
     785         * @return bool
     786         */
     787        protected function make_image( $filename, $function, $arguments ) {
     788                if ( wp_is_stream( $filename ) ) {
     789                        $tmp = wp_tempnam();
     790                        if ( empty( $this->_tmp ) ) {
     791                                $this->_tmp = array();
     792                        }
     793                        $this->_tmp[] = $tmp;
     794
     795                        $arguments[0] = $tmp;
     796                }
     797
     798                if ( ! parent::make_image( $filename, $function, $arguments ) ) {
     799                        return false;
     800                }
     801
     802                if ( wp_is_stream( $filename ) ) {
     803                        return copy( $tmp, $filename );
     804                }
     805        }
    752806}
  • new file tests/phpunit/includes/class-wp-test-stream.php

    diff --git a/tests/phpunit/includes/class-wp-test-stream.php b/tests/phpunit/includes/class-wp-test-stream.php
    new file mode 100644
    index 0000000000..4eb0f4dcfc
    - +  
     1<?php
     2class WP_Test_Stream {
     3        const FILE_MODE      = 33206; // 100666 in octal
     4        const DIRECTORY_MODE = 16895; // 40777 in octal
     5
     6        static $data = array();
     7
     8        var $position;
     9        var $file;
     10        var $bucket;
     11
     12        private function open( $path ) {
     13                $url = array_merge(
     14                        array(
     15                                'host' => '',
     16                                'path' => '',
     17                        ),
     18                        parse_url( $path )
     19                );
     20
     21                $this->bucket = $url['host'];
     22                $this->file   = $url['path'] ? $url['path'] : '/';
     23
     24                if ( empty( $this->bucket ) ) {
     25                        trigger_error( 'Cannot use an empty bucket name', E_USER_ERROR );
     26                }
     27
     28                if ( ! isset( WP_Test_Stream::$data[ $this->bucket ] ) ) {
     29                        WP_Test_Stream::$data[ $this->bucket ] = array();
     30                }
     31
     32                $this->position = 0;
     33        }
     34
     35        function stream_open( $path, $mode, $options, &$opened_path ) {
     36                $this->open( $path );
     37                return true;
     38        }
     39
     40        function stream_read( $count ) {
     41                if ( ! isset( WP_Test_Stream::$data[ $this->bucket ][ $this->file ] ) ) {
     42                        return '';
     43                }
     44
     45                $ret             = substr( WP_Test_Stream::$data[ $this->bucket ][ $this->file ], $this->position, $count );
     46                $this->position += strlen( $ret );
     47                return $ret;
     48        }
     49
     50        function stream_write( $data ) {
     51                if ( ! isset( WP_Test_Stream::$data[ $this->bucket ][ $this->file ] ) ) {
     52                        WP_Test_Stream::$data[ $this->bucket ][ $this->file ] = '';
     53                }
     54
     55                $left  = substr( WP_Test_Stream::$data[ $this->bucket ][ $this->file ], 0, $this->position );
     56                $right = substr( WP_Test_Stream::$data[ $this->bucket ][ $this->file ], $this->position + strlen( $data ) );
     57                WP_Test_Stream::$data[ $this->bucket ][ $this->file ] = $left . $data . $right;
     58                $this->position                                      += strlen( $data );
     59                return strlen( $data );
     60        }
     61
     62        function stream_tell() {
     63                return $this->position;
     64        }
     65
     66        function stream_eof() {
     67                if ( ! isset( WP_Test_Stream::$data[ $this->bucket ][ $this->file ] ) ) {
     68                        return true;
     69                }
     70
     71                return $this->position >= strlen( WP_Test_Stream::$data[ $this->bucket ][ $this->file ] );
     72        }
     73
     74        function stream_seek( $offset, $whence ) {
     75                switch ( $whence ) {
     76                        case SEEK_SET:
     77                                if ( $offset < strlen( WP_Test_Stream::$data[ $this->bucket ][ $this->file ] ) && $offset >= 0 ) {
     78                                        $this->position = $offset;
     79                                        return true;
     80                                } else {
     81                                        return false;
     82                                }
     83                                break;
     84
     85                        case SEEK_CUR:
     86                                if ( $offset >= 0 ) {
     87                                        $this->position += $offset;
     88                                        return true;
     89                                } else {
     90                                        return false;
     91                                }
     92                                break;
     93
     94                        case SEEK_END:
     95                                if ( strlen( WP_Test_Stream::$data[ $this->bucket ][ $this->file ] ) + $offset >= 0 ) {
     96                                        $this->position = strlen( WP_Test_Stream::$data[ $this->bucket ][ $this->file ] ) + $offset;
     97                                        return true;
     98                                } else {
     99                                        return false;
     100                                }
     101                                break;
     102
     103                        default:
     104                                return false;
     105                }
     106        }
     107
     108        function stream_metadata( $path, $option, $var ) {
     109                $this->open( $path );
     110                if ( STREAM_META_TOUCH == $option ) {
     111                        if ( ! isset( WP_Test_Stream::$data[ $this->bucket ][ $this->file ] ) ) {
     112                                WP_Test_Stream::$data[ $this->bucket ][ $this->file ] = '';
     113                        }
     114                        return true;
     115                }
     116                return false;
     117        }
     118
     119        function mkdir( $path, $mode, $options ) {
     120                $this->open( $path );
     121                if ( isset( WP_Test_Stream::$data[ $this->bucket ][ rtrim( $this->file, '/' ) ] ) ) {
     122                        return false;
     123                }
     124                WP_Test_Stream::$data[ $this->bucket ][ rtrim( $this->file, '/' ) . '/' ] = 'DIRECTORY';
     125                return true;
     126        }
     127
     128        private function make_stat( $stats ) {
     129                $defaults = array(
     130                        'dev'     => 0,
     131                        'ino'     => 0,
     132                        'mode'    => 0,
     133                        'nlink'   => 0,
     134                        'uid'     => 0,
     135                        'gid'     => 0,
     136                        'rdev'    => 0,
     137                        'size'    => 0,
     138                        'atime'   => 0,
     139                        'mtime'   => 0,
     140                        'ctime'   => 0,
     141                        'blksize' => 0,
     142                        'blocks'  => 0,
     143                );
     144
     145                return array_merge( $defaults, $stats );
     146        }
     147
     148        public function stream_stat() {
     149                if ( substr( $this->file, -1 ) == '/' || isset( WP_Test_Stream::$data[ $this->bucket ][ rtrim( $this->file, '/' ) . '/' ] ) ) {
     150                        return $this->make_stat(
     151                                array(
     152                                        'mode' => WP_Test_Stream::DIRECTORY_MODE,
     153                                )
     154                        );
     155                }
     156
     157                if ( ! isset( WP_Test_Stream::$data[ $this->bucket ][ $this->file ] ) ) {
     158                        return false;
     159                }
     160
     161                return $this->make_stat(
     162                        array(
     163                                'size' => strlen( WP_Test_Stream::$data[ $this->bucket ][ $this->file ] ),
     164                                'mode' => WP_Test_Stream::FILE_MODE,
     165                        )
     166                );
     167        }
     168
     169        public function url_stat( $path, $flags ) {
     170                $this->open( $path );
     171                return $this->stream_stat();
     172        }
     173}
  • new file tests/phpunit/tests/image/streams.php

    diff --git a/tests/phpunit/tests/image/streams.php b/tests/phpunit/tests/image/streams.php
    new file mode 100644
    index 0000000000..5e3719b739
    - +  
     1<?php
     2
     3/**
     4 * @group image
     5 * @group media
     6 * @group upload
     7 */
     8class Tests_Image_Stream_Wrappers extends WP_UnitTestCase {
     9
     10        /**
     11         * Setup test fixture
     12         */
     13        public function setUp() {
     14                parent::setUp();
     15
     16                require_once( ABSPATH . WPINC . '/class-wp-image-editor.php' );
     17                require_once( ABSPATH . WPINC . '/class-wp-image-editor-gd.php' );
     18                require_once( ABSPATH . WPINC . '/class-wp-image-editor-imagick.php' );
     19
     20                require_once( DIR_TESTDATA . '/../includes/class-wp-test-stream.php' );
     21                include_once( DIR_TESTDATA . '/../includes/mock-image-editor.php' );
     22
     23                if ( in_array( 'dummy', stream_get_wrappers() ) ) {
     24                        stream_wrapper_unregister( 'dummy' );
     25                }
     26                stream_wrapper_register( 'dummy', 'WP_Test_Stream' );
     27                WP_Test_Stream::$data = array();
     28
     29                // Ensure no legacy / failed tests detritus.
     30                $folder = '/tmp/wordpress-gsoc-flyer*.{jpg,pdf}';
     31
     32                foreach ( glob( $folder, GLOB_BRACE ) as $file ) {
     33                        unlink( $file );
     34                }
     35        }
     36
     37        public function image_editor_class() {
     38                return array(
     39                        array( 'WP_Image_Editor_GD' ),
     40                        array( 'WP_Image_Editor_Imagick' ),
     41                );
     42        }
     43
     44        /**
     45         * @dataProvider image_editor_class
     46         */
     47        public function test_save_to_stream_wrappers( $class ) {
     48                // If the image editor isn't available, skip it
     49                if ( ! call_user_func( array( $class, 'test' ) ) ) {
     50                        $this->markTestSkipped( "$class is not available" );
     51                }
     52
     53                $img = new $class( DIR_TESTDATA . '/images/canola.jpg' );
     54                $this->assertNotInstanceOf( 'WP_Error', $img );
     55                $loaded = $img->load();
     56                $this->assertTrue( $loaded );
     57
     58                $new_filename = 'dummy://test/canola.jpg';
     59                $this->assertTrue( wp_is_stream( $new_filename ) );
     60
     61                $ret = $img->save( $new_filename );
     62                $this->assertNotInstanceOf( 'WP_Error', $ret );
     63                $this->assertArrayHasKey( '/canola.jpg', WP_Test_Stream::$data['test'] );
     64
     65                // Clean up
     66                unset( $img );
     67        }
     68
     69        /**
     70         * @dataProvider image_editor_class
     71         */
     72        public function test_load_from_stream_wrappers( $class ) {
     73                // If the image editor isn't available, skip it
     74                if ( ! call_user_func( array( $class, 'test' ) ) ) {
     75                        $this->markTestSkipped( "$class is not available" );
     76                }
     77
     78                $filename = 'dummy://test/canola.jpg';
     79                $this->assertTrue( copy( DIR_TESTDATA . '/images/canola.jpg', $filename ) );
     80                $this->assertArrayHasKey( '/canola.jpg', WP_Test_Stream::$data['test'] );
     81
     82                $img = new $class( $filename );
     83                $this->assertNotInstanceOf( 'WP_Error', $img );
     84                $loaded = $img->load();
     85                $this->assertTrue( $loaded );
     86
     87                // Clean up
     88                unset( $img );
     89        }
     90
     91        /**
     92         * @dataProvider image_editor_class
     93         */
     94        public function test_image_manipulation( $class ) {
     95                // If the image editor isn't available, skip it
     96                if ( ! call_user_func( array( $class, 'test' ) ) ) {
     97                        $this->markTestSkipped( "$class is not available" );
     98                }
     99
     100                $filename = 'dummy://test/canola.jpg';
     101                $this->assertTrue( copy( DIR_TESTDATA . '/images/canola.jpg', $filename ) );
     102                $this->assertArrayHasKey( '/canola.jpg', WP_Test_Stream::$data['test'] );
     103
     104                $img = new $class( $filename );
     105                $this->assertNotInstanceOf( 'WP_Error', $img );
     106                $loaded = $img->load();
     107                $this->assertTrue( $loaded );
     108
     109                $cropped = $img->crop( 0, 0, 100, 100 );
     110                $this->assertNotInstanceOf( 'WP_Error', $cropped );
     111
     112                $ret = $img->save( 'dummy://test/canola-100x100.jpg' );
     113                $this->assertNotInstanceOf( 'WP_Error', $ret );
     114                $this->assertArrayHasKey( '/canola-100x100.jpg', WP_Test_Stream::$data['test'] );
     115
     116                $orig_content    = WP_Test_Stream::$data['test']['/canola.jpg'];
     117                $resized_content = WP_Test_Stream::$data['test']['/canola-100x100.jpg'];
     118
     119                $this->assertFalse( $orig_content == $resized_content );
     120
     121                // Clean up
     122                unset( $img );
     123        }
     124
     125        /**
     126         * @dataProvider image_editor_class
     127         */
     128
     129        public function test_image_upload( $class ) {
     130                // If the image editor isn't available, skip it
     131                if ( ! call_user_func( array( $class, 'test' ) ) ) {
     132                        $this->markTestSkipped( "$class is not available" );
     133                }
     134
     135                add_filter(
     136                        'wp_image_editors',
     137                        function ( $editors ) use ( $class ) {
     138                                return array( $class );
     139                        }
     140                );
     141
     142                add_filter(
     143                        'upload_dir',
     144                        function ( $dir ) {
     145                                $dir['base_dir'] = 'dummy://test/uploads';
     146                                $dir['path']     = 'dummy://test/uploads' . $dir['subdir'];
     147                                return $dir;
     148                        }
     149                );
     150
     151                $filename = DIR_TESTDATA . '/images/canola.jpg';
     152                $contents = file_get_contents( $filename );
     153                $upload   = wp_upload_bits( basename( $filename ), null, $contents );
     154                $this->assertTrue( empty( $upload['error'] ), print_r( $upload, true ) );
     155                $id = $this->_make_attachment( $upload );
     156
     157                $path = wp_upload_dir()['path'];
     158                $this->assertEquals( substr( $path, 0, 13 ), 'dummy://test/' );
     159
     160                $this->assertFileExists( sprintf( '%s/%s', $path, 'canola.jpg' ) );
     161                $this->assertFileExists( sprintf( '%s/%s', $path, 'canola-150x150.jpg' ) );
     162                $this->assertFileExists( sprintf( '%s/%s', $path, 'canola-300x225.jpg' ) );
     163        }
     164
     165}
     166
     167/* vim: set ft=php.wp: */