SiteWeaver_CMS/tests/unit/Core/TOTPServiceTest.php

101 lines
2.9 KiB
PHP
Raw Normal View History

<?php
/**
* File: tests/unit/Core/TOTPServiceTest.php
*
* Author: Funky Waddle
* Date: 2026-09-12
*
* Purpose:
* Unit tests for the TOTPService.
*/
declare(strict_types=1);
namespace Tests\unit\Core;
use SiteWeaver\Core\Services\TOTPService;
use OTPHP\TOTP;
use Psr\Clock\ClockInterface;
use PHPUnit\Framework\TestCase;
final class TOTPServiceTest extends TestCase
{
private ?ClockInterface $clock;
protected function setUp(): void
{
$this->clock = new class implements ClockInterface {
public function now(): \DateTimeImmutable
{
return new \DateTimeImmutable();
}
};
}
protected function tearDown(): void
{
$this->clock = null;
}
public function testGenerateAndVerify(): void
{
$totpService = new TOTPService();
$secret = $totpService->generateSecret();
// Generate a current OTP using the secret and clock
$otp = TOTP::create($secret, clock: $this->clock)->now();
$this->assertTrue($totpService->verify($secret, $otp));
}
public function testGenerateSecretUniqueness(): void
{
$totpService = new TOTPService();
$secret1 = $totpService->generateSecret();
$secret2 = $totpService->generateSecret();
$this->assertNotEquals($secret1, $secret2);
$this->assertNotEmpty($secret1);
$this->assertNotEmpty($secret2);
}
public function testVerifyWithWrongOTP(): void
{
$totpService = new TOTPService();
$secret = $totpService->generateSecret();
// correct OTP
$otpCorrect = TOTP::create($secret, clock: $this->clock)->now();
$this->assertTrue($totpService->verify($secret, $otpCorrect));
// wrong OTP
$wrongOtp = '000000';
$this->assertFalse($totpService->verify($secret, $wrongOtp));
}
public function testGetProvisioningUri(): void
{
$totpService = new TOTPService();
$secret = $totpService->generateSecret();
// Use a known account name and issuer
$accountName = 'alice@example.com';
$issuer = 'SiteWeaverCMS';
$uri = $totpService->getProvisioningUri($accountName, $issuer);
// The URI should start with otpauth://totp/
$this->assertStringStartsWith('otpauth://totp/', $uri);
// It should contain the issuer and account name (URL‑encoded)
$expectedIssuer = rawurlencode($issuer);
$expectedAccount = rawurlencode($accountName);
$this->assertStringContainsString($expectedIssuer, $uri);
$this->assertStringContainsString($expectedAccount, $uri);
// Compare with the library's own provisioning URI
$libUri = TOTP::create($secret, clock: $this->clock)
->withLabel($accountName)
->withIssuer($issuer)
->getProvisioningUri();
$this->assertEquals($libUri, $uri);
}
}