diff --git a/.gitattributes b/.gitattributes index bbdd753cf..912ac1990 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,22 +5,23 @@ # https://www.reddit.com/r/PHP/comments/2jzp6k/i_dont_need_your_tests_in_my_production # https://blog.madewithlove.be/post/gitattributes/ # -/.cache export-ignore -/.github export-ignore -/config export-ignore -/svn-assets export-ignore -/tests export-ignore -.babelrc export-ignore -.editorconfig export-ignore -.gitattributes export-ignore -.gitignore export-ignore -.phpcs.xml.dist export-ignore -CHANGELOG export-ignore -Gruntfile.js export-ignore -LICENSE export-ignore -package.json export-ignore -phpunit.xml.dist export-ignore -README.md export-ignore +/.cache export-ignore +/.github export-ignore +/config export-ignore +/svn-assets export-ignore +/tests export-ignore +.babelrc export-ignore +.editorconfig export-ignore +.gitattributes export-ignore +.gitignore export-ignore +.phpcs.xml.dist export-ignore +CHANGELOG export-ignore +Gruntfile.js export-ignore +LICENSE export-ignore +package.json export-ignore +phpunit.xml.dist export-ignore +phpunit-wp.xml.dist export-ignore +README.md export-ignore # # Auto detect text files and perform LF normalization diff --git a/.github/workflows/cs.yml b/.github/workflows/cs.yml index 6738b8b40..e44fdd010 100644 --- a/.github/workflows/cs.yml +++ b/.github/workflows/cs.yml @@ -19,6 +19,7 @@ on: - 'LICENSE' - 'package.json' - 'phpunit.xml.dist' + - 'phpunit-wp.xml.dist' - 'yarn.lock' - '.github/dependabot.yml' - '.github/workflows/deploy.yml' @@ -42,6 +43,7 @@ on: - 'LICENSE' - 'package.json' - 'phpunit.xml.dist' + - 'phpunit-wp.xml.dist' - 'yarn.lock' - '.github/dependabot.yml' - '.github/workflows/deploy.yml' diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index cc0795188..0a8c524a3 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -25,6 +25,7 @@ on: - '.phpcs.xml.dist' - 'phpcs.xml.dist' - 'phpunit.xml.dist' + - 'phpunit-wp.xml.dist' - 'yarn.lock' - '.github/dependabot.yml' - '.github/workflows/cs.yml' @@ -50,6 +51,7 @@ on: - '.phpcs.xml.dist' - 'phpcs.xml.dist' - 'phpunit.xml.dist' + - 'phpunit-wp.xml.dist' - 'yarn.lock' - '.github/dependabot.yml' - '.github/workflows/cs.yml' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c8b0d8830..c43949388 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -30,6 +30,7 @@ on: - '.github/workflows/deploy.yml' - '.github/workflows/lint.yml' - 'config/**' + - '!config/scripts/install-wp-tests.sh' - 'css/**' - 'js/**' pull_request: @@ -54,6 +55,7 @@ on: - '.github/workflows/deploy.yml' - '.github/workflows/lint.yml' - 'config/**' + - '!config/scripts/install-wp-tests.sh' - 'css/**' - 'js/**' # Allow manually triggering the workflow. @@ -131,6 +133,130 @@ jobs: COVERALLS_FLAG_NAME: php-${{ matrix.php_version }} run: php-coveralls -v -x build/logs/clover.xml + integration-test: + runs-on: ubuntu-latest + + strategy: + matrix: + include: + - php_version: "7.2" + wp_version: "6.2" + multisite: true + coverage: true + + - php_version: "7.3" + wp_version: "trunk" + multisite: true + coverage: false + + - php_version: "7.4" + wp_version: "latest" + multisite: false + coverage: false + + - php_version: "8.0" + wp_version: "6.2" + multisite: false + coverage: false + + - php_version: "8.1" + wp_version: "latest" + multisite: true + coverage: false + + - php_version: "8.2" + wp_version: "6.3" + multisite: true + coverage: true + + name: "Integration Test: PHP ${{ matrix.php_version }} | WP ${{ matrix.wp_version }}${{ matrix.multisite == true && ' (+ ms)' || '' }}" + + # Allow builds to fail on as-of-yet unreleased WordPress versions. + continue-on-error: ${{ matrix.wp_version == 'trunk' }} + + services: + mysql: + # Use MySQL 5.6 for PHP 7.2, use MySQL 5.7 for PHP 7.3 < 7.4, otherwise MySQL 8.0. + # Also see: https://core.trac.wordpress.org/ticket/52496 + image: mysql:${{ ( matrix.php_version == '7.2' && '5.6' ) || ( matrix.php_version < '7.4' && '5.7' ) || '8.0' }} + env: + MYSQL_ALLOW_EMPTY_PASSWORD: false + ports: + - 3306:3306 + options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=10s --health-retries=10 + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php_version }} + ini-values: zend.assertions=1, error_reporting=-1, display_errors=On + coverage: ${{ matrix.coverage == true && 'xdebug' || 'none' }} + + # Install dependencies and handle caching in one go. + # @link https://github.com/marketplace/actions/install-composer-dependencies + - name: Install Composer dependencies + uses: ramsey/composer-install@v2 + with: + # Bust the cache at least once a month - output format: YYYY-MM. + custom-cache-suffix: $(date -u "+%Y-%m") + + - name: Install WP + shell: bash + run: config/scripts/install-wp-tests.sh wordpress_test root '' 127.0.0.1:3306 ${{ matrix.wp_version }} + + - name: Run integration tests - single site + if: ${{ matrix.coverage == false }} + run: composer integration-test + + - name: Run integration tests - multisite + if: ${{ matrix.multisite == true && matrix.coverage == false }} + run: composer integration-test + env: + WP_MULTISITE: 1 + + - name: Run integration tests with code coverage - single site + if: ${{ matrix.coverage == true }} + run: composer integration-coverage + + - name: Run integration tests with code coverage - multisite + if: ${{ matrix.multisite == true && matrix.coverage == true }} + run: composer integration-coverage -- --coverage-clover build/logs/clover-integration-ms.xml + env: + WP_MULTISITE: 1 + + # PHP Coveralls doesn't fully support PHP 8.x yet, so switch the PHP version. + - name: Switch to PHP 7.4 + if: ${{ success() && matrix.coverage == true && startsWith( matrix.php_version, '8' ) }} + uses: shivammathur/setup-php@v2 + with: + php-version: 7.4 + coverage: none + + # Global install is used to prevent a conflict with the local composer.lock in PHP 8.0+. + - name: Install Coveralls + if: ${{ success() && matrix.coverage == true }} + run: composer global require php-coveralls/php-coveralls:"^2.5.3" --no-interaction + + - name: Upload coverage results to Coveralls + if: ${{ success() && matrix.coverage == true }} + env: + COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }} + COVERALLS_PARALLEL: true + COVERALLS_FLAG_NAME: intgr-php-${{ matrix.php_version }}-wp-${{ matrix.wp_version }} + run: php-coveralls -v -x build/logs/clover-integration.xml + + - name: Upload coverage results to Coveralls - multisite + if: ${{ success() && matrix.multisite == true && matrix.coverage == true }} + env: + COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }} + COVERALLS_PARALLEL: true + COVERALLS_FLAG_NAME: intgr-php-${{ matrix.php_version }}-wp-${{ matrix.wp_version }}-ms + run: php-coveralls -v -x build/logs/clover-integration-ms.xml + coveralls-finish: needs: unit runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index 909d53deb..0ea5601bf 100644 --- a/.gitignore +++ b/.gitignore @@ -54,6 +54,8 @@ composer.lock phpcs.xml .cache/phpcs.cache phpunit.xml +phpunit-integration.xml +phpunit-wp.xml .phpunit.result.cache ############ diff --git a/.phpcs.xml.dist b/.phpcs.xml.dist index 9cb8f12f3..cde1e5400 100644 --- a/.phpcs.xml.dist +++ b/.phpcs.xml.dist @@ -108,7 +108,7 @@ - + /tests/*\.php$ @@ -118,7 +118,7 @@ /tests/* - + /tests/* diff --git a/composer.json b/composer.json index 9468caf69..3bc1623d7 100644 --- a/composer.json +++ b/composer.json @@ -56,6 +56,12 @@ ], "coverage": [ "@php ./vendor/phpunit/phpunit/phpunit" + ], + "integration-test": [ + "@php ./vendor/phpunit/phpunit/phpunit -c phpunit-wp.xml.dist --no-coverage" + ], + "integration-coverage": [ + "@php ./vendor/phpunit/phpunit/phpunit -c phpunit-wp.xml.dist" ] }, "config": { diff --git a/config/scripts/install-wp-tests.sh b/config/scripts/install-wp-tests.sh new file mode 100755 index 000000000..8c0004eee --- /dev/null +++ b/config/scripts/install-wp-tests.sh @@ -0,0 +1,189 @@ +#!/usr/bin/env bash + +######################################################################## +# Script to download and install WordPress for use in automated testing. +# +# Source: https://github.com/wp-cli/scaffold-command/blob/main/templates/install-wp-tests.sh +# Last updated based on commit https://github.com/wp-cli/scaffold-command/commit/503ac569875d3665a0b28b9a5b7e8d136112b6d6 +# dated December 15 2022. +######################################################################## + +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/phpunit-wp.xml.dist b/phpunit-wp.xml.dist new file mode 100644 index 000000000..3c3a0d933 --- /dev/null +++ b/phpunit-wp.xml.dist @@ -0,0 +1,43 @@ + + + + + ./tests/wp + + + + + + ./admin-functions.php + ./common-functions.php + ./duplicate-post.php + ./options.php + ./compat + ./src + + + + + + + + + diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 2c132cba2..2a4179710 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -4,7 +4,7 @@ xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/8.5/phpunit.xsd" backupGlobals="false" backupStaticAttributes="false" - bootstrap="tests/bootstrap.php" + bootstrap="tests/unit/bootstrap.php" colors="true" convertDeprecationsToExceptions="true" convertErrorsToExceptions="true" @@ -20,7 +20,7 @@ > - ./tests/ + ./tests/unit diff --git a/tests/admin/options-form-generator-test.php b/tests/unit/admin/options-form-generator-test.php similarity index 99% rename from tests/admin/options-form-generator-test.php rename to tests/unit/admin/options-form-generator-test.php index 297e64660..81b90aa65 100644 --- a/tests/admin/options-form-generator-test.php +++ b/tests/unit/admin/options-form-generator-test.php @@ -1,6 +1,6 @@ instance = new Post_Duplicator(); + } + + /** + * Tests whether the admin page is generated correctly. + * + * @covers ::create_duplicate + * @covers ::get_default_options + * @covers ::generate_copy_title + * @covers ::generate_copy_status + * @covers ::generate_copy_author + * @covers ::set_modified + */ + public function test_create_duplicate() { + + $post = $this->factory->post->create_and_get(); + + $id = $this->instance->create_duplicate( $post, [ 'copy_date' => true ] ); + + $this->assertIsInt( $id ); + } +}