refactor: consolidate JS toggle components, grid query parsers, and add tests

JS components: migrate app-custom-field-options-toggle, app-color-default-toggle,
and app-settings-telemetry to shared conditional-controls factory/utility,
removing duplicated syncControlState logic and init boilerplate.

grid.php: extract gridQueryCsvInput() to DRY up 3 CSV parsers, simplify
multi_csv handler via gridNormalizeLabelList, delegate order type to gridQueryEnum.

Tests: add 23 SearchQueryNormalizer tests (LIKE escaping, wildcards, Unicode)
and 7 additional Crypto edge-case tests (empty input, missing fields, special
chars, binary content, truncation).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-13 22:22:15 +02:00
parent 7496903544
commit 99f8b55d49
6 changed files with 297 additions and 180 deletions

View File

@@ -67,4 +67,58 @@ final class CryptoTest extends TestCase
$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);
}
}