diff --git a/composer.json b/composer.json index 0c95a6f..adc4df3 100644 --- a/composer.json +++ b/composer.json @@ -59,7 +59,8 @@ "verify": [ "vendor/bin/phpcs -p", "vendor/bin/phpunit --no-coverage --testdox", - "vendor/bin/phpstan --memory-limit=256M analyze -c phpstan.neon" + "vendor/bin/phpstan --memory-limit=256M analyze -c phpstan.neon", + "vendor/bin/phpstan --memory-limit=256M analyze -c phpstan-dev.neon" ], "tests": [ "vendor/bin/phpunit --no-coverage" diff --git a/phpstan-dev-baseline.neon b/phpstan-dev-baseline.neon deleted file mode 100644 index 0d60c92..0000000 --- a/phpstan-dev-baseline.neon +++ /dev/null @@ -1,43 +0,0 @@ -parameters: - ignoreErrors: - - - message: '#^Property SimpleSAML\\Module\\casserver\\Tests\\Controller\\Cas10ControllerTest\:\:\$sessionMock is never read, only written\.$#' - identifier: property.onlyWritten - count: 1 - path: tests/src/Controller/Cas10ControllerTest.php - - - - message: '#^Property SimpleSAML\\Module\\casserver\\Tests\\Controller\\Cas20ControllerTest\:\:\$sessionMock is never read, only written\.$#' - identifier: property.onlyWritten - count: 1 - path: tests/src/Controller/Cas20ControllerTest.php - - - - message: '#^Property SimpleSAML\\Module\\casserver\\Tests\\Controller\\Cas20ControllerTest\:\:\$ticketValidatorMock is never read, only written\.$#' - identifier: property.onlyWritten - count: 1 - path: tests/src/Controller/Cas20ControllerTest.php - - - - message: '#^Call to an undefined method SimpleSAML\\Module\\casserver\\Cas\\TicketValidator\:\:expects\(\)\.$#' - identifier: method.notFound - count: 2 - path: tests/src/Controller/Cas30ControllerTest.php - - - - message: '#^Property SimpleSAML\\Module\\casserver\\Tests\\Controller\\Cas30ControllerTest\:\:\$sessionMock is never read, only written\.$#' - identifier: property.onlyWritten - count: 1 - path: tests/src/Controller/Cas30ControllerTest.php - - - - message: '#^Parameter \#2 \$renew of method SimpleSAML\\Module\\casserver\\Controller\\LoginController\:\:login\(\) expects bool, string given\.$#' - identifier: argument.type - count: 1 - path: tests/src/Controller/LoginControllerTest.php - - - - message: '#^Property SimpleSAML\\Module\\casserver\\Tests\\Controller\\LoginControllerTest\:\:\$sspContainer is never read, only written\.$#' - identifier: property.onlyWritten - count: 1 - path: tests/src/Controller/LoginControllerTest.php diff --git a/phpstan-dev.neon b/phpstan-dev.neon index c3c9ab6..71c90ad 100644 --- a/phpstan-dev.neon +++ b/phpstan-dev.neon @@ -3,5 +3,3 @@ parameters: paths: - tests -includes: - - phpstan-dev-baseline.neon diff --git a/tests/src/Controller/Cas10ControllerTest.php b/tests/src/Controller/Cas10ControllerTest.php index 01d3a6e..bcc5a99 100644 --- a/tests/src/Controller/Cas10ControllerTest.php +++ b/tests/src/Controller/Cas10ControllerTest.php @@ -10,15 +10,12 @@ use SimpleSAML\Configuration; use SimpleSAML\Module\casserver\Cas\Ticket\FileSystemTicketStore; use SimpleSAML\Module\casserver\Controller\Cas10Controller; -use SimpleSAML\Session; use Symfony\Component\HttpFoundation\Request; class Cas10ControllerTest extends TestCase { private array $moduleConfig; - private Session $sessionMock; - private array $ticket; private string $sessionId; @@ -37,11 +34,6 @@ protected function setUp(): void ], ]; - $this->sessionMock = $this->getMockBuilder(Session::class) - ->disableOriginalConstructor() - ->onlyMethods(['getSessionId']) - ->getMock(); - $this->ticket = [ 'id' => 'ST-' . $this->sessionId, 'validBefore' => 1731111111, diff --git a/tests/src/Controller/Cas20ControllerTest.php b/tests/src/Controller/Cas20ControllerTest.php index 0fe5f3b..4f780e8 100644 --- a/tests/src/Controller/Cas20ControllerTest.php +++ b/tests/src/Controller/Cas20ControllerTest.php @@ -5,16 +5,13 @@ namespace SimpleSAML\Module\casserver\Tests\Controller; use PHPUnit\Framework\Attributes\DataProvider; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use SimpleSAML\CAS\Constants as C; use SimpleSAML\Configuration; use SimpleSAML\Module; use SimpleSAML\Module\casserver\Cas\Factories\TicketFactory; use SimpleSAML\Module\casserver\Cas\Ticket\FileSystemTicketStore; -use SimpleSAML\Module\casserver\Cas\TicketValidator; use SimpleSAML\Module\casserver\Controller\Cas20Controller; -use SimpleSAML\Session; use SimpleSAML\Utils; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -23,8 +20,6 @@ class Cas20ControllerTest extends TestCase { private array $moduleConfig; - private Session $sessionMock; - private Request $samlValidateRequest; private string $sessionId; @@ -33,10 +28,6 @@ class Cas20ControllerTest extends TestCase private FileSystemTicketStore $ticketStore; - private TicketValidator $ticketValidatorMock; - - private Utils\HTTP|MockObject $utilsHttpMock; - private array $ticket; private array $proxyTicket; @@ -59,21 +50,6 @@ protected function setUp(): void // Hard code the ticket store $this->ticketStore = new FileSystemTicketStore(Configuration::loadFromArray($this->moduleConfig)); - $this->ticketValidatorMock = $this->getMockBuilder(TicketValidator::class) - ->setConstructorArgs([Configuration::loadFromArray($this->moduleConfig)]) - ->onlyMethods(['validateAndDeleteTicket']) - ->getMock(); - - $this->sessionMock = $this->getMockBuilder(Session::class) - ->disableOriginalConstructor() - ->onlyMethods(['getSessionId']) - ->getMock(); - - $this->utilsHttpMock = $this->getMockBuilder(Utils\HTTP::class) - ->disableOriginalConstructor() - ->onlyMethods(['fetch']) - ->getMock(); - $this->ticket = [ 'id' => 'ST-' . $this->sessionId, 'validBefore' => 1731111111, @@ -152,6 +128,7 @@ public function testProxyValidatePassesTheCorrectMethodToValidate(string $prefix $controllerMock->expects($this->once()) ->method('validate') ->with($request, $method, false, null, $prefix . $this->sessionId, 'https://myservice.com/abcd', null); + $controllerMock->$method($request, ...$requestParameters); } @@ -355,7 +332,7 @@ public function testProxyReturnsProxyTicket(): void $xml->registerXPathNamespace('cas', 'serviceResponse'); $this->assertEquals('serviceResponse', $xml->getName()); $this->assertNotNull($xml->xpath('//cas:proxySuccess')); - $ticketId = (string)$xml->xpath('//cas:proxyTicket')[0]; + $ticketId = (string) $xml->xpath('//cas:proxyTicket')[0]; $proxyTicket = $this->ticketStore->getTicket($ticketId); $this->assertTrue(filter_var($ticketFactory->isProxyTicket($proxyTicket), FILTER_VALIDATE_BOOLEAN)); } @@ -748,14 +725,19 @@ public function testThrowOnProxyServiceIdentityFail(): void parameters: $params, ); - $this->utilsHttpMock->expects($this->once()) + $httpUtilsMock = $this->getMockBuilder(Utils\HTTP::class) + ->disableOriginalConstructor() + ->onlyMethods(['fetch']) + ->getMock(); + + $httpUtilsMock->expects($this->once()) ->method('fetch') ->willThrowException(new \Exception()); $cas20Controller = new Cas20Controller( sspConfig: $this->sspConfig, casConfig: $config, - httpUtils: $this->utilsHttpMock, + httpUtils: $httpUtilsMock, ); $ticketStore = $cas20Controller->getTicketStore(); $ticketStore->addTicket($this->ticket); diff --git a/tests/src/Controller/Cas30ControllerTest.php b/tests/src/Controller/Cas30ControllerTest.php index 2ebdda8..70202f1 100644 --- a/tests/src/Controller/Cas30ControllerTest.php +++ b/tests/src/Controller/Cas30ControllerTest.php @@ -11,7 +11,6 @@ use SimpleSAML\Module\casserver\Cas\Ticket\FileSystemTicketStore; use SimpleSAML\Module\casserver\Cas\TicketValidator; use SimpleSAML\Module\casserver\Controller\Cas30Controller; -use SimpleSAML\Session; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -19,8 +18,6 @@ class Cas30ControllerTest extends TestCase { private array $moduleConfig; - private Session $sessionMock; - private Request $samlValidateRequest; private string $sessionId; @@ -29,8 +26,6 @@ class Cas30ControllerTest extends TestCase private FileSystemTicketStore $ticketStore; - private TicketValidator $ticketValidatorMock; - private array $ticket; @@ -51,16 +46,6 @@ protected function setUp(): void // Hard code the ticket store $this->ticketStore = new FileSystemTicketStore(Configuration::loadFromArray($this->moduleConfig)); - $this->ticketValidatorMock = $this->getMockBuilder(TicketValidator::class) - ->setConstructorArgs([Configuration::loadFromArray($this->moduleConfig)]) - ->onlyMethods(['validateAndDeleteTicket']) - ->getMock(); - - $this->sessionMock = $this->getMockBuilder(Session::class) - ->disableOriginalConstructor() - ->onlyMethods(['getSessionId']) - ->getMock(); - $this->ticket = [ 'id' => 'ST-' . $this->sessionId, 'validBefore' => 9999999999, @@ -236,7 +221,12 @@ public function testCasValidateAndDeleteTicketThrowsException(): void content: $samlRequest, ); - $this->ticketValidatorMock + $ticketValidatorMock = $this->getMockBuilder(TicketValidator::class) + ->setConstructorArgs([Configuration::loadFromArray($this->moduleConfig)]) + ->onlyMethods(['validateAndDeleteTicket']) + ->getMock(); + + $ticketValidatorMock ->expects($this->once()) ->method('validateAndDeleteTicket') ->willThrowException(new \RuntimeException('Cas validateAndDeleteTicket failed')); @@ -244,7 +234,7 @@ public function testCasValidateAndDeleteTicketThrowsException(): void $cas30Controller = new Cas30Controller( $this->sspConfig, $casconfig, - $this->ticketValidatorMock, + $ticketValidatorMock, ); // Exception expected @@ -289,7 +279,12 @@ public function testUnableToLoadTicket(): void content: $samlRequest, ); - $this->ticketValidatorMock + $ticketValidatorMock = $this->getMockBuilder(TicketValidator::class) + ->setConstructorArgs([Configuration::loadFromArray($this->moduleConfig)]) + ->onlyMethods(['validateAndDeleteTicket']) + ->getMock(); + + $ticketValidatorMock ->expects($this->once()) ->method('validateAndDeleteTicket') ->willReturn('i am a string'); @@ -297,7 +292,7 @@ public function testUnableToLoadTicket(): void $cas30Controller = new Cas30Controller( $this->sspConfig, $casconfig, - $this->ticketValidatorMock, + $ticketValidatorMock, ); // Exception expected diff --git a/tests/src/Controller/LoginControllerTest.php b/tests/src/Controller/LoginControllerTest.php index 0896d7f..6e647e8 100644 --- a/tests/src/Controller/LoginControllerTest.php +++ b/tests/src/Controller/LoginControllerTest.php @@ -8,7 +8,6 @@ use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use SimpleSAML\Auth\Simple; -use SimpleSAML\Compat\SspContainer; use SimpleSAML\Configuration; use SimpleSAML\HTTP\RunnableResponse; use SimpleSAML\Module; @@ -23,11 +22,9 @@ class LoginControllerTest extends TestCase private Simple|MockObject $authSimpleMock; - private SspContainer|MockObject $sspContainer; - private Configuration $sspConfig; - private Utils\HTTP|MockObject $httpUtils; + private Utils\HTTP $httpUtils; private Session|MockObject $sessionMock; @@ -39,15 +36,11 @@ protected function setUp(): void ->onlyMethods(['getAuthData', 'isAuthenticated', 'login', 'getAuthDataArray']) ->getMock(); - $this->sspContainer = $this->getMockBuilder(SspContainer::class) - ->disableOriginalConstructor() - ->onlyMethods(['redirect']) - ->getMock(); - - $this->httpUtils = $this->getMockBuilder(Utils\HTTP::class) - ->disableOriginalConstructor() - ->onlyMethods(['redirectTrustedURL']) - ->getMock(); + // Use a real HTTP utils instance: + // - LoginController builds ReturnTo using getSelfURLNoQuery() + // - Tests only inspect RunnableResponse callables; they never execute them + // - Avoid PHPUnit "mock without expectations" warnings + $this->httpUtils = new Utils\HTTP(); $this->sessionMock = $this->getMockBuilder(Session::class) ->disableOriginalConstructor() @@ -82,6 +75,29 @@ public static function setUpBeforeClass(): void } + /** + * Call LoginController::login() with correctly typed arguments derived from query parameters. + * (In production Symfony would populate these via #[MapQueryParameter], but tests call the method directly.) + * + * @param array $params + */ + private function callLogin(LoginController $controller, Request $request, array $params): mixed + { + return $controller->login( + $request, + renew: (bool)($params['renew'] ?? false), + gateway: (bool)($params['gateway'] ?? false), + service: isset($params['service']) ? (string)$params['service'] : null, + TARGET: isset($params['TARGET']) ? (string)$params['TARGET'] : null, + scope: isset($params['scope']) ? (string)$params['scope'] : null, + language: isset($params['language']) ? (string)$params['language'] : null, + entityId: isset($params['entityId']) ? (string)$params['entityId'] : null, + debugMode: isset($params['debugMode']) ? (string)$params['debugMode'] : null, + method: isset($params['method']) ? (string)$params['method'] : null, + ); + } + + public static function loginParameters(): array { return [ @@ -109,6 +125,11 @@ public static function loginParameters(): array #[DataProvider('loginParameters')] public function testLoginFails(array $params, string $message): void { + // These tests throw during configuration validation, before any auth/session interaction. + // Configure explicit "never" expectations to avoid PHPUnit warnings about mocks without expectations. + $this->authSimpleMock->expects($this->never())->method('isAuthenticated'); + $this->sessionMock->expects($this->never())->method('getSessionId'); + $casconfig = Configuration::loadFromArray($this->moduleConfig); $loginRequest = Request::create( @@ -124,7 +145,7 @@ public function testLoginFails(array $params, string $message): void $this->expectException(\RuntimeException::class); $this->expectExceptionMessage($message); - $loginController->login($loginRequest, ...$params); + $this->callLogin($loginController, $loginRequest, $params); } @@ -219,7 +240,7 @@ public function testAuthSourceLogin(array $requestParameters, array $loginParame $sessionId = session_create_id(); $this->sessionMock->expects($this->once())->method('getSessionId')->willReturn($sessionId); - $response = $controllerMock->login($loginRequest, ...$requestParameters); + $response = $this->callLogin($controllerMock, $loginRequest, $requestParameters); $this->assertInstanceOf(RunnableResponse::class, $response); // Assert we call into authSource->login @@ -328,7 +349,7 @@ public function testValidServiceUrl(string $serviceParam, string $redirectURL, b ); /** @psalm-suppress InvalidArgument */ - $response = $controllerMock->login($loginRequest, ...$queryParameters); + $response = $this->callLogin($controllerMock, $loginRequest, $queryParameters); $this->assertInstanceOf(RunnableResponse::class, $response); $arguments = $response->getArguments(); $this->assertEquals('https://example.com/ssp/module.php/cas/linkback.php', $arguments[0]); @@ -387,7 +408,7 @@ public function testGatewayPassiveDisabledRedirectsWithoutParams(string $service $this->sessionMock->expects($this->once())->method('getSessionId')->willReturn(session_create_id()); // Execute - $response = $controllerMock->login($loginRequest, ...$params); + $response = $this->callLogin($controllerMock, $loginRequest, $params); // Validate redirect with original service URL and no CAS parameters appended $this->assertInstanceOf(RunnableResponse::class, $response); @@ -428,7 +449,7 @@ public function testGatewayPassiveEnabledPerformsPassiveAttempt(): void $controllerMock->expects($this->once())->method('getSession')->willReturn($this->sessionMock); $this->sessionMock->expects($this->once())->method('getSessionId')->willReturn(session_create_id()); - $response = $controllerMock->login($loginRequest, ...$params); + $response = $this->callLogin($controllerMock, $loginRequest, $params); $this->assertInstanceOf(RunnableResponse::class, $response); @@ -473,7 +494,7 @@ public function testGatewayNoServicePassiveDisabledFallsBackToInteractive(): voi $controllerMock->expects($this->once())->method('getSession')->willReturn($this->sessionMock); $this->sessionMock->expects($this->once())->method('getSessionId')->willReturn(session_create_id()); - $response = $controllerMock->login($loginRequest, ...$params); + $response = $this->callLogin($controllerMock, $loginRequest, $params); $this->assertInstanceOf(RunnableResponse::class, $response); $callable = (array)$response->getCallable(); @@ -514,7 +535,7 @@ public function testRenewAndGatewayConflictDisablesPassive(): void $controllerMock->expects($this->once())->method('getSession')->willReturn($this->sessionMock); $this->sessionMock->expects($this->once())->method('getSessionId')->willReturn(session_create_id()); - $response = $controllerMock->login($loginRequest, ...$params); + $response = $this->callLogin($controllerMock, $loginRequest, $params); $this->assertInstanceOf(RunnableResponse::class, $response); $callable = (array)$response->getCallable(); @@ -565,7 +586,7 @@ public function testAuthenticatedPostSubmitsViaPostWithTicket(): void ]); /** @psalm-suppress InvalidArgument */ - $response = $controllerMock->login($loginRequest, ...$requestParams); + $response = $this->callLogin($controllerMock, $loginRequest, $requestParams); $this->assertInstanceOf(RunnableResponse::class, $response); $callable = (array)$response->getCallable(); diff --git a/tests/src/Controller/LogoutControllerTest.php b/tests/src/Controller/LogoutControllerTest.php index 79ac96e..b0ed497 100644 --- a/tests/src/Controller/LogoutControllerTest.php +++ b/tests/src/Controller/LogoutControllerTest.php @@ -5,7 +5,6 @@ namespace SimpleSAML\Module\casserver\Tests\Controller; use PHPUnit\Framework\Attributes\DataProvider; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use RuntimeException; use SimpleSAML\Auth\Simple; @@ -23,7 +22,7 @@ class LogoutControllerTest extends TestCase { private array $moduleConfig; - private Simple|MockObject $authSimpleMock; + private Simple $authSimple; private Utils\HTTP $httpUtils; @@ -32,10 +31,7 @@ class LogoutControllerTest extends TestCase protected function setUp(): void { - $this->authSimpleMock = $this->getMockBuilder(Simple::class) - ->disableOriginalConstructor() - ->onlyMethods(['logout', 'isAuthenticated']) - ->getMock(); + $this->authSimple = $this->createStub(Simple::class); $this->moduleConfig = [ 'ticketstore' => [ @@ -68,11 +64,11 @@ public static function setUpBeforeClass(): void public static function crossProtocolLogoutReturnUrlValidatedProvider(): array { return [ - 'validV3' => [ - true, - 'https://valid.edu/v3', - true, - ], + 'validV3' => [ + true, + 'https://valid.edu/v3', + true, + ], 'validV2' => [ false, 'https://valid.edu/v2', @@ -107,16 +103,22 @@ public function testCrossProtocolLogoutReturnUrlValidated(bool $isV3, string $qu $this->moduleConfig['skip_logout_page'] = false; $config = Configuration::loadFromArray($this->moduleConfig); + /** @var \PHPUnit\Framework\MockObject\MockObject&\SimpleSAML\Auth\Simple $authSimpleMock */ + $authSimpleMock = $this->getMockBuilder(Simple::class) + ->disableOriginalConstructor() + ->onlyMethods(['logout', 'isAuthenticated']) + ->getMock(); + // Unauthenticated - $this->authSimpleMock->expects($this->once())->method('isAuthenticated')->willReturn(false); + $authSimpleMock->expects($this->once())->method('isAuthenticated')->willReturn(false); - $controller = new LogoutController($this->sspConfig, $config, $this->authSimpleMock, $this->httpUtils); + $controller = new LogoutController($this->sspConfig, $config, $authSimpleMock, $this->httpUtils); $logoutUrl = Module::getModuleURL('casserver/logout.php'); $request = Request::create( uri: $logoutUrl, - parameters: [ $isV3 ? 'service' : 'url' => $queryValue], + parameters: [$isV3 ? 'service' : 'url' => $queryValue], ); $response = $controller->logout($request, $isV3 ? null : $queryValue, $isV3 ? $queryValue : null); @@ -132,7 +134,7 @@ public function testLogoutNotAllowed(): void $this->expectException(RuntimeException::class); $this->expectExceptionMessage('Logout not allowed'); - $controller = new LogoutController($this->sspConfig, $config, $this->authSimpleMock); + $controller = new LogoutController($this->sspConfig, $config, $this->authSimple); $controller->logout(Request::create('/')); } @@ -143,7 +145,7 @@ public function testLogoutNoRedirectUrlOnSkipLogout(): void $this->moduleConfig['skip_logout_page'] = true; $config = Configuration::loadFromArray($this->moduleConfig); - $controller = new LogoutController($this->sspConfig, $config, $this->authSimpleMock); + $controller = new LogoutController($this->sspConfig, $config, $this->authSimple); $response = $controller->logout(Request::create('/')); $this->validateLogoutResponse($response); } @@ -156,10 +158,16 @@ public function testLogoutWithRedirectUrlOnSkipLogout(): void $config = Configuration::loadFromArray($this->moduleConfig); $urlParam = 'https://example.com/test'; + /** @var \PHPUnit\Framework\MockObject\MockObject&\SimpleSAML\Auth\Simple $authSimpleMock */ + $authSimpleMock = $this->getMockBuilder(Simple::class) + ->disableOriginalConstructor() + ->onlyMethods(['logout', 'isAuthenticated']) + ->getMock(); + // Unauthenticated - $this->authSimpleMock->expects($this->once())->method('isAuthenticated')->willReturn(false); + $authSimpleMock->expects($this->once())->method('isAuthenticated')->willReturn(false); - $controller = new LogoutController($this->sspConfig, $config, $this->authSimpleMock, $this->httpUtils); + $controller = new LogoutController($this->sspConfig, $config, $authSimpleMock, $this->httpUtils); $logoutUrl = Module::getModuleURL('casserver/logout.php'); @@ -178,10 +186,16 @@ public function testLogoutNoRedirectUrlOnNoSkipLogoutUnAuthenticated(): void $this->moduleConfig['skip_logout_page'] = false; $config = Configuration::loadFromArray($this->moduleConfig); + /** @var \PHPUnit\Framework\MockObject\MockObject&\SimpleSAML\Auth\Simple $authSimpleMock */ + $authSimpleMock = $this->getMockBuilder(Simple::class) + ->disableOriginalConstructor() + ->onlyMethods(['logout', 'isAuthenticated']) + ->getMock(); + // Unauthenticated - $this->authSimpleMock->expects($this->once())->method('isAuthenticated')->willReturn(false); + $authSimpleMock->expects($this->once())->method('isAuthenticated')->willReturn(false); - $controller = new LogoutController($this->sspConfig, $config, $this->authSimpleMock, $this->httpUtils); + $controller = new LogoutController($this->sspConfig, $config, $authSimpleMock, $this->httpUtils); $response = $controller->logout(Request::create('/')); $this->validateLogoutResponse($response); } @@ -195,10 +209,16 @@ public function testLogoutWithRedirectUrlOnNoSkipLogoutUnAuthenticated(): void $urlParam = 'https://example.com/test'; $logoutUrl = Module::getModuleURL('casserver/loggedOut'); + /** @var \PHPUnit\Framework\MockObject\MockObject&\SimpleSAML\Auth\Simple $authSimpleMock */ + $authSimpleMock = $this->getMockBuilder(Simple::class) + ->disableOriginalConstructor() + ->onlyMethods(['logout', 'isAuthenticated']) + ->getMock(); + // Unauthenticated - $this->authSimpleMock->expects($this->once())->method('isAuthenticated')->willReturn(false); + $authSimpleMock->expects($this->once())->method('isAuthenticated')->willReturn(false); - $controller = new LogoutController($this->sspConfig, $config, $this->authSimpleMock, $this->httpUtils); + $controller = new LogoutController($this->sspConfig, $config, $authSimpleMock, $this->httpUtils); $request = Request::create( uri: $logoutUrl, parameters: ['url' => $urlParam], @@ -214,19 +234,25 @@ public function testLogoutNoRedirectUrlOnNoSkipLogoutAuthenticated(): void $this->moduleConfig['skip_logout_page'] = false; $config = Configuration::loadFromArray($this->moduleConfig); - // Unauthenticated - $this->authSimpleMock->expects($this->once())->method('isAuthenticated')->willReturn(true); + /** @var \PHPUnit\Framework\MockObject\MockObject&\SimpleSAML\Auth\Simple $authSimpleMock */ + $authSimpleMock = $this->getMockBuilder(Simple::class) + ->disableOriginalConstructor() + ->onlyMethods(['logout', 'isAuthenticated']) + ->getMock(); - $controller = new LogoutController($this->sspConfig, $config, $this->authSimpleMock, $this->httpUtils); + // Authenticated + $authSimpleMock->expects($this->once())->method('isAuthenticated')->willReturn(true); + + $controller = new LogoutController($this->sspConfig, $config, $authSimpleMock, $this->httpUtils); $queryParameters = ['url' => 'http://localhost/module.php/casserver/loggedOut']; $logoutRequest = Request::create( - uri: Module::getModuleURL('casserver/loggedOut'), + uri: Module::getModuleURL('casserver/loggedOut'), parameters: $queryParameters, ); $response = $controller->logout($logoutRequest, ...$queryParameters); - $callable = (array)$response->getCallable(); + $callable = (array) $response->getCallable(); $this->assertEquals('logout', $callable[1] ?? ''); } @@ -238,7 +264,7 @@ public function testTicketIdGetsDeletedOnLogout(): void $config = Configuration::loadFromArray($this->moduleConfig); $controllerMock = $this->getMockBuilder(LogoutController::class) - ->setConstructorArgs([$this->sspConfig, $config, $this->authSimpleMock, $this->httpUtils]) + ->setConstructorArgs([$this->sspConfig, $config, $this->authSimple, $this->httpUtils]) ->onlyMethods(['getSession']) ->getMock(); @@ -292,8 +318,6 @@ public function validateLogoutResponse( ?string $redirectUrl = null, bool $isShowPage = true, ): void { - - if ($isShowPage) { $this->assertInstanceOf(Template::class, $response); if (is_null($redirectUrl)) {