BookableAvailableTest   A
last analyzed

Complexity

Total Complexity 11

Size/Duplication

Total Lines 99
Duplicated Lines 0 %

Importance

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