Skip to content

Commit 9b248e7

Browse files
committed
Added plan.md for EnvTrait refactoring.
1 parent a672b9e commit 9b248e7

1 file changed

Lines changed: 239 additions & 0 deletions

File tree

.vortex/installer/plan.md

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
# Plan: Refactor Unit Tests to Use EnvTrait for Environment Variable Management
2+
3+
## Problem Statement
4+
5+
Some unit tests use `putenv()` directly instead of `EnvTrait` methods. This bypasses automatic environment variable cleanup, causing environment variables to leak between tests and pollute child processes spawned by `#[RunInSeparateProcess]`.
6+
7+
## Root Cause
8+
9+
- Unit tests run in the main PHPUnit process
10+
- Child processes (spawned by `#[RunInSeparateProcess]`) inherit the parent's environment
11+
- Tests that use raw `putenv()` don't get automatic cleanup via `EnvTrait`
12+
- If a test fails before its manual cleanup code runs, env vars leak
13+
14+
## Solution
15+
16+
Add `EnvTrait` to `UnitTestCase` base class so all unit tests automatically get:
17+
- `envSet($name, $value)` - sets env var and tracks for cleanup
18+
- `envUnset($name)` - unsets env var
19+
- Automatic cleanup in `tearDown()` even if test fails
20+
21+
## Implementation Steps
22+
23+
### Step 1: Add EnvTrait to UnitTestCase
24+
25+
**File:** `.vortex/installer/tests/Unit/UnitTestCase.php`
26+
27+
Add the import and trait usage:
28+
29+
```php
30+
use AlexSkrypnyk\PhpunitHelpers\Traits\EnvTrait;
31+
32+
abstract class UnitTestCase extends UpstreamUnitTestCase {
33+
use SerializableClosureTrait;
34+
use DirectoryAssertionsTrait;
35+
use FileAssertionsTrait;
36+
use EnvTrait; // Add this
37+
```
38+
39+
### Step 2: Update ConfigTest.php
40+
41+
**File:** `.vortex/installer/tests/Unit/ConfigTest.php`
42+
43+
Replace `putenv()` calls in setUp():
44+
```php
45+
// Before
46+
foreach ($constants as $constant) {
47+
unset($_ENV[$constant]);
48+
if (getenv($constant) !== FALSE) {
49+
putenv($constant);
50+
}
51+
}
52+
53+
// After
54+
foreach ($constants as $constant) {
55+
unset($_ENV[$constant]);
56+
static::envUnset($constant);
57+
}
58+
```
59+
60+
Replace `putenv()` calls in test methods:
61+
- `testSetWithEnvironmentVariable()`: Replace `putenv($env_key . '=' . $env_value)` with `static::envSet($env_key, $env_value)` and remove manual cleanup
62+
- `testSetSkipEnvironment()`: Same as above
63+
- `testEnvironmentVariablePrecedenceInConstructor()`: Replace `putenv(Config::ROOT . '=/env/root')` etc. with `static::envSet(Config::ROOT, '/env/root')` and remove manual cleanup
64+
65+
### Step 3: Update TuiTest.php
66+
67+
**File:** `.vortex/installer/tests/Unit/TuiTest.php`
68+
69+
Update `testBox()`:
70+
```php
71+
// Before
72+
$original_columns = getenv('COLUMNS');
73+
try {
74+
if ($terminal_width !== NULL) {
75+
putenv('COLUMNS=' . $terminal_width);
76+
}
77+
// ... test code ...
78+
} finally {
79+
// Restore environment.
80+
if ($original_columns !== FALSE) {
81+
putenv('COLUMNS=' . $original_columns);
82+
} else {
83+
putenv('COLUMNS');
84+
}
85+
}
86+
87+
// After (no try/finally needed)
88+
if ($terminal_width !== NULL) {
89+
static::envSet('COLUMNS', (string) $terminal_width);
90+
}
91+
// ... test code ...
92+
```
93+
94+
Update `testUtfPadding()`:
95+
```php
96+
// Before
97+
$original_terminal_emulator = getenv('TERMINAL_EMULATOR');
98+
$original_term_program = getenv('TERM_PROGRAM');
99+
try {
100+
if ($terminal_emulator !== NULL) {
101+
putenv('TERMINAL_EMULATOR=' . $terminal_emulator);
102+
} else {
103+
putenv('TERMINAL_EMULATOR');
104+
}
105+
// ... similar for TERM_PROGRAM ...
106+
} finally {
107+
// restore logic
108+
}
109+
110+
// After
111+
if ($terminal_emulator !== NULL) {
112+
static::envSet('TERMINAL_EMULATOR', $terminal_emulator);
113+
} else {
114+
static::envUnset('TERMINAL_EMULATOR');
115+
}
116+
if ($term_program !== NULL) {
117+
static::envSet('TERM_PROGRAM', $term_program);
118+
} else {
119+
static::envUnset('TERM_PROGRAM');
120+
}
121+
// ... test code (no finally block needed) ...
122+
```
123+
124+
### Step 4: Update EnvTest.php
125+
126+
**File:** `.vortex/installer/tests/Unit/EnvTest.php`
127+
128+
Update `testGet()`:
129+
```php
130+
// Before
131+
putenv(sprintf('%s=%s', $name, $expected));
132+
$this->assertSame($expected, Env::get($name, $default));
133+
putenv($name);
134+
135+
// After
136+
static::envSet($name, $expected);
137+
$this->assertSame($expected, Env::get($name, $default));
138+
```
139+
140+
Update `testGetFromDotenv()`:
141+
```php
142+
// Before
143+
putenv(sprintf('%s=%s', $name, $expected));
144+
// ...
145+
putenv($name);
146+
147+
// After
148+
if ($expected !== NULL) {
149+
static::envSet($name, $expected);
150+
} else {
151+
static::envUnset($name);
152+
}
153+
// ... (no manual cleanup needed)
154+
```
155+
156+
Update `testPutFromDotenv()`:
157+
```php
158+
// Before
159+
if ($value) {
160+
putenv(sprintf('%s=%s', $name, $value));
161+
// ...
162+
}
163+
164+
// After
165+
if ($value) {
166+
static::envSet($name, $value);
167+
// ...
168+
}
169+
```
170+
171+
Update `testPut()`:
172+
```php
173+
// Before
174+
Env::put($name, $value);
175+
$this->assertEquals($value, getenv($name));
176+
putenv($name);
177+
178+
// After
179+
Env::put($name, $value);
180+
$this->assertEquals($value, getenv($name));
181+
// Note: Env::put() uses native putenv(), track it for cleanup
182+
static::envUnset($name);
183+
```
184+
185+
Update `testGetFromDotenvReturnsParsedValue()`:
186+
```php
187+
// Before
188+
if (getenv('TEST_VAR') !== FALSE) {
189+
putenv('TEST_VAR');
190+
}
191+
192+
// After
193+
static::envUnset('TEST_VAR');
194+
```
195+
196+
### Step 5: Update DownloaderTest.php
197+
198+
**File:** `.vortex/installer/tests/Unit/Downloader/DownloaderTest.php`
199+
200+
Update `testDiscoverLatestReleaseRemoteWithGithubToken()`:
201+
```php
202+
// Before
203+
putenv('GITHUB_TOKEN=test_token_12345');
204+
// ... test code ...
205+
putenv('GITHUB_TOKEN');
206+
207+
// After
208+
static::envSet('GITHUB_TOKEN', 'test_token_12345');
209+
// ... test code (no manual cleanup needed) ...
210+
```
211+
212+
Update `testDownloadArchiveWithGithubToken()`:
213+
```php
214+
// Before
215+
putenv('GITHUB_TOKEN=test_token_67890');
216+
// ... test code ...
217+
putenv('GITHUB_TOKEN');
218+
219+
// After
220+
static::envSet('GITHUB_TOKEN', 'test_token_67890');
221+
// ... test code (no manual cleanup needed) ...
222+
```
223+
224+
## Verification
225+
226+
After making changes, run all unit tests:
227+
228+
```bash
229+
cd .vortex/installer
230+
./vendor/bin/phpunit tests/Unit --no-coverage
231+
```
232+
233+
All 1037 tests should pass.
234+
235+
## Notes
236+
237+
- The `EnvTrait` automatically tracks all env vars set via `envSet()` and cleans them up in `tearDown()`
238+
- This cleanup happens even if a test fails, preventing env var leakage
239+
- The trait also provides `envUnsetPrefix($prefix)` for bulk cleanup (already used in functional tests)

0 commit comments

Comments
 (0)