Skip to content

Commit d829f7b

Browse files
feat(tests): Add TestSupport trait and corresponding test suite for inaccessible properties and methods. (#12)
1 parent b5613ed commit d829f7b

File tree

5 files changed

+146
-112
lines changed

5 files changed

+146
-112
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
Change Log
22
==========
33

4-
## 0.1.1 August 18, 2025
4+
## 0.2.0 August 18, 2025
55

66
- Bug #11: Refactor project structure and update dependencies (@terabytesoftw)
7+
- Enh #12: Add `TestSupport` trait and corresponding test suite for inaccessible properties and methods (@terabytesoftw)
78

89
## 0.1.0 January 21, 2024
910

README.md

Lines changed: 85 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
- Invoke inaccessible methods to expand testing coverage.
2929

3030
**Cross-Platform String Assertions**
31-
- Eliminate false positives/negatives caused by Windows vs. Unix line-ending differences.
31+
- Avoid false positives and negatives caused by Windows vs. Unix line ending differences.
3232
- Normalize line endings for consistent string comparisons across platforms.
3333

3434
**File System Test Management**
@@ -50,7 +50,7 @@
5050
Install the extension.
5151

5252
```bash
53-
composer require --dev --prefer-dist php-forge/support:^0.1
53+
composer require --dev --prefer-dist php-forge/support:^0.2
5454
```
5555

5656
#### Method 2: Manual installation
@@ -60,7 +60,7 @@ Add to your `composer.json`.
6060
```json
6161
{
6262
"require-dev": {
63-
"php-forge/support": "^0.1"
63+
"php-forge/support": "^0.2"
6464
}
6565
}
6666
```
@@ -77,94 +77,133 @@ composer update
7777

7878
```php
7979
<?php
80-
8180
declare(strict_types=1);
8281

83-
use PHPForge\Support\Assert;
82+
use PHPForge\Support\TestSupport;
83+
use PHPUnit\Framework\TestCase;
8484

85-
$object = new class () {
86-
private string $secretValue = 'hidden';
87-
};
85+
final class AccessPrivatePropertyTest extends TestCase
86+
{
87+
use TestSupport;
8888

89-
// access private properties for testing
90-
$value = Assert::inaccessibleProperty($object, 'secretValue');
89+
public function testInaccessibleProperty(): void
90+
{
91+
$object = new class () {
92+
private string $secretValue = 'hidden';
93+
};
9194

92-
self::assertSame('hidden', $value);
95+
$value = self::inaccessibleProperty($object, 'secretValue');
96+
97+
self::assertSame('hidden', $value, "Should access the private property and return its value.");
98+
}
99+
}
93100
```
94101

95-
### Equals without line ending
102+
### Invoking protected methods
96103

97104
```php
98105
<?php
99-
100106
declare(strict_types=1);
101107

102-
use PHPForge\Support\Assert;
108+
use PHPForge\Support\TestSupport;
109+
use PHPUnit\Framework\TestCase;
110+
111+
final class InvokeProtectedMethodTest extends TestCase
112+
{
113+
use TestSupport;
114+
115+
public function testInvokeMethod(): void
116+
{
117+
$object = new class () {
118+
protected function calculate(int $a, int $b): int
119+
{
120+
return $a + $b;
121+
}
122+
};
103123

104-
// normalize line endings for consistent comparisons
105-
Assert::equalsWithoutLE(
106-
"Foo\r\nBar",
107-
"Foo\nBar",
108-
"Should match regardless of line ending style"
109-
);
124+
$result = self::invokeMethod($object, 'calculate', [5, 3]);
125+
126+
self::assertSame(8, $result, "Should invoke the protected method and return the correct sum.");
127+
}
128+
}
110129
```
111130

112-
### Invoking protected methods
131+
### Normalize line endings
113132

114133
```php
115134
<?php
116-
117135
declare(strict_types=1);
118136

119-
use PHPForge\Support\Assert;
137+
use PHPForge\Support\TestSupport;
138+
use PHPUnit\Framework\TestCase;
120139

121-
$object = new class () {
122-
protected function calculate(int $a, int $b): int
140+
final class NormalizeLineEndingsTest extends TestCase
141+
{
142+
use TestSupport;
143+
144+
public function testNormalizedComparison(): void
123145
{
124-
return $a + $b;
146+
self::assertSame(
147+
self::normalizeLineEndings("Foo\r\nBar"),
148+
self::normalizeLineEndings("Foo\nBar"),
149+
"Should match regardless of line ending style",
150+
);
125151
}
126-
};
127-
128-
// test protected method behavior
129-
$result = Assert::invokeMethod($object, 'calculate', [5, 3]);
130-
131-
self::assertSame(8, $result);
152+
}
132153
```
133154

134155
### Remove files from directory
135156

136157
```php
137158
<?php
138-
139159
declare(strict_types=1);
140160

141-
use PHPForge\Support\Assert;
161+
use PHPForge\Support\TestSupport;
162+
use PHPUnit\Framework\TestCase;
163+
164+
final class RemoveFilesFromDirectoryTest extends TestCase
165+
{
166+
use TestSupport;
167+
168+
public function testCleanup(): void
169+
{
170+
$testDir = dirname(__DIR__) . '/runtime';
171+
// clean up test artifacts (preserves '.gitignore' and '.gitkeep')
142172

143-
$testDir = dirname(__DIR__) . '/runtime';
173+
self::removeFilesFromDirectory($testDir);
144174

145-
// clean up test artifacts (preserves '.gitignore' and '.gitkeep')
146-
Assert::removeFilesFromDirectory($testDir);
175+
self::assertTrue(true, "Should remove all files in the test directory while preserving Git-tracked files.");
176+
}
177+
}
147178
```
148179

149180
### Set inaccessible property
150181

151182
```php
152183
<?php
153-
154184
declare(strict_types=1);
155185

156-
use PHPForge\Support\Assert;
186+
use PHPForge\Support\TestSupport;
187+
use PHPUnit\Framework\TestCase;
188+
189+
final class SetInaccessiblePropertyTest extends TestCase
190+
{
191+
use TestSupport;
157192

158-
$object = new class () {
159-
private string $config = 'default';
160-
};
193+
public function testSetProperty(): void
194+
{
195+
$object = new class () {
196+
private string $config = 'default';
197+
};
161198

162-
// set private property for testing scenarios
163-
Assert::setInaccessibleProperty($object, 'config', 'test-mode');
199+
// set private property for testing scenarios
200+
self::setInaccessibleProperty($object, 'config', 'test-mode');
164201

165-
$newValue = Assert::inaccessibleProperty($object, 'config');
202+
$newValue = self::inaccessibleProperty($object, 'config');
166203

167-
self::assertSame('test-mode', $newValue);
204+
self::assertSame('test-mode', $newValue, "Should set the inaccessible property to 'test-mode'.");
205+
}
206+
}
168207
```
169208

170209
## Documentation

composer.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "php-forge/support",
33
"type": "library",
4-
"description": "Support library tests for PHP",
4+
"description": "Support utilities for enhanced testing capabilities.",
55
"keywords": [
66
"php",
77
"php-forge",
@@ -11,16 +11,16 @@
1111
],
1212
"license": "BSD-3-Clause",
1313
"require": {
14-
"php": "^8.1",
15-
"phpunit/phpunit": "^10.5"
14+
"php": "^8.1"
1615
},
1716
"require-dev": {
1817
"infection/infection": "^0.27|^0.31",
1918
"maglnet/composer-require-checker": "^4.7",
20-
"phpstan/phpstan-strict-rules": "^2.0.3",
21-
"symplify/easy-coding-standard": "^12.5",
2219
"phpstan/phpstan": "^2.1",
23-
"rector/rector": "^2.1"
20+
"phpstan/phpstan-strict-rules": "^2.0.3",
21+
"phpunit/phpunit": "^10.5",
22+
"rector/rector": "^2.1",
23+
"symplify/easy-coding-standard": "^12.5"
2424
},
2525
"autoload": {
2626
"psr-4": {
@@ -34,7 +34,7 @@
3434
},
3535
"extra": {
3636
"branch-alias": {
37-
"dev-main": "0.1-dev"
37+
"dev-main": "0.3.x-dev"
3838
}
3939
},
4040
"config": {

src/Assert.php renamed to src/TestSupport.php

Lines changed: 25 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -20,46 +20,20 @@
2020
use function unlink;
2121

2222
/**
23-
* Assertion utility class for advanced test introspection and manipulation.
23+
* Trait providing utilities for testing inaccessible properties, methods, and filesystem cleanup.
2424
*
25-
* Provides static helper methods for accessing and modifying inaccessible properties and methods invoking parent class
26-
* logic, and performing file system cleanup in test environments.
25+
* Supplies static helper methods for normalizing line endings, accessing or modifying private/protected properties and
26+
* methods (including those inherited from parent classes), invoking inaccessible methods, and recursively removing
27+
* files from directories.
2728
*
28-
* Extends {@see \PHPUnit\Framework\Assert} to offer additional capabilities for testing private/protected members and
29-
* for managing test artifacts, supporting robust and isolated unit tests.
29+
* These utilities are designed to facilitate comprehensive unit testing by enabling assertions and manipulations that
30+
* would otherwise be restricted by visibility constraints or platform differences.
3031
*
31-
* Key features.
32-
* - Access and modify inaccessible (private/protected) properties and methods via reflection.
33-
* - Invoke parent class methods and properties for testing inheritance scenarios.
34-
* - Normalize line endings for cross-platform string assertions.
35-
* - Remove files and directories recursively for test environment cleanup.
36-
*
37-
* @copyright Copyright (C) 2025 PHPForge.
32+
* @copyright Copyright (C) 2025 Terabytesoftw.
3833
* @license https://opensource.org/license/bsd-3-clause BSD 3-Clause License.
3934
*/
40-
final class Assert extends \PHPUnit\Framework\Assert
35+
trait TestSupport
4136
{
42-
/**
43-
* Asserts that two strings are equal after normalizing line endings to unix style ('\n').
44-
*
45-
* Replaces all windows style ('\r\n') line endings with unix style ('\n') in both the expected and actual strings
46-
* before performing the equality assertion.
47-
*
48-
* This ensures cross-platform consistency in string comparisons where line ending differences may otherwise cause
49-
* `false` negatives.
50-
*
51-
* @param string $expected Expected string value, with any line endings.
52-
* @param string $actual Actual string value, with any line endings.
53-
* @param string $message Optional failure message to display if the assertion fails. Default is an empty string.
54-
*/
55-
public static function equalsWithoutLE(string $expected, string $actual, string $message = ''): void
56-
{
57-
$expected = str_replace("\r\n", "\n", $expected);
58-
$actual = str_replace("\r\n", "\n", $actual);
59-
60-
self::assertEquals($expected, $actual, $message);
61-
}
62-
6337
/**
6438
* Retrieves the value of an inaccessible property from a parent class instance.
6539
*
@@ -185,6 +159,23 @@ public static function invokeParentMethod(
185159
return $result ?? null;
186160
}
187161

162+
/**
163+
* Normalizes line endings to Unix style ('\n') for cross-platform string assertions.
164+
*
165+
* Converts Windows style ('\r\n') line endings to Unix style ('\n') to ensure consistent string comparisons across
166+
* different operating systems during testing.
167+
*
168+
* This method is useful for eliminating false negatives in assertions caused by platform-specific line endings.
169+
*
170+
* @param string $line Input string potentially containing Windows style line endings.
171+
*
172+
* @return string String with normalized Unix style line endings.
173+
*/
174+
public static function normalizeLineEndings(string $line): string
175+
{
176+
return str_replace(["\r\n", "\r"], "\n", $line);
177+
}
178+
188179
/**
189180
* Removes all files and directories recursively from the specified base path, excluding '.gitignore' and
190181
* '.gitkeep'.

0 commit comments

Comments
 (0)