فهرست منبع

add unit tests for FileVoter

Olivier Massot 2 سال پیش
والد
کامیت
6197796107
2فایلهای تغییر یافته به همراه620 افزوده شده و 2 حذف شده
  1. 4 2
      src/Security/Voter/Core/FileVoter.php
  2. 616 0
      tests/Unit/Security/Voter/Core/FileVoterTest.php

+ 4 - 2
src/Security/Voter/Core/FileVoter.php

@@ -69,7 +69,7 @@ class FileVoter extends AbstractVoter
                 return true;
             }
 
-            // User has the requested role and owns the file or belongs to the organization who does
+            // User has the requested role and owns the file or belongs to the organization who does (deprecated)
             if (
                 $this->isInFileOwningGroupWithRole($subject, $this->getUser())
             ) {
@@ -184,14 +184,16 @@ class FileVoter extends AbstractVoter
      * @return bool
      * @throws \Exception
      */
-    protected function isAvailable(File $file, Access $user): bool {
+    protected function isAvailable(File $file, ?Access $user): bool {
 
         $today = DatesUtils::new();
 
         if ($file->getAvailabilityDate() !== null && $file->getAvailabilityDate() > $today) {
 
             //  Cas particulier de la liste des factures
+            // TODO: clarifier le ou les cas particulier(s) et les sortir de cette méthode (celle ci devrait tenir en deux lignes max)
             if (
+                $user &&
                 $file->getType() === FileTypeEnum::BILL()->getValue() &&
                 $this->accessUtils->hasRole($user, 'ROLE_BILLACCOUNTING')
             ) {

+ 616 - 0
tests/Unit/Security/Voter/Core/FileVoterTest.php

@@ -0,0 +1,616 @@
+<?php
+
+namespace App\Tests\Unit\Security\Voter\Core;
+
+use App\Entity\Access\Access;
+use App\Entity\Core\File;
+use App\Entity\Organization\Organization;
+use App\Entity\Person\Person;
+use App\Enum\Core\FileTypeEnum;
+use App\Enum\Core\FileVisibilityEnum;
+use App\Security\Voter\Core\FileVoter;
+use App\Service\Access\Utils;
+use App\Service\Security\InternalRequestsService;
+use App\Service\Security\SwitchUser;
+use App\Service\Utils\DatesUtils;
+use App\Tests\Unit\Security\Voter\TestableAbstractVoter;
+use Doctrine\Common\Collections\ArrayCollection;
+use Doctrine\ORM\EntityManagerInterface;
+use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\TestCase;
+use Ramsey\Collection\Collection;
+use Symfony\Bundle\SecurityBundle\Security;
+
+class TestableFileVoter extends FileVoter {
+    public function canView(object $subject): bool {
+        return parent::canView($subject);
+    }
+    public function canEdit(object $subject): bool {
+        return parent::canEdit($subject);
+    }
+    public function canCreate(object $subject): bool {
+        return parent::canCreate($subject);
+    }
+    public function canDelete(object $subject): bool {
+        return parent::canDelete($subject);
+    }
+    public function isInFileOwningGroup(File $file, Access $user): bool {
+        return parent::isInFileOwningGroup($file, $user);
+    }
+    public function isInFileOwningGroupWithRole(File $file, Access $user): bool {
+        return parent::isInFileOwningGroupWithRole($file, $user);
+    }
+    public function isAvailable(File $file, ?Access $user): bool { return parent::isAvailable($file, $user); }
+
+    public function getUser(): ?Access { return parent::getUser(); }
+    public function isUserLoggedIn(): bool { return parent::isUserLoggedIn(); }
+    public function isValidInternalRequest(): bool { return parent::isValidInternalRequest(); }
+}
+
+
+class FileVoterTest extends TestCase
+{
+    protected Security | MockObject $security;
+    protected Utils | MockObject $accessUtils;
+    protected EntityManagerInterface | MockObject $entityManager;
+    protected InternalRequestsService | MockObject $internalRequestsService;
+    protected SwitchUser | MockObject $switchUserService;
+
+    public function setUp(): void {
+        $this->security = $this->getMockBuilder(Security::class)->disableOriginalConstructor()->getMock();
+        $this->accessUtils = $this->getMockBuilder(Utils::class)->disableOriginalConstructor()->getMock();
+        $this->internalRequestsService = $this->getMockBuilder(InternalRequestsService::class)->disableOriginalConstructor()->getMock();
+        $this->entityManager = $this->getMockBuilder(EntityManagerInterface::class)->disableOriginalConstructor()->getMock();
+        $this->switchUserService = $this->getMockBuilder(SwitchUser::class)->disableOriginalConstructor()->getMock();
+    }
+
+    public function tearDown(): void
+    {
+        DatesUtils::clearFakeDatetime();
+    }
+
+    private function makeFileVoterMockFor(string $methodName): MockObject | TestableFileVoter {
+        return $this->getMockBuilder(TestableFileVoter::class)
+            ->setConstructorArgs([
+                $this->security,
+                $this->accessUtils,
+                $this->internalRequestsService,
+                $this->entityManager,
+                $this->switchUserService
+            ])
+            ->setMethodsExcept([$methodName])
+            ->getMock();
+    }
+
+    public function testCanViewPublicFile(): void {
+        $fileVoter = $this->makeFileVoterMockFor('canView');
+
+        $file = $this->getMockBuilder(File::class)->getMock();
+
+        $user = $this->getMockBuilder(Access::class)->getMock();
+        $fileVoter->method('getUser')->willReturn($user);
+
+        $fileVoter->method('isAvailable')->with($file, $user)->willReturn(true);
+
+        $file->method('getVisibility')->willReturn(FileVisibilityEnum::EVERYBODY()->getValue());
+
+        $this->assertTrue($fileVoter->canView($file));
+    }
+
+    public function testCanViewWithValidInternalRequest(): void {
+        $fileVoter = $this->makeFileVoterMockFor('canView');
+
+        $file = $this->getMockBuilder(File::class)->getMock();
+
+        $user = $this->getMockBuilder(Access::class)->getMock();
+        $fileVoter->method('getUser')->willReturn($user);
+
+        $fileVoter->method('isAvailable')->with($file, $user)->willReturn(true);
+        $fileVoter->method('isValidInternalRequest')->willReturn(true);
+
+        $file->method('getVisibility')->willReturn(FileVisibilityEnum::NOBODY()->getValue());
+
+        $this->assertTrue($fileVoter->canView($file));
+    }
+
+    public function testCanViewNoUserLoggedIn(): void {
+        $fileVoter = $this->makeFileVoterMockFor('canView');
+
+        $file = $this->getMockBuilder(File::class)->getMock();
+
+        $user = $this->getMockBuilder(Access::class)->getMock();
+        $fileVoter->method('getUser')->willReturn($user);
+
+        $fileVoter->method('isAvailable')->with($file, $user)->willReturn(true);
+        $fileVoter->method('isValidInternalRequest')->willReturn(false);
+        $fileVoter->method('isUserLoggedIn')->willReturn(false);
+
+        $file->method('getVisibility')->willReturn(FileVisibilityEnum::NOBODY()->getValue());
+
+        $this->assertFalse($fileVoter->canView($file));
+    }
+
+    public function testCanViewUserInFilePersons(): void {
+        $fileVoter = $this->makeFileVoterMockFor('canView');
+
+        $file = $this->getMockBuilder(File::class)->getMock();
+
+        $user = $this->getMockBuilder(Access::class)->getMock();
+        $fileVoter->method('getUser')->willReturn($user);
+
+        $fileVoter->method('isAvailable')->with($file, $user)->willReturn(true);
+        $fileVoter->method('isValidInternalRequest')->willReturn(false);
+        $fileVoter->method('isUserLoggedIn')->willReturn(true);
+
+        $file->method('getVisibility')->willReturn(FileVisibilityEnum::NOBODY()->getValue());
+
+        $owner = $this->getMockBuilder(Person::class)->getMock();
+        $userPerson = $this->getMockBuilder(Person::class)->getMock();
+
+        $user->method('getPerson')->willReturn($userPerson);
+
+        $file->method('getAccessPersons')->willReturn(new ArrayCollection([$userPerson]));
+
+        $this->assertTrue($fileVoter->canView($file));
+    }
+
+    public function testCanViewUserIsOwner(): void {
+        $fileVoter = $this->makeFileVoterMockFor('canView');
+
+        $file = $this->getMockBuilder(File::class)->getMock();
+
+        $user = $this->getMockBuilder(Access::class)->getMock();
+        $fileVoter->method('getUser')->willReturn($user);
+
+        $fileVoter->method('isAvailable')->with($file, $user)->willReturn(true);
+        $fileVoter->method('isValidInternalRequest')->willReturn(false);
+        $fileVoter->method('isUserLoggedIn')->willReturn(true);
+
+        $file->method('getVisibility')->willReturn(FileVisibilityEnum::NOBODY()->getValue());
+
+        $owner = $this->getMockBuilder(Person::class)->getMock();
+
+        $user->method('getPerson')->willReturn($owner);
+
+        $file->method('getAccessPersons')->willReturn(new ArrayCollection([]));
+        $file->method('getPerson')->willReturn($owner);
+
+        $this->assertTrue($fileVoter->canView($file));
+    }
+
+    public function testCanViewUserHasRoleFile(): void {
+        $fileVoter = $this->makeFileVoterMockFor('canView');
+
+        $file = $this->getMockBuilder(File::class)->getMock();
+
+        $user = $this->getMockBuilder(Access::class)->getMock();
+        $fileVoter->method('getUser')->willReturn($user);
+
+        $fileVoter->method('isAvailable')->with($file, $user)->willReturn(true);
+        $fileVoter->method('isValidInternalRequest')->willReturn(false);
+        $fileVoter->method('isUserLoggedIn')->willReturn(true);
+
+        $file->method('getVisibility')->willReturn(FileVisibilityEnum::NOBODY()->getValue());
+
+        $owner = $this->getMockBuilder(Person::class)->getMock();
+        $userPerson = $this->getMockBuilder(Person::class)->getMock();
+
+        $file->method('getAccessPersons')->willReturn(new ArrayCollection([]));
+
+        $this->accessUtils->method('hasRole')->with($user, 'ROLE_FILE')->willReturn(true);
+        $fileVoter->method('isInFileOwningGroup')->with($file, $user)->willReturn(true);
+
+        $this->assertTrue($fileVoter->canView($file));
+    }
+
+    public function testCanViewUserInOwningGroupWithRole(): void {
+        $fileVoter = $this->makeFileVoterMockFor('canView');
+
+        $file = $this->getMockBuilder(File::class)->getMock();
+
+        $user = $this->getMockBuilder(Access::class)->getMock();
+        $fileVoter->method('getUser')->willReturn($user);
+
+        $fileVoter->method('isAvailable')->with($file, $user)->willReturn(true);
+        $fileVoter->method('isValidInternalRequest')->willReturn(false);
+        $fileVoter->method('isUserLoggedIn')->willReturn(true);
+
+        $file->method('getVisibility')->willReturn(FileVisibilityEnum::NOBODY()->getValue());
+
+        $owner = $this->getMockBuilder(Person::class)->getMock();
+        $userPerson = $this->getMockBuilder(Person::class)->getMock();
+
+        $file->method('getAccessPersons')->willReturn(new ArrayCollection([]));
+
+        $this->accessUtils->method('hasRole')->with($user, 'ROLE_FILE')->willReturn(false);
+        $fileVoter->method('isInFileOwningGroup')->with($file, $user)->willReturn(true);
+        $fileVoter->method('isInFileOwningGroupWithRole')->with($file, $user)->willReturn(true);
+
+        $this->assertTrue($fileVoter->canView($file));
+    }
+
+    public function testCanViewUserHasNotRoleFile(): void {
+        $fileVoter = $this->makeFileVoterMockFor('canView');
+
+        $file = $this->getMockBuilder(File::class)->getMock();
+
+        $user = $this->getMockBuilder(Access::class)->getMock();
+        $fileVoter->method('getUser')->willReturn($user);
+
+        $fileVoter->method('isAvailable')->with($file, $user)->willReturn(true);
+
+        $fileVoter->method('isValidInternalRequest')->willReturn(false);
+
+        $fileVoter->method('isUserLoggedIn')->willReturn(true);
+
+        $file->method('getVisibility')->willReturn(FileVisibilityEnum::NOBODY()->getValue());
+
+        $owner = $this->getMockBuilder(Person::class)->getMock();
+        $userPerson = $this->getMockBuilder(Person::class)->getMock();
+
+        $file->method('getAccessPersons')->willReturn(new ArrayCollection([]));
+
+        $this->accessUtils->method('hasRole')->with($user, 'ROLE_FILE')->willReturn(false);
+        $fileVoter->method('isInFileOwningGroup')->with($file, $user)->willReturn(true);
+
+        $this->assertFalse($fileVoter->canView($file));
+    }
+
+    public function testCanViewUserNotInOwningGroup(): void {
+        $fileVoter = $this->makeFileVoterMockFor('canView');
+
+        $file = $this->getMockBuilder(File::class)->getMock();
+
+        $user = $this->getMockBuilder(Access::class)->getMock();
+        $fileVoter->method('getUser')->willReturn($user);
+
+        $fileVoter->method('isAvailable')->with($file, $user)->willReturn(true);
+
+        $fileVoter->method('isValidInternalRequest')->willReturn(false);
+
+        $fileVoter->method('isUserLoggedIn')->willReturn(true);
+
+        $file->method('getVisibility')->willReturn(FileVisibilityEnum::NOBODY()->getValue());
+
+        $owner = $this->getMockBuilder(Person::class)->getMock();
+        $userPerson = $this->getMockBuilder(Person::class)->getMock();
+
+        $file->method('getAccessPersons')->willReturn(new ArrayCollection([]));
+
+        $this->accessUtils->method('hasRole')->with($user, 'ROLE_FILE')->willReturn(true);
+        $fileVoter->method('isInFileOwningGroup')->with($file, $user)->willReturn(false);
+
+        $this->assertFalse($fileVoter->canView($file));
+    }
+
+    public function testCanViewFileNotAvailable(): void {
+        $fileVoter = $this->makeFileVoterMockFor('canView');
+
+        $file = $this->getMockBuilder(File::class)->getMock();
+
+        $user = $this->getMockBuilder(Access::class)->getMock();
+        $fileVoter->method('getUser')->willReturn($user);
+
+        $fileVoter->method('isAvailable')->with($file, $user)->willReturn(false);
+
+        $this->assertFalse($fileVoter->canView($file));
+    }
+
+    public function testCanEditNotAvailable(): void {
+        $fileVoter = $this->makeFileVoterMockFor('canEdit');
+
+        $file = $this->getMockBuilder(File::class)->getMock();
+        $user = $this->getMockBuilder(Access::class)->getMock();
+        $fileVoter->method('getUser')->willReturn($user);
+
+        $fileVoter->method('isAvailable')->with($file, $user)->willReturn(false);
+
+        $this->assertFalse($fileVoter->canEdit($file));
+    }
+
+    public function testCanEditNoUserLoggedIn(): void {
+        $fileVoter = $this->makeFileVoterMockFor('canEdit');
+
+        $file = $this->getMockBuilder(File::class)->getMock();
+        $fileVoter->method('getUser')->willReturn(null);
+        $fileVoter->method('isUserLoggedIn')->willReturn(false);
+
+        $fileVoter->method('isAvailable')->with($file, null)->willReturn(true);
+
+        $this->assertFalse($fileVoter->canEdit($file));
+    }
+
+    public function testCanEditUserHasRoleFile(): void {
+        $fileVoter = $this->makeFileVoterMockFor('canEdit');
+
+        $file = $this->getMockBuilder(File::class)->getMock();
+
+        $user = $this->getMockBuilder(Access::class)->getMock();
+        $fileVoter->method('getUser')->willReturn($user);
+        $fileVoter->method('isUserLoggedIn')->willReturn(true);
+
+        $fileVoter->method('isAvailable')->with($file, $user)->willReturn(true);
+
+        $this->accessUtils->method('hasRole')->with($user, 'ROLE_FILE')->willReturn(true);
+        $fileVoter->method('isInFileOwningGroup')->with($file, $user)->willReturn(true);
+
+        $this->assertTrue($fileVoter->canEdit($file));
+    }
+
+    public function testCanEditUserHasRoleFileButNotInOwningGroup(): void {
+        $fileVoter = $this->makeFileVoterMockFor('canEdit');
+
+        $file = $this->getMockBuilder(File::class)->getMock();
+
+        $user = $this->getMockBuilder(Access::class)->getMock();
+        $fileVoter->method('getUser')->willReturn($user);
+        $fileVoter->method('isUserLoggedIn')->willReturn(true);
+
+        $fileVoter->method('isAvailable')->with($file, $user)->willReturn(true);
+
+        $this->accessUtils->method('hasRole')->with($user, 'ROLE_FILE')->willReturn(true);
+        $fileVoter->method('isInFileOwningGroup')->with($file, $user)->willReturn(false);
+
+        $this->assertFalse($fileVoter->canEdit($file));
+    }
+
+    public function testCanEditUserInOwningGroupButHasNotRoleFile(): void {
+        $fileVoter = $this->makeFileVoterMockFor('canEdit');
+
+        $file = $this->getMockBuilder(File::class)->getMock();
+
+        $user = $this->getMockBuilder(Access::class)->getMock();
+        $fileVoter->method('getUser')->willReturn($user);
+        $fileVoter->method('isUserLoggedIn')->willReturn(true);
+
+        $fileVoter->method('isAvailable')->with($file, $user)->willReturn(true);
+
+        $this->accessUtils->method('hasRole')->with($user, 'ROLE_FILE')->willReturn(false);
+        $fileVoter->method('isInFileOwningGroup')->with($file, $user)->willReturn(true);
+
+        $this->assertFalse($fileVoter->canEdit($file));
+    }
+
+    public function testCanEditIsOwner(): void {
+        $fileVoter = $this->makeFileVoterMockFor('canEdit');
+
+        $file = $this->getMockBuilder(File::class)->getMock();
+
+        $user = $this->getMockBuilder(Access::class)->getMock();
+        $userPerson = $this->getMockBuilder(Person::class)->getMock();
+        $userPerson->method('getId')->willReturn(1);
+        $user->method('getPerson')->willReturn($userPerson);
+
+        $fileVoter->method('getUser')->willReturn($user);
+        $fileVoter->method('isUserLoggedIn')->willReturn(true);
+
+        $fileVoter->method('isAvailable')->with($file, $user)->willReturn(true);
+
+        $this->accessUtils->method('hasRole')->with($user, 'ROLE_FILE')->willReturn(false);
+        $fileVoter->method('isInFileOwningGroup')->with($file, $user)->willReturn(true);
+
+        $file->method('getPerson')->willReturn($userPerson);
+
+        $this->assertTrue($fileVoter->canEdit($file));
+    }
+
+    public function testCanEditLoggedInButHasNotRight(): void {
+        $fileVoter = $this->makeFileVoterMockFor('canEdit');
+
+        $file = $this->getMockBuilder(File::class)->getMock();
+
+        $user = $this->getMockBuilder(Access::class)->getMock();
+        $userPerson = $this->getMockBuilder(Person::class)->getMock();
+        $userPerson->method('getId')->willReturn(1);
+        $user->method('getPerson')->willReturn($userPerson);
+
+        $fileVoter->method('getUser')->willReturn($user);
+        $fileVoter->method('isUserLoggedIn')->willReturn(true);
+
+        $fileVoter->method('isAvailable')->with($file, $user)->willReturn(true);
+
+        $this->accessUtils->method('hasRole')->with($user, 'ROLE_FILE')->willReturn(false);
+        $fileVoter->method('isInFileOwningGroup')->with($file, $user)->willReturn(true);
+
+        $owner = $this->getMockBuilder(Person::class)->getMock();
+        $owner->method('getId')->willReturn(2);
+
+        $file->method('getPerson')->willReturn($owner);
+
+        $this->assertFalse($fileVoter->canEdit($file));
+    }
+
+    public function testCanCreateUserLoggedIn(): void
+    {
+        $fileVoter = $this->makeFileVoterMockFor('canCreate');
+
+        $file = $this->getMockBuilder(File::class)->getMock();
+
+        $fileVoter->method('isUserLoggedIn')->willReturn(true);
+
+        $this->assertTrue($fileVoter->canCreate($file));
+    }
+
+    public function testCanCreateUserNotLoggedIn(): void
+    {
+        $fileVoter = $this->makeFileVoterMockFor('canCreate');
+
+        $file = $this->getMockBuilder(File::class)->getMock();
+
+        $fileVoter->method('isUserLoggedIn')->willReturn(false);
+
+        $this->assertFalse($fileVoter->canCreate($file));
+    }
+
+    public function testCanDeleteCanEdit(): void
+    {
+        $fileVoter = $this->makeFileVoterMockFor('canDelete');
+
+        $file = $this->getMockBuilder(File::class)->getMock();
+
+        $fileVoter->method('canEdit')->with($file)->willReturn(true);
+
+        $this->assertTrue($fileVoter->canDelete($file));
+    }
+
+    public function testCanDeleteCanNotEdit(): void
+    {
+        $fileVoter = $this->makeFileVoterMockFor('canDelete');
+
+        $file = $this->getMockBuilder(File::class)->getMock();
+
+        $fileVoter->method('canEdit')->with($file)->willReturn(false);
+
+        $this->assertFalse($fileVoter->canDelete($file));
+    }
+
+    public function testIsInFileOwningGroupIsOrganizationOwned(): void {
+        $fileVoter = $this->makeFileVoterMockFor('isInFileOwningGroup');
+
+        $userPerson = $this->getMockBuilder(Person::class)->getMock();
+        $userPerson->method('getId')->willReturn(2);
+
+        $userOrganization = $this->getMockBuilder(Organization::class)->getMock();
+        $userOrganization->method('getId')->willReturn(10);
+
+        $user = $this->getMockBuilder(Access::class)->getMock();
+        $user->method('getOrganization')->willReturn($userOrganization);
+        $user->method('getPerson')->willReturn($userPerson);
+        $fileVoter->method('getUser')->willReturn($user);
+
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
+        $organization->method('getId')->willReturn(10);
+
+        $person = $this->getMockBuilder(Person::class)->getMock();
+        $person->method('getId')->willReturn(1);
+
+        $file = $this->getMockBuilder(File::class)->getMock();
+        $file->method('getOrganization')->willReturn($organization);
+        $file->method('getPerson')->willReturn($person);
+
+        $this->assertTrue($fileVoter->isInFileOwningGroup($file, $user));
+    }
+
+    public function testIsInFileOwningGroupIsPersonOwned(): void {
+        $fileVoter = $this->makeFileVoterMockFor('isInFileOwningGroup');
+
+        $userPerson = $this->getMockBuilder(Person::class)->getMock();
+        $userPerson->method('getId')->willReturn(1);
+
+        $userOrganization = $this->getMockBuilder(Organization::class)->getMock();
+        $userOrganization->method('getId')->willReturn(20);
+
+        $user = $this->getMockBuilder(Access::class)->getMock();
+        $user->method('getOrganization')->willReturn($userOrganization);
+        $user->method('getPerson')->willReturn($userPerson);
+        $fileVoter->method('getUser')->willReturn($user);
+
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
+        $organization->method('getId')->willReturn(10);
+
+        $person = $this->getMockBuilder(Person::class)->getMock();
+        $person->method('getId')->willReturn(1);
+
+        $file = $this->getMockBuilder(File::class)->getMock();
+        $file->method('getOrganization')->willReturn($organization);
+        $file->method('getPerson')->willReturn($person);
+
+        $this->assertTrue($fileVoter->isInFileOwningGroup($file, $user));
+    }
+
+    public function testIsInFileOwningGroupNotInGroup(): void {
+        $fileVoter = $this->makeFileVoterMockFor('isInFileOwningGroup');
+
+        $userPerson = $this->getMockBuilder(Person::class)->getMock();
+        $userPerson->method('getId')->willReturn(2);
+
+        $userOrganization = $this->getMockBuilder(Organization::class)->getMock();
+        $userOrganization->method('getId')->willReturn(20);
+
+        $user = $this->getMockBuilder(Access::class)->getMock();
+        $user->method('getOrganization')->willReturn($userOrganization);
+        $user->method('getPerson')->willReturn($userPerson);
+        $fileVoter->method('getUser')->willReturn($user);
+
+        $organization = $this->getMockBuilder(Organization::class)->getMock();
+        $organization->method('getId')->willReturn(10);
+
+        $person = $this->getMockBuilder(Person::class)->getMock();
+        $person->method('getId')->willReturn(1);
+
+        $file = $this->getMockBuilder(File::class)->getMock();
+        $file->method('getOrganization')->willReturn($organization);
+        $file->method('getPerson')->willReturn($person);
+
+        $this->assertFalse($fileVoter->isInFileOwningGroup($file, $user));
+    }
+
+    public function testIsAvailablePassedAvailabilityDate(): void {
+        $fileVoter = $this->makeFileVoterMockFor('isAvailable');
+
+        $user = $this->getMockBuilder(Access::class)->getMock();
+        $fileVoter->method('getUser')->willReturn($user);
+
+        DatesUtils::setFakeDatetime('2020-01-31');
+
+        $file = $this->getMockBuilder(File::class)->getMock();
+        $file->method('getAvailabilityDate')->willReturn(new \DateTime('2020-01-01'));
+
+        $this->assertTrue($fileVoter->isAvailable($file, $user));
+    }
+
+    public function testIsAvailableAnonymousAndPassedAvailabilityDate(): void {
+        $fileVoter = $this->makeFileVoterMockFor('isAvailable');
+
+        DatesUtils::setFakeDatetime('2020-01-31');
+
+        $file = $this->getMockBuilder(File::class)->getMock();
+        $file->method('getAvailabilityDate')->willReturn(new \DateTime('2020-01-01'));
+
+        $this->assertTrue($fileVoter->isAvailable($file, null));
+    }
+
+    public function testIsAvailableNoAvailabilityDate(): void {
+        $fileVoter = $this->makeFileVoterMockFor('isAvailable');
+
+        $user = $this->getMockBuilder(Access::class)->getMock();
+        $fileVoter->method('getUser')->willReturn($user);
+
+        $file = $this->getMockBuilder(File::class)->getMock();
+        $file->method('getAvailabilityDate')->willReturn(null);
+
+        $this->assertTrue($fileVoter->isAvailable($file, $user));
+    }
+
+    public function testIsAvailableFutureAvailabilityDate(): void {
+        $fileVoter = $this->makeFileVoterMockFor('isAvailable');
+
+        $user = $this->getMockBuilder(Access::class)->getMock();
+        $fileVoter->method('getUser')->willReturn($user);
+
+        DatesUtils::setFakeDatetime('2020-01-01');
+
+        $file = $this->getMockBuilder(File::class)->getMock();
+        $file->method('getAvailabilityDate')->willReturn(new \DateTime('2020-01-31'));
+        $file->method('getType')->willReturn(FileTypeEnum::UNKNOWN()->getValue());
+        $this->accessUtils->method('hasRole')->with($user, 'ROLE_BILLACCOUNTING')->willReturn(false);
+
+        $this->assertFalse($fileVoter->isAvailable($file, $user));
+    }
+
+    public function testIsAvailableFutureAvailabilityDateSpecialBillingCase(): void {
+        $fileVoter = $this->makeFileVoterMockFor('isAvailable');
+
+        $user = $this->getMockBuilder(Access::class)->getMock();
+        $fileVoter->method('getUser')->willReturn($user);
+
+        DatesUtils::setFakeDatetime('2020-01-01');
+
+        $file = $this->getMockBuilder(File::class)->getMock();
+        $file->method('getAvailabilityDate')->willReturn(new \DateTime('2020-01-31'));
+        $file->method('getType')->willReturn(FileTypeEnum::BILL()->getValue());
+        $this->accessUtils->method('hasRole')->with($user, 'ROLE_BILLACCOUNTING')->willReturn(true);
+
+        $this->assertTrue($fileVoter->isAvailable($file, $user));
+    }
+}