From 6be4151bf754575e2567c46436b1dba06bffb1c0 Mon Sep 17 00:00:00 2001 From: Nikolay Strikhar Date: Fri, 31 Jul 2026 14:51:01 +0200 Subject: [PATCH 1/4] Add Config facade and Config_Exception --- README.md | 13 ++- src/Config.php | 139 ++++++++++++++++++++++++++++ src/Exceptions/Config_Exception.php | 18 ++++ tests/_support/Test_Container.php | 57 ++++++++++++ tests/unit/ConfigTest.php | 107 +++++++++++++++++++++ 5 files changed, 333 insertions(+), 1 deletion(-) create mode 100644 src/Config.php create mode 100644 src/Exceptions/Config_Exception.php create mode 100644 tests/_support/Test_Container.php create mode 100644 tests/unit/ConfigTest.php diff --git a/README.md b/README.md index d17516b..fcf0e10 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,18 @@ Requires PHP 7.4+ and WordPress 6.4+. ## Usage -_Added as each piece lands._ +### Configure + +```php +use Nexcess\PluginAbsorber\Config; + +Config::set_hook_prefix( 'give' ); // required — keys hooks, transients, options +Config::set_version( GIVE_VERSION ); // optional +Config::set_container( give()->container ); // optional — see Rebinding below +``` + +The hook prefix accepts letters, numbers, hyphens, and underscores. Anything else throws +`Config_Exception`, as does reading it before it is set. ## License diff --git a/src/Config.php b/src/Config.php new file mode 100644 index 0000000..de2bce1 --- /dev/null +++ b/src/Config.php @@ -0,0 +1,139 @@ +container = $container ?: new DI52Container(); + } + + /** + * @inheritDoc + */ + public function bind( string $id, $implementation = null ) { + $this->container->bind( $id, $implementation ); + } + + /** + * @inheritDoc + */ + public function get( string $id ) { + return $this->container->get( $id ); + } + + /** + * @inheritDoc + */ + public function has( string $id ) { + return $this->container->has( $id ); + } + + /** + * @inheritDoc + */ + public function singleton( string $id, $implementation = null ) { + $this->container->singleton( $id, $implementation ); + } +} diff --git a/tests/unit/ConfigTest.php b/tests/unit/ConfigTest.php new file mode 100644 index 0000000..2633d74 --- /dev/null +++ b/tests/unit/ConfigTest.php @@ -0,0 +1,107 @@ +assertSame( 'give', Config::get_hook_prefix() ); + } + + public function test_it_accepts_letters_numbers_hyphens_and_underscores(): void { + Config::set_hook_prefix( 'give-recurring_2' ); + + $this->assertSame( 'give-recurring_2', Config::get_hook_prefix() ); + } + + /** + * @dataProvider invalid_hook_prefixes + * + * @param string $prefix Prefix under test. + */ + public function test_it_rejects_invalid_hook_prefixes( string $prefix ): void { + $this->expectException( Config_Exception::class ); + + Config::set_hook_prefix( $prefix ); + } + + /** + * @return array + */ + public function invalid_hook_prefixes(): array { + return [ + 'slash' => [ 'give/recurring' ], + 'space' => [ 'give recurring' ], + 'dot' => [ 'give.recurring' ], + 'backslash' => [ 'give\\recurring' ], + ]; + } + + public function test_it_rejects_an_empty_hook_prefix(): void { + $this->expectException( Config_Exception::class ); + + Config::set_hook_prefix( '' ); + } + + public function test_it_throws_when_the_hook_prefix_was_never_set(): void { + $this->expectException( Config_Exception::class ); + + Config::get_hook_prefix(); + } + + public function test_it_stores_and_returns_the_version(): void { + Config::set_version( '3.0.0' ); + + $this->assertSame( '3.0.0', Config::get_version() ); + } + + public function test_the_version_defaults_to_an_empty_string(): void { + $this->assertSame( '', Config::get_version() ); + } + + public function test_it_reports_no_container_by_default(): void { + $this->assertFalse( Config::has_container() ); + $this->assertNull( Config::get_container() ); + } + + public function test_it_stores_and_returns_a_container(): void { + $container = new Test_Container(); + + Config::set_container( $container ); + + $this->assertTrue( Config::has_container() ); + $this->assertSame( $container, Config::get_container() ); + } + + public function test_reset_clears_every_value(): void { + Config::set_hook_prefix( 'give' ); + Config::set_version( '3.0.0' ); + Config::set_container( new Test_Container() ); + + Config::reset(); + + $this->assertSame( '', Config::get_version() ); + $this->assertFalse( Config::has_container() ); + $this->assertNull( Config::get_container() ); + + $this->expectException( Config_Exception::class ); + Config::get_hook_prefix(); + } +} From 7d317876b8eaf219781c5653293bd6796faeb517 Mon Sep 17 00:00:00 2001 From: Nikolay Strikhar Date: Mon, 3 Aug 2026 13:04:32 +0200 Subject: [PATCH 2/4] Address review: prove the RuntimeException contract, isolate Config state - Assert Config_Exception is catchable as RuntimeException; nothing covered that inheritance, so dropping it would have left the suite green. - Reset Config in setUp() as well as tearDown(), so the tests asserting on default state no longer depend on class execution order. - Note that the container fixture inherits DI52's class_exists() fallback in has(). - Drop a README pointer to a section that does not exist yet. --- README.md | 2 +- tests/_support/Test_Container.php | 5 +++++ tests/unit/ConfigTest.php | 12 ++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fcf0e10..8d2381b 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ use Nexcess\PluginAbsorber\Config; Config::set_hook_prefix( 'give' ); // required — keys hooks, transients, options Config::set_version( GIVE_VERSION ); // optional -Config::set_container( give()->container ); // optional — see Rebinding below +Config::set_container( give()->container ); // optional — lets you rebind collaborators ``` The hook prefix accepts letters, numbers, hyphens, and underscores. Anything else throws diff --git a/tests/_support/Test_Container.php b/tests/_support/Test_Container.php index eeab57c..46e7c1f 100644 --- a/tests/_support/Test_Container.php +++ b/tests/_support/Test_Container.php @@ -42,6 +42,11 @@ public function get( string $id ) { } /** + * Reports whether the id is bound. + * + * Inherits DI52's permissive semantics: any existing *class* name reports true even with + * nothing bound, because DI52 falls back to `class_exists()`. Interface names are unaffected. + * * @inheritDoc */ public function has( string $id ) { diff --git a/tests/unit/ConfigTest.php b/tests/unit/ConfigTest.php index 2633d74..47f8d89 100644 --- a/tests/unit/ConfigTest.php +++ b/tests/unit/ConfigTest.php @@ -9,11 +9,17 @@ use Nexcess\PluginAbsorber\Config; use Nexcess\PluginAbsorber\Exceptions\Config_Exception; use Nexcess\PluginAbsorber\Tests\Support\Test_Container; +use RuntimeException; /** * @since 1.0.0 */ class ConfigTest extends WPTestCase { + public function setUp(): void { + parent::setUp(); + Config::reset(); + } + public function tearDown(): void { Config::reset(); parent::tearDown(); @@ -66,6 +72,12 @@ public function test_it_throws_when_the_hook_prefix_was_never_set(): void { Config::get_hook_prefix(); } + public function test_config_exception_is_catchable_as_a_runtime_exception(): void { + $this->expectException( RuntimeException::class ); + + Config::set_hook_prefix( 'give/recurring' ); + } + public function test_it_stores_and_returns_the_version(): void { Config::set_version( '3.0.0' ); From b4fcc161fb6506e3643d6d92b573323befddf319 Mon Sep 17 00:00:00 2001 From: Nikolay Strikhar Date: Mon, 3 Aug 2026 13:04:33 +0200 Subject: [PATCH 3/4] Plan: record the container-contract correction and prefix-guard deviation --- .../plans/2026-07-31-plugin-absorber.md | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/docs/superpowers/plans/2026-07-31-plugin-absorber.md b/docs/superpowers/plans/2026-07-31-plugin-absorber.md index 07fa151..ec4ba12 100644 --- a/docs/superpowers/plans/2026-07-31-plugin-absorber.md +++ b/docs/superpowers/plans/2026-07-31-plugin-absorber.md @@ -32,7 +32,7 @@ Every task's requirements implicitly include this section. ``` - **Branching:** stacked. Each branch cuts from the previous branch, and merges to `main` in order. Never open PR N+1 before PR N's branch exists. - **Commits:** no co-author trailers, ever. -- **Every source file** carries a file-level docblock with `@package Nexcess\PluginAbsorber` and every method a docblock with `@since 1.0.0`. +- **Every source file** carries a file-level docblock with `@package Nexcess\PluginAbsorber` and every method a docblock with `@since 1.0.0`. This binds `src/` only. Test classes and test support classes keep the file-level docblock, but their methods do not need `@since` — the test code in this plan's own tasks is written that way deliberately (ruled 2026-07-31). ## File Structure @@ -864,6 +864,11 @@ Expected: all matrix legs green. **Do not proceed until they are** — every lat > `RuntimeException`. This throws `Config_Exception`, which extends `RuntimeException`, so the > documented contract still holds while callers get one catchable type across the whole library. +> **Second deviation, deliberate (added 2026-08-03):** `set_hook_prefix()` also rejects the empty +> string. The character-class check alone would accept `''` — it contains no invalid character — +> and the failure would resurface at `get_hook_prefix()` as the misleading "You must call +> `Config::set_hook_prefix()`" long after the real mistake. + - [ ] **Step 1: Cut the branch** ```bash @@ -976,8 +981,18 @@ class ConfigTest extends WPTestCase { } ``` -> `lucatume\DI52\Container` implements `StellarWP\ContainerContract\ContainerInterface` and is the -> dev-only container this library tests against. +> **CORRECTION (2026-07-31, verified against vendor/):** `lucatume\DI52\Container` does **not** +> implement `StellarWP\ContainerContract\ContainerInterface`. It implements `ArrayAccess` and +> **PSR's** `Psr\Container\ContainerInterface`. `stellarwp/container-contract` ships an adapter +> example at `examples/di52/Container.php` precisely because DI52 must be wrapped. +> `new Container()` therefore cannot be passed to `Config::set_container()` — it is a `TypeError`. +> +> Tests must use the test-support adapter `Nexcess\PluginAbsorber\Tests\Support\Test_Container` +> (wraps a DI52 container, implements the StellarWP contract's four methods: `bind`, `get`, +> `has`, `singleton`). This affects **Task 4 and Task 10** — both of their test blocks below still +> show the incorrect `use lucatume\DI52\Container;`. `Config::set_container()`'s signature is +> unchanged: the StellarWP contract stays the public API, per the Global Constraint that +> `stellarwp/container-contract` is the only production dependency. - [ ] **Step 3: Run it to verify it fails** From dfec458bf80238c84b3983aa56cf4d4be2f49273 Mon Sep 17 00:00:00 2001 From: Nikolay Strikhar Date: Tue, 11 Aug 2026 11:01:33 +0200 Subject: [PATCH 4/4] Remove version handling and reset method from Config; introduce Config_State for test state management. Update tests to reflect changes and ensure proper exception handling for invalid hook prefixes. --- README.md | 1 - .../plans/2026-07-31-plugin-absorber.md | 34 +++++++-- .../2026-07-31-plugin-absorber-design.md | 8 +- src/Config.php | 38 ---------- tests/_support/Config_State.php | 59 ++++++++++++++ tests/unit/ConfigTest.php | 76 +++++++++---------- 6 files changed, 130 insertions(+), 86 deletions(-) create mode 100644 tests/_support/Config_State.php diff --git a/README.md b/README.md index 8d2381b..aae9564 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,6 @@ Requires PHP 7.4+ and WordPress 6.4+. use Nexcess\PluginAbsorber\Config; Config::set_hook_prefix( 'give' ); // required — keys hooks, transients, options -Config::set_version( GIVE_VERSION ); // optional Config::set_container( give()->container ); // optional — lets you rebind collaborators ``` diff --git a/docs/superpowers/plans/2026-07-31-plugin-absorber.md b/docs/superpowers/plans/2026-07-31-plugin-absorber.md index ec4ba12..805a6ea 100644 --- a/docs/superpowers/plans/2026-07-31-plugin-absorber.md +++ b/docs/superpowers/plans/2026-07-31-plugin-absorber.md @@ -33,6 +33,7 @@ Every task's requirements implicitly include this section. - **Branching:** stacked. Each branch cuts from the previous branch, and merges to `main` in order. Never open PR N+1 before PR N's branch exists. - **Commits:** no co-author trailers, ever. - **Every source file** carries a file-level docblock with `@package Nexcess\PluginAbsorber` and every method a docblock with `@since 1.0.0`. This binds `src/` only. Test classes and test support classes keep the file-level docblock, but their methods do not need `@since` — the test code in this plan's own tasks is written that way deliberately (ruled 2026-07-31). +- **No test-only seams in `src/`** (ruled 2026-08-11, PR 4 review). Production classes do not carry a `reset()` for the suite's benefit — that is API the library then supports forever. Tests clear static state by reflection instead, through a helper under `tests/_support/`. `Config` is served by `Nexcess\PluginAbsorber\Tests\Support\Config_State::reset()`; **every `Config::reset()` in the task blocks below means `Config_State::reset()`.** The same applies to `Registrar` and `Loader` when tasks 8 and 9 land. ## File Structure @@ -854,11 +855,9 @@ Expected: all matrix legs green. **Do not proceed until they are** — every lat - `Config_Exception extends \RuntimeException` - `Config::set_hook_prefix( string ): void` — throws `Config_Exception` on characters outside `[a-zA-Z0-9_-]` - `Config::get_hook_prefix(): string` — throws `Config_Exception` when unset - - `Config::set_version( string ): void` / `Config::get_version(): string` - `Config::set_container( ContainerInterface ): void` / `get_container(): ?ContainerInterface` / `has_container(): bool` - - `Config::reset(): void` - Every later task calls `Config::set_hook_prefix()` in `setUp()` and `Config::reset()` in `tearDown()`. + Every later task calls `Config::set_hook_prefix()` in `setUp()` and `Config_State::reset()` in `tearDown()`. > **Deviation from the engineering plan, deliberate:** the plan's sketch throws bare > `RuntimeException`. This throws `Config_Exception`, which extends `RuntimeException`, so the @@ -869,6 +868,26 @@ Expected: all matrix legs green. **Do not proceed until they are** — every lat > and the failure would resurface at `get_hook_prefix()` as the misleading "You must call > `Config::set_hook_prefix()`" long after the real mistake. +> **Third deviation, from the PR 4 review (2026-08-11) — two removals. The code blocks below still +> show both; they are wrong and were left for the record.** +> +> 1. **`set_version()` / `get_version()` are gone**, along with the `$version` property, its two +> tests, and the README line. Nothing in the library reads a host version, and the one scenario +> that would want it — telling a bundled copy apart from a standalone at a specific release, à la +> ProPanel v3.0 — is the host's problem, not this library's. This closes spec known-issue F by +> deletion rather than by use. +> 2. **`Config::reset()` is gone.** It existed only so the suite could clear static state, and a +> public method is a promise to everyone, not just to tests. The suite now uses +> `Tests\Support\Config_State::reset()`, which walks `Config`'s declared static defaults by +> reflection — so state added to `Config` later is cleared with no change to the helper. See the +> Global Constraint on test-only seams. +> +> The `ConfigTest` block below is also superseded on two points the review raised: the prefix tests +> are driven by `public static` `Generator` data providers (valid and invalid, the empty string +> among the invalid), and the `RuntimeException` test now catches as `RuntimeException` and asserts +> `instanceof Config_Exception` — proving both halves of the contract instead of passing merely +> because one extends the other. + - [ ] **Step 1: Cut the branch** ```bash @@ -1209,9 +1228,9 @@ RuntimeException`, so the documented contract still holds and callers get one ca the library. `set_hook_prefix()` validates eagerly rather than at use, because a bad prefix otherwise surfaces as a silently-never-firing filter much later. -Verify: `slic run unit` — 13 tests covering the validation regex, the unset-prefix throw, container -storage, and `reset()`. `get_version()` is stored but not yet read by anything; see the spec is -known-issue F.' +Verify: `slic run unit` — the validation regex over valid and invalid prefixes, the unset-prefix +throw, the `RuntimeException` catchability contract, and container storage. Version handling is not +covered because it no longer exists; see the third deviation above.' ``` --- @@ -5635,7 +5654,8 @@ Recorded in the spec, deliberately not fixed in 1.0.0: Matches both reference implementations as-is. - **E** — `Activation::maybe_run()` reads the option, runs the callback, then writes. Two simultaneous first requests can both run it. `add_option()` as an atomic claim would close it. -- **F** — `Config::get_version()` is stored but never read. +- ~~**F** — `Config::get_version()` is stored but never read.~~ Closed 2026-08-11 by removing + version handling from `Config` outright; see Task 4's third deviation. ## Self-review diff --git a/docs/superpowers/specs/2026-07-31-plugin-absorber-design.md b/docs/superpowers/specs/2026-07-31-plugin-absorber-design.md index a113edc..720226d 100644 --- a/docs/superpowers/specs/2026-07-31-plugin-absorber-design.md +++ b/docs/superpowers/specs/2026-07-31-plugin-absorber-design.md @@ -100,6 +100,8 @@ callback — which may be `create_tables()`. Claiming the slot with `add_option( would close the window. **F. `Config::get_version()` is never read.** Set by the consumer, unused by the library. +*Resolved 2026-08-11 (PR 4 review): version handling was removed from `Config` rather than given a +reader. Nothing in the library needs the host's version.* --- @@ -228,8 +230,10 @@ message. This is documented in `tests/README.md`. - **3 — smoke.** Three tests: WordPress is loaded; `uopz` is available; a function can be stubbed. There is deliberately no test that `exit` can be neutralised. -- **4 — `Config`.** Prefix regex rejects invalid characters (throws); `get_hook_prefix()` throws - when unset; version set/get; container set/get/has; `reset()` clears all three. +- **4 — `Config`.** Prefix regex accepts valid characters and rejects invalid ones, the empty + string included (throws); `get_hook_prefix()` throws when unset; `Config_Exception` is catchable + as `RuntimeException`; container set/get/has. No version handling and no production `reset()` — + see the plan's Task 4 deviations. - **6 — `Conflict_Policy`.** Constant values; the three are distinct. - **7 — `Sub_Plugin`.** Each of the three required keys missing throws `Config_Exception`; `is_enabled()` bool vs callable; `is_already_loaded()` reacts to `define()`; diff --git a/src/Config.php b/src/Config.php index de2bce1..a4779f0 100644 --- a/src/Config.php +++ b/src/Config.php @@ -19,11 +19,6 @@ class Config { */ protected static $hook_prefix = ''; - /** - * @var string - */ - protected static $version = ''; - /** * @var ContainerInterface|null */ @@ -71,26 +66,6 @@ public static function get_hook_prefix(): string { return self::$hook_prefix; } - /** - * @since 1.0.0 - * - * @param string $version Host plugin version. - * - * @return void - */ - public static function set_version( string $version ): void { - self::$version = $version; - } - - /** - * @since 1.0.0 - * - * @return string - */ - public static function get_version(): string { - return self::$version; - } - /** * Share the host's container so collaborators become bindable. * @@ -123,17 +98,4 @@ public static function get_container(): ?ContainerInterface { public static function has_container(): bool { return self::$container !== null; } - - /** - * Reset all static state. Test seam. - * - * @since 1.0.0 - * - * @return void - */ - public static function reset(): void { - self::$hook_prefix = ''; - self::$version = ''; - self::$container = null; - } } diff --git a/tests/_support/Config_State.php b/tests/_support/Config_State.php new file mode 100644 index 0000000..aa06199 --- /dev/null +++ b/tests/_support/Config_State.php @@ -0,0 +1,59 @@ + + */ + protected const DEFAULTS = [ + 'hook_prefix' => '', + 'container' => null, + ]; + + /** + * Return every static property of `Config` to its default. + * + * @throws LogicException When `Config` has grown a static property this helper does not know + * about, rather than leaving it to leak between tests. + * + * @return void + */ + public static function reset(): void { + $reflection = new ReflectionClass( Config::class ); + + foreach ( $reflection->getProperties( ReflectionProperty::IS_STATIC ) as $property ) { + $name = $property->getName(); + + if ( ! array_key_exists( $name, self::DEFAULTS ) ) { + throw new LogicException( + sprintf( 'Config::$%s has no default in %s. Add one.', $name, self::class ) + ); + } + + $property->setAccessible( true ); + $property->setValue( null, self::DEFAULTS[ $name ] ); + } + } +} diff --git a/tests/unit/ConfigTest.php b/tests/unit/ConfigTest.php index 47f8d89..9e6d6d6 100644 --- a/tests/unit/ConfigTest.php +++ b/tests/unit/ConfigTest.php @@ -6,8 +6,10 @@ namespace Nexcess\PluginAbsorber\Tests\Unit; use Codeception\TestCase\WPTestCase; +use Generator; use Nexcess\PluginAbsorber\Config; use Nexcess\PluginAbsorber\Exceptions\Config_Exception; +use Nexcess\PluginAbsorber\Tests\Support\Config_State; use Nexcess\PluginAbsorber\Tests\Support\Test_Container; use RuntimeException; @@ -17,24 +19,35 @@ class ConfigTest extends WPTestCase { public function setUp(): void { parent::setUp(); - Config::reset(); + Config_State::reset(); } public function tearDown(): void { - Config::reset(); + Config_State::reset(); parent::tearDown(); } - public function test_it_stores_and_returns_the_hook_prefix(): void { - Config::set_hook_prefix( 'give' ); + /** + * @dataProvider valid_hook_prefixes + * + * @param string $prefix Prefix under test. + */ + public function test_it_stores_and_returns_a_valid_hook_prefix( string $prefix ): void { + Config::set_hook_prefix( $prefix ); - $this->assertSame( 'give', Config::get_hook_prefix() ); + $this->assertSame( $prefix, Config::get_hook_prefix() ); } - public function test_it_accepts_letters_numbers_hyphens_and_underscores(): void { - Config::set_hook_prefix( 'give-recurring_2' ); - - $this->assertSame( 'give-recurring_2', Config::get_hook_prefix() ); + /** + * @return Generator + */ + public static function valid_hook_prefixes(): Generator { + yield 'lowercase' => [ 'give' ]; + yield 'mixed case' => [ 'GiveRecurring' ]; + yield 'digits' => [ 'give2' ]; + yield 'hyphen' => [ 'give-recurring' ]; + yield 'underscore' => [ 'give_recurring' ]; + yield 'all of it' => [ 'give-recurring_2' ]; } /** @@ -49,21 +62,14 @@ public function test_it_rejects_invalid_hook_prefixes( string $prefix ): void { } /** - * @return array + * @return Generator */ - public function invalid_hook_prefixes(): array { - return [ - 'slash' => [ 'give/recurring' ], - 'space' => [ 'give recurring' ], - 'dot' => [ 'give.recurring' ], - 'backslash' => [ 'give\\recurring' ], - ]; - } - - public function test_it_rejects_an_empty_hook_prefix(): void { - $this->expectException( Config_Exception::class ); - - Config::set_hook_prefix( '' ); + public static function invalid_hook_prefixes(): Generator { + yield 'empty string' => [ '' ]; + yield 'slash' => [ 'give/recurring' ]; + yield 'space' => [ 'give recurring' ]; + yield 'dot' => [ 'give.recurring' ]; + yield 'backslash' => [ 'give\\recurring' ]; } public function test_it_throws_when_the_hook_prefix_was_never_set(): void { @@ -73,19 +79,15 @@ public function test_it_throws_when_the_hook_prefix_was_never_set(): void { } public function test_config_exception_is_catchable_as_a_runtime_exception(): void { - $this->expectException( RuntimeException::class ); + try { + Config::set_hook_prefix( 'give/recurring' ); + } catch ( RuntimeException $exception ) { + $this->assertInstanceOf( Config_Exception::class, $exception ); - Config::set_hook_prefix( 'give/recurring' ); - } - - public function test_it_stores_and_returns_the_version(): void { - Config::set_version( '3.0.0' ); - - $this->assertSame( '3.0.0', Config::get_version() ); - } + return; + } - public function test_the_version_defaults_to_an_empty_string(): void { - $this->assertSame( '', Config::get_version() ); + $this->fail( 'set_hook_prefix() accepted an invalid prefix instead of throwing.' ); } public function test_it_reports_no_container_by_default(): void { @@ -102,14 +104,12 @@ public function test_it_stores_and_returns_a_container(): void { $this->assertSame( $container, Config::get_container() ); } - public function test_reset_clears_every_value(): void { + public function test_the_state_helper_clears_every_value(): void { Config::set_hook_prefix( 'give' ); - Config::set_version( '3.0.0' ); Config::set_container( new Test_Container() ); - Config::reset(); + Config_State::reset(); - $this->assertSame( '', Config::get_version() ); $this->assertFalse( Config::has_container() ); $this->assertNull( Config::get_container() );