Skip to content

Commit

Permalink
Test enum CLI
Browse files Browse the repository at this point in the history
  • Loading branch information
cerbero90 committed Jan 8, 2025
1 parent 42a31c9 commit bb4fdda
Show file tree
Hide file tree
Showing 17 changed files with 457 additions and 0 deletions.
13 changes: 13 additions & 0 deletions tests/Enums/Unloaded/NoTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace Cerbero\Enum\Enums\Unloaded;

/**
* The testing enum with no trait.
*/
enum NoTrait
{
// code
}
40 changes: 40 additions & 0 deletions tests/Feature/EnumAnnotateTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

use Cerbero\Enum\Enums;

it('warns that no enums were annotated if invalid enums are provided', function() {
expect(runEnum('annotate InvalidEnum'))
->output->toContain('No enums to annotate.')
->status->toBe(0);
});

it('warns that no enums were annotated if no enums can be found', function() {
expect(runEnum('annotate --all'))
->output->toContain('No enums to annotate.')
->status->toBe(0);
});

it('displays an error message when it fails', function() {
expect(runEnum('annotate "Cerbero\Enum\Enums\Unloaded\NoTrait"'))
->output->toContain('The enum Cerbero\Enum\Enums\Unloaded\NoTrait must use the trait Cerbero\Enum\Concerns\Enumerates')
->status->toBe(1);
});

it('annotates all the discoverable enums', function() {
Enums::setBasePath(__DIR__ . '/../Skeleton');
Enums::setPaths('app/Enums', 'domain/*/Enums');

expect($namespaces = [...Enums::namespaces()])->toBe([
App\Enums\Enum1::class,
App\Enums\Enum2::class,
Domain\Common\Enums\Enum3::class,
Domain\Payouts\Enums\Enum4::class,
]);

$enums = array_map(fn($namespace) => "\"{$namespace}\"", $namespaces);

expect(fn() => runEnum('annotate ' . implode(' ', $enums)))->toAnnotate($namespaces);

(fn() => self::$paths = [])->bindTo(null, Enums::class)();
(fn() => self::$basePath = null)->bindTo(null, Enums::class)();
});
25 changes: 25 additions & 0 deletions tests/Integration/AnnotatorTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

use Cerbero\Enum\Services\Annotator;

it('fails if the main trait is not used', function() {
(new Annotator(Cerbero\Enum\Enums\Unloaded\NoTrait::class))->annotate();
})->throws('The enum Cerbero\Enum\Enums\Unloaded\NoTrait must use the trait Cerbero\Enum\Concerns\Enumerates');

it('annotates enums', function(string $enum) {
expect(fn() => (new Annotator($enum))->annotate())->toAnnotate([$enum]);
})->with([
App\Enums\Enum1::class,
App\Enums\Enum2::class,
Domain\Common\Enums\Enum3::class,
Domain\Payouts\Enums\Enum4::class,
]);

it('annotates enums overwriting existing annotations', function(string $enum) {
expect(fn() => (new Annotator($enum))->annotate(overwrite: true))->toAnnotate([$enum], true);
})->with([
App\Enums\Enum1::class,
App\Enums\Enum2::class,
Domain\Common\Enums\Enum3::class,
Domain\Payouts\Enums\Enum4::class,
]);
86 changes: 86 additions & 0 deletions tests/Pest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?php

/*
|--------------------------------------------------------------------------
| Test Case
|--------------------------------------------------------------------------
|
| The closure you provide to your test functions is always bound to a specific PHPUnit test
| case class. By default, that class is "PHPUnit\Framework\TestCase". Of course, you may
| need to change it using the "uses()" function to bind a different classes or traits.
|
*/

// uses(Tests\TestCase::class)->in('Feature');

/*
|--------------------------------------------------------------------------
| Expectations
|--------------------------------------------------------------------------
|
| When you're writing tests, you often need to check that values meet certain conditions. The
| "expect()" function gives you access to a set of "expectations" methods that you can use
| to assert different things. Of course, you may extend the Expectation API at any time.
|
*/

expect()->extend('toAnnotate', function (array $enums, bool $overwrite = false) {
$oldContents = [];

foreach ($enums as $enum) {
$filename = (new ReflectionEnum($enum))->getFileName();

$oldContents[$filename] = file_get_contents($filename);
}

try {
if (is_bool($value = ($this->value)())) {
expect($value)->toBeTrue();
} else {
expect($value)
->output->toContain(...$enums)
->status->toBe(0);
}

foreach ($oldContents as $filename => $oldContent) {
$stub = __DIR__ . '/stubs/' . basename($filename, '.php') . '.stub';

if ($overwrite && file_exists($path = __DIR__ . '/stubs/' . basename($filename, '.php') . '.force.stub')) {
$stub = $path;
}

expect(file_get_contents($filename))->toBe(file_get_contents($stub));
}
} finally {
foreach ($oldContents as $filename => $oldContent) {
file_put_contents($filename, $oldContent);
}
}
});

/*
|--------------------------------------------------------------------------
| Functions
|--------------------------------------------------------------------------
|
| While Pest is very powerful out-of-the-box, you may have some testing code specific to your
| project that you don't want to repeat in every file. Here you can also expose helpers as
| global functions to help you to reduce the number of lines of code in your test files.
|
*/

/**
* Retrieve the outcome of the given enum console command.
*
* @return object{output: string, status: int}
*/
function runEnum(string $command): stdClass
{
ob_start();

passthru(__DIR__ . "/../bin/enum {$command} 2>&1", $status);

$output = ob_get_clean();

return (object) compact('output', 'status');
}
23 changes: 23 additions & 0 deletions tests/Skeleton/app/Enums/Enum1.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace App\Enums;

use Cerbero\Enum\Attributes\Meta;
use Cerbero\Enum\Concerns\Enumerates;

#[Meta(next: null, isEven: false, alias: null)]
enum Enum1: int
{
use Enumerates;

#[Meta(next: 2, float: 1.0)]
case One = 1;

#[Meta(next: 3, isEven: true, float: 2.0)]
case Two = 2;

#[Meta(float: 3.0, alias: 'III')]
case Three = 3;
}
15 changes: 15 additions & 0 deletions tests/Skeleton/app/Enums/Enum2.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace App\Enums;

use Cerbero\Enum\Concerns\Enumerates;

/**
* The enum 2.
*/
enum Enum2
{
use Enumerates;
}
13 changes: 13 additions & 0 deletions tests/Skeleton/app/Enums/IgnoredClass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace App\Enums;

/**
* The class that should not be auto-discovered: only enums should be discovered.
*/
class IgnoredClass
{
// code
}
8 changes: 8 additions & 0 deletions tests/Skeleton/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"autoload": {
"psr-4": {
"App\\": "app/",
"Domain\\": "domain/"
}
}
}
28 changes: 28 additions & 0 deletions tests/Skeleton/domain/Common/Enums/Enum3.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace Domain\Common\Enums;

use Cerbero\Enum\Attributes\Meta;
use Cerbero\Enum\Concerns\Enumerates;

/**
* The enum 3.
*
* @method static list<string> names()
*/
#[Meta(next: null, isEven: false, alias: null)]
enum Enum3: string
{
use Enumerates;

#[Meta(next: 'next is 2', float: 1.0)]
case One = 'number 1';

#[Meta(next: 'next is 3', isEven: true, float: 2.0)]
case Two = 'number 2';

#[Meta(float: 3.0, alias: 'III')]
case Three = 'number 3';
}
13 changes: 13 additions & 0 deletions tests/Skeleton/domain/Common/Enums/IgnoredClass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace Domain\Common\Enums;

/**
* The class that should not be auto-discovered: only enums should be discovered.
*/
class IgnoredClass
{
// code
}
28 changes: 28 additions & 0 deletions tests/Skeleton/domain/Payouts/Enums/Enum4.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace Domain\Payouts\Enums;

use Cerbero\Enum\Attributes\Meta;
use Cerbero\Enum\Concerns\Enumerates;

/**
* The enum 4.
*
* Secondary description.
*/
#[Meta(next: null, isEven: false, alias: null)]
enum Enum4: int
{
use Enumerates;

#[Meta(next: 2, float: 1.0)]
case One = 1 << 0;

#[Meta(next: 3.0, isEven: true, float: 2.0)]
case Two = 1 << 1;

#[Meta(next: null, float: 3.0, alias: 'III')]
case Three = 1 << 2;
}
13 changes: 13 additions & 0 deletions tests/Skeleton/domain/Payouts/Enums/IgnoredClass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace Domain\Payouts\Enums;

/**
* The class that should not be auto-discovered: only enums should be discovered.
*/
class IgnoredClass
{
// code
}
32 changes: 32 additions & 0 deletions tests/stubs/Enum1.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace App\Enums;

use Cerbero\Enum\Attributes\Meta;
use Cerbero\Enum\Concerns\Enumerates;

/**
* @method static int One()
* @method static int Three()
* @method static int Two()
* @method ?string alias()
* @method float float()
* @method bool isEven()
* @method ?int next()
*/
#[Meta(next: null, isEven: false, alias: null)]
enum Enum1: int
{
use Enumerates;

#[Meta(next: 2, float: 1.0)]
case One = 1;

#[Meta(next: 3, isEven: true, float: 2.0)]
case Two = 2;

#[Meta(float: 3.0, alias: 'III')]
case Three = 3;
}
15 changes: 15 additions & 0 deletions tests/stubs/Enum2.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace App\Enums;

use Cerbero\Enum\Concerns\Enumerates;

/**
* The enum 2.
*/
enum Enum2
{
use Enumerates;
}
Loading

0 comments on commit bb4fdda

Please sign in to comment.