From 90ae5f054e64012a79850495dca89859333a0bab Mon Sep 17 00:00:00 2001
From: Dezer <my@ipro.dev>
Date: Sun, 1 Jan 2023 21:55:38 +0200
Subject: [PATCH] Add provider for fakerphp/faker

---
 composer.json                                 |  3 +-
 src/Faker/FakerEnumProvider.php               | 78 +++++++++++++++++++
 tests/Unit/Faker/EnumFixture.php              | 18 +++++
 .../Unit/Faker/FakerEnumProviderUnitTest.php  | 49 ++++++++++++
 4 files changed, 147 insertions(+), 1 deletion(-)
 create mode 100644 src/Faker/FakerEnumProvider.php
 create mode 100644 tests/Unit/Faker/EnumFixture.php
 create mode 100644 tests/Unit/Faker/FakerEnumProviderUnitTest.php

diff --git a/composer.json b/composer.json
index 2513db7..ebb120f 100644
--- a/composer.json
+++ b/composer.json
@@ -31,6 +31,7 @@
     "require-dev": {
         "phpunit/phpunit": "^9.5",
         "squizlabs/php_codesniffer": "1.*",
-        "vimeo/psalm": "^4.6.2 || ^5.2"
+        "vimeo/psalm": "^4.6.2 || ^5.2",
+        "fakerphp/faker": "^1.21"
     }
 }
diff --git a/src/Faker/FakerEnumProvider.php b/src/Faker/FakerEnumProvider.php
new file mode 100644
index 0000000..2ee2ed1
--- /dev/null
+++ b/src/Faker/FakerEnumProvider.php
@@ -0,0 +1,78 @@
+<?php
+
+declare(strict_types=1);
+
+namespace MyCLabs\Enum\Faker;
+
+use Faker\Provider\Base;
+use InvalidArgumentException;
+use MyCLabs\Enum\Enum;
+
+class FakerEnumProvider extends Base
+{
+    /**
+     * A random instance of the enum you pass in.
+     *
+     * @param class-string $enum
+     *
+     * @return Enum
+     */
+    public static function randomEnum(string $enum): Enum
+    {
+        if (!is_subclass_of($enum, Enum::class)) {
+            throw new InvalidArgumentException(
+                sprintf(
+                    'You have to pass the FQCN of a "%s" class but you passed "%s".',
+                    Enum::class,
+                    $enum
+                )
+            );
+        }
+
+        return static::randomElement($enum::values());
+    }
+
+    /**
+     * A random value of the enum you pass in.
+     *
+     * @param class-string $enum
+     *
+     * @return string|int
+     */
+    public static function randomEnumValue(string $enum)
+    {
+        if (!is_subclass_of($enum, Enum::class)) {
+            throw new InvalidArgumentException(
+                sprintf(
+                    'You have to pass the FQCN of a "%s" class but you passed "%s".',
+                    Enum::class,
+                    $enum
+                )
+            );
+        }
+
+        return static::randomElement($enum::toArray());
+    }
+
+    /**
+     * A random label of the enum you pass in.
+     *
+     * @param class-string $enum
+     *
+     * @return string
+     */
+    public static function randomEnumKey(string $enum): string
+    {
+        if (!is_subclass_of($enum, Enum::class)) {
+            throw new InvalidArgumentException(
+                sprintf(
+                    'You have to pass the FQCN of a "%s" class but you passed "%s".',
+                    Enum::class,
+                    $enum
+                )
+            );
+        }
+
+        return static::randomElement($enum::keys());
+    }
+}
\ No newline at end of file
diff --git a/tests/Unit/Faker/EnumFixture.php b/tests/Unit/Faker/EnumFixture.php
new file mode 100644
index 0000000..0b4e934
--- /dev/null
+++ b/tests/Unit/Faker/EnumFixture.php
@@ -0,0 +1,18 @@
+<?php
+
+declare(strict_types=1);
+
+namespace MyCLabs\Tests\Enum\Unit\Faker;
+
+use MyCLabs\Enum\Enum;
+
+/**
+ * @method static self TESTED()
+ * @method static self UNTESTED()
+ */
+class EnumFixture extends Enum
+{
+    private const TESTED = 'tested';
+
+    private const UNTESTED = 'untested';
+}
\ No newline at end of file
diff --git a/tests/Unit/Faker/FakerEnumProviderUnitTest.php b/tests/Unit/Faker/FakerEnumProviderUnitTest.php
new file mode 100644
index 0000000..e288333
--- /dev/null
+++ b/tests/Unit/Faker/FakerEnumProviderUnitTest.php
@@ -0,0 +1,49 @@
+<?php
+
+declare(strict_types=1);
+
+namespace MyCLabs\Tests\Enum\Unit\Faker;
+
+use Faker\Factory;
+use Faker\Generator;
+use MyCLabs\Enum\Faker\FakerEnumProvider;
+use PHPUnit\Framework\TestCase;
+
+class FakerEnumProviderUnitTest extends TestCase
+{
+    /** @var Generator */
+    private $faker;
+
+    public function testSuccessCanFakeEnum(): void
+    {
+        /** @var EnumFixture $value */
+        $value = $this->faker->randomEnum(EnumFixture::class);
+
+        self::assertContains($value->getKey(), EnumFixture::keys());
+        self::assertContains($value->getValue(), EnumFixture::toArray());
+    }
+
+    public function testSuccessCanFakeEnumValue(): void
+    {
+        /** @var EnumFixture $value */
+        $value = $this->faker->randomEnumValue(EnumFixture::class);
+
+        self::assertContains($value, EnumFixture::toArray());
+    }
+
+    public function testSuccessCanFakeEnumKey(): void
+    {
+        /** @var EnumFixture $value */
+        $value = $this->faker->randomEnumKey(EnumFixture::class);
+
+        self::assertContains($value, EnumFixture::keys());
+    }
+
+    protected function setUp(): void
+    {
+        parent::setUp();
+
+        $this->faker = Factory::create();
+        $this->faker->addProvider(FakerEnumProvider::class);
+    }
+}
\ No newline at end of file