Completed
Push — master ( c70077...3d32a9 )
by Alejandro
16s queued 10s
created

VisitServiceTest::provideIsNonLocatableAddress()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
declare(strict_types=1);
3
4
namespace ShlinkioTest\Shlink\Core\Service;
5
6
use Doctrine\ORM\EntityManager;
7
use PHPUnit\Framework\TestCase;
8
use Prophecy\Argument;
9
use Prophecy\Prophecy\ObjectProphecy;
10
use Shlinkio\Shlink\Common\IpGeolocation\Model\Location;
11
use Shlinkio\Shlink\Core\Entity\ShortUrl;
12
use Shlinkio\Shlink\Core\Entity\Visit;
13
use Shlinkio\Shlink\Core\Entity\VisitLocation;
14
use Shlinkio\Shlink\Core\Exception\IpCannotBeLocatedException;
15
use Shlinkio\Shlink\Core\Model\Visitor;
16
use Shlinkio\Shlink\Core\Repository\VisitRepository;
17
use Shlinkio\Shlink\Core\Service\VisitService;
18
use function array_shift;
19
use function count;
20
use function floor;
21
use function func_get_args;
22
use function Functional\map;
23
use function range;
24
use function sprintf;
25
26
class VisitServiceTest extends TestCase
27
{
28
    /** @var VisitService */
29
    private $visitService;
30
    /** @var ObjectProphecy */
31
    private $em;
32
33
    public function setUp(): void
34
    {
35
        $this->em = $this->prophesize(EntityManager::class);
36
        $this->visitService = new VisitService($this->em->reveal());
37
    }
38
39
    /** @test */
40
    public function locateVisitsIteratesAndLocatesUnlocatedVisits(): void
41
    {
42
        $unlocatedVisits = map(range(1, 200), function (int $i) {
43
            return new Visit(new ShortUrl(sprintf('short_code_%s', $i)), Visitor::emptyInstance());
44
        });
45
46
        $repo = $this->prophesize(VisitRepository::class);
47
        $findUnlocatedVisits = $repo->findUnlocatedVisits(false)->willReturn($unlocatedVisits);
48
        $getRepo = $this->em->getRepository(Visit::class)->willReturn($repo->reveal());
49
50
        $persist = $this->em->persist(Argument::type(Visit::class))->will(function () {
51
        });
52
        $flush = $this->em->flush()->will(function () {
53
        });
54
        $clear = $this->em->clear()->will(function () {
55
        });
56
57
        $this->visitService->locateUnlocatedVisits(function () {
58
            return Location::emptyInstance();
59
        }, function () {
60
            $args = func_get_args();
61
62
            $this->assertInstanceOf(VisitLocation::class, array_shift($args));
63
            $this->assertInstanceOf(Visit::class, array_shift($args));
64
        });
65
66
        $findUnlocatedVisits->shouldHaveBeenCalledOnce();
67
        $getRepo->shouldHaveBeenCalledOnce();
68
        $persist->shouldHaveBeenCalledTimes(count($unlocatedVisits));
69
        $flush->shouldHaveBeenCalledTimes(floor(count($unlocatedVisits) / 200) + 1);
70
        $clear->shouldHaveBeenCalledTimes(floor(count($unlocatedVisits) / 200) + 1);
71
    }
72
73
    /**
74
     * @test
75
     * @dataProvider provideIsNonLocatableAddress
76
     */
77
    public function visitsWhichCannotBeLocatedAreIgnoredOrLocatedAsEmpty(bool $isNonLocatableAddress): void
78
    {
79
        $unlocatedVisits = [
80
            new Visit(new ShortUrl('foo'), Visitor::emptyInstance()),
81
        ];
82
83
        $repo = $this->prophesize(VisitRepository::class);
84
        $findUnlocatedVisits = $repo->findUnlocatedVisits(false)->willReturn($unlocatedVisits);
85
        $getRepo = $this->em->getRepository(Visit::class)->willReturn($repo->reveal());
86
87
        $persist = $this->em->persist(Argument::type(Visit::class))->will(function () {
88
        });
89
        $flush = $this->em->flush()->will(function () {
90
        });
91
        $clear = $this->em->clear()->will(function () {
92
        });
93
94
        $this->visitService->locateUnlocatedVisits(function () use ($isNonLocatableAddress) {
95
            throw new IpCannotBeLocatedException($isNonLocatableAddress, 'Cannot be located');
96
        });
97
98
        $findUnlocatedVisits->shouldHaveBeenCalledOnce();
99
        $getRepo->shouldHaveBeenCalledOnce();
100
        $persist->shouldHaveBeenCalledTimes($isNonLocatableAddress ? 1 : 0);
101
        $flush->shouldHaveBeenCalledOnce();
102
        $clear->shouldHaveBeenCalledOnce();
103
    }
104
105
    public function provideIsNonLocatableAddress(): iterable
106
    {
107
        yield 'The address is locatable' => [false];
108
        yield 'The address is non-locatable' => [true];
109
    }
110
}
111