Completed
Push — master ( 30297a...987919 )
by Alejandro
13s
created

UrlShortenerTest::cachedShortCodeDoesNotHitDatabase()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 10
rs 9.9332
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace ShlinkioTest\Shlink\Core\Service;
5
6
use Cocur\Slugify\SlugifyInterface;
7
use Doctrine\Common\Persistence\ObjectRepository;
8
use Doctrine\DBAL\Connection;
9
use Doctrine\ORM\EntityManagerInterface;
10
use Doctrine\ORM\ORMException;
11
use GuzzleHttp\ClientInterface;
12
use GuzzleHttp\Exception\ClientException;
13
use GuzzleHttp\Psr7\Request;
14
use PHPUnit\Framework\TestCase;
15
use Prophecy\Argument;
16
use Prophecy\Prophecy\MethodProphecy;
17
use Prophecy\Prophecy\ObjectProphecy;
18
use Shlinkio\Shlink\Core\Entity\ShortUrl;
19
use Shlinkio\Shlink\Core\Exception\NonUniqueSlugException;
20
use Shlinkio\Shlink\Core\Repository\ShortUrlRepositoryInterface;
21
use Shlinkio\Shlink\Core\Service\UrlShortener;
22
use Zend\Diactoros\Uri;
23
24
class UrlShortenerTest extends TestCase
25
{
26
    /**
27
     * @var UrlShortener
28
     */
29
    protected $urlShortener;
30
    /**
31
     * @var ObjectProphecy
32
     */
33
    protected $em;
34
    /**
35
     * @var ObjectProphecy
36
     */
37
    protected $httpClient;
38
    /**
39
     * @var ObjectProphecy
40
     */
41
    protected $slugger;
42
43
    public function setUp()
44
    {
45
        $this->httpClient = $this->prophesize(ClientInterface::class);
46
47
        $this->em = $this->prophesize(EntityManagerInterface::class);
48
        $conn = $this->prophesize(Connection::class);
49
        $conn->isTransactionActive()->willReturn(false);
50
        $this->em->getConnection()->willReturn($conn->reveal());
51
        $this->em->flush()->willReturn(null);
52
        $this->em->commit()->willReturn(null);
53
        $this->em->beginTransaction()->willReturn(null);
54
        $this->em->persist(Argument::any())->will(function ($arguments) {
55
            /** @var ShortUrl $shortUrl */
56
            $shortUrl = $arguments[0];
57
            $shortUrl->setId(10);
58
        });
59
        $repo = $this->prophesize(ObjectRepository::class);
60
        $repo->findOneBy(Argument::any())->willReturn(null);
61
        $this->em->getRepository(ShortUrl::class)->willReturn($repo->reveal());
62
63
        $this->slugger = $this->prophesize(SlugifyInterface::class);
64
65
        $this->setUrlShortener(false);
66
    }
67
68
    /**
69
     * @param bool $urlValidationEnabled
70
     */
71
    public function setUrlShortener($urlValidationEnabled)
72
    {
73
        $this->urlShortener = new UrlShortener(
74
            $this->httpClient->reveal(),
75
            $this->em->reveal(),
76
            $urlValidationEnabled,
77
            UrlShortener::DEFAULT_CHARS,
78
            $this->slugger->reveal()
79
        );
80
    }
81
82
    /**
83
     * @test
84
     */
85
    public function urlIsProperlyShortened()
86
    {
87
        // 10 -> 12C1c
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
88
        $shortCode = $this->urlShortener->urlToShortCode(new Uri('http://foobar.com/12345/hello?foo=bar'));
89
        $this->assertEquals('12C1c', $shortCode);
90
    }
91
92
    /**
93
     * @test
94
     * @expectedException \Shlinkio\Shlink\Core\Exception\RuntimeException
95
     */
96
    public function exceptionIsThrownWhenOrmThrowsException()
97
    {
98
        $conn = $this->prophesize(Connection::class);
99
        $conn->isTransactionActive()->willReturn(true);
100
        $this->em->getConnection()->willReturn($conn->reveal());
101
        $this->em->rollback()->shouldBeCalledTimes(1);
102
        $this->em->close()->shouldBeCalledTimes(1);
103
104
        $this->em->flush()->willThrow(new ORMException());
105
        $this->urlShortener->urlToShortCode(new Uri('http://foobar.com/12345/hello?foo=bar'));
106
    }
107
108
    /**
109
     * @test
110
     * @expectedException \Shlinkio\Shlink\Core\Exception\InvalidUrlException
111
     */
112
    public function exceptionIsThrownWhenUrlDoesNotExist()
113
    {
114
        $this->setUrlShortener(true);
115
116
        $this->httpClient->request(Argument::cetera())->willThrow(
117
            new ClientException('', $this->prophesize(Request::class)->reveal())
118
        );
119
        $this->urlShortener->urlToShortCode(new Uri('http://foobar.com/12345/hello?foo=bar'));
120
    }
121
122
    /**
123
     * @test
124
     */
125
    public function whenShortUrlExistsItsShortcodeIsReturned()
126
    {
127
        $shortUrl = new ShortUrl();
128
        $shortUrl->setShortCode('expected_shortcode');
129
        $repo = $this->prophesize(ObjectRepository::class);
130
        $repo->findOneBy(Argument::any())->willReturn($shortUrl);
131
        $this->em->getRepository(ShortUrl::class)->willReturn($repo->reveal());
132
133
        $shortCode = $this->urlShortener->urlToShortCode(new Uri('http://foobar.com/12345/hello?foo=bar'));
134
        $this->assertEquals($shortUrl->getShortCode(), $shortCode);
135
    }
136
137
    /**
138
     * @test
139
     */
140
    public function whenCustomSlugIsProvidedItIsUsed()
141
    {
142
        /** @var MethodProphecy $slugify */
143
        $slugify = $this->slugger->slugify('custom-slug')->willReturnArgument();
144
145
        $this->urlShortener->urlToShortCode(
146
            new Uri('http://foobar.com/12345/hello?foo=bar'),
147
            [],
148
            null,
149
            null,
150
            'custom-slug'
151
        );
152
153
        $slugify->shouldHaveBeenCalledTimes(1);
154
    }
155
156
    /**
157
     * @test
158
     */
159
    public function exceptionIsThrownWhenNonUniqueSlugIsProvided()
160
    {
161
        /** @var MethodProphecy $slugify */
162
        $slugify = $this->slugger->slugify('custom-slug')->willReturnArgument();
163
164
        $repo = $this->prophesize(ShortUrlRepositoryInterface::class);
165
        /** @var MethodProphecy $findBySlug */
166
        $findBySlug = $repo->findOneBy(['shortCode' => 'custom-slug'])->willReturn(new ShortUrl());
167
        $repo->findOneBy(Argument::cetera())->willReturn(null);
168
        /** @var MethodProphecy $getRepo */
169
        $getRepo = $this->em->getRepository(ShortUrl::class)->willReturn($repo->reveal());
170
171
        $slugify->shouldBeCalledTimes(1);
172
        $findBySlug->shouldBeCalledTimes(1);
173
        $getRepo->shouldBeCalled();
174
        $this->expectException(NonUniqueSlugException::class);
175
176
        $this->urlShortener->urlToShortCode(
177
            new Uri('http://foobar.com/12345/hello?foo=bar'),
178
            [],
179
            null,
180
            null,
181
            'custom-slug'
182
        );
183
    }
184
185
    /**
186
     * @test
187
     */
188
    public function shortCodeIsProperlyParsed()
189
    {
190
        // 12C1c -> 10
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
191
        $shortCode = '12C1c';
192
        $shortUrl = new ShortUrl();
193
        $shortUrl->setShortCode($shortCode)
0 ignored issues
show
Deprecated Code introduced by
The method Shlinkio\Shlink\Core\Ent...rtUrl::setOriginalUrl() has been deprecated with message: Use setLongUrl() instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
194
                 ->setOriginalUrl('expected_url');
195
196
        $repo = $this->prophesize(ShortUrlRepositoryInterface::class);
197
        $repo->findOneByShortCode($shortCode)->willReturn($shortUrl);
198
        $this->em->getRepository(ShortUrl::class)->willReturn($repo->reveal());
199
200
        $url = $this->urlShortener->shortCodeToUrl($shortCode);
201
        $this->assertSame($shortUrl, $url);
202
    }
203
204
    /**
205
     * @test
206
     * @expectedException \Shlinkio\Shlink\Core\Exception\InvalidShortCodeException
207
     */
208
    public function invalidCharSetThrowsException()
209
    {
210
        $this->urlShortener->shortCodeToUrl('&/(');
211
    }
212
}
213