{"id":20684567,"url":"https://github.com/php-forge/support","last_synced_at":"2026-04-17T20:32:36.404Z","repository":{"id":177908249,"uuid":"661073468","full_name":"php-forge/support","owner":"php-forge","description":"Support utilities for enhanced testing capabilities.","archived":false,"fork":false,"pushed_at":"2026-02-19T09:34:20.000Z","size":67,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-04-15T23:11:34.964Z","etag":null,"topics":["helper","phpunit","support","tests"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/php-forge.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["terabytesoftw"]}},"created_at":"2023-07-01T17:49:18.000Z","updated_at":"2026-02-04T00:08:27.000Z","dependencies_parsed_at":"2024-11-16T22:23:18.381Z","dependency_job_id":"87165008-2524-4fac-85b4-b59092568eda","html_url":"https://github.com/php-forge/support","commit_stats":null,"previous_names":["php-forge/support"],"tags_count":5,"template":false,"template_full_name":"yii-tools/template","purl":"pkg:github/php-forge/support","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/php-forge%2Fsupport","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/php-forge%2Fsupport/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/php-forge%2Fsupport/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/php-forge%2Fsupport/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/php-forge","download_url":"https://codeload.github.com/php-forge/support/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/php-forge%2Fsupport/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31945051,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-17T17:29:20.459Z","status":"ssl_error","status_checked_at":"2026-04-17T17:28:47.801Z","response_time":62,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["helper","phpunit","support","tests"],"created_at":"2024-11-16T22:22:54.492Z","updated_at":"2026-04-17T20:32:36.390Z","avatar_url":"https://github.com/php-forge.png","language":"PHP","funding_links":["https://github.com/sponsors/terabytesoftw"],"categories":[],"sub_categories":[],"readme":"\u003c!-- markdownlint-disable MD041 --\u003e\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://github.com/php-forge/support\" target=\"_blank\"\u003e\n        \u003cimg src=\"https://avatars.githubusercontent.com/u/103309199?s%25253D400%252526u%25253Dca3561c692f53ed7eb290d3bb226a2828741606f%252526v%25253D4\" height=\"150px\" alt=\"PHP Forge\"\u003e\n    \u003c/a\u003e\n    \u003ch1 align=\"center\"\u003eSupport\u003c/h1\u003e\n    \u003cbr\u003e\n\u003c/p\u003e\n\u003c!-- markdownlint-enable MD041 --\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://github.com/php-forge/support/actions/workflows/build.yml\" target=\"_blank\"\u003e\n        \u003cimg src=\"https://img.shields.io/github/actions/workflow/status/php-forge/support/build.yml?style=for-the-badge\u0026label=PHPUnit\u0026logo=github\" alt=\"PHPUnit\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://dashboard.stryker-mutator.io/reports/github.com/php-forge/support/main\" target=\"_blank\"\u003e\n        \u003cimg src=\"https://img.shields.io/endpoint?style=for-the-badge\u0026url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2Fphp-forge%2Fsupport%2Fmain\" alt=\"Mutation Testing\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/php-forge/support/actions/workflows/static.yml\" target=\"_blank\"\u003e\n        \u003cimg src=\"https://img.shields.io/github/actions/workflow/status/php-forge/support/static.yml?style=for-the-badge\u0026label=PHPStan\u0026logo=github\" alt=\"PHPStan\"\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003cstrong\u003eSupport utilities for PHPUnit-focused development\u003c/strong\u003e\u003cbr\u003e\n    \u003cem\u003eReflection helpers, line ending normalization, and filesystem cleanup for deterministic tests.\u003c/em\u003e\n\u003c/p\u003e\n\n## Features\n\n\u003cpicture\u003e\n    \u003csource media=\"(min-width: 768px)\" srcset=\"./docs/svgs/features.svg\"\u003e\n    \u003cimg src=\"./docs/svgs/features-mobile.svg\" alt=\"Feature Overview\" style=\"width: 100%;\"\u003e\n\u003c/picture\u003e\n\n### Installation\n\n```bash\ncomposer require php-forge/support:^0.2 --dev\n```\n\n### Quick start\n\nThis package provides helper classes for PHPUnit tests.\n\nIt supports reflection-based access to non-public members, deterministic string comparisons across platforms, and filesystem cleanup for isolated test environments.\n\n#### Accessing private properties\n\n```php\n\u003c?php\n\ndeclare(strict_types=1);\n\nuse PHPForge\\Support\\ReflectionHelper;\nuse PHPUnit\\Framework\\TestCase;\n\nfinal class AccessPrivatePropertyTest extends TestCase\n{\n\n    public function testInaccessibleProperty(): void\n    {\n        $object = new class () {\n            private string $secretValue = 'hidden';\n        };\n\n        $value = ReflectionHelper::inaccessibleProperty($object, 'secretValue');\n\n        self::assertSame('hidden', $value);\n    }\n}\n```\n\n#### Invoking protected methods\n\n```php\n\u003c?php\n\ndeclare(strict_types=1);\n\nuse PHPForge\\Support\\ReflectionHelper;\nuse PHPUnit\\Framework\\TestCase;\n\nfinal class InvokeProtectedMethodTest extends TestCase\n{\n\n    public function testInvokeMethod(): void\n    {\n        $object = new class () {\n            protected function calculate(int $a, int $b): int\n            {\n                return $a + $b;\n            }\n        };\n\n        $result = ReflectionHelper::invokeMethod($object, 'calculate', [5, 3]);\n\n        self::assertSame(8, $result);\n    }\n}\n```\n\n#### Normalize line endings\n\n```php\n\u003c?php\n\ndeclare(strict_types=1);\n\nuse PHPForge\\Support\\LineEndingNormalizer;\nuse PHPUnit\\Framework\\TestCase;\n\nfinal class NormalizeLineEndingsTest extends TestCase\n{\n\n    public function testNormalizedComparison(): void\n    {\n        self::assertSame(\n            LineEndingNormalizer::normalize(\"Foo\\r\\nBar\"),\n            LineEndingNormalizer::normalize(\"Foo\\nBar\"),\n        );\n    }\n}\n```\n\n#### Remove files from directory\n\n```php\n\u003c?php\n\ndeclare(strict_types=1);\n\nuse PHPForge\\Support\\DirectoryCleaner;\nuse PHPUnit\\Framework\\TestCase;\n\nfinal class RemoveFilesFromDirectoryTest extends TestCase\n{\n\n    public function testCleanup(): void\n    {\n        $testDir = sys_get_temp_dir() . '/php-forge-support-' . bin2hex(random_bytes(8));\n        mkdir($testDir);\n\n        try {\n            file_put_contents($testDir . '/artifact.txt', 'test');\n            file_put_contents($testDir . '/.gitignore', \"*\\n\");\n\n            DirectoryCleaner::clean($testDir);\n\n            self::assertFileDoesNotExist($testDir . '/artifact.txt');\n            self::assertFileExists($testDir . '/.gitignore');\n        } finally {\n            @unlink($testDir . '/.gitignore');\n            @rmdir($testDir);\n        }\n    }\n}\n```\n\n#### Set inaccessible property\n\n```php\n\u003c?php\n\ndeclare(strict_types=1);\n\nuse PHPForge\\Support\\ReflectionHelper;\nuse PHPUnit\\Framework\\TestCase;\n\nfinal class SetInaccessiblePropertyTest extends TestCase\n{\n\n    public function testSetProperty(): void\n    {\n        $object = new class () {\n            private string $config = 'default';\n        };\n\n        ReflectionHelper::setInaccessibleProperty($object, 'config', 'test-mode');\n\n        $newValue = ReflectionHelper::inaccessibleProperty($object, 'config');\n\n        self::assertSame('test-mode', $newValue);\n    }\n}\n```\n\n#### Enum data provider\n\nUse `PHPForge\\Support\\EnumDataProvider` to build deterministic datasets from `UnitEnum::cases()` and normalized enum values.\n\n##### Attribute fragment output (HTML)\n\n```php\n\u003c?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Tests;\n\nuse PHPForge\\Support\\EnumDataProvider;\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse UnitEnum;\n\nenum Size\n{\n    case Small;\n    case Large;\n}\n\nfinal class EnumDataProviderHtmlTest extends TestCase\n{\n    public static function provideEnumAttributes(): array\n    {\n        return EnumDataProvider::attributeCases(Size::class, 'data-size', true);\n    }\n\n    #[DataProvider('provideEnumAttributes')]\n    public function testBuildsAttributeFragment(UnitEnum $case, array $args, string $expected, string $message): void\n    {\n        $normalized = $case-\u003ename;\n        $attributeFragment = \" data-size=\\\"{$normalized}\\\"\";\n\n        self::assertSame($expected, $attributeFragment, $message);\n    }\n}\n```\n\n##### Enum instance output (non-HTML)\n\n```php\n\u003c?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Tests;\n\nuse PHPForge\\Support\\EnumDataProvider;\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\nuse UnitEnum;\n\nenum State\n{\n    case Active;\n    case Disabled;\n}\n\nfinal class EnumDataProviderEnumTest extends TestCase\n{\n    public static function provideEnumInstances(): array\n    {\n        return EnumDataProvider::attributeCases(State::class, 'state', false);\n    }\n\n    #[DataProvider('provideEnumInstances')]\n    public function testReturnsEnumInstance(UnitEnum $case, array $args, UnitEnum $expected, string $message): void\n    {\n        self::assertSame($case, $expected, $message);\n    }\n}\n```\n\n##### Tag cases\n\n```php\n\u003c?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Tests;\n\nuse PHPForge\\Support\\EnumDataProvider;\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse PHPUnit\\Framework\\TestCase;\n\nenum Heading\n{\n    case H1;\n    case H2;\n}\n\nfinal class EnumDataProviderTagCasesTest extends TestCase\n{\n    public static function provideTags(): array\n    {\n        return EnumDataProvider::tagCases(Heading::class, 'heading');\n    }\n\n    #[DataProvider('provideTags')]\n    public function testProvidesNormalizedTag(Heading $case, string $normalized): void\n    {\n        self::assertSame($case-\u003ename, $normalized);\n    }\n}\n```\n\n## Documentation\n\nFor detailed configuration options and advanced usage.\n\n- 🧪 [Testing Guide](docs/testing.md)\n- 🛠️ [Development Guide](docs/development.md)\n\n## Package information\n\n[![PHP](https://img.shields.io/badge/%3E%3D8.1-777BB4.svg?style=for-the-badge\u0026logo=php\u0026logoColor=white)](https://www.php.net/releases/8.1/en.php)\n[![Latest Stable Version](https://img.shields.io/packagist/v/php-forge/support.svg?style=for-the-badge\u0026logo=packagist\u0026logoColor=white\u0026label=Stable)](https://packagist.org/packages/php-forge/support)\n[![Total Downloads](https://img.shields.io/packagist/dt/php-forge/support.svg?style=for-the-badge\u0026logo=composer\u0026logoColor=white\u0026label=Downloads)](https://packagist.org/packages/php-forge/support)\n\n## Quality code\n\n[![Codecov](https://img.shields.io/codecov/c/github/php-forge/support.svg?style=for-the-badge\u0026logo=codecov\u0026logoColor=white\u0026label=Coverage)](https://codecov.io/github/php-forge/support)\n[![PHPStan Level Max](https://img.shields.io/badge/PHPStan-Level%20Max-4F5D95.svg?style=for-the-badge\u0026logo=github\u0026logoColor=white)](https://github.com/php-forge/support/actions/workflows/static.yml)\n[![Super-Linter](https://img.shields.io/github/actions/workflow/status/php-forge/support/linter.yml?style=for-the-badge\u0026label=Super-Linter\u0026logo=github)](https://github.com/php-forge/support/actions/workflows/linter.yml)\n[![StyleCI](https://img.shields.io/badge/StyleCI-Passed-44CC11.svg?style=for-the-badge\u0026logo=github\u0026logoColor=white)](https://github.styleci.io/repos/779611775?branch=main)\n\n## Our social networks\n\n[![Follow on X](https://img.shields.io/badge/-Follow%20on%20X-1DA1F2.svg?style=for-the-badge\u0026logo=x\u0026logoColor=white\u0026labelColor=000000)](https://x.com/Terabytesoftw)\n\n## License\n\n[![License](https://img.shields.io/badge/License-BSD--3--Clause-brightgreen.svg?style=for-the-badge\u0026logo=opensourceinitiative\u0026logoColor=white\u0026labelColor=555555)](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphp-forge%2Fsupport","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphp-forge%2Fsupport","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphp-forge%2Fsupport/lists"}