<commit_before><?php

declare(strict_types=1);

namespace ShlinkioTest\Shlink\CLI\Command\Api;

use Cake\Chronos\Chronos;
use PHPUnit\Framework\TestCase;
use Prophecy\Prophecy\ObjectProphecy;
use Shlinkio\Shlink\CLI\Command\Api\ListKeysCommand;
use Shlinkio\Shlink\Core\Domain\Entity\Domain;
use Shlinkio\Shlink\Rest\ApiKey\Model\ApiKeyMeta;
use Shlinkio\Shlink\Rest\ApiKey\Model\RoleDefinition;
use Shlinkio\Shlink\Rest\Entity\ApiKey;
use Shlinkio\Shlink\Rest\Service\ApiKeyServiceInterface;
use ShlinkioTest\Shlink\CLI\CliTestUtilsTrait;
use Symfony\Component\Console\Tester\CommandTester;

class ListKeysCommandTest extends TestCase
{
    use CliTestUtilsTrait;

    private CommandTester $commandTester;
    private ObjectProphecy $apiKeyService;

    protected function setUp(): void
    {
        $this->apiKeyService = $this->prophesize(ApiKeyServiceInterface::class);
        $this->commandTester = $this->testerForCommand(new ListKeysCommand($this->apiKeyService->reveal()));
    }

    /**
     * @test
     * @dataProvider provideKeysAndOutputs
     */
    public function returnsExpectedOutput(array $keys, bool $enabledOnly, string $expected): void
    {
        $listKeys = $this->apiKeyService->listKeys($enabledOnly)->willReturn($keys);

        $this->commandTester->execute(['--enabled-only' => $enabledOnly]);
        $output = $this->commandTester->getDisplay();

        self::assertEquals($expected, $output);
        $listKeys->shouldHaveBeenCalledOnce();
    }

    public function provideKeysAndOutputs(): iterable
    {
        $dateInThePast = Chronos::createFromFormat('Y-m-d H:i:s', '2020-01-01 00:00:00');

        yield 'all keys' => [
            [
                $apiKey1 = ApiKey::create()->disable(),
                $apiKey2 = ApiKey::fromMeta(ApiKeyMeta::withExpirationDate($dateInThePast)),
                $apiKey3 = ApiKey::create(),
            ],
            false,
            <<<OUTPUT
            +--------------------------------------+------+------------+---------------------------+-------+
            | Key                                  | Name | Is enabled | Expiration date           | Roles |
            +--------------------------------------+------+------------+---------------------------+-------+
            | {$apiKey1} | -    | ---        | -                         | Admin |
            +--------------------------------------+------+------------+---------------------------+-------+
            | {$apiKey2} | -    | ---        | 2020-01-01T00:00:00+00:00 | Admin |
            +--------------------------------------+------+------------+---------------------------+-------+
            | {$apiKey3} | -    | +++        | -                         | Admin |
            +--------------------------------------+------+------------+---------------------------+-------+

            OUTPUT,
        ];
        yield 'enabled keys' => [
            [$apiKey1 = ApiKey::create()->disable(), $apiKey2 = ApiKey::create()],
            true,<commit_msg>Migrated ListKeysCommandTest to use PHPUnit mocks<commit_after><?php

declare(strict_types=1);

namespace ShlinkioTest\Shlink\CLI\Command\Api;

use Cake\Chronos\Chronos;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\CLI\Command\Api\ListKeysCommand;
use Shlinkio\Shlink\Core\Domain\Entity\Domain;
use Shlinkio\Shlink\Rest\ApiKey\Model\ApiKeyMeta;
use Shlinkio\Shlink\Rest\ApiKey\Model\RoleDefinition;
use Shlinkio\Shlink\Rest\Entity\ApiKey;
use Shlinkio\Shlink\Rest\Service\ApiKeyServiceInterface;
use ShlinkioTest\Shlink\CLI\CliTestUtilsTrait;
use Symfony\Component\Console\Tester\CommandTester;

class ListKeysCommandTest extends TestCase
{
    use CliTestUtilsTrait;

    private CommandTester $commandTester;
    private MockObject $apiKeyService;

    protected function setUp(): void
    {
        $this->apiKeyService = $this->createMock(ApiKeyServiceInterface::class);
        $this->commandTester = $this->testerForCommand(new ListKeysCommand($this->apiKeyService));
    }

    /**
     * @test
     * @dataProvider provideKeysAndOutputs
     */
    public function returnsExpectedOutput(array $keys, bool $enabledOnly, string $expected): void
    {
        $this->apiKeyService->expects($this->once())->method('listKeys')->with(
            $this->equalTo($enabledOnly),
        )->willReturn($keys);

        $this->commandTester->execute(['--enabled-only' => $enabledOnly]);
        $output = $this->commandTester->getDisplay();

        self::assertEquals($expected, $output);
    }

    public function provideKeysAndOutputs(): iterable
    {
        $dateInThePast = Chronos::createFromFormat('Y-m-d H:i:s', '2020-01-01 00:00:00');

        yield 'all keys' => [
            [
                $apiKey1 = ApiKey::create()->disable(),
                $apiKey2 = ApiKey::fromMeta(ApiKeyMeta::withExpirationDate($dateInThePast)),
                $apiKey3 = ApiKey::create(),
            ],
            false,
            <<<OUTPUT
            +--------------------------------------+------+------------+---------------------------+-------+
            | Key                                  | Name | Is enabled | Expiration date           | Roles |
            +--------------------------------------+------+------------+---------------------------+-------+
            | {$apiKey1} | -    | ---        | -                         | Admin |
            +--------------------------------------+------+------------+---------------------------+-------+
            | {$apiKey2} | -    | ---        | 2020-01-01T00:00:00+00:00 | Admin |
            +--------------------------------------+------+------------+---------------------------+-------+
            | {$apiKey3} | -    | +++        | -                         | Admin |
            +--------------------------------------+------+------------+---------------------------+-------+

            OUTPUT,
        ];
        yield 'enabled keys' => [
            [$apiKey1 = ApiKey::create()->disable(), $apiKey2 = ApiKey::create()],
            true,
{'fraction_non_alphanumeric': 0.269389099291948, 'fraction_numerical': 0.013502387617322576, 'mean_word_length': 1.4452495974235104, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1557310', 'n_tokens_mistral': 1674, 'n_tokens_neox': 1580, 'n_words': 226}