Passed
Push — develop ( 0d7fb1...8577d6 )
by Alejandro
09:01 queued 01:01
created

UrlShortenerTest::urlIsProperlyShortened()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 4
c 1
b 0
f 0
dl 0
loc 9
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ShlinkioTest\Shlink\Core\Service;
6
7
use Cake\Chronos\Chronos;
8
use Doctrine\Common\Collections\ArrayCollection;
9
use Doctrine\ORM\EntityManagerInterface;
10
use PHPUnit\Framework\TestCase;
11
use Prophecy\Argument;
12
use Prophecy\PhpUnit\ProphecyTrait;
13
use Prophecy\Prophecy\ObjectProphecy;
14
use Shlinkio\Shlink\Core\Entity\ShortUrl;
15
use Shlinkio\Shlink\Core\Entity\Tag;
16
use Shlinkio\Shlink\Core\Exception\NonUniqueSlugException;
17
use Shlinkio\Shlink\Core\Model\ShortUrlMeta;
18
use Shlinkio\Shlink\Core\Repository\ShortUrlRepository;
19
use Shlinkio\Shlink\Core\Service\ShortUrl\ShortCodeHelperInterface;
20
use Shlinkio\Shlink\Core\Service\UrlShortener;
21
use Shlinkio\Shlink\Core\ShortUrl\Resolver\SimpleShortUrlRelationResolver;
22
use Shlinkio\Shlink\Core\Util\UrlValidatorInterface;
23
24
class UrlShortenerTest extends TestCase
25
{
26
    use ProphecyTrait;
27
28
    private UrlShortener $urlShortener;
29
    private ObjectProphecy $em;
30
    private ObjectProphecy $urlValidator;
31
    private ObjectProphecy $shortCodeHelper;
32
33
    public function setUp(): void
34
    {
35
        $this->urlValidator = $this->prophesize(UrlValidatorInterface::class);
36
        $this->urlValidator->validateUrl('http://foobar.com/12345/hello?foo=bar', null)->will(
37
            function (): void {
38
            },
39
        );
40
41
        $this->em = $this->prophesize(EntityManagerInterface::class);
42
        $this->em->persist(Argument::any())->will(function ($arguments): void {
43
            /** @var ShortUrl $shortUrl */
44
            [$shortUrl] = $arguments;
45
            $shortUrl->setId('10');
46
        });
47
        $this->em->transactional(Argument::type('callable'))->will(function (array $args) {
48
            /** @var callable $callback */
49
            [$callback] = $args;
50
51
            return $callback();
52
        });
53
        $repo = $this->prophesize(ShortUrlRepository::class);
54
        $repo->shortCodeIsInUse(Argument::cetera())->willReturn(false);
55
        $this->em->getRepository(ShortUrl::class)->willReturn($repo->reveal());
56
57
        $this->shortCodeHelper = $this->prophesize(ShortCodeHelperInterface::class);
58
        $this->shortCodeHelper->ensureShortCodeUniqueness(Argument::cetera())->willReturn(true);
59
60
        $this->urlShortener = new UrlShortener(
61
            $this->urlValidator->reveal(),
62
            $this->em->reveal(),
63
            new SimpleShortUrlRelationResolver(),
64
            $this->shortCodeHelper->reveal(),
65
        );
66
    }
67
68
    /** @test */
69
    public function urlIsProperlyShortened(): void
70
    {
71
        $shortUrl = $this->urlShortener->shorten(
72
            'http://foobar.com/12345/hello?foo=bar',
73
            [],
74
            ShortUrlMeta::createEmpty(),
75
        );
76
77
        self::assertEquals('http://foobar.com/12345/hello?foo=bar', $shortUrl->getLongUrl());
78
    }
79
80
    /** @test */
81
    public function exceptionIsThrownWhenNonUniqueSlugIsProvided(): void
82
    {
83
        $ensureUniqueness = $this->shortCodeHelper->ensureShortCodeUniqueness(Argument::cetera())->willReturn(false);
84
85
        $ensureUniqueness->shouldBeCalledOnce();
86
        $this->expectException(NonUniqueSlugException::class);
87
88
        $this->urlShortener->shorten(
89
            'http://foobar.com/12345/hello?foo=bar',
90
            [],
91
            ShortUrlMeta::fromRawData(['customSlug' => 'custom-slug']),
92
        );
93
    }
94
95
    /**
96
     * @test
97
     * @dataProvider provideExistingShortUrls
98
     */
99
    public function existingShortUrlIsReturnedWhenRequested(
100
        string $url,
101
        array $tags,
102
        ShortUrlMeta $meta,
103
        ShortUrl $expected
104
    ): void {
105
        $repo = $this->prophesize(ShortUrlRepository::class);
106
        $findExisting = $repo->findOneMatching(Argument::cetera())->willReturn($expected);
107
        $getRepo = $this->em->getRepository(ShortUrl::class)->willReturn($repo->reveal());
108
109
        $result = $this->urlShortener->shorten($url, $tags, $meta);
110
111
        $findExisting->shouldHaveBeenCalledOnce();
112
        $getRepo->shouldHaveBeenCalledOnce();
113
        $this->em->persist(Argument::cetera())->shouldNotHaveBeenCalled();
114
        $this->urlValidator->validateUrl(Argument::cetera())->shouldNotHaveBeenCalled();
115
        self::assertSame($expected, $result);
116
    }
117
118
    public function provideExistingShortUrls(): iterable
119
    {
120
        $url = 'http://foo.com';
121
122
        yield [$url, [], ShortUrlMeta::fromRawData(['findIfExists' => true]), new ShortUrl($url)];
123
        yield [$url, [], ShortUrlMeta::fromRawData(
124
            ['findIfExists' => true, 'customSlug' => 'foo'],
125
        ), new ShortUrl($url)];
126
        yield [
127
            $url,
128
            ['foo', 'bar'],
129
            ShortUrlMeta::fromRawData(['findIfExists' => true]),
130
            (new ShortUrl($url))->setTags(new ArrayCollection([new Tag('bar'), new Tag('foo')])),
131
        ];
132
        yield [
133
            $url,
134
            [],
135
            ShortUrlMeta::fromRawData(['findIfExists' => true, 'maxVisits' => 3]),
136
            new ShortUrl($url, ShortUrlMeta::fromRawData(['maxVisits' => 3])),
137
        ];
138
        yield [
139
            $url,
140
            [],
141
            ShortUrlMeta::fromRawData(['findIfExists' => true, 'validSince' => Chronos::parse('2017-01-01')]),
142
            new ShortUrl($url, ShortUrlMeta::fromRawData(['validSince' => Chronos::parse('2017-01-01')])),
143
        ];
144
        yield [
145
            $url,
146
            [],
147
            ShortUrlMeta::fromRawData(['findIfExists' => true, 'validUntil' => Chronos::parse('2017-01-01')]),
148
            new ShortUrl($url, ShortUrlMeta::fromRawData(['validUntil' => Chronos::parse('2017-01-01')])),
149
        ];
150
        yield [
151
            $url,
152
            [],
153
            ShortUrlMeta::fromRawData(['findIfExists' => true, 'domain' => 'example.com']),
154
            new ShortUrl($url, ShortUrlMeta::fromRawData(['domain' => 'example.com'])),
155
        ];
156
        yield [
157
            $url,
158
            ['baz', 'foo', 'bar'],
159
            ShortUrlMeta::fromRawData([
160
                'findIfExists' => true,
161
                'validUntil' => Chronos::parse('2017-01-01'),
162
                'maxVisits' => 4,
163
            ]),
164
            (new ShortUrl($url, ShortUrlMeta::fromRawData([
165
                'validUntil' => Chronos::parse('2017-01-01'),
166
                'maxVisits' => 4,
167
            ])))->setTags(new ArrayCollection([new Tag('foo'), new Tag('bar'), new Tag('baz')])),
168
        ];
169
    }
170
}
171