BookableAvailableTest   A
last analyzed

Complexity

Total Complexity 12

Size/Duplication

Total Lines 99
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 12
eloc 55
c 1
b 0
f 0
dl 0
loc 99
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A addBookings() 0 6 2
A tearDown() 0 3 1
A providerAssert() 0 20 1
B testAssert() 0 59 8
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ApplicationTest\Acl\Assertion;
6
7
use Application\Acl\Acl;
8
use Application\Acl\Assertion\BookableAvailable;
9
use Application\Enum\BookableStatus;
10
use Application\Enum\BookingStatus;
11
use Application\Model\Bookable;
12
use Application\Model\Booking;
13
use Application\Model\License;
14
use Application\Model\User;
15
use Ecodev\Felix\Acl\ModelResource;
16
use PHPUnit\Framework\TestCase;
17
18
class BookableAvailableTest extends TestCase
19
{
20
    protected function tearDown(): void
21
    {
22
        User::setCurrent(null);
23
    }
24
25
    /**
26
     * @dataProvider providerAssert
27
     */
28
    public function testAssert(
29
        ?string $expectedMessage,
30
        ?string $withUserRole,
31
        bool $withBooking,
32
        bool $withBookable = false,
33
        bool $bookableIsActive = false,
34
        bool $bookableRequiresLicense = false,
35
        bool $useHasLicense = false,
36
        BookingStatus $bookingStatus = BookingStatus::Application,
37
        int $confirmedBookings = 0,
38
        int $applicationBookings = 0,
39
        int $simultaneousBookingMaximum = 1,
40
        int $waitingListLength = 0,
41
    ): void {
42
        $user = $this->getMockBuilder(User::class)->onlyMethods(['getRole'])->getMock();
43
44
        $booking = null;
45
        if ($withBooking) {
46
            $booking = new Booking();
47
            $booking->setStatus($bookingStatus);
48
49
            if ($withBookable) {
50
                $bookable = new Bookable();
51
                $booking->setBookable($bookable);
52
                $bookable->setStatus($bookableIsActive ? BookableStatus::Active : BookableStatus::Inactive);
53
                $bookable->setSimultaneousBookingMaximum($simultaneousBookingMaximum);
54
                $bookable->setWaitingListLength($waitingListLength);
55
56
                if ($bookableRequiresLicense) {
57
                    $license = new License();
58
                    $license->setName('my license');
59
                    $license->addBookable($bookable);
60
61
                    if ($useHasLicense) {
62
                        $license->addUser($user);
63
                    }
64
                }
65
66
                $this->addBookings($bookable, $confirmedBookings, BookingStatus::Booked);
67
                $this->addBookings($bookable, $applicationBookings, BookingStatus::Application);
68
            }
69
        }
70
71
        $acl = $this->createMock(Acl::class);
72
        $acl->expects(self::exactly($expectedMessage ? 1 : 0))
73
            ->method('reject')
74
            ->with($expectedMessage)
75
            ->willReturn(false);
76
77
        $resource = new ModelResource(Booking::class, $booking);
78
        if ($withUserRole) {
79
            $user->method('getRole')
80
                ->willReturn($withUserRole);
81
82
            User::setCurrent($user);
83
        }
84
85
        $assert = new BookableAvailable();
86
        self::assertSame(!$expectedMessage, $assert->assert($acl, null, $resource));
87
    }
88
89
    public static function providerAssert(): iterable
90
    {
91
        yield 'rejects anonymous' => ['the user is not logged in', null, false];
92
        yield 'rejects anonymous even with a booking' => ['the user is not logged in', null, true];
93
        yield 'rejects absence of booking, because that would be a critical bug in our architecture' => ['the booking does not exist', User::ROLE_MEMBER, false];
94
        yield 'allows booking without bookable' => [null, User::ROLE_MEMBER, true];
95
        yield 'rejects inactive bookable' => ['the bookable is not active', User::ROLE_MEMBER, true, true];
96
        yield 'rejects bookable requiring license' => ['the user does not have the required license: my license', User::ROLE_MEMBER, true, true, true, true];
97
        yield 'allows bookable requiring license if booking_only' => [null, User::ROLE_BOOKING_ONLY, true, true, true, true];
98
        yield 'allows bookable requiring license if have license' => [null, User::ROLE_MEMBER, true, true, true, true, true];
99
        yield 'rejects bookable who reached its limit' => ['the limit of simultaneous bookings was reached: 0/0', User::ROLE_MEMBER, true, true, true, false, false, BookingStatus::Application, 0, 0, 0];
100
        yield 'allows bookable with infinite limit' => [null, User::ROLE_MEMBER, true, true, true, false, false, BookingStatus::Application, -1];
101
        yield 'rejects application if 3 confirmed and limit to 3' => ['the limit of simultaneous bookings was reached: 3/3', User::ROLE_MEMBER, true, true, true, false, false, BookingStatus::Application, 3, 0, 3];
102
        yield 'rejects booked if 3 confirmed and limit to 3' => ['the limit of simultaneous bookings was reached: 3/3', User::ROLE_MEMBER, true, true, true, false, false, BookingStatus::Booked, 3, 0, 3];
103
        yield 'rejects application if 2 confirmed, 1 application and limit to 3' => ['the limit of simultaneous bookings was reached: 3/3', User::ROLE_MEMBER, true, true, true, false, false, BookingStatus::Application, 2, 1, 3];
104
        yield 'allows application if 2 confirmed, 1 application and limit to 3 and 5' => [null, User::ROLE_MEMBER, true, true, true, false, false, BookingStatus::Application, 2, 1, 3, 5];
105
        yield 'allows application if 3 confirmed, 1 application and limit to 3 and 5' => [null, User::ROLE_MEMBER, true, true, true, false, false, BookingStatus::Application, 3, 1, 3, 5];
106
        yield 'rejects booked if 3 confirmed, 1 application and limit to 3 and 5, because it would be stealing a spot in the waiting list, instead we must pass via an application' => ['the limit of simultaneous bookings was reached: 3/3 and the waiting list is full: 1/5', User::ROLE_MEMBER, true, true, true, false, false, BookingStatus::Booked, 3, 1, 3, 5];
107
        yield 'rejects application if 3 confirmed, 5 application and limit to 3 and 5' => ['the limit of simultaneous bookings was reached: 3/3 and the waiting list is full: 5/5', User::ROLE_MEMBER, true, true, true, false, false, BookingStatus::Application, 3, 5, 3, 5];
108
        yield 'rejects application if 1 confirmed, 7 application and limit to 3 and 5' => ['the limit of simultaneous bookings was reached: 3/3 and the waiting list is full: 5/5', User::ROLE_MEMBER, true, true, true, false, false, BookingStatus::Application, 1, 7, 3, 5];
109
    }
110
111
    private function addBookings(Bookable $bookable, int $count, BookingStatus $bookingStatus): void
112
    {
113
        for ($i = 0; $i < $count; ++$i) {
114
            $booking = new Booking();
115
            $booking->setStatus($bookingStatus);
116
            $booking->setBookable($bookable);
117
        }
118
    }
119
}
120