diff --git a/.circleci/config.yml b/.circleci/config.yml
new file mode 100644
index 0000000..bdb5be1
--- /dev/null
+++ b/.circleci/config.yml
@@ -0,0 +1,109 @@
+workflows:
+ version: 2
+ main:
+ jobs:
+ - php56-build
+ - php70-build
+ - php71-build
+ - php72-build
+ - php73-build
+ - php74-build
+
+version: 2
+
+job-references:
+ mysql_image: &mysql_image
+ circleci/mysql:5.6
+
+ setup_environment: &setup_environment
+ name: "Setup Environment Variables"
+ command: |
+ echo "export PATH=$HOME/.composer/vendor/bin:$PATH" >> $BASH_ENV
+ source /home/circleci/.bashrc
+
+ install_dependencies: &install_dependencies
+ name: "Install Dependencies"
+ command: |
+ sudo apt-get update && sudo apt-get install subversion
+ sudo -E docker-php-ext-install mysqli
+ sudo sh -c "printf '\ndeb http://ftp.us.debian.org/debian sid main\n' >> /etc/apt/sources.list"
+ sudo apt-get update && sudo apt-get install mysql-client-5.7
+
+ php_job: &php_job
+ environment:
+ - WP_TESTS_DIR: "/tmp/wordpress-tests-lib"
+ - WP_CORE_DIR: "/tmp/wordpress/"
+ steps:
+ - checkout
+ - run: *setup_environment
+ - run: *install_dependencies
+ - run:
+ name: "Run Tests"
+ command: |
+ composer global require "phpunit/phpunit=5.7.*"
+ composer global require wp-coding-standards/wpcs
+ phpcs --config-set installed_paths $HOME/.composer/vendor/wp-coding-standards/wpcs
+ phpcs
+ rm -rf $WP_TESTS_DIR $WP_CORE_DIR
+ bash bin/install-wp-tests.sh wordpress_test root '' 127.0.0.1 latest
+ phpunit
+ WP_MULTISITE=1 phpunit
+
+jobs:
+ php56-build:
+ <<: *php_job
+ docker:
+ - image: circleci/php:5.6
+ - image: *mysql_image
+ steps:
+ - checkout
+ - run: *setup_environment
+ - run: *install_dependencies
+ - run:
+ name: "Run Tests"
+ command: |
+ composer global require "phpunit/phpunit=5.7.*"
+ composer global require wp-coding-standards/wpcs
+ phpcs --config-set installed_paths $HOME/.composer/vendor/wp-coding-standards/wpcs
+ phpcs
+ SKIP_DB_CREATE=false
+ rm -rf $WP_TESTS_DIR $WP_CORE_DIR
+ bash bin/install-wp-tests.sh wordpress_test root '' 127.0.0.1 latest $SKIP_DB_CREATE
+ phpunit
+ WP_MULTISITE=1 phpunit
+ SKIP_DB_CREATE=true
+ rm -rf $WP_TESTS_DIR $WP_CORE_DIR
+ bash bin/install-wp-tests.sh wordpress_test root '' 127.0.0.1 trunk $SKIP_DB_CREATE
+ phpunit
+ WP_MULTISITE=1 phpunit
+ SKIP_DB_CREATE=true
+
+ php70-build:
+ <<: *php_job
+ docker:
+ - image: circleci/php:7.0
+ - image: *mysql_image
+
+ php71-build:
+ <<: *php_job
+ docker:
+ - image: circleci/php:7.1
+ - image: *mysql_image
+
+ php72-build:
+ <<: *php_job
+ docker:
+ - image: circleci/php:7.2
+ - image: *mysql_image
+
+ php73-build:
+ <<: *php_job
+ docker:
+ - image: circleci/php:7.3
+ - image: *mysql_image
+
+ php74-build:
+ <<: *php_job
+ docker:
+ - image: circleci/php:7.4
+ - image: *mysql_image
diff --git a/.distignore b/.distignore
index d4a97d2..d9b1119 100644
--- a/.distignore
+++ b/.distignore
@@ -1,15 +1,23 @@
+/.circleci
/.git
/.github
/.wordpress-org
/assets/_src
+/bin
/node_modules
+/tests
+/vendor
.distignore
.eslintrc.json
.gitattributes
.gitignore
+.phpcs.xml.dist
+composer.json
+composer.lock
LICENSE
package.json
package-lock.json
+phpunit.xml.dist
tsconfig.json
webpack.config.js
diff --git a/.gitattributes b/.gitattributes
index 713bcdf..949d0c8 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,16 +1,25 @@
# Directories
+/.circleci export-ignore
/.git export-ignore
/.github export-ignore
/.wordpress-org export-ignore
/assets/_src export-ignore
+/bin export-ignore
/node_modules export-ignore
+/tests export-ignore
+/vendor export-ignore
# Files
/.distignore export-ignore
+/.eslintrc.json export-ignore
/.gitattributes export-ignore
/.gitignore export-ignore
+/.phpcs.xml.dist export-ignore
+/composer.json export-ignore
+/composer.lock export-ignore
/LICENSE export-ignore
/package.json export-ignore
/package-lock.json export-ignore
+/phpunit.xml.dist export-ignore
/tsconfig.json export-ignore
/webpack.config.js export-ignore
diff --git a/.gitignore b/.gitignore
index ee70956..11bb515 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,9 @@
.DS_Store
.idea
+.phpunit.result.cache
node_modules
+vendor
+composer.lock
package-lock.json
assets/css
assets/js
diff --git a/.phpcs.xml.dist b/.phpcs.xml.dist
new file mode 100644
index 0000000..952b9f5
--- /dev/null
+++ b/.phpcs.xml.dist
@@ -0,0 +1,47 @@
+
+
+ Generally-applicable sniffs for WordPress plugins.
+
+
+ .
+ /vendor/
+ /node_modules/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bin/install-wp-tests.sh b/bin/install-wp-tests.sh
new file mode 100755
index 0000000..c6f53dc
--- /dev/null
+++ b/bin/install-wp-tests.sh
@@ -0,0 +1,181 @@
+#!/usr/bin/env bash
+
+if [ $# -lt 3 ]; then
+ echo "usage: $0 [db-host] [wp-version] [skip-database-creation]"
+ exit 1
+fi
+
+DB_NAME=$1
+DB_USER=$2
+DB_PASS=$3
+DB_HOST=${4-localhost}
+WP_VERSION=${5-latest}
+SKIP_DB_CREATE=${6-false}
+
+TMPDIR=${TMPDIR-/tmp}
+TMPDIR=$(echo $TMPDIR | sed -e "s/\/$//")
+WP_TESTS_DIR=${WP_TESTS_DIR-$TMPDIR/wordpress-tests-lib}
+WP_CORE_DIR=${WP_CORE_DIR-$TMPDIR/wordpress}
+
+download() {
+ if [ `which curl` ]; then
+ curl -s "$1" > "$2";
+ elif [ `which wget` ]; then
+ wget -nv -O "$2" "$1"
+ fi
+}
+
+if [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+\-(beta|RC)[0-9]+$ ]]; then
+ WP_BRANCH=${WP_VERSION%\-*}
+ WP_TESTS_TAG="branches/$WP_BRANCH"
+
+elif [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+$ ]]; then
+ WP_TESTS_TAG="branches/$WP_VERSION"
+elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; then
+ if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then
+ # version x.x.0 means the first release of the major version, so strip off the .0 and download version x.x
+ WP_TESTS_TAG="tags/${WP_VERSION%??}"
+ else
+ WP_TESTS_TAG="tags/$WP_VERSION"
+ fi
+elif [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
+ WP_TESTS_TAG="trunk"
+else
+ # http serves a single offer, whereas https serves multiple. we only want one
+ download http://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json
+ grep '[0-9]+\.[0-9]+(\.[0-9]+)?' /tmp/wp-latest.json
+ LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//')
+ if [[ -z "$LATEST_VERSION" ]]; then
+ echo "Latest WordPress version could not be found"
+ exit 1
+ fi
+ WP_TESTS_TAG="tags/$LATEST_VERSION"
+fi
+set -ex
+
+install_wp() {
+
+ if [ -d $WP_CORE_DIR ]; then
+ return;
+ fi
+
+ mkdir -p $WP_CORE_DIR
+
+ if [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
+ mkdir -p $TMPDIR/wordpress-trunk
+ rm -rf $TMPDIR/wordpress-trunk/*
+ svn export --quiet https://core.svn.wordpress.org/trunk $TMPDIR/wordpress-trunk/wordpress
+ mv $TMPDIR/wordpress-trunk/wordpress/* $WP_CORE_DIR
+ else
+ if [ $WP_VERSION == 'latest' ]; then
+ local ARCHIVE_NAME='latest'
+ elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+ ]]; then
+ # https serves multiple offers, whereas http serves single.
+ download https://api.wordpress.org/core/version-check/1.7/ $TMPDIR/wp-latest.json
+ if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then
+ # version x.x.0 means the first release of the major version, so strip off the .0 and download version x.x
+ LATEST_VERSION=${WP_VERSION%??}
+ else
+ # otherwise, scan the releases and get the most up to date minor version of the major release
+ local VERSION_ESCAPED=`echo $WP_VERSION | sed 's/\./\\\\./g'`
+ LATEST_VERSION=$(grep -o '"version":"'$VERSION_ESCAPED'[^"]*' $TMPDIR/wp-latest.json | sed 's/"version":"//' | head -1)
+ fi
+ if [[ -z "$LATEST_VERSION" ]]; then
+ local ARCHIVE_NAME="wordpress-$WP_VERSION"
+ else
+ local ARCHIVE_NAME="wordpress-$LATEST_VERSION"
+ fi
+ else
+ local ARCHIVE_NAME="wordpress-$WP_VERSION"
+ fi
+ download https://wordpress.org/${ARCHIVE_NAME}.tar.gz $TMPDIR/wordpress.tar.gz
+ tar --strip-components=1 -zxmf $TMPDIR/wordpress.tar.gz -C $WP_CORE_DIR
+ fi
+
+ download https://raw.githubusercontent.com/markoheijnen/wp-mysqli/master/db.php $WP_CORE_DIR/wp-content/db.php
+}
+
+install_test_suite() {
+ # portable in-place argument for both GNU sed and Mac OSX sed
+ if [[ $(uname -s) == 'Darwin' ]]; then
+ local ioption='-i.bak'
+ else
+ local ioption='-i'
+ fi
+
+ # set up testing suite if it doesn't yet exist
+ if [ ! -d $WP_TESTS_DIR ]; then
+ # set up testing suite
+ mkdir -p $WP_TESTS_DIR
+ rm -rf $WP_TESTS_DIR/{includes,data}
+ svn export --quiet --ignore-externals https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes
+ svn export --quiet --ignore-externals https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/data/ $WP_TESTS_DIR/data
+ fi
+
+ if [ ! -f wp-tests-config.php ]; then
+ download https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php
+ # remove all forward slashes in the end
+ WP_CORE_DIR=$(echo $WP_CORE_DIR | sed "s:/\+$::")
+ sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR"/wp-tests-config.php
+ sed $ioption "s:__DIR__ . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR"/wp-tests-config.php
+ sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php
+ sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php
+ sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php
+ sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php
+ fi
+
+}
+
+recreate_db() {
+ shopt -s nocasematch
+ if [[ $1 =~ ^(y|yes)$ ]]
+ then
+ mysqladmin drop $DB_NAME -f --user="$DB_USER" --password="$DB_PASS"$EXTRA
+ create_db
+ echo "Recreated the database ($DB_NAME)."
+ else
+ echo "Leaving the existing database ($DB_NAME) in place."
+ fi
+ shopt -u nocasematch
+}
+
+create_db() {
+ mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA
+}
+
+install_db() {
+
+ if [ ${SKIP_DB_CREATE} = "true" ]; then
+ return 0
+ fi
+
+ # parse DB_HOST for port or socket references
+ local PARTS=(${DB_HOST//\:/ })
+ local DB_HOSTNAME=${PARTS[0]};
+ local DB_SOCK_OR_PORT=${PARTS[1]};
+ local EXTRA=""
+
+ if ! [ -z $DB_HOSTNAME ] ; then
+ if [ $(echo $DB_SOCK_OR_PORT | grep -e '^[0-9]\{1,\}$') ]; then
+ EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp"
+ elif ! [ -z $DB_SOCK_OR_PORT ] ; then
+ EXTRA=" --socket=$DB_SOCK_OR_PORT"
+ elif ! [ -z $DB_HOSTNAME ] ; then
+ EXTRA=" --host=$DB_HOSTNAME --protocol=tcp"
+ fi
+ fi
+
+ # create database
+ if [ $(mysql --user="$DB_USER" --password="$DB_PASS"$EXTRA --execute='show databases;' | grep ^$DB_NAME$) ]
+ then
+ echo "Reinstalling will delete the existing test database ($DB_NAME)"
+ read -p 'Are you sure you want to proceed? [y/N]: ' DELETE_EXISTING_DB
+ recreate_db $DELETE_EXISTING_DB
+ else
+ create_db
+ fi
+}
+
+install_wp
+install_test_suite
+install_db
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..e44c2e9
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,6 @@
+{
+ "require-dev": {
+ "phpunit/phpunit": "^9",
+ "yoast/phpunit-polyfills": "^3.0"
+ }
+}
diff --git a/package.json b/package.json
index 863697a..317e8d9 100644
--- a/package.json
+++ b/package.json
@@ -35,7 +35,8 @@
"scripts": {
"watch": "webpack --watch",
"build": "webpack --progress",
- "translate": "wp i18n make-pot . languages/cf-images.pot"
+ "translate": "wp i18n make-pot . languages/cf-images.pot",
+ "install-unit-tests": "bash bin/install-wp-tests.sh wordpress_test root root localhost latest"
},
"dependencies": {
"@mdi/js": "^7.4.47",
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
new file mode 100644
index 0000000..50421ec
--- /dev/null
+++ b/phpunit.xml.dist
@@ -0,0 +1,16 @@
+
+
+
+
+ ./tests/
+ ./tests/test-sample.php
+
+
+
diff --git a/tests/assets/test-image.jpg b/tests/assets/test-image.jpg
new file mode 100644
index 0000000..e689746
Binary files /dev/null and b/tests/assets/test-image.jpg differ
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
new file mode 100644
index 0000000..40d0759
--- /dev/null
+++ b/tests/bootstrap.php
@@ -0,0 +1,38 @@
+attachment->create_upload_object( __DIR__ . '/assets/test-image.jpg' );
+ }
+
+ /**
+ * Runs the routine after all tests have been run.
+ */
+ public static function tear_down_after_class() {
+ wp_delete_attachment( self::$attachment_id, true );
+ delete_post_meta( self::$attachment_id, '_cloudflare_image_id' ); // Just in case.
+ delete_site_option( 'cf-images-hash' );
+
+ parent::tear_down_after_class();
+ }
+
+ /**
+ * Set up before each test.
+ */
+ public function set_up() {
+ parent::set_up();
+
+ // Instantiate the module.
+ $this->cf_images = $this->getMockBuilder( Cloudflare_Images::class )
+ ->disableOriginalConstructor()
+ ->onlyMethods( array( 'can_run', 'is_module_enabled' ) )
+ ->getMock();
+
+ $this->cf_images->init();
+
+ remove_filter( 'wp_get_attachment_url', array( $this->cf_images, 'get_attachment_url' ) );
+
+ $this->cf_images
+ ->expects( $this->once() )
+ ->method( 'can_run' )
+ ->willReturn( true );
+ }
+
+ /**
+ * Get original image object.
+ *
+ * @param string $size WordPress attachment size.
+ *
+ * @return array
+ */
+ private function get_original_image_object( string $size = 'medium' ): array {
+ $year = gmdate( 'Y' );
+ $month = gmdate( 'm' );
+
+ switch ( $size ) {
+ case 'thumbnail':
+ $image = array( "http://example.org/wp-content/uploads/$year/$month/test-image-150x150.jpg", 150, 150, true );
+ break;
+ case 'medium':
+ default:
+ $image = array( "http://example.org/wp-content/uploads/$year/$month/test-image-300x200.jpg", 300, 200, true );
+ break;
+ case 'large':
+ $image = array( "http://example.org/wp-content/uploads/$year/$month/test-image-1024x683.jpg", 1024, 1024, false );
+ break;
+ case 'scaled':
+ $image = array( "http://example.org/wp-content/uploads/$year/$month/test-image-scaled.jpg", 2560, 0, false );
+ break;
+ case 'full':
+ case 'original':
+ $image = array( "http://example.org/wp-content/uploads/$year/$month/test-image.jpg", 2400, 1600, false );
+ break;
+ }
+
+ return $image;
+ }
+
+ /**
+ * Add Cloudflare image ID and hash.
+ */
+ private function add_cf_image_id_and_hash() {
+ add_post_meta( self::$attachment_id, '_cloudflare_image_id', 'CLOUDFLARE_IMAGE_ID' );
+ update_site_option( 'cf-images-hash', 'CF_IMAGES_HASH' );
+ }
+
+ /**
+ * Test: Returns the original image if `can_run()` is false.
+ *
+ * @covers Cloudflare_Images::get_attachment_image_src()
+ */
+ public function test_returns_original_if_can_run_is_false() {
+ $original = $this->get_original_image_object();
+
+ // Force `can_run()` to return false.
+ $this->cf_images
+ ->expects( $this->once() )
+ ->method( 'can_run' )
+ ->willReturn( false );
+
+ $image = wp_get_attachment_image_src( self::$attachment_id, 'medium' );
+ $this->assertSame( $original, $image, 'Should return original image if can_run() is false.' );
+ }
+
+ /**
+ * Test: Returns original if Cloudflare image ID is missing.
+ *
+ * @covers Cloudflare_Images::get_attachment_image_src()
+ */
+ public function test_returns_original_if_missing_cloudflare_image_id() {
+ $original = $this->get_original_image_object();
+
+ $image = wp_get_attachment_image_src( self::$attachment_id, 'medium' );
+ $this->assertSame( $original, $image, 'Should return original image if Cloudflare image ID is missing.' );
+ }
+
+ /**
+ * Test: Returns original if Cloudflare hash is missing.
+ *
+ * @covers Cloudflare_Images::get_attachment_image_src()
+ */
+ public function test_returns_original_if_missing_cloudflare_hash() {
+ $original = $this->get_original_image_object();
+
+ add_post_meta( self::$attachment_id, '_cloudflare_image_id', 'CLOUDFLARE_IMAGE_ID' );
+
+ $image = wp_get_attachment_image_src( self::$attachment_id, 'medium' );
+ $this->assertSame( $original, $image, 'Should return original image if Cloudflare hash is missing.' );
+ }
+
+ /**
+ * Test: Known crop image with a named size.
+ *
+ * @see Cloudflare_Images::$registered_sizes
+ *
+ * @covers Cloudflare_Images::get_attachment_image_src()
+ */
+ public function test_known_crop_image_size() {
+ $this->cf_images->populate_image_sizes();
+ $this->add_cf_image_id_and_hash();
+
+ $image = wp_get_attachment_image_src( self::$attachment_id ); // Default thumbnail size is cropped 150x150.
+ $this->assertStringEndsWith( 'w=150,h=150,fit=crop', $image[0], 'Should return offloaded image.' );
+ }
+
+ /**
+ * Test: Image with defined dimensions [width, height].
+ *
+ * @covers Cloudflare_Images::get_attachment_image_src()
+ */
+ public function test_defined_dimensions() {
+ $this->add_cf_image_id_and_hash();
+
+ $image = wp_get_attachment_image_src( self::$attachment_id, 'medium' );
+ $this->assertStringEndsWith( 'w=300,h=200', $image[0], 'Should return offloaded image.' );
+ }
+
+ /**
+ * Test: Image with `-x` in the filename.
+ *
+ * @covers Cloudflare_Images::get_attachment_image_src()
+ */
+ public function test_variant_image_filename() {
+ $original = $this->get_original_image_object( 'large' );
+
+ $this->cf_images->populate_image_sizes();
+ $this->add_cf_image_id_and_hash();
+
+ // Pass in just an image link without the sizes.
+ $image = $this->cf_images->get_attachment_image_src( array( $original[0] ), self::$attachment_id, null );
+ $this->assertStringEndsWith( 'w=1024,h=683', $image[0], 'Should detect file suffix from file name.' );
+ }
+
+ /**
+ * Test: Image with `-x` in the filename, and width = height.
+ *
+ * @covers Cloudflare_Images::get_attachment_image_src()
+ */
+ public function test_variant_image_filename_with_crop() {
+ $original = $this->get_original_image_object( 'thumbnail' );
+
+ $this->cf_images->populate_image_sizes();
+ $this->add_cf_image_id_and_hash();
+
+ // Pass in just an image link without the sizes.
+ $image = $this->cf_images->get_attachment_image_src( array( $original[0] ), self::$attachment_id, null );
+ $this->assertStringEndsWith( 'w=150,h=150,fit=crop', $image[0], 'Should detect file suffix and apply cropping if matched in arrays.' );
+ }
+
+ /**
+ * Test: `$size` is an integer => /w=$size
+ *
+ * @covers Cloudflare_Images::get_attachment_image_src()
+ */
+ public function test_size_is_int() {
+ $original = $this->get_original_image_object( 'original' );
+
+ $this->add_cf_image_id_and_hash();
+
+ $image = $this->cf_images->get_attachment_image_src( array( $original[0] ), self::$attachment_id, 2400 );
+ $this->assertStringEndsWith( '/w=2400', $image[0], 'Should add /w=2400 if $size is an integer.' );
+ }
+
+ /**
+ * Test: `-scaled` image handling.
+ *
+ * @covers Cloudflare_Images::get_attachment_image_src()
+ */
+ public function test_scaled_image_handling() {
+ $original = $this->get_original_image_object( 'scaled' );
+
+ $this->add_cf_image_id_and_hash();
+
+ $image = $this->cf_images->get_attachment_image_src( array( $original[0] ), self::$attachment_id, null );
+ $this->assertStringEndsWith( '/w=2560', $image[0], 'Should add /w=2560 if image is scaled.' );
+ }
+
+ /**
+ * Test: No size prefix, no $image[1], => default to /w=9999
+ *
+ * @covers Cloudflare_Images::get_attachment_image_src()
+ */
+ public function test_no_size_prefix_and_no_width_property() {
+ $original = $this->get_original_image_object( 'original' );
+
+ $this->add_cf_image_id_and_hash();
+
+ $image = $this->cf_images->get_attachment_image_src( array( $original[0] ), self::$attachment_id, null );
+ $this->assertStringContainsString( '/w=9999', $image[0], 'Should default to /w=9999 if no size is found.' );
+ }
+}
diff --git a/tests/test-sample.php b/tests/test-sample.php
new file mode 100644
index 0000000..0b42481
--- /dev/null
+++ b/tests/test-sample.php
@@ -0,0 +1,20 @@
+assertTrue( true );
+ }
+}