createMock(OidcHttpGateway::class); $mock->method('call') ->willReturn(['status' => 200, 'data' => '{"access_token":"abc"}']); $result = $mock->call('POST', 'https://login.example.com/token', 'grant_type=authorization_code'); $this->assertSame(200, $result['status']); $this->assertStringContainsString('access_token', $result['data']); } public function testMockCanSimulateNetworkError(): void { $mock = $this->createMock(OidcHttpGateway::class); $mock->method('call') ->willReturn(['status' => 0, 'data' => '']); $result = $mock->call('GET', 'https://unreachable.example.com'); $this->assertSame(0, $result['status']); $this->assertSame('', $result['data']); } public function testMockCanSimulate401Unauthorized(): void { $mock = $this->createMock(OidcHttpGateway::class); $mock->method('call') ->willReturn(['status' => 401, 'data' => '{"error":"invalid_client"}']); $result = $mock->call('POST', 'https://login.example.com/token', 'grant_type=client_credentials'); $this->assertSame(401, $result['status']); } public function testMockCanSimulate500ServerError(): void { $mock = $this->createMock(OidcHttpGateway::class); $mock->method('call') ->willReturn(['status' => 500, 'data' => 'Internal Server Error']); $result = $mock->call('POST', 'https://login.example.com/token'); $this->assertSame(500, $result['status']); } public function testMockCanSimulateMalformedJsonResponse(): void { $mock = $this->createMock(OidcHttpGateway::class); $mock->method('call') ->willReturn(['status' => 200, 'data' => '{malformed']); $result = $mock->call('GET', 'https://login.example.com/.well-known/openid-configuration'); $this->assertSame(200, $result['status']); $decoded = json_decode($result['data'], true); $this->assertNull($decoded, 'Malformed JSON should decode to null'); } // --- Method signature contract --- public function testCallMethodAcceptsAllParameters(): void { $mock = $this->createMock(OidcHttpGateway::class); $mock->expects($this->once()) ->method('call') ->with( 'POST', 'https://login.example.com/token', 'grant_type=authorization_code&code=abc', ['Content-Type' => 'application/x-www-form-urlencoded'] ) ->willReturn(['status' => 200, 'data' => '{}']); $mock->call( 'POST', 'https://login.example.com/token', 'grant_type=authorization_code&code=abc', ['Content-Type' => 'application/x-www-form-urlencoded'] ); } public function testCallMethodHasCorrectDefaultParameters(): void { $gateway = new OidcHttpGateway(); $reflection = new \ReflectionMethod($gateway, 'call'); $params = $reflection->getParameters(); $this->assertCount(4, $params); $this->assertSame('method', $params[0]->getName()); $this->assertSame('url', $params[1]->getName()); $this->assertSame('data', $params[2]->getName()); $this->assertTrue($params[2]->isDefaultValueAvailable()); $this->assertSame('', $params[2]->getDefaultValue()); $this->assertSame('headers', $params[3]->getName()); $this->assertTrue($params[3]->isDefaultValueAvailable()); $this->assertSame([], $params[3]->getDefaultValue()); } public function testCallMethodReturnTypeIsArray(): void { $gateway = new OidcHttpGateway(); $reflection = new \ReflectionMethod($gateway, 'call'); $returnType = $reflection->getReturnType(); $this->assertNotNull($returnType); $this->assertSame('array', (string) $returnType); } }