Commit 7aa557b4463 for woocommerce

commit 7aa557b4463fd936bfd05b47a0a572a26600233f
Author: Vlad Olaru <vlad.olaru@automattic.com>
Date:   Mon Aug 31 18:23:16 2026 +0300

    [tests] Allow disabling the PHPUnit code hacker with an environment variable (#68195)

    test: allow disabling the code hacker with WC_TEST_DISABLE_CODE_HACKER

    The PHPUnit bootstrap always enables the code hacker, which takes
    over PHP's `file` stream wrapper for the whole run and restores the
    built-in wrapper whenever it needs a native file operation. Tools
    that must own that wrapper themselves cannot run alongside it:
    mutation testers such as Infection swap mutated files in at include
    time through their own wrapper, and the code hacker silently drops
    it, so every mutant loads the original code and escapes.

    Skip the code hacker when the WC_TEST_DISABLE_CODE_HACKER
    environment variable is set, mirroring how DISABLE_HPOS is read, and
    print a notice so the trade-off is visible in the output. Tests that
    mock functions or static methods, or subclass final classes, fail
    loudly without it ("Call to a member function register_function_mocks()
    on null"), so runs using the switch need to be narrowed to test
    classes that do not rely on the hacks.

diff --git a/plugins/woocommerce/changelog/dev-test-bootstrap-disable-code-hacker b/plugins/woocommerce/changelog/dev-test-bootstrap-disable-code-hacker
new file mode 100644
index 00000000000..dc1b51278d0
--- /dev/null
+++ b/plugins/woocommerce/changelog/dev-test-bootstrap-disable-code-hacker
@@ -0,0 +1,4 @@
+Significance: patch
+Type: dev
+
+Allow running the PHPUnit suite without the code hacker by setting the WC_TEST_DISABLE_CODE_HACKER environment variable, for tools such as mutation testers that need to own the file stream wrapper.
diff --git a/plugins/woocommerce/tests/Tools/CodeHacking/README.md b/plugins/woocommerce/tests/Tools/CodeHacking/README.md
index bcb657fc1d2..5076ed10f01 100644
--- a/plugins/woocommerce/tests/Tools/CodeHacking/README.md
+++ b/plugins/woocommerce/tests/Tools/CodeHacking/README.md
@@ -151,6 +151,16 @@ In a few rare cases the code hacker will cause problems with tests that do write

 One of these cases is the usage of the `copy` command to copy files. Since this function is used in a few tests, a convenience `file_copy` method is defined in `WC_Unit_Test_Case`; it just temporarily disables the hacker, does the copy, and reenables the hacker.

+## Disabling the code hacker for a whole run
+
+The code hacker owns PHP's `file` stream wrapper while it is enabled, so it cannot coexist with other tools that need that wrapper for themselves, such as mutation testing frameworks that swap mutated files in at include time. Set the `WC_TEST_DISABLE_CODE_HACKER` environment variable to any non-empty value to skip the code hacker for the whole run:
+
+```sh
+pnpm wp-env:test run --env-cwd='wp-content/plugins/woocommerce' cli env WC_TEST_DISABLE_CODE_HACKER=1 tests/php/bin/run-phpunit.sh -c phpunit.xml --filter SomeTest
+```
+
+The bootstrap prints a notice when it does this. Tests that mock functions or static methods, or that subclass `final` classes, fail without the code hacker, so narrow the run to test classes that do not rely on it.
+
 ## An important note

 The code hacker is intended to be a **last resort** mechanism to test stuff that it's **really** difficult or impossible to test otherwise - the mechanisms already in place to help testing (e.g. the PHPUnit's mocks or the Woo helpers) should still be used whenever possible. And of course, the code hacker should not be an excuse to write code that's difficult to test.
diff --git a/plugins/woocommerce/tests/legacy/bootstrap.php b/plugins/woocommerce/tests/legacy/bootstrap.php
index 83113959cd7..61ad96a6d3d 100644
--- a/plugins/woocommerce/tests/legacy/bootstrap.php
+++ b/plugins/woocommerce/tests/legacy/bootstrap.php
@@ -42,7 +42,7 @@ class WC_Unit_Tests_Bootstrap {

 		$this->register_autoloader_for_testing_tools();

-		$this->initialize_code_hacker();
+		$this->maybe_initialize_code_hacker();

 		ini_set( 'display_errors', 'on' ); // phpcs:ignore WordPress.PHP.IniSet.display_errors_Blacklisted
 		error_reporting( E_ALL ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.prevent_path_disclosure_error_reporting, WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_error_reporting
@@ -149,7 +149,23 @@ class WC_Unit_Tests_Bootstrap {
 	}

 	/**
-	 * Initialize the code hacker.
+	 * Initialize the code hacker unless the WC_TEST_DISABLE_CODE_HACKER environment variable is set.
+	 *
+	 * The code hacker owns PHP's file stream wrapper, so tools that need that wrapper
+	 * themselves (for example mutation testers, which swap mutated files in at include
+	 * time) cannot run alongside it.
+	 */
+	private function maybe_initialize_code_hacker() {
+		if ( empty( getenv( 'WC_TEST_DISABLE_CODE_HACKER' ) ) ) {
+			$this->initialize_code_hacker();
+			return;
+		}
+
+		echo 'Not enabling the code hacker (WC_TEST_DISABLE_CODE_HACKER is set). Tests that mock functions or static methods, or that subclass final classes, will fail.' . PHP_EOL;
+	}
+
+	/**
+	 * Initialize the code hacker and register the hacks.
 	 *
 	 * @throws Exception Error when initializing one of the hacks.
 	 */