Initial commit after upgrading to php 8.3 and splitting to seperated tool chain

This commit is contained in:
2026-07-18 14:10:59 +02:00
commit df77e19b8d
24 changed files with 6422 additions and 0 deletions
+180
View File
@@ -0,0 +1,180 @@
<?php
declare(strict_types=1);
namespace Tez\Utils\Tests\Enum;
use PHPUnit\Framework\TestCase;
use Tez\Utils\Enum\BackedEnumTrait;
// String-backed enum
enum Color: string
{
use BackedEnumTrait;
case Red = 'red';
case Green = 'green';
case Blue = 'blue';
}
// Integer-backed enum
enum Priority: int
{
use BackedEnumTrait;
case Low = 1;
case Medium = 2;
case High = 3;
}
final class BackedEnumTraitTest extends TestCase
{
// -------------------------------------------------------------------------
// values()
// -------------------------------------------------------------------------
public function testValuesReturnsAllStringValues(): void
{
self::assertSame(['red', 'green', 'blue'], Color::values());
}
public function testValuesReturnsAllIntValues(): void
{
self::assertSame([1, 2, 3], Priority::values());
}
// -------------------------------------------------------------------------
// hasValue()
// -------------------------------------------------------------------------
public function testHasValueReturnsTrueForExistingValue(): void
{
self::assertTrue(Color::hasValue('green'));
self::assertTrue(Priority::hasValue(2));
}
public function testHasValueReturnsFalseForUnknownValue(): void
{
self::assertFalse(Color::hasValue('yellow'));
self::assertFalse(Priority::hasValue(99));
}
public function testHasValueIsStrictlyTyped(): void
{
// integer 1 must not match string '1'
self::assertFalse(Color::hasValue(1));
}
// -------------------------------------------------------------------------
// fromName()
// -------------------------------------------------------------------------
public function testFromNameReturnsCorrectCase(): void
{
self::assertSame(Color::Blue, Color::fromName('Blue'));
self::assertSame(Priority::High, Priority::fromName('High'));
}
public function testFromNameThrowsValueErrorForUnknownName(): void
{
$this->expectException(\ValueError::class);
Color::fromName('Purple');
}
// -------------------------------------------------------------------------
// tryFromName()
// -------------------------------------------------------------------------
public function testTryFromNameReturnsCorrectCase(): void
{
self::assertSame(Color::Red, Color::tryFromName('Red'));
}
public function testTryFromNameReturnsNullForUnknownName(): void
{
self::assertNull(Color::tryFromName('Magenta'));
}
// -------------------------------------------------------------------------
// toArray() — inherited via EnumTrait, but backed path tested here
// -------------------------------------------------------------------------
public function testToArrayReturnsValueToNameMapping(): void
{
self::assertSame(
['red' => 'Red', 'green' => 'Green', 'blue' => 'Blue'],
Color::toArray(),
);
}
public function testToArrayForIntBackedEnum(): void
{
self::assertSame(
[1 => 'Low', 2 => 'Medium', 3 => 'High'],
Priority::toArray(),
);
}
// -------------------------------------------------------------------------
// is() with scalar (backed enum path)
// -------------------------------------------------------------------------
public function testIsReturnsTrueForMatchingValue(): void
{
self::assertTrue(Color::Green->is('green'));
}
public function testIsReturnsFalseForOtherValue(): void
{
self::assertFalse(Color::Green->is('red'));
}
public function testIsReturnsTrueForIntValue(): void
{
self::assertTrue(Priority::Medium->is(2));
}
// -------------------------------------------------------------------------
// find() — backed enum paths (value + case-insensitive)
// -------------------------------------------------------------------------
public function testFindByValue(): void
{
self::assertSame(Color::Blue, Color::find('blue'));
}
public function testFindByValueCaseInsensitive(): void
{
self::assertSame(Color::Red, Color::find('RED', ignoreCase: true));
}
public function testFindByNameCaseInsensitive(): void
{
self::assertSame(Color::Green, Color::find('green', ignoreCase: true));
}
public function testFindReturnsNullForUnknown(): void
{
self::assertNull(Color::find('violet'));
}
// -------------------------------------------------------------------------
// toValueArray()
// -------------------------------------------------------------------------
public function testToValueArrayReturnsNameToValueMapping(): void
{
self::assertSame(
['Red' => 'red', 'Green' => 'green', 'Blue' => 'blue'],
Color::toValueArray(),
);
}
public function testToValueArrayForIntBackedEnum(): void
{
self::assertSame(
['Low' => 1, 'Medium' => 2, 'High' => 3],
Priority::toValueArray(),
);
}
}
+183
View File
@@ -0,0 +1,183 @@
<?php
declare(strict_types=1);
namespace Tez\Utils\Tests\Enum;
use PHPUnit\Framework\TestCase;
use Tez\Utils\Enum\BackedEnumTrait;
use Tez\Utils\Enum\BitFlagTrait;
enum Permission: int
{
use BackedEnumTrait;
use BitFlagTrait;
case Read = 1;
case Write = 2;
case Delete = 4;
case Admin = 8;
}
final class BitFlagTraitTest extends TestCase
{
// -------------------------------------------------------------------------
// combine()
// -------------------------------------------------------------------------
public function testCombineWithNoArgumentsReturnsZero(): void
{
self::assertSame(0, Permission::combine());
}
public function testCombineWithSingleCase(): void
{
self::assertSame(1, Permission::combine(Permission::Read));
}
public function testCombineWithTwoCases(): void
{
self::assertSame(3, Permission::combine(Permission::Read, Permission::Write));
}
public function testCombineWithAllCases(): void
{
self::assertSame(15, Permission::combine(
Permission::Read,
Permission::Write,
Permission::Delete,
Permission::Admin,
));
}
public function testCombineIsDeduplicated(): void
{
self::assertSame(1, Permission::combine(Permission::Read, Permission::Read));
}
// -------------------------------------------------------------------------
// fromBitmask()
// -------------------------------------------------------------------------
public function testFromBitmaskWithZeroReturnsEmptyArray(): void
{
self::assertSame([], Permission::fromBitmask(0));
}
public function testFromBitmaskWithSingleBitReturnsSingleCase(): void
{
self::assertSame([Permission::Read], Permission::fromBitmask(1));
}
public function testFromBitmaskWithCombinedMaskReturnsMatchingCases(): void
{
$mask = Permission::combine(Permission::Read, Permission::Write);
self::assertSame([Permission::Read, Permission::Write], Permission::fromBitmask($mask));
}
public function testFromBitmaskWithAllBitsReturnsAllCases(): void
{
$mask = Permission::combine(
Permission::Read,
Permission::Write,
Permission::Delete,
Permission::Admin,
);
self::assertSame(
[Permission::Read, Permission::Write, Permission::Delete, Permission::Admin],
Permission::fromBitmask($mask),
);
}
// -------------------------------------------------------------------------
// isSetIn()
// -------------------------------------------------------------------------
public function testIsSetInReturnsTrueWhenBitIsPresent(): void
{
$mask = Permission::combine(Permission::Read, Permission::Write);
self::assertTrue(Permission::Read->isSetIn($mask));
self::assertTrue(Permission::Write->isSetIn($mask));
}
public function testIsSetInReturnsFalseWhenBitIsAbsent(): void
{
$mask = Permission::combine(Permission::Read, Permission::Write);
self::assertFalse(Permission::Delete->isSetIn($mask));
self::assertFalse(Permission::Admin->isSetIn($mask));
}
public function testIsSetInReturnsFalseForZeroMask(): void
{
self::assertFalse(Permission::Read->isSetIn(0));
}
// -------------------------------------------------------------------------
// addTo()
// -------------------------------------------------------------------------
public function testAddToSetsBit(): void
{
$mask = Permission::combine(Permission::Read);
$mask = Permission::Write->addTo($mask);
self::assertSame(3, $mask);
self::assertTrue(Permission::Write->isSetIn($mask));
}
public function testAddToIsIdempotent(): void
{
$mask = Permission::combine(Permission::Read);
$mask = Permission::Read->addTo($mask);
self::assertSame(1, $mask);
}
public function testAddToOnEmptyMask(): void
{
self::assertSame(4, Permission::Delete->addTo(0));
}
// -------------------------------------------------------------------------
// removeFrom()
// -------------------------------------------------------------------------
public function testRemoveFromClearsBit(): void
{
$mask = Permission::combine(Permission::Read, Permission::Write);
$mask = Permission::Write->removeFrom($mask);
self::assertSame(1, $mask);
self::assertFalse(Permission::Write->isSetIn($mask));
}
public function testRemoveFromIsIdempotent(): void
{
$mask = Permission::combine(Permission::Read);
$mask = Permission::Write->removeFrom($mask);
self::assertSame(1, $mask);
}
public function testRemoveFromOnZeroMaskReturnsZero(): void
{
self::assertSame(0, Permission::Read->removeFrom(0));
}
// -------------------------------------------------------------------------
// Workflow: add then remove
// -------------------------------------------------------------------------
public function testAddThenRemoveRestoresOriginalMask(): void
{
$original = Permission::combine(Permission::Read, Permission::Delete);
$modified = Permission::Write->addTo($original);
$restored = Permission::Write->removeFrom($modified);
self::assertSame($original, $restored);
}
}
+157
View File
@@ -0,0 +1,157 @@
<?php
declare(strict_types=1);
namespace Tez\Utils\Tests\Enum;
use PHPUnit\Framework\TestCase;
use Tez\Utils\Enum\BackedEnumTrait;
use Tez\Utils\Enum\ComparableTrait;
enum Level: int
{
use BackedEnumTrait;
use ComparableTrait;
case Low = 1;
case Medium = 2;
case High = 3;
case Ultra = 4;
}
final class ComparableTraitTest extends TestCase
{
// -------------------------------------------------------------------------
// isGreaterThan()
// -------------------------------------------------------------------------
public function testIsGreaterThanReturnsTrueWhenHigher(): void
{
self::assertTrue(Level::High->isGreaterThan(Level::Low));
}
public function testIsGreaterThanReturnsFalseWhenEqual(): void
{
self::assertFalse(Level::Medium->isGreaterThan(Level::Medium));
}
public function testIsGreaterThanReturnsFalseWhenLower(): void
{
self::assertFalse(Level::Low->isGreaterThan(Level::High));
}
// -------------------------------------------------------------------------
// isGreaterThanOrEqual()
// -------------------------------------------------------------------------
public function testIsGreaterThanOrEqualReturnsTrueWhenHigher(): void
{
self::assertTrue(Level::High->isGreaterThanOrEqual(Level::Low));
}
public function testIsGreaterThanOrEqualReturnsTrueWhenEqual(): void
{
self::assertTrue(Level::Medium->isGreaterThanOrEqual(Level::Medium));
}
public function testIsGreaterThanOrEqualReturnsFalseWhenLower(): void
{
self::assertFalse(Level::Low->isGreaterThanOrEqual(Level::High));
}
// -------------------------------------------------------------------------
// isLessThan()
// -------------------------------------------------------------------------
public function testIsLessThanReturnsTrueWhenLower(): void
{
self::assertTrue(Level::Low->isLessThan(Level::High));
}
public function testIsLessThanReturnsFalseWhenEqual(): void
{
self::assertFalse(Level::Medium->isLessThan(Level::Medium));
}
public function testIsLessThanReturnsFalseWhenHigher(): void
{
self::assertFalse(Level::High->isLessThan(Level::Low));
}
// -------------------------------------------------------------------------
// isLessThanOrEqual()
// -------------------------------------------------------------------------
public function testIsLessThanOrEqualReturnsTrueWhenLower(): void
{
self::assertTrue(Level::Low->isLessThanOrEqual(Level::High));
}
public function testIsLessThanOrEqualReturnsTrueWhenEqual(): void
{
self::assertTrue(Level::Medium->isLessThanOrEqual(Level::Medium));
}
public function testIsLessThanOrEqualReturnsFalseWhenHigher(): void
{
self::assertFalse(Level::High->isLessThanOrEqual(Level::Low));
}
// -------------------------------------------------------------------------
// between()
// -------------------------------------------------------------------------
public function testBetweenReturnsTrueWhenWithinRange(): void
{
self::assertTrue(Level::Medium->between(Level::Low, Level::High));
}
public function testBetweenReturnsTrueAtLowerBound(): void
{
self::assertTrue(Level::Low->between(Level::Low, Level::High));
}
public function testBetweenReturnsTrueAtUpperBound(): void
{
self::assertTrue(Level::High->between(Level::Low, Level::High));
}
public function testBetweenReturnsFalseWhenBelowRange(): void
{
self::assertFalse(Level::Low->between(Level::Medium, Level::Ultra));
}
public function testBetweenReturnsFalseWhenAboveRange(): void
{
self::assertFalse(Level::Ultra->between(Level::Low, Level::High));
}
// -------------------------------------------------------------------------
// clamp()
// -------------------------------------------------------------------------
public function testClampReturnsValueWhenWithinRange(): void
{
self::assertSame(Level::Medium, Level::Medium->clamp(Level::Low, Level::High));
}
public function testClampReturnsMinWhenBelowRange(): void
{
self::assertSame(Level::Medium, Level::Low->clamp(Level::Medium, Level::Ultra));
}
public function testClampReturnsMaxWhenAboveRange(): void
{
self::assertSame(Level::High, Level::Ultra->clamp(Level::Low, Level::High));
}
public function testClampReturnsMinWhenEqualToMin(): void
{
self::assertSame(Level::Low, Level::Low->clamp(Level::Low, Level::High));
}
public function testClampReturnsMaxWhenEqualToMax(): void
{
self::assertSame(Level::High, Level::High->clamp(Level::Low, Level::High));
}
}
+135
View File
@@ -0,0 +1,135 @@
<?php
declare(strict_types=1);
namespace Tez\Utils\Tests\Enum;
use PHPUnit\Framework\TestCase;
use Tez\Utils\Enum\EnumCollectionTrait;
enum Suit: string
{
use EnumCollectionTrait;
case Hearts = 'H';
case Diamonds = 'D';
case Clubs = 'C';
case Spades = 'S';
}
enum Compass
{
use EnumCollectionTrait;
case North;
case East;
case South;
case West;
}
final class EnumCollectionTraitTest extends TestCase
{
// -------------------------------------------------------------------------
// random()
// -------------------------------------------------------------------------
public function testRandomReturnsACaseInstance(): void
{
$case = Suit::random();
self::assertInstanceOf(Suit::class, $case);
}
public function testRandomEventuallyReturnsAllCases(): void
{
$seen = [];
for ($i = 0; $i < 200; $i++) {
$seen[Suit::random()->name] = true;
}
self::assertCount(4, $seen, 'Expected all 4 suits to appear within 200 draws');
}
public function testRandomWorksForPureEnum(): void
{
$case = Compass::random();
self::assertInstanceOf(Compass::class, $case);
}
// -------------------------------------------------------------------------
// except()
// -------------------------------------------------------------------------
public function testExceptRemovesGivenCases(): void
{
$result = Suit::except(Suit::Hearts, Suit::Spades);
self::assertSame([Suit::Diamonds, Suit::Clubs], $result);
}
public function testExceptWithNoCasesReturnsAll(): void
{
self::assertSame(Suit::cases(), Suit::except());
}
public function testExceptWithAllCasesReturnsEmpty(): void
{
$result = Suit::except(...Suit::cases());
self::assertSame([], $result);
}
public function testExceptPreservesEnumOrder(): void
{
$result = Suit::except(Suit::Diamonds);
self::assertSame([Suit::Hearts, Suit::Clubs, Suit::Spades], $result);
}
public function testExceptWorksForPureEnum(): void
{
$result = Compass::except(Compass::North, Compass::South);
self::assertSame([Compass::East, Compass::West], $result);
}
// -------------------------------------------------------------------------
// only()
// -------------------------------------------------------------------------
public function testOnlyReturnsRequestedCases(): void
{
$result = Suit::only(Suit::Hearts, Suit::Spades);
self::assertSame([Suit::Hearts, Suit::Spades], $result);
}
public function testOnlyPreservesEnumDefinitionOrder(): void
{
// Pass in reverse order — result must follow enum definition order
$result = Suit::only(Suit::Spades, Suit::Hearts);
self::assertSame([Suit::Hearts, Suit::Spades], $result);
}
public function testOnlyWithNoCasesReturnsEmpty(): void
{
self::assertSame([], Suit::only());
}
public function testOnlyWithAllCasesReturnsAll(): void
{
$result = Suit::only(...Suit::cases());
self::assertSame(Suit::cases(), $result);
}
public function testOnlyWorksForPureEnum(): void
{
$result = Compass::only(Compass::East, Compass::West);
self::assertSame([Compass::East, Compass::West], $result);
}
}
+211
View File
@@ -0,0 +1,211 @@
<?php
declare(strict_types=1);
namespace Tez\Utils\Tests\Enum;
use PHPUnit\Framework\TestCase;
use Tez\Utils\Enum\BackedEnumTrait;
use Tez\Utils\Enum\EnumTrait;
// Pure (unit) enum used across all EnumTrait tests
enum Season
{
use EnumTrait;
case Spring;
case Summer;
case Autumn;
case Winter;
}
// Backed enum to verify backed paths of EnumTrait (toArray, is, find)
enum Direction: string
{
use BackedEnumTrait;
case North = 'north';
case South = 'south';
case East = 'east';
case West = 'west';
}
final class EnumTraitTest extends TestCase
{
// -------------------------------------------------------------------------
// is()
// -------------------------------------------------------------------------
public function testIsReturnsTrueForSameInstance(): void
{
self::assertTrue(Season::Summer->is(Season::Summer));
}
public function testIsReturnsFalseForNull(): void
{
self::assertFalse(Season::Summer->is(null));
}
public function testIsReturnsFalseForDifferentCase(): void
{
self::assertFalse(Season::Summer->is(Season::Winter));
}
public function testIsReturnsTrueForMatchingStringName(): void
{
self::assertTrue(Season::Autumn->is('Autumn'));
}
public function testIsReturnsFalseForNonMatchingStringName(): void
{
self::assertFalse(Season::Autumn->is('Spring'));
}
public function testIsReturnsTrueForBackedEnumByValue(): void
{
self::assertTrue(Direction::North->is('north'));
}
public function testIsReturnsFalseForBackedEnumWithWrongValue(): void
{
self::assertFalse(Direction::North->is('south'));
}
// -------------------------------------------------------------------------
// isOneOf() / isNoneOf()
// -------------------------------------------------------------------------
public function testIsOneOfReturnsTrueWhenMatchFound(): void
{
self::assertTrue(Season::Winter->isOneOf([Season::Autumn, Season::Winter]));
}
public function testIsOneOfReturnsFalseWhenNoMatch(): void
{
self::assertFalse(Season::Spring->isOneOf([Season::Autumn, Season::Winter]));
}
public function testIsOneOfReturnsFalseForNull(): void
{
self::assertFalse(Season::Spring->isOneOf(null));
}
public function testIsNoneOfIsInverseOfIsOneOf(): void
{
self::assertTrue(Season::Spring->isNoneOf([Season::Autumn, Season::Winter]));
self::assertFalse(Season::Winter->isNoneOf([Season::Autumn, Season::Winter]));
}
// -------------------------------------------------------------------------
// toArray()
// -------------------------------------------------------------------------
public function testToArrayForPureEnumReturnsNameToNameMapping(): void
{
$expected = [
'Spring' => 'Spring',
'Summer' => 'Summer',
'Autumn' => 'Autumn',
'Winter' => 'Winter',
];
self::assertSame($expected, Season::toArray());
}
public function testToArrayForBackedEnumReturnsValueToNameMapping(): void
{
$expected = [
'north' => 'North',
'south' => 'South',
'east' => 'East',
'west' => 'West',
];
self::assertSame($expected, Direction::toArray());
}
// -------------------------------------------------------------------------
// find()
// -------------------------------------------------------------------------
public function testFindReturnsNullForNull(): void
{
self::assertNull(Season::find(null));
}
public function testFindReturnsEnumInstanceWhenPassedItself(): void
{
self::assertSame(Season::Spring, Season::find(Season::Spring));
}
public function testFindByNameForPureEnum(): void
{
self::assertSame(Season::Summer, Season::find('Summer'));
}
public function testFindReturnsNullForUnknownName(): void
{
self::assertNull(Season::find('Unknown'));
}
public function testFindIgnoreCasePureEnum(): void
{
self::assertSame(Season::Winter, Season::find('winter', ignoreCase: true));
}
public function testFindByValueForBackedEnum(): void
{
self::assertSame(Direction::East, Direction::find('east'));
}
public function testFindIgnoreCaseBackedEnum(): void
{
self::assertSame(Direction::West, Direction::find('WEST', ignoreCase: true));
}
// -------------------------------------------------------------------------
// filter()
// -------------------------------------------------------------------------
public function testFilterReturnsCasesMatchingCallback(): void
{
$result = Season::filter(fn(Season $c) => in_array($c, [Season::Spring, Season::Summer], true));
self::assertCount(2, $result);
self::assertContains(Season::Spring, $result);
self::assertContains(Season::Summer, $result);
}
public function testFilterReturnsEmptyArrayWhenNothingMatches(): void
{
$result = Season::filter(fn() => false);
self::assertSame([], $result);
}
// -------------------------------------------------------------------------
// ordinal()
// -------------------------------------------------------------------------
public function testOrdinalReturnsZeroBasedPosition(): void
{
self::assertSame(0, Season::Spring->ordinal());
self::assertSame(1, Season::Summer->ordinal());
self::assertSame(2, Season::Autumn->ordinal());
self::assertSame(3, Season::Winter->ordinal());
}
// -------------------------------------------------------------------------
// first() / last()
// -------------------------------------------------------------------------
public function testFirstReturnsFirstCase(): void
{
self::assertSame(Season::Spring, Season::first());
}
public function testLastReturnsLastCase(): void
{
self::assertSame(Season::Winter, Season::last());
}
}
+107
View File
@@ -0,0 +1,107 @@
<?php
declare(strict_types=1);
namespace Tez\Utils\Tests\Enum;
use PHPUnit\Framework\TestCase;
use Tez\Utils\Enum\EnumTrait;
use Tez\Utils\Enum\StepTrait;
enum OrderStatus
{
use EnumTrait;
use StepTrait;
case Draft;
case Pending;
case Shipped;
case Delivered;
case Cancelled;
}
final class StepTraitTest extends TestCase
{
// -------------------------------------------------------------------------
// next()
// -------------------------------------------------------------------------
public function testNextReturnsFollowingCase(): void
{
self::assertSame(OrderStatus::Shipped, OrderStatus::Pending->next());
}
public function testNextFromFirstReturnsSecond(): void
{
self::assertSame(OrderStatus::Pending, OrderStatus::Draft->next());
}
public function testNextFromLastReturnsNull(): void
{
self::assertNull(OrderStatus::Cancelled->next());
}
public function testNextFromSecondToLastReturnsLast(): void
{
self::assertSame(OrderStatus::Cancelled, OrderStatus::Delivered->next());
}
// -------------------------------------------------------------------------
// prev()
// -------------------------------------------------------------------------
public function testPrevReturnsPrecedingCase(): void
{
self::assertSame(OrderStatus::Draft, OrderStatus::Pending->prev());
}
public function testPrevFromLastReturnsPenultimate(): void
{
self::assertSame(OrderStatus::Delivered, OrderStatus::Cancelled->prev());
}
public function testPrevFromFirstReturnsNull(): void
{
self::assertNull(OrderStatus::Draft->prev());
}
public function testPrevFromSecondReturnsFirst(): void
{
self::assertSame(OrderStatus::Draft, OrderStatus::Pending->prev());
}
// -------------------------------------------------------------------------
// Chaining
// -------------------------------------------------------------------------
public function testNextThenPrevReturnsSameCase(): void
{
$case = OrderStatus::Pending;
self::assertSame($case, $case->next()?->prev());
}
public function testPrevThenNextReturnsSameCase(): void
{
$case = OrderStatus::Shipped;
self::assertSame($case, $case->prev()?->next());
}
// -------------------------------------------------------------------------
// Single-case enum edge case
// -------------------------------------------------------------------------
public function testNextAndPrevReturnNullForOnlyCase(): void
{
self::assertNull(Alone::Only->next());
self::assertNull(Alone::Only->prev());
}
}
enum Alone
{
use StepTrait;
case Only;
}
+122
View File
@@ -0,0 +1,122 @@
<?php
declare(strict_types=1);
namespace Tez\Utils\Tests\Enum;
use PHPUnit\Framework\TestCase;
use Tez\Utils\Enum\BackedEnumTrait;
use Tez\Utils\Enum\TranslatableTrait;
enum StatusWithLabels: string
{
use BackedEnumTrait;
use TranslatableTrait;
case Active = 'active';
case Pending = 'pending';
case Archived = 'archived';
/** @return array<string, string> */
protected static function labels(): array
{
return [
self::Active->name => 'Aktiv',
self::Pending->name => 'Ausstehend',
// Archived intentionally has no label → fallback to name
];
}
}
enum PureWithLabels
{
use TranslatableTrait;
case Open;
case Closed;
/** @return array<string, string> */
protected static function labels(): array
{
return [
self::Open->name => 'Offen',
self::Closed->name => 'Geschlossen',
];
}
}
enum NoLabels: int
{
use TranslatableTrait;
case One = 1;
case Two = 2;
}
final class TranslatableTraitTest extends TestCase
{
// -------------------------------------------------------------------------
// label()
// -------------------------------------------------------------------------
public function testLabelReturnsConfiguredString(): void
{
self::assertSame('Aktiv', StatusWithLabels::Active->label());
self::assertSame('Ausstehend', StatusWithLabels::Pending->label());
}
public function testLabelFallsBackToCaseNameWhenNotConfigured(): void
{
self::assertSame('Archived', StatusWithLabels::Archived->label());
}
public function testLabelWorksForPureEnum(): void
{
self::assertSame('Offen', PureWithLabels::Open->label());
self::assertSame('Geschlossen', PureWithLabels::Closed->label());
}
public function testLabelFallsBackWhenNoLabelsMethodOverridden(): void
{
self::assertSame('One', NoLabels::One->label());
self::assertSame('Two', NoLabels::Two->label());
}
// -------------------------------------------------------------------------
// labelsArray()
// -------------------------------------------------------------------------
public function testLabelsArrayReturnsAllCasesMappedToLabels(): void
{
self::assertSame(
[
'Active' => 'Aktiv',
'Pending' => 'Ausstehend',
'Archived' => 'Archived',
],
StatusWithLabels::labelsArray(),
);
}
public function testLabelsArrayWorksForPureEnum(): void
{
self::assertSame(
[
'Open' => 'Offen',
'Closed' => 'Geschlossen',
],
PureWithLabels::labelsArray(),
);
}
public function testLabelsArrayFallsBackToNamesWhenEmpty(): void
{
self::assertSame(
[
'One' => 'One',
'Two' => 'Two',
],
NoLabels::labelsArray(),
);
}
}