115 lines
4.5 KiB
PHP
115 lines
4.5 KiB
PHP
|
|
<?php
|
|||
|
|
|
|||
|
|
declare(strict_types=1);
|
|||
|
|
|
|||
|
|
namespace Tests\Unit\Shared\Helpers;
|
|||
|
|
|
|||
|
|
use PHPUnit\Framework\TestCase;
|
|||
|
|
use Shared\Helpers\StringEncoder;
|
|||
|
|
|
|||
|
|
covers(StringEncoder::class);
|
|||
|
|
|
|||
|
|
uses(TestCase::class);
|
|||
|
|
|
|||
|
|
describe('StringEncoder Unit Tests', function (): void {
|
|||
|
|
it('prevents direct instantiation', function (): void {
|
|||
|
|
$reflection = new \ReflectionClass(StringEncoder::class);
|
|||
|
|
|
|||
|
|
expect(fn () => $reflection->newInstance())
|
|||
|
|
->toThrow(\ReflectionException::class);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
describe('toUtf8', function (): void {
|
|||
|
|
it('returns empty string for empty input', function (): void {
|
|||
|
|
expect(StringEncoder::toUtf8('', 'UTF-8'))->toBe('')
|
|||
|
|
->and(StringEncoder::toUtf8('', 'Windows-1252'))->toBe('');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('passes valid UTF-8 through unchanged', function (): void {
|
|||
|
|
$utf8 = 'Émincés & Rôti de poulet fermier';
|
|||
|
|
expect(StringEncoder::toUtf8($utf8, 'UTF-8'))->toBe($utf8);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('converts Windows-1252 special characters to UTF-8', function (): void {
|
|||
|
|
// 0x80 (€), 0x8C (Œ), 0x9C (œ), 0x92 (’)
|
|||
|
|
$win1252 = "\x80 50 \x8Cuf \x9Cuf l\x92arbre";
|
|||
|
|
$expected = '€ 50 Œuf œuf l’arbre';
|
|||
|
|
|
|||
|
|
expect(StringEncoder::toUtf8($win1252, 'Windows-1252'))->toBe($expected);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('converts ISO-8859-15 specific characters to UTF-8', function (): void {
|
|||
|
|
// 0xA4 (€ in Latin-9), 0xBC (Œ), 0xBD (œ)
|
|||
|
|
$latin9 = "\xA4 50 \xBCuf \xBDuf";
|
|||
|
|
$expected = '€ 50 Œuf œuf';
|
|||
|
|
|
|||
|
|
expect(StringEncoder::toUtf8($latin9, 'ISO-8859-15'))->toBe($expected);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('supports encoding aliases case-insensitively', function (string $alias): void {
|
|||
|
|
$input = "\xE9"; // é in Latin-1/Win-1252
|
|||
|
|
expect(StringEncoder::toUtf8($input, $alias))->toBe('é');
|
|||
|
|
})->with(['windows-1252', 'WIN1252', 'cp1252', 'latin1', 'latin-1', 'iso-8859-1']);
|
|||
|
|
|
|||
|
|
it('strips UTF-8 BOM when stripBom is true', function (): void {
|
|||
|
|
$withBom = "\xEF\xBB\xBFHello World";
|
|||
|
|
expect(StringEncoder::toUtf8($withBom, 'UTF-8', stripBom: true))->toBe('Hello World')
|
|||
|
|
->and(StringEncoder::toUtf8($withBom, 'UTF-8', stripBom: false))->toBe($withBom);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('throws ValueError for unsupported encoding', function (): void {
|
|||
|
|
expect(fn () => StringEncoder::toUtf8('test', 'Shift-JIS'))
|
|||
|
|
->toThrow(\ValueError::class);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('throws ValueError for invalid UTF-8 in toUtf8 with UTF-8 encoding', function (): void {
|
|||
|
|
$invalidUtf8 = "\xC3\x28"; // Invalid UTF-8 sequence
|
|||
|
|
expect(fn () => StringEncoder::toUtf8($invalidUtf8, 'UTF-8'))
|
|||
|
|
->toThrow(\ValueError::class);
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
describe('detectAndConvertToUtf8', function (): void {
|
|||
|
|
it('returns empty string for empty input', function (): void {
|
|||
|
|
expect(StringEncoder::detectAndConvertToUtf8(''))->toBe('');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('preserves valid UTF-8 without re-encoding', function (): void {
|
|||
|
|
$utf8 = 'Volaille rôti bio';
|
|||
|
|
expect(StringEncoder::detectAndConvertToUtf8($utf8))->toBe($utf8);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('converts non-UTF8 strings using fallback encoding', function (): void {
|
|||
|
|
// Non-UTF-8: "é" in Windows-1252 is 0xE9
|
|||
|
|
$win1252 = "R\xE9gal du Volailler";
|
|||
|
|
expect(StringEncoder::detectAndConvertToUtf8($win1252, 'Windows-1252'))->toBe('Régal du Volailler');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('throws ValueError when fallbackEncoding is UTF-8', function (): void {
|
|||
|
|
expect(fn () => StringEncoder::detectAndConvertToUtf8('test', 'UTF-8'))
|
|||
|
|
->toThrow(\ValueError::class);
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
describe('arrayToUtf8', function (): void {
|
|||
|
|
it('converts an array of strings to UTF-8', function (): void {
|
|||
|
|
$inputs = ["\xE9", "\xE0", "\xE8"];
|
|||
|
|
$expected = ['é', 'à', 'è'];
|
|||
|
|
|
|||
|
|
expect(StringEncoder::arrayToUtf8($inputs, 'Windows-1252'))->toBe($expected);
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
describe('supportedEncodings', function (): void {
|
|||
|
|
it('returns list of all supported canonical and alias encodings', function (): void {
|
|||
|
|
$encodings = StringEncoder::supportedEncodings();
|
|||
|
|
|
|||
|
|
expect($encodings)->toContain('UTF-8')
|
|||
|
|
->and($encodings)->toContain('Windows-1252')
|
|||
|
|
->and($encodings)->toContain('ISO-8859-15')
|
|||
|
|
->and($encodings)->toContain('latin1')
|
|||
|
|
->and($encodings)->toContain('cp1252');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
});
|