diff --git a/.gitignore b/.gitignore index 629afb2..9b96323 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,4 @@ composer.lock *.swp *.swo *~ - +/.phpunit.cache/ \ No newline at end of file diff --git a/README.md b/README.md index 4dd4172..dfa4ee5 100644 --- a/README.md +++ b/README.md @@ -70,9 +70,12 @@ Some ideas for future classes: ## Development -This project uses PHP CodeSniffer with PSR-12 standard for code quality. +This project uses PHP CodeSniffer with PSR-12 standard for code quality and PHPUnit for testing. ```bash +# Run tests +composer test + # Check code style composer check @@ -80,6 +83,7 @@ composer check composer fix # Or use vendor binaries directly +vendor/bin/phpunit vendor/bin/phpcs --standard=PSR12 src/ vendor/bin/phpcbf --standard=PSR12 src/ ``` diff --git a/composer.json b/composer.json index 03d8793..f7f8343 100644 --- a/composer.json +++ b/composer.json @@ -7,16 +7,23 @@ "php": "^8.1" }, "require-dev": { - "squizlabs/php_codesniffer": "^4.0" + "squizlabs/php_codesniffer": "^4.0", + "phpunit/phpunit": "^10.0" }, "autoload": { "psr-4": { "Calvert\\DndErrors\\": "src/" } }, + "autoload-dev": { + "psr-4": { + "Calvert\\DndErrors\\Tests\\": "tests/" + } + }, "scripts": { "check": "phpcs --standard=PSR12 src/", - "fix": "phpcbf --standard=PSR12 src/" + "fix": "phpcbf --standard=PSR12 src/", + "test": "phpunit" }, "minimum-stability": "stable" } diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..b9b83be --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,24 @@ + + + + + tests + + + + + src + + + + diff --git a/tests/Archetype/PaladinTest.php b/tests/Archetype/PaladinTest.php new file mode 100644 index 0000000..ab6f31f --- /dev/null +++ b/tests/Archetype/PaladinTest.php @@ -0,0 +1,93 @@ +paladin = new Paladin(); + } + + public function testGetSlugReturnsPaladin(): void + { + $this->assertSame('paladin', $this->paladin->getSlug()); + } + + public function testRenderContainsMessage(): void + { + $context = new ErrorContext( + type: 'Error', + message: 'Test error message', + file: '/path/to/file.php', + line: 42 + ); + + $output = $this->paladin->render($context); + + $this->assertStringContainsString('Test error message', $output); + $this->assertStringContainsString('/path/to/file.php:42', $output); + } + + public function testRenderContainsPaladinEmoji(): void + { + $context = new ErrorContext( + type: 'Error', + message: 'Test error', + ); + + $output = $this->paladin->render($context); + + // Should contain paladin emoji (✨ or ⚔️) + $this->assertTrue( + str_contains($output, '✨') || str_contains($output, '⚔️'), + 'Output should contain paladin emoji' + ); + } + + public function testRenderIncludesLocationWhenProvided(): void + { + $context = new ErrorContext( + type: 'Error', + message: 'Test error', + file: 'test.php', + line: 10 + ); + + $output = $this->paladin->render($context); + + $this->assertStringContainsString('test.php:10', $output); + } + + public function testRenderShowsUnknownLocationWhenFileOrLineMissing(): void + { + $context = new ErrorContext( + type: 'Error', + message: 'Test error', + ); + + $output = $this->paladin->render($context); + + $this->assertStringContainsString('Unknown location', $output); + } + + public function testRenderForFatalError(): void + { + $context = new ErrorContext( + type: 'fatal', + message: 'Fatal error occurred', + ); + + $output = $this->paladin->render($context); + + // Fatal errors should have special headers + $this->assertStringContainsString('Fatal error occurred', $output); + } +} + diff --git a/tests/Archetype/RangerTest.php b/tests/Archetype/RangerTest.php new file mode 100644 index 0000000..39954fc --- /dev/null +++ b/tests/Archetype/RangerTest.php @@ -0,0 +1,51 @@ +ranger = new Ranger(); + } + + public function testGetSlugReturnsRanger(): void + { + $this->assertSame('ranger', $this->ranger->getSlug()); + } + + public function testRenderContainsMessage(): void + { + $context = new ErrorContext( + type: 'Error', + message: 'Trail lost', + file: '/forest/path.php', + line: 15 + ); + + $output = $this->ranger->render($context); + + $this->assertStringContainsString('Trail lost', $output); + $this->assertStringContainsString('/forest/path.php:15', $output); + } + + public function testRenderContainsRangerEmoji(): void + { + $context = new ErrorContext( + type: 'Error', + message: 'Test error', + ); + + $output = $this->ranger->render($context); + + // Should contain ranger emoji 🏹 + $this->assertStringContainsString('🏹', $output); + } +} + diff --git a/tests/Archetype/WizardTest.php b/tests/Archetype/WizardTest.php new file mode 100644 index 0000000..bdf4ff0 --- /dev/null +++ b/tests/Archetype/WizardTest.php @@ -0,0 +1,51 @@ +wizard = new Wizard(); + } + + public function testGetSlugReturnsWizard(): void + { + $this->assertSame('wizard', $this->wizard->getSlug()); + } + + public function testRenderContainsMessage(): void + { + $context = new ErrorContext( + type: 'Error', + message: 'Arcane failure', + file: '/spellbook/incantation.php', + line: 7 + ); + + $output = $this->wizard->render($context); + + $this->assertStringContainsString('Arcane failure', $output); + $this->assertStringContainsString('/spellbook/incantation.php:7', $output); + } + + public function testRenderContainsWizardEmoji(): void + { + $context = new ErrorContext( + type: 'Error', + message: 'Test error', + ); + + $output = $this->wizard->render($context); + + // Should contain wizard emoji 🧙 + $this->assertStringContainsString('🧙', $output); + } +} + diff --git a/tests/ErrorContextTest.php b/tests/ErrorContextTest.php new file mode 100644 index 0000000..e1b7a42 --- /dev/null +++ b/tests/ErrorContextTest.php @@ -0,0 +1,44 @@ + 'data'), + phpVersion: '8.1.0' + ); + + $this->assertSame('RuntimeException', $context->type); + $this->assertSame('Test error message', $context->message); + $this->assertSame('/path/to/file.php', $context->file); + $this->assertSame(42, $context->line); + $this->assertSame(array('trace' => 'data'), $context->trace); + $this->assertSame('8.1.0', $context->phpVersion); + } + + public function testCanCreateErrorContextWithMinimalProperties(): void + { + $context = new ErrorContext( + type: 'Error', + message: 'Test message' + ); + + $this->assertSame('Error', $context->type); + $this->assertSame('Test message', $context->message); + $this->assertNull($context->file); + $this->assertNull($context->line); + $this->assertSame(array(), $context->trace); + $this->assertNull($context->phpVersion); + } +} +