VisitsTrackerTest   A
last analyzed

Complexity

Total Complexity 6

Size/Duplication

Total Lines 97
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 6
eloc 52
dl 0
loc 97
rs 10
c 3
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A throwsExceptionWhenRequestingVisitsForInvalidShortCode() 0 11 1
A visitsForTagAreReturnedAsExpected() 0 18 1
A infoReturnsVisitsForCertainShortCode() 0 17 1
A throwsExceptionWhenRequestingVisitsForInvalidTag() 0 12 1
A trackPersistsVisit() 0 10 1
A setUp() 0 6 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ShlinkioTest\Shlink\Core\Service;
6
7
use Doctrine\ORM\EntityManager;
8
use Laminas\Stdlib\ArrayUtils;
9
use PHPUnit\Framework\TestCase;
10
use Prophecy\Argument;
11
use Prophecy\PhpUnit\ProphecyTrait;
12
use Prophecy\Prophecy\ObjectProphecy;
13
use Psr\EventDispatcher\EventDispatcherInterface;
14
use Shlinkio\Shlink\Common\Util\DateRange;
15
use Shlinkio\Shlink\Core\Entity\ShortUrl;
16
use Shlinkio\Shlink\Core\Entity\Tag;
17
use Shlinkio\Shlink\Core\Entity\Visit;
18
use Shlinkio\Shlink\Core\EventDispatcher\ShortUrlVisited;
19
use Shlinkio\Shlink\Core\Exception\ShortUrlNotFoundException;
20
use Shlinkio\Shlink\Core\Exception\TagNotFoundException;
21
use Shlinkio\Shlink\Core\Model\ShortUrlIdentifier;
22
use Shlinkio\Shlink\Core\Model\Visitor;
23
use Shlinkio\Shlink\Core\Model\VisitsParams;
24
use Shlinkio\Shlink\Core\Repository\ShortUrlRepositoryInterface;
25
use Shlinkio\Shlink\Core\Repository\TagRepository;
26
use Shlinkio\Shlink\Core\Repository\VisitRepository;
27
use Shlinkio\Shlink\Core\Service\VisitsTracker;
28
29
use function Functional\map;
30
use function range;
31
32
class VisitsTrackerTest extends TestCase
33
{
34
    use ProphecyTrait;
35
36
    private VisitsTracker $visitsTracker;
37
    private ObjectProphecy $em;
38
    private ObjectProphecy $eventDispatcher;
39
40
    public function setUp(): void
41
    {
42
        $this->em = $this->prophesize(EntityManager::class);
43
        $this->eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
44
45
        $this->visitsTracker  = new VisitsTracker($this->em->reveal(), $this->eventDispatcher->reveal(), true);
46
    }
47
48
    /** @test */
49
    public function trackPersistsVisit(): void
50
    {
51
        $shortCode = '123ABC';
52
53
        $this->em->persist(Argument::that(fn (Visit $visit) => $visit->setId('1')))->shouldBeCalledOnce();
54
        $this->em->flush()->shouldBeCalledOnce();
55
56
        $this->visitsTracker->track(new ShortUrl($shortCode), Visitor::emptyInstance());
57
58
        $this->eventDispatcher->dispatch(Argument::type(ShortUrlVisited::class))->shouldHaveBeenCalled();
59
    }
60
61
    /** @test */
62
    public function infoReturnsVisitsForCertainShortCode(): void
63
    {
64
        $shortCode = '123ABC';
65
        $repo = $this->prophesize(ShortUrlRepositoryInterface::class);
66
        $count = $repo->shortCodeIsInUse($shortCode, null)->willReturn(true);
67
        $this->em->getRepository(ShortUrl::class)->willReturn($repo->reveal())->shouldBeCalledOnce();
68
69
        $list = map(range(0, 1), fn () => new Visit(new ShortUrl(''), Visitor::emptyInstance()));
70
        $repo2 = $this->prophesize(VisitRepository::class);
71
        $repo2->findVisitsByShortCode($shortCode, null, Argument::type(DateRange::class), 1, 0)->willReturn($list);
72
        $repo2->countVisitsByShortCode($shortCode, null, Argument::type(DateRange::class))->willReturn(1);
73
        $this->em->getRepository(Visit::class)->willReturn($repo2->reveal())->shouldBeCalledOnce();
74
75
        $paginator = $this->visitsTracker->info(new ShortUrlIdentifier($shortCode), new VisitsParams());
76
77
        self::assertEquals($list, ArrayUtils::iteratorToArray($paginator->getCurrentItems()));
78
        $count->shouldHaveBeenCalledOnce();
79
    }
80
81
    /** @test */
82
    public function throwsExceptionWhenRequestingVisitsForInvalidShortCode(): void
83
    {
84
        $shortCode = '123ABC';
85
        $repo = $this->prophesize(ShortUrlRepositoryInterface::class);
86
        $count = $repo->shortCodeIsInUse($shortCode, null)->willReturn(false);
87
        $this->em->getRepository(ShortUrl::class)->willReturn($repo->reveal())->shouldBeCalledOnce();
88
89
        $this->expectException(ShortUrlNotFoundException::class);
90
        $count->shouldBeCalledOnce();
91
92
        $this->visitsTracker->info(new ShortUrlIdentifier($shortCode), new VisitsParams());
93
    }
94
95
    /** @test */
96
    public function throwsExceptionWhenRequestingVisitsForInvalidTag(): void
97
    {
98
        $tag = 'foo';
99
        $repo = $this->prophesize(TagRepository::class);
100
        $count = $repo->count(['name' => $tag])->willReturn(0);
101
        $getRepo = $this->em->getRepository(Tag::class)->willReturn($repo->reveal());
102
103
        $this->expectException(TagNotFoundException::class);
104
        $count->shouldBeCalledOnce();
105
        $getRepo->shouldBeCalledOnce();
106
107
        $this->visitsTracker->visitsForTag($tag, new VisitsParams());
108
    }
109
110
    /** @test */
111
    public function visitsForTagAreReturnedAsExpected(): void
112
    {
113
        $tag = 'foo';
114
        $repo = $this->prophesize(TagRepository::class);
115
        $count = $repo->count(['name' => $tag])->willReturn(1);
116
        $getRepo = $this->em->getRepository(Tag::class)->willReturn($repo->reveal());
117
118
        $list = map(range(0, 1), fn () => new Visit(new ShortUrl(''), Visitor::emptyInstance()));
119
        $repo2 = $this->prophesize(VisitRepository::class);
120
        $repo2->findVisitsByTag($tag, Argument::type(DateRange::class), 1, 0)->willReturn($list);
121
        $repo2->countVisitsByTag($tag, Argument::type(DateRange::class))->willReturn(1);
122
        $this->em->getRepository(Visit::class)->willReturn($repo2->reveal())->shouldBeCalledOnce();
123
124
        $paginator = $this->visitsTracker->visitsForTag($tag, new VisitsParams());
125
126
        self::assertEquals($list, ArrayUtils::iteratorToArray($paginator->getCurrentItems()));
127
        $count->shouldHaveBeenCalledOnce();
128
        $getRepo->shouldHaveBeenCalledOnce();
129
    }
130
}
131