Completed
Push — develop ( 1f78f5...10fbf8 )
by Alejandro
16s queued 11s
created

providingNonUniqueSlugOutputsError()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 7
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 12
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ShlinkioTest\Shlink\CLI\Command\ShortUrl;
6
7
use PHPUnit\Framework\Assert;
8
use PHPUnit\Framework\TestCase;
9
use Prophecy\Argument;
10
use Prophecy\Prophecy\ObjectProphecy;
11
use Shlinkio\Shlink\CLI\Command\ShortUrl\GenerateShortUrlCommand;
12
use Shlinkio\Shlink\CLI\Util\ExitCodes;
13
use Shlinkio\Shlink\Core\Entity\ShortUrl;
14
use Shlinkio\Shlink\Core\Exception\InvalidUrlException;
15
use Shlinkio\Shlink\Core\Exception\NonUniqueSlugException;
16
use Shlinkio\Shlink\Core\Model\ShortUrlMeta;
17
use Shlinkio\Shlink\Core\Service\UrlShortener;
18
use Symfony\Component\Console\Application;
19
use Symfony\Component\Console\Tester\CommandTester;
20
21
class GenerateShortUrlCommandTest extends TestCase
22
{
23
    private const DOMAIN_CONFIG = [
24
        'schema' => 'http',
25
        'hostname' => 'foo.com',
26
    ];
27
28
    private CommandTester $commandTester;
29
    private ObjectProphecy $urlShortener;
30
31
    public function setUp(): void
32
    {
33
        $this->urlShortener = $this->prophesize(UrlShortener::class);
34
        $command = new GenerateShortUrlCommand($this->urlShortener->reveal(), self::DOMAIN_CONFIG, 5);
35
        $app = new Application();
36
        $app->add($command);
37
        $this->commandTester = new CommandTester($command);
38
    }
39
40
    /** @test */
41
    public function properShortCodeIsCreatedIfLongUrlIsCorrect(): void
42
    {
43
        $shortUrl = new ShortUrl('');
44
        $urlToShortCode = $this->urlShortener->urlToShortCode(Argument::cetera())->willReturn($shortUrl);
45
46
        $this->commandTester->execute([
47
            'longUrl' => 'http://domain.com/foo/bar',
48
            '--maxVisits' => '3',
49
        ]);
50
        $output = $this->commandTester->getDisplay();
51
52
        $this->assertEquals(ExitCodes::EXIT_SUCCESS, $this->commandTester->getStatusCode());
53
        $this->assertStringContainsString($shortUrl->toString(self::DOMAIN_CONFIG), $output);
54
        $urlToShortCode->shouldHaveBeenCalledOnce();
55
    }
56
57
    /** @test */
58
    public function exceptionWhileParsingLongUrlOutputsError(): void
59
    {
60
        $url = 'http://domain.com/invalid';
61
        $this->urlShortener->urlToShortCode(Argument::cetera())->willThrow(InvalidUrlException::fromUrl($url))
62
                                                               ->shouldBeCalledOnce();
63
64
        $this->commandTester->execute(['longUrl' => $url]);
65
        $output = $this->commandTester->getDisplay();
66
67
        $this->assertEquals(ExitCodes::EXIT_FAILURE, $this->commandTester->getStatusCode());
68
        $this->assertStringContainsString('Provided URL http://domain.com/invalid is invalid.', $output);
69
    }
70
71
    /** @test */
72
    public function providingNonUniqueSlugOutputsError(): void
73
    {
74
        $urlToShortCode = $this->urlShortener->urlToShortCode(Argument::cetera())->willThrow(
75
            NonUniqueSlugException::fromSlug('my-slug'),
76
        );
77
78
        $this->commandTester->execute(['longUrl' => 'http://domain.com/invalid', '--customSlug' => 'my-slug']);
79
        $output = $this->commandTester->getDisplay();
80
81
        $this->assertEquals(ExitCodes::EXIT_FAILURE, $this->commandTester->getStatusCode());
82
        $this->assertStringContainsString('Provided slug "my-slug" is already in use', $output);
83
        $urlToShortCode->shouldHaveBeenCalledOnce();
84
    }
85
86
    /** @test */
87
    public function properlyProcessesProvidedTags(): void
88
    {
89
        $shortUrl = new ShortUrl('');
90
        $urlToShortCode = $this->urlShortener->urlToShortCode(
91
            Argument::type('string'),
92
            Argument::that(function (array $tags) {
93
                Assert::assertEquals(['foo', 'bar', 'baz', 'boo', 'zar'], $tags);
94
                return $tags;
95
            }),
96
            Argument::cetera(),
97
        )->willReturn($shortUrl);
98
99
        $this->commandTester->execute([
100
            'longUrl' => 'http://domain.com/foo/bar',
101
            '--tags' => ['foo,bar', 'baz', 'boo,zar,baz'],
102
        ]);
103
        $output = $this->commandTester->getDisplay();
104
105
        $this->assertEquals(ExitCodes::EXIT_SUCCESS, $this->commandTester->getStatusCode());
106
        $this->assertStringContainsString($shortUrl->toString(self::DOMAIN_CONFIG), $output);
107
        $urlToShortCode->shouldHaveBeenCalledOnce();
108
    }
109
110
    /**
111
     * @test
112
     * @dataProvider provideFlags
113
     */
114
    public function urlValidationHasExpectedValueBasedOnProvidedTags(array $options, ?bool $expectedValidateUrl): void
115
    {
116
        $shortUrl = new ShortUrl('');
117
        $urlToShortCode = $this->urlShortener->urlToShortCode(
118
            Argument::type('string'),
119
            Argument::type('array'),
120
            Argument::that(function (ShortUrlMeta $meta) use ($expectedValidateUrl) {
121
                Assert::assertEquals($expectedValidateUrl, $meta->doValidateUrl());
122
                return $meta;
123
            }),
124
        )->willReturn($shortUrl);
125
126
        $options['longUrl'] = 'http://domain.com/foo/bar';
127
        $this->commandTester->execute($options);
128
129
        $urlToShortCode->shouldHaveBeenCalledOnce();
130
    }
131
132
    public function provideFlags(): iterable
133
    {
134
        yield 'no flags' => [[], null];
135
        yield 'no-validate-url only' => [['--no-validate-url' => true], false];
136
        yield 'validate-url' => [['--validate-url' => true], true];
137
        yield 'both flags' => [['--validate-url' => true, '--no-validate-url' => true], false];
138
    }
139
}
140