DeleteShortUrlCommandTest   A
last analyzed

Complexity

Total Complexity 7

Size/Duplication

Total Lines 111
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 7
eloc 56
dl 0
loc 111
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A setUp() 0 9 1
A deleteIsNotRetriedWhenThresholdIsReachedAndQuestionIsDeclined() 0 17 1
A provideRetryDeleteAnswers() 0 5 1
A successMessageIsPrintedIfUrlIsProperlyDeleted() 0 16 1
A deleteIsRetriedWhenThresholdIsReachedAndQuestionIsAccepted() 0 27 2
A invalidShortCodePrintsMessage() 0 13 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ShlinkioTest\Shlink\CLI\Command\ShortUrl;
6
7
use PHPUnit\Framework\TestCase;
8
use Prophecy\Argument;
9
use Prophecy\PhpUnit\ProphecyTrait;
10
use Prophecy\Prophecy\ObjectProphecy;
11
use Shlinkio\Shlink\CLI\Command\ShortUrl\DeleteShortUrlCommand;
12
use Shlinkio\Shlink\Core\Exception;
13
use Shlinkio\Shlink\Core\Model\ShortUrlIdentifier;
14
use Shlinkio\Shlink\Core\Service\ShortUrl\DeleteShortUrlServiceInterface;
15
use Symfony\Component\Console\Application;
16
use Symfony\Component\Console\Tester\CommandTester;
17
18
use function array_pop;
19
use function sprintf;
20
21
use const PHP_EOL;
22
23
class DeleteShortUrlCommandTest extends TestCase
24
{
25
    use ProphecyTrait;
26
27
    private CommandTester $commandTester;
28
    private ObjectProphecy $service;
29
30
    public function setUp(): void
31
    {
32
        $this->service = $this->prophesize(DeleteShortUrlServiceInterface::class);
33
34
        $command = new DeleteShortUrlCommand($this->service->reveal());
35
        $app = new Application();
36
        $app->add($command);
37
38
        $this->commandTester = new CommandTester($command);
39
    }
40
41
    /** @test */
42
    public function successMessageIsPrintedIfUrlIsProperlyDeleted(): void
43
    {
44
        $shortCode = 'abc123';
45
        $deleteByShortCode = $this->service->deleteByShortCode(new ShortUrlIdentifier($shortCode), false)->will(
46
            function (): void {
47
            },
48
        );
49
50
        $this->commandTester->execute(['shortCode' => $shortCode]);
51
        $output = $this->commandTester->getDisplay();
52
53
        self::assertStringContainsString(
54
            sprintf('Short URL with short code "%s" successfully deleted.', $shortCode),
55
            $output,
56
        );
57
        $deleteByShortCode->shouldHaveBeenCalledOnce();
58
    }
59
60
    /** @test */
61
    public function invalidShortCodePrintsMessage(): void
62
    {
63
        $shortCode = 'abc123';
64
        $identifier = new ShortUrlIdentifier($shortCode);
65
        $deleteByShortCode = $this->service->deleteByShortCode($identifier, false)->willThrow(
66
            Exception\ShortUrlNotFoundException::fromNotFound($identifier),
67
        );
68
69
        $this->commandTester->execute(['shortCode' => $shortCode]);
70
        $output = $this->commandTester->getDisplay();
71
72
        self::assertStringContainsString(sprintf('No URL found with short code "%s"', $shortCode), $output);
73
        $deleteByShortCode->shouldHaveBeenCalledOnce();
74
    }
75
76
    /**
77
     * @test
78
     * @dataProvider provideRetryDeleteAnswers
79
     */
80
    public function deleteIsRetriedWhenThresholdIsReachedAndQuestionIsAccepted(
81
        array $retryAnswer,
82
        int $expectedDeleteCalls,
83
        string $expectedMessage
84
    ): void {
85
        $shortCode = 'abc123';
86
        $identifier = new ShortUrlIdentifier($shortCode);
87
        $deleteByShortCode = $this->service->deleteByShortCode($identifier, Argument::type('bool'))->will(
88
            function (array $args) use ($shortCode): void {
89
                $ignoreThreshold = array_pop($args);
90
91
                if (!$ignoreThreshold) {
92
                    throw Exception\DeleteShortUrlException::fromVisitsThreshold(10, $shortCode);
93
                }
94
            },
95
        );
96
        $this->commandTester->setInputs($retryAnswer);
97
98
        $this->commandTester->execute(['shortCode' => $shortCode]);
99
        $output = $this->commandTester->getDisplay();
100
101
        self::assertStringContainsString(sprintf(
102
            'Impossible to delete short URL with short code "%s" since it has more than "10" visits.',
103
            $shortCode,
104
        ), $output);
105
        self::assertStringContainsString($expectedMessage, $output);
106
        $deleteByShortCode->shouldHaveBeenCalledTimes($expectedDeleteCalls);
107
    }
108
109
    public function provideRetryDeleteAnswers(): iterable
110
    {
111
        yield 'answering yes to retry' => [['yes'], 2, 'Short URL with short code "abc123" successfully deleted.'];
112
        yield 'answering no to retry' => [['no'], 1, 'Short URL was not deleted.'];
113
        yield 'answering default to retry' => [[PHP_EOL], 1, 'Short URL was not deleted.'];
114
    }
115
116
    /** @test */
117
    public function deleteIsNotRetriedWhenThresholdIsReachedAndQuestionIsDeclined(): void
118
    {
119
        $shortCode = 'abc123';
120
        $deleteByShortCode = $this->service->deleteByShortCode(new ShortUrlIdentifier($shortCode), false)->willThrow(
121
            Exception\DeleteShortUrlException::fromVisitsThreshold(10, $shortCode),
122
        );
123
        $this->commandTester->setInputs(['no']);
124
125
        $this->commandTester->execute(['shortCode' => $shortCode]);
126
        $output = $this->commandTester->getDisplay();
127
128
        self::assertStringContainsString(sprintf(
129
            'Impossible to delete short URL with short code "%s" since it has more than "10" visits.',
130
            $shortCode,
131
        ), $output);
132
        self::assertStringContainsString('Short URL was not deleted.', $output);
133
        $deleteByShortCode->shouldHaveBeenCalledOnce();
134
    }
135
}
136