189 lines
5.9 KiB
PHP
189 lines
5.9 KiB
PHP
|
|
<?php declare(strict_types=1);
|
||
|
|
/**
|
||
|
|
* This file is part of the SplendidBear Websites' projects.
|
||
|
|
*
|
||
|
|
* Copyright (c) 2026 @ www.splendidbear.org
|
||
|
|
*
|
||
|
|
* For the full copyright and license information, please view the LICENSE
|
||
|
|
* file that was distributed with this source code.
|
||
|
|
*/
|
||
|
|
|
||
|
|
namespace App\Tests\Service;
|
||
|
|
|
||
|
|
use App\Service\RecaptchaService;
|
||
|
|
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
|
||
|
|
use PHPUnit\Framework\Attributes\Test;
|
||
|
|
use PHPUnit\Framework\Attributes\TestDox;
|
||
|
|
use PHPUnit\Framework\TestCase;
|
||
|
|
use Psr\Log\LoggerInterface;
|
||
|
|
use Symfony\Component\HttpClient\MockHttpClient;
|
||
|
|
use Symfony\Component\HttpClient\Response\MockResponse;
|
||
|
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Class RecaptchaServiceTest
|
||
|
|
*
|
||
|
|
* @package App\Tests\Service
|
||
|
|
* @author Lang <https://www.splendidbear.org>
|
||
|
|
* @category Class
|
||
|
|
* @license https://www.gnu.org/licenses/lgpl-3.0.en.html GNU Lesser General Public License
|
||
|
|
* @link www.splendidbear.org
|
||
|
|
* @since 2026. 04. 21.
|
||
|
|
*/
|
||
|
|
#[AllowMockObjectsWithoutExpectations]
|
||
|
|
#[TestDox('Recaptcha Service')]
|
||
|
|
class RecaptchaServiceTest extends TestCase
|
||
|
|
{
|
||
|
|
private const SECRET_KEY = 'test-secret-key';
|
||
|
|
|
||
|
|
#[Test]
|
||
|
|
#[TestDox('Verify returns false for empty token')]
|
||
|
|
public function verifyReturnsFalseForEmptyToken(): void
|
||
|
|
{
|
||
|
|
$httpClient = $this->createMock(HttpClientInterface::class);
|
||
|
|
$logger = $this->createMock(LoggerInterface::class);
|
||
|
|
|
||
|
|
$service = new RecaptchaService($httpClient, $logger, self::SECRET_KEY);
|
||
|
|
|
||
|
|
$result = $service->verify('');
|
||
|
|
|
||
|
|
$this->assertFalse($result);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[Test]
|
||
|
|
#[TestDox('Verify returns false when api returns failure')]
|
||
|
|
public function verifyReturnsFalseWhenApiReturnsFailure(): void
|
||
|
|
{
|
||
|
|
$mockResponse = new MockResponse(json_encode([
|
||
|
|
'success' => false,
|
||
|
|
'error-codes' => ['invalid-input-secret'],
|
||
|
|
], JSON_THROW_ON_ERROR));
|
||
|
|
|
||
|
|
$httpClient = new MockHttpClient($mockResponse);
|
||
|
|
$logger = $this->createMock(LoggerInterface::class);
|
||
|
|
$logger->expects($this->once())->method('info');
|
||
|
|
|
||
|
|
$service = new RecaptchaService($httpClient, $logger, self::SECRET_KEY);
|
||
|
|
|
||
|
|
$result = $service->verify('invalid-token');
|
||
|
|
|
||
|
|
$this->assertFalse($result);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[Test]
|
||
|
|
#[TestDox('Verify returns true when api returns success and high score')]
|
||
|
|
public function verifyReturnsTrueWhenApiReturnsSuccessAndHighScore(): void
|
||
|
|
{
|
||
|
|
$mockResponse = new MockResponse(json_encode([
|
||
|
|
'success' => true,
|
||
|
|
'score' => 0.8,
|
||
|
|
'hostname' => 'test.com',
|
||
|
|
], JSON_THROW_ON_ERROR));
|
||
|
|
|
||
|
|
$httpClient = new MockHttpClient($mockResponse);
|
||
|
|
$logger = $this->createMock(LoggerInterface::class);
|
||
|
|
$logger->expects($this->once())->method('info');
|
||
|
|
|
||
|
|
$service = new RecaptchaService($httpClient, $logger, self::SECRET_KEY);
|
||
|
|
|
||
|
|
$result = $service->verify('valid-token');
|
||
|
|
|
||
|
|
$this->assertTrue($result);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[Test]
|
||
|
|
#[TestDox('Verify returns false when score below threshold')]
|
||
|
|
public function verifyReturnsFalseWhenScoreBelowThreshold(): void
|
||
|
|
{
|
||
|
|
$mockResponse = new MockResponse(json_encode([
|
||
|
|
'success' => true,
|
||
|
|
'score' => 0.3,
|
||
|
|
'hostname' => 'test.com',
|
||
|
|
], JSON_THROW_ON_ERROR));
|
||
|
|
|
||
|
|
$httpClient = new MockHttpClient($mockResponse);
|
||
|
|
$logger = $this->createMock(LoggerInterface::class);
|
||
|
|
$logger->expects($this->once())->method('info');
|
||
|
|
|
||
|
|
$service = new RecaptchaService($httpClient, $logger, self::SECRET_KEY);
|
||
|
|
|
||
|
|
$result = $service->verify('low-score-token');
|
||
|
|
|
||
|
|
$this->assertFalse($result);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[Test]
|
||
|
|
#[TestDox('Verify returns false when api throws exception')]
|
||
|
|
public function verifyReturnsFalseWhenApiThrowsException(): void
|
||
|
|
{
|
||
|
|
$mockResponse = new MockResponse('', ['http_code' => 500]);
|
||
|
|
|
||
|
|
$httpClient = new MockHttpClient($mockResponse);
|
||
|
|
$logger = $this->createMock(LoggerInterface::class);
|
||
|
|
$logger->expects($this->once())->method('error');
|
||
|
|
|
||
|
|
$service = new RecaptchaService($httpClient, $logger, self::SECRET_KEY);
|
||
|
|
|
||
|
|
$result = $service->verify('test-token');
|
||
|
|
|
||
|
|
$this->assertFalse($result);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[Test]
|
||
|
|
#[TestDox('Verify includes remote ip when provided')]
|
||
|
|
public function verifyIncludesRemoteIpWhenProvided(): void
|
||
|
|
{
|
||
|
|
$mockResponse = new MockResponse(json_encode([
|
||
|
|
'success' => true,
|
||
|
|
'score' => 0.9,
|
||
|
|
], JSON_THROW_ON_ERROR));
|
||
|
|
|
||
|
|
$httpClient = new MockHttpClient($mockResponse);
|
||
|
|
$logger = $this->createMock(LoggerInterface::class);
|
||
|
|
$logger->expects($this->once())->method('info');
|
||
|
|
|
||
|
|
$service = new RecaptchaService($httpClient, $logger, self::SECRET_KEY);
|
||
|
|
|
||
|
|
$result = $service->verify('test-token', '192.168.1.1');
|
||
|
|
|
||
|
|
$this->assertTrue($result);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[Test]
|
||
|
|
#[TestDox('Verify with score at threshold')]
|
||
|
|
public function verifyWithScoreAtThreshold(): void
|
||
|
|
{
|
||
|
|
$mockResponse = new MockResponse(json_encode([
|
||
|
|
'success' => true,
|
||
|
|
'score' => 0.5,
|
||
|
|
], JSON_THROW_ON_ERROR));
|
||
|
|
|
||
|
|
$httpClient = new MockHttpClient($mockResponse);
|
||
|
|
$logger = $this->createMock(LoggerInterface::class);
|
||
|
|
|
||
|
|
$service = new RecaptchaService($httpClient, $logger, self::SECRET_KEY);
|
||
|
|
|
||
|
|
$result = $service->verify('threshold-token');
|
||
|
|
|
||
|
|
$this->assertTrue($result);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[Test]
|
||
|
|
#[TestDox('Verify with no score fails')]
|
||
|
|
public function verifyWithNoScoreFails(): void
|
||
|
|
{
|
||
|
|
$mockResponse = new MockResponse(json_encode([
|
||
|
|
'success' => true,
|
||
|
|
], JSON_THROW_ON_ERROR));
|
||
|
|
|
||
|
|
$httpClient = new MockHttpClient($mockResponse);
|
||
|
|
$logger = $this->createMock(LoggerInterface::class);
|
||
|
|
|
||
|
|
$service = new RecaptchaService($httpClient, $logger, self::SECRET_KEY);
|
||
|
|
|
||
|
|
$result = $service->verify('no-score-token');
|
||
|
|
|
||
|
|
$this->assertFalse($result);
|
||
|
|
}
|
||
|
|
}
|