1
0
Files
breadcrumb-the-shire/tests/Unit/Support/CryptoTest.php

125 lines
3.7 KiB
PHP
Raw Normal View History

2026-03-19 19:36:17 +01:00
<?php
namespace MintyPHP\Tests\Unit\Support;
use MintyPHP\Support\Crypto;
use PHPUnit\Framework\TestCase;
final class CryptoTest extends TestCase
{
protected function setUp(): void
{
if (!defined('APP_CRYPTO_KEY')) {
define('APP_CRYPTO_KEY', str_repeat('ab', 32));
}
}
public function testIsConfiguredReturnsTrueWhenKeyIsSet(): void
{
self::assertTrue(Crypto::isConfigured());
}
public function testEncryptDecryptRoundTrip(): void
{
$plaintext = 'client-secret-for-sso';
$encrypted = Crypto::encryptString($plaintext);
self::assertNotSame($plaintext, $encrypted);
self::assertSame($plaintext, Crypto::decryptString($encrypted));
}
public function testEncryptProducesDifferentCiphertextEachTime(): void
{
$plaintext = 'same-settings-value';
self::assertNotSame(
Crypto::encryptString($plaintext),
Crypto::encryptString($plaintext)
);
}
public function testDecryptThrowsOnInvalidOrTamperedPayload(): void
{
$encrypted = Crypto::encryptString('secret');
$tampered = substr($encrypted, 0, 5) . 'Z' . substr($encrypted, 6);
try {
Crypto::decryptString('garbage-data');
self::fail('Expected invalid payload to throw.');
} catch (\RuntimeException) {
}
try {
Crypto::decryptString(base64_encode('{}'));
self::fail('Expected malformed payload to throw.');
} catch (\RuntimeException) {
}
$this->expectException(\RuntimeException::class);
Crypto::decryptString($tampered);
}
public function testEncryptEmptyStringProducesMalformedPayloadOnDecrypt(): void
{
$encrypted = Crypto::encryptString('');
$this->expectException(\RuntimeException::class);
$this->expectExceptionMessage('malformed');
Crypto::decryptString($encrypted);
}
public function testDecryptThrowsOnEmptyString(): void
{
$this->expectException(\RuntimeException::class);
Crypto::decryptString('');
}
public function testDecryptThrowsOnMissingPayloadFields(): void
{
// Valid base64 wrapping valid JSON, but missing required fields.
$payload = base64_encode(json_encode(['v' => 1]));
$this->expectException(\RuntimeException::class);
$this->expectExceptionMessage('malformed');
Crypto::decryptString($payload);
}
public function testRoundTripWithSpecialCharacters(): void
{
$values = [
'unicode: Ünterström ñ 日本語',
"newlines:\nand\ttabs",
'json-like: {"key": "value"}',
str_repeat('x', 10000),
];
foreach ($values as $plaintext) {
$encrypted = Crypto::encryptString($plaintext);
self::assertSame($plaintext, Crypto::decryptString($encrypted), "Round-trip failed for: " . substr($plaintext, 0, 40));
}
}
public function testRoundTripWithBinaryLikeContent(): void
{
$plaintext = "null-bytes:\x00\x01\x02 and high-bytes:\xFE\xFF";
$encrypted = Crypto::encryptString($plaintext);
self::assertSame($plaintext, Crypto::decryptString($encrypted));
}
public function testDecryptThrowsOnNonBase64Input(): void
{
$this->expectException(\RuntimeException::class);
Crypto::decryptString('not!valid@base64###');
}
public function testDecryptThrowsOnTruncatedPayload(): void
{
$encrypted = Crypto::encryptString('secret');
$truncated = substr($encrypted, 0, (int) (strlen($encrypted) / 2));
$this->expectException(\RuntimeException::class);
Crypto::decryptString($truncated);
}
2026-03-19 19:36:17 +01:00
}