BookableAvailableTest::testAssert()   B
last analyzed

Complexity

Conditions 7
Paths 10

Size

Total Lines 59
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 31
c 1
b 0
f 0
dl 0
loc 59
rs 8.4906
cc 7
nc 10
nop 12

How to fix   Long Method    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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