Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion server/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
}
},
"require-dev": {
"phpunit/phpunit": "^11.0"
"phpunit/phpunit": "^12.5"
},
"scripts": {
"test": "phpunit"
Expand Down
575 changes: 232 additions & 343 deletions server/composer.lock

Large diffs are not rendered by default.

27 changes: 27 additions & 0 deletions server/tests/Support/RedisClientStub.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace Swordfish\Server\Tests\Support;

use Predis\Client;

/**
* Predis\Client dispatches all Redis commands through __call(), so reflection
* sees none of them. PHPUnit 12 removed MockBuilder::addMethods(), leaving
* onlyMethods() as the only option — but onlyMethods() requires the methods to
* exist on the target class. This subclass exposes the commands the suite
* mocks as concrete no-ops so onlyMethods() can override them.
*/
class RedisClientStub extends Client
{
public function setex($key, $ttl, $value): mixed { return null; }
public function get($key): mixed { return null; }
public function incr($key): mixed { return null; }
public function incrby($key, $amount): mixed { return null; }
public function expire($key, $seconds): mixed { return null; }
public function ping(...$args): mixed { return null; }
public function keys($pattern): mixed { return null; }
public function mget(...$keys): mixed { return null; }
public function eval(...$args): mixed { return null; }
}
17 changes: 5 additions & 12 deletions server/tests/Unit/CreateRequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Swordfish\Server\Tests;

use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Swordfish\Server\CreateRequest;

Expand Down Expand Up @@ -77,9 +78,7 @@ public function testFromStringAcceptsZeroMaxViewsForUnlimited(): void
$this->assertSame(0, $request->maxViews());
}

/**
* @dataProvider invalidMaxViewsProvider
*/
#[DataProvider('invalidMaxViewsProvider')]
public function testFromStringRejectsInvalidMaxViews(int $invalid): void
{
$salt = bin2hex(str_repeat('a', 16));
Expand Down Expand Up @@ -115,9 +114,7 @@ public function testFromStringRejectsDisallowedTtlValue(): void
CreateRequest::fromString("{$salt}\${$verifier}\${$secret}\$7200");
}

/**
* @dataProvider allowedTtlProvider
*/
#[DataProvider('allowedTtlProvider')]
public function testFromStringAcceptsAllowedTtlValues(int $ttl): void
{
$salt = bin2hex(str_repeat('a', 16));
Expand Down Expand Up @@ -173,9 +170,7 @@ public function testFromJsonThrowsOnInvalidJson(): void
CreateRequest::fromJson('not-json');
}

/**
* @dataProvider allowedTtlProvider
*/
#[DataProvider('allowedTtlProvider')]
public function testFromJsonAcceptsAllowedTtlValues(int $ttl): void
{
$json = json_encode([
Expand All @@ -192,9 +187,7 @@ public static function allowedTtlProvider(): array
return [[3600], [21600], [86400], [259200], [604800]];
}

/**
* @dataProvider disallowedTtlProvider
*/
#[DataProvider('disallowedTtlProvider')]
public function testFromJsonThrowsOnDisallowedTtlValue(int $ttl): void
{
$json = json_encode([
Expand Down
5 changes: 3 additions & 2 deletions server/tests/Unit/CreateSecretJsonTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@
use PHPUnit\Framework\TestCase;
use Predis\Client as RedisClient;
use Swordfish\Server\ServerRoutes;
use Swordfish\Server\Tests\Support\RedisClientStub;

class CreateSecretJsonTest extends TestCase
{
private function makeRedisMock(): RedisClient
{
return $this->getMockBuilder(RedisClient::class)
return $this->getMockBuilder(RedisClientStub::class)
->disableOriginalConstructor()
->addMethods(['setex'])
->onlyMethods(['setex'])
->getMock();
}

Expand Down
5 changes: 3 additions & 2 deletions server/tests/Unit/DashboardMetricsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@
use PHPUnit\Framework\TestCase;
use Predis\Client as RedisClient;
use Swordfish\Server\ServerRoutes;
use Swordfish\Server\Tests\Support\RedisClientStub;

class DashboardMetricsTest extends TestCase
{
private function makeRedisMock(): RedisClient
{
return $this->getMockBuilder(RedisClient::class)
return $this->getMockBuilder(RedisClientStub::class)
->disableOriginalConstructor()
->addMethods(['mget'])
->onlyMethods(['mget'])
->getMock();
}

Expand Down
5 changes: 3 additions & 2 deletions server/tests/Unit/HealthCheckTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use Predis\Client as RedisClient;
use Predis\Connection\ConnectionException;
use Swordfish\Server\ServerRoutes;
use Swordfish\Server\Tests\Support\RedisClientStub;

class HealthCheckTest extends TestCase
{
Expand All @@ -24,9 +25,9 @@ private function makeRequest(): Request

private function makeRedisMock(): RedisClient
{
return $this->getMockBuilder(RedisClient::class)
return $this->getMockBuilder(RedisClientStub::class)
->disableOriginalConstructor()
->addMethods(['ping'])
->onlyMethods(['ping'])
->getMock();
}

Expand Down
5 changes: 3 additions & 2 deletions server/tests/Unit/MetricsEndpointTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use PHPUnit\Framework\TestCase;
use Predis\Client as RedisClient;
use Swordfish\Server\ServerRoutes;
use Swordfish\Server\Tests\Support\RedisClientStub;

class MetricsEndpointTest extends TestCase
{
Expand All @@ -24,9 +25,9 @@ private function makeRequest(array $headers = []): Request

private function makeRedisMock(): RedisClient
{
return $this->getMockBuilder(RedisClient::class)
return $this->getMockBuilder(RedisClientStub::class)
->disableOriginalConstructor()
->addMethods(['keys', 'mget'])
->onlyMethods(['keys', 'mget'])
->getMock();
}

Expand Down
5 changes: 3 additions & 2 deletions server/tests/Unit/MetricsServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@
use PHPUnit\Framework\TestCase;
use Predis\Client as RedisClient;
use Swordfish\Server\MetricsService;
use Swordfish\Server\Tests\Support\RedisClientStub;

class MetricsServiceTest extends TestCase
{
private function makeRedisMock(): RedisClient
{
return $this->getMockBuilder(RedisClient::class)
return $this->getMockBuilder(RedisClientStub::class)
->disableOriginalConstructor()
->addMethods(['incrby', 'expire'])
->onlyMethods(['incrby', 'expire'])
->getMock();
}

Expand Down
5 changes: 3 additions & 2 deletions server/tests/Unit/RateLimiterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@
use PHPUnit\Framework\TestCase;
use Predis\Client as RedisClient;
use Swordfish\Server\RateLimiter;
use Swordfish\Server\Tests\Support\RedisClientStub;

class RateLimiterTest extends TestCase
{
private function makeRedisMock(): RedisClient
{
return $this->getMockBuilder(RedisClient::class)
return $this->getMockBuilder(RedisClientStub::class)
->disableOriginalConstructor()
->addMethods(['incr', 'expire'])
->onlyMethods(['incr', 'expire'])
->getMock();
}

Expand Down
9 changes: 5 additions & 4 deletions server/tests/Unit/RetrieveRateLimitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@
use PHPUnit\Framework\TestCase;
use Predis\Client as RedisClient;
use Swordfish\Server\ServerRoutes;
use Swordfish\Server\Tests\Support\RedisClientStub;

class RetrieveRateLimitTest extends TestCase
{
private function makeRedisMock(int $incrReturn): RedisClient
{
$redis = $this->getMockBuilder(RedisClient::class)
$redis = $this->getMockBuilder(RedisClientStub::class)
->disableOriginalConstructor()
->addMethods(['incr', 'expire'])
->onlyMethods(['incr', 'expire'])
->getMock();
$redis->method('incr')->willReturn($incrReturn);
return $redis;
Expand Down Expand Up @@ -70,9 +71,9 @@ public function testReturns429AtLimitPlusOne(): void
public function testDoesNotReturn429WhenUnderLimit(): void
{
$logger = new Logger('test');
$redis = $this->getMockBuilder(RedisClient::class)
$redis = $this->getMockBuilder(RedisClientStub::class)
->disableOriginalConstructor()
->addMethods(['incr', 'expire', 'get'])
->onlyMethods(['incr', 'expire', 'get'])
->getMock();
$redis->method('incr')->willReturn(1);
$redis->method('get')->willReturn(null); // secret not found → 400 bad request path
Expand Down
5 changes: 3 additions & 2 deletions server/tests/Unit/RetrieveSecretJsonTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use PHPUnit\Framework\TestCase;
use Predis\Client as RedisClient;
use Swordfish\Server\ServerRoutes;
use Swordfish\Server\Tests\Support\RedisClientStub;

/**
* Tests for the JSON API POST /api/retrieve handler (happy path, error paths, view limits).
Expand All @@ -23,9 +24,9 @@ class RetrieveSecretJsonTest extends TestCase
{
private function makeRedisMock(array $methods = ['incr', 'expire', 'get', 'eval']): RedisClient
{
$redis = $this->getMockBuilder(RedisClient::class)
$redis = $this->getMockBuilder(RedisClientStub::class)
->disableOriginalConstructor()
->addMethods($methods)
->onlyMethods($methods)
->getMock();

// Default: rate limiter allows the request (count = 1)
Expand Down
5 changes: 3 additions & 2 deletions server/tests/Unit/RetrieveSecretTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use PHPUnit\Framework\TestCase;
use Predis\Client as RedisClient;
use Swordfish\Server\ServerRoutes;
use Swordfish\Server\Tests\Support\RedisClientStub;

/**
* Tests for the v1 (backward-compatible) POST /retrieve handler.
Expand All @@ -22,9 +23,9 @@ class RetrieveSecretTest extends TestCase
{
private function makeRedisMock(): RedisClient
{
return $this->getMockBuilder(RedisClient::class)
return $this->getMockBuilder(RedisClientStub::class)
->disableOriginalConstructor()
->addMethods(['get'])
->onlyMethods(['get'])
->getMock();
}

Expand Down
5 changes: 3 additions & 2 deletions server/tests/Unit/SecretInfoTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@
use Swordfish\Server\SecretNotFoundException;
use Swordfish\Server\SecretService;
use Swordfish\Server\ServerRoutes;
use Swordfish\Server\Tests\Support\RedisClientStub;

class SecretInfoTest extends TestCase
{
private function makeRedisMock(): RedisClient
{
return $this->getMockBuilder(RedisClient::class)
return $this->getMockBuilder(RedisClientStub::class)
->disableOriginalConstructor()
->addMethods(['get'])
->onlyMethods(['get'])
->getMock();
}

Expand Down
5 changes: 3 additions & 2 deletions server/tests/Unit/SecretServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use PHPUnit\Framework\TestCase;
use Predis\Client as RedisClient;
use Swordfish\Server\Tests\Support\RedisClientStub;
use Swordfish\Server\CreateRequest;
use Swordfish\Server\InvalidVerifierException;
use Swordfish\Server\SecretNotFoundException;
Expand All @@ -15,9 +16,9 @@ class SecretServiceTest extends TestCase
{
private function makeRedisMock(): RedisClient
{
return $this->getMockBuilder(RedisClient::class)
return $this->getMockBuilder(RedisClientStub::class)
->disableOriginalConstructor()
->addMethods(['setex', 'get', 'eval'])
->onlyMethods(['setex', 'get', 'eval'])
->getMock();
}

Expand Down
11 changes: 7 additions & 4 deletions server/tests/Unit/SecurityHeadersTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use PHPUnit\Framework\TestCase;
use Predis\Client as RedisClient;
use Swordfish\Server\ServerRoutes;
use Swordfish\Server\Tests\Support\RedisClientStub;

class SecurityHeadersTest extends TestCase
{
Expand Down Expand Up @@ -49,10 +50,12 @@ private function makePostRequest(string $path, string $body = ''): Request

private function makeRedisMock(array $methods = []): RedisClient
{
return $this->getMockBuilder(RedisClient::class)
->disableOriginalConstructor()
->addMethods($methods)
->getMock();
$builder = $this->getMockBuilder(RedisClientStub::class)
->disableOriginalConstructor();
if ($methods !== []) {
$builder->onlyMethods($methods);
}
return $builder->getMock();
}

public function testMainContentIncludesSecurityHeaders(): void
Expand Down
5 changes: 3 additions & 2 deletions server/tests/Unit/VerifierServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@

use PHPUnit\Framework\TestCase;
use Predis\Client as RedisClient;
use Swordfish\Server\Tests\Support\RedisClientStub;
use Swordfish\Server\VerifierService;

class VerifierServiceTest extends TestCase
{
private function makeRedisMock(): RedisClient
{
return $this->getMockBuilder(RedisClient::class)
return $this->getMockBuilder(RedisClientStub::class)
->disableOriginalConstructor()
->addMethods(['setex', 'get'])
->onlyMethods(['setex', 'get'])
->getMock();
}

Expand Down
Loading