chore: complete update
This commit is contained in:
84
tests/Domain/QrCode/End2EndTest.php
Normal file
84
tests/Domain/QrCode/End2EndTest.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Application\Service\QrCodeService;
|
||||
use App\Domain\QrCode\QrCode;
|
||||
use App\Domain\QrCode\Service\QrCodeEncoder;
|
||||
use App\Domain\QrCode\Service\QrCodeGenerator;
|
||||
use App\Domain\QrCode\Service\QrCodeMasker;
|
||||
use App\Domain\QrCode\Service\QrCodeRenderer;
|
||||
use App\Domain\QrCode\Service\ReedSolomon;
|
||||
use App\Domain\QrCode\ValueObject\ErrorCorrectionLevel;
|
||||
use App\Domain\QrCode\ValueObject\QrCodeMatrix;
|
||||
use App\Domain\QrCode\ValueObject\QrCodeVersion;
|
||||
|
||||
test('End-to-End QR-Code-Generierung funktioniert', function () {
|
||||
// Abhängigkeiten aufbauen
|
||||
$encoder = new QrCodeEncoder();
|
||||
$renderer = new QrCodeRenderer(new QrCodeMasker(), new ReedSolomon());
|
||||
$generator = new QrCodeGenerator($encoder, $renderer);
|
||||
|
||||
// Test-Daten
|
||||
$data = 'https://example.com';
|
||||
$errorLevel = ErrorCorrectionLevel::M;
|
||||
$version = 2; // Fixe Version für Test-Vorhersagbarkeit
|
||||
|
||||
// QR-Code generieren
|
||||
$qrCode = new QrCode($data, $errorLevel, new QrCodeVersion($version));
|
||||
$matrix = $generator->generate($qrCode);
|
||||
|
||||
// Prüfungen
|
||||
expect($matrix)->toBeInstanceOf(QrCodeMatrix::class);
|
||||
|
||||
// Prüfe die Größe (Version 2 = 25x25)
|
||||
$expectedSize = 25; // 21 + (2-1)*4 = 25
|
||||
expect($matrix->getSize())->toBe($expectedSize);
|
||||
|
||||
// Prüfe, ob Finder-Patterns vorhanden sind (3 Ecken haben spezifische Muster)
|
||||
$topLeft = $this->hasFinderPattern($matrix->getMatrix(), 0, 0);
|
||||
$topRight = $this->hasFinderPattern($matrix->getMatrix(), 0, $expectedSize - 7);
|
||||
$bottomLeft = $this->hasFinderPattern($matrix->getMatrix(), $expectedSize - 7, 0);
|
||||
|
||||
expect($topLeft)->toBeTrue('Finder Pattern oben links fehlt');
|
||||
expect($topRight)->toBeTrue('Finder Pattern oben rechts fehlt');
|
||||
expect($bottomLeft)->toBeTrue('Finder Pattern unten links fehlt');
|
||||
});
|
||||
|
||||
// Hilfsfunktion zur Prüfung von Finder-Patterns
|
||||
function hasFinderPattern(array $matrix, int $startRow, int $startCol): bool
|
||||
{
|
||||
// Prüfe das 7x7 Finder-Pattern-Muster
|
||||
// Das äußere Quadrat sollte 7x7 sein und vollständig dunkel
|
||||
for ($i = 0; $i < 7; $i++) {
|
||||
for ($j = 0; $j < 7; $j++) {
|
||||
if ($i === 0 || $i === 6 || $j === 0 || $j === 6) {
|
||||
if ($matrix[$startRow + $i][$startCol + $j] !== true) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Das mittlere Quadrat sollte 5x5 sein und weiß (false)
|
||||
for ($i = 1; $i < 6; $i++) {
|
||||
for ($j = 1; $j < 6; $j++) {
|
||||
if ($i === 1 || $i === 5 || $j === 1 || $j === 5) {
|
||||
if ($matrix[$startRow + $i][$startCol + $j] !== false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Das innerste Quadrat sollte 3x3 sein und dunkel (true)
|
||||
for ($i = 2; $i < 5; $i++) {
|
||||
for ($j = 2; $j < 5; $j++) {
|
||||
if ($matrix[$startRow + $i][$startCol + $j] !== true) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
96
tests/Domain/QrCode/QrCodeTest.php
Normal file
96
tests/Domain/QrCode/QrCodeTest.php
Normal file
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Domain\QrCode\QrCode;
|
||||
use App\Domain\QrCode\Exception\QrCodeException;
|
||||
use App\Domain\QrCode\Service\QrCodeEncoder;
|
||||
use App\Domain\QrCode\Service\QrCodeGenerator;
|
||||
use App\Domain\QrCode\Service\QrCodeMasker;
|
||||
use App\Domain\QrCode\Service\QrCodeRenderer;
|
||||
use App\Domain\QrCode\Service\ReedSolomon;
|
||||
use App\Domain\QrCode\ValueObject\ErrorCorrectionLevel;
|
||||
use App\Domain\QrCode\ValueObject\MaskPattern;
|
||||
use App\Domain\QrCode\ValueObject\QrCodeVersion;
|
||||
|
||||
test('QrCode Objekt kann erstellt werden', function () {
|
||||
$qrCode = new QrCode('Testdaten');
|
||||
|
||||
expect($qrCode->getData())->toBe('Testdaten');
|
||||
expect($qrCode->getErrorCorrectionLevel())->toBe(ErrorCorrectionLevel::M);
|
||||
expect($qrCode->getVersion())->toBeNull();
|
||||
});
|
||||
|
||||
test('QrCode wirft Exception bei leeren Daten', function () {
|
||||
expect(fn() => new QrCode(''))->toThrow(QrCodeException::class);
|
||||
});
|
||||
|
||||
test('QrCode withMethods erzeugen neue Instanzen', function () {
|
||||
$original = new QrCode('Test');
|
||||
$withLevel = $original->withErrorCorrectionLevel(ErrorCorrectionLevel::H);
|
||||
$withVersion = $original->withVersion(new QrCodeVersion(5));
|
||||
|
||||
expect($withLevel)->not->toBe($original);
|
||||
expect($withVersion)->not->toBe($original);
|
||||
expect($withLevel->getErrorCorrectionLevel())->toBe(ErrorCorrectionLevel::H);
|
||||
expect($withVersion->getVersion()->getValue())->toBe(5);
|
||||
});
|
||||
|
||||
test('MaskPattern kann Maskenbedingungen korrekt auswerten', function () {
|
||||
$pattern = MaskPattern::PATTERN_0;
|
||||
|
||||
expect($pattern->shouldMask(0, 0))->toBeTrue(); // (0+0)%2 = 0
|
||||
expect($pattern->shouldMask(1, 0))->toBeFalse(); // (1+0)%2 = 1
|
||||
expect($pattern->shouldMask(1, 1))->toBeTrue(); // (1+1)%2 = 0
|
||||
});
|
||||
|
||||
test('QrCodeEncoder kann Daten kodieren', function () {
|
||||
$encoder = new QrCodeEncoder();
|
||||
$qrCode = new QrCode('123');
|
||||
$version = new QrCodeVersion(1);
|
||||
|
||||
$encoded = $encoder->encode($qrCode, $version);
|
||||
|
||||
expect($encoded)->toBeString();
|
||||
expect(strlen($encoded))->toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test('QrCodeGenerator kann QR-Code-Matrix generieren', function () {
|
||||
$generator = new QrCodeGenerator(
|
||||
new QrCodeEncoder(),
|
||||
new QrCodeRenderer(new QrCodeMasker(), new ReedSolomon())
|
||||
);
|
||||
|
||||
$qrCode = new QrCode('Test123');
|
||||
$matrix = $generator->generate($qrCode);
|
||||
|
||||
expect($matrix->getSize())->toBeGreaterThan(20); // QR-Code ist mindestens Version 1 (21x21)
|
||||
});
|
||||
|
||||
test('QrCodeMasker berechnet Maskenstrafen korrekt', function () {
|
||||
$masker = new QrCodeMasker();
|
||||
$size = 21; // Version 1
|
||||
|
||||
// Matrix mit alternierenden Modulen (geringe Strafe)
|
||||
$alternatingMatrix = [];
|
||||
for ($i = 0; $i < $size; $i++) {
|
||||
$alternatingMatrix[$i] = [];
|
||||
for ($j = 0; $j < $size; $j++) {
|
||||
$alternatingMatrix[$i][$j] = ($i + $j) % 2 === 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Matrix mit vielen aufeinanderfolgenden gleichen Modulen (hohe Strafe)
|
||||
$repeatingMatrix = [];
|
||||
for ($i = 0; $i < $size; $i++) {
|
||||
$repeatingMatrix[$i] = [];
|
||||
for ($j = 0; $j < $size; $j++) {
|
||||
$repeatingMatrix[$i][$j] = $j < $size / 2;
|
||||
}
|
||||
}
|
||||
|
||||
$alternatingPenalty = $masker->calculateMaskPenalty($alternatingMatrix, $size);
|
||||
$repeatingPenalty = $masker->calculateMaskPenalty($repeatingMatrix, $size);
|
||||
|
||||
expect($alternatingPenalty)->toBeLessThan($repeatingPenalty);
|
||||
});
|
||||
72
tests/Domain/QrCode/Service/QrCodeEncoderTest.php
Normal file
72
tests/Domain/QrCode/Service/QrCodeEncoderTest.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Domain\QrCode\QrCode;
|
||||
use App\Domain\QrCode\Service\QrCodeEncoder;
|
||||
use App\Domain\QrCode\ValueObject\ErrorCorrectionLevel;
|
||||
use App\Domain\QrCode\ValueObject\QrCodeVersion;
|
||||
|
||||
test('QrCodeEncoder kann numerische Daten kodieren', function () {
|
||||
$encoder = new QrCodeEncoder();
|
||||
$qrCode = new QrCode('12345', ErrorCorrectionLevel::M);
|
||||
$version = new QrCodeVersion(1);
|
||||
|
||||
$encoded = $encoder->encode($qrCode, $version);
|
||||
|
||||
// Prüfe, dass das Ergebnis ein binärer String ist
|
||||
expect($encoded)->toBeString();
|
||||
expect(strlen($encoded) % 8)->toBe(0); // Muss ein Vielfaches von 8 sein
|
||||
|
||||
// Prüfe den Mode Indicator für numerische Daten (0001)
|
||||
expect(substr($encoded, 0, 4))->toBe('0001');
|
||||
});
|
||||
|
||||
test('QrCodeEncoder kann alphanumerische Daten kodieren', function () {
|
||||
$encoder = new QrCodeEncoder();
|
||||
$qrCode = new QrCode('ABC123', ErrorCorrectionLevel::M);
|
||||
$version = new QrCodeVersion(1);
|
||||
|
||||
$encoded = $encoder->encode($qrCode, $version);
|
||||
|
||||
// Prüfe, dass das Ergebnis ein binärer String ist
|
||||
expect($encoded)->toBeString();
|
||||
expect(strlen($encoded) % 8)->toBe(0); // Muss ein Vielfaches von 8 sein
|
||||
|
||||
// Prüfe den Mode Indicator für alphanumerische Daten (0010)
|
||||
expect(substr($encoded, 0, 4))->toBe('0010');
|
||||
});
|
||||
|
||||
test('QrCodeEncoder kann Byte-Daten kodieren', function () {
|
||||
$encoder = new QrCodeEncoder();
|
||||
$qrCode = new QrCode('Hello World!', ErrorCorrectionLevel::M);
|
||||
$version = new QrCodeVersion(1);
|
||||
|
||||
$encoded = $encoder->encode($qrCode, $version);
|
||||
|
||||
// Prüfe, dass das Ergebnis ein binärer String ist
|
||||
expect($encoded)->toBeString();
|
||||
expect(strlen($encoded) % 8)->toBe(0); // Muss ein Vielfaches von 8 sein
|
||||
|
||||
// Prüfe den Mode Indicator für Byte-Daten (0100)
|
||||
expect(substr($encoded, 0, 4))->toBe('0100');
|
||||
});
|
||||
|
||||
test('QrCodeEncoder fügt Terminator und Padding korrekt hinzu', function () {
|
||||
$encoder = new QrCodeEncoder();
|
||||
$qrCode = new QrCode('1', ErrorCorrectionLevel::M); // Minimale Daten
|
||||
$version = new QrCodeVersion(1);
|
||||
|
||||
$encoded = $encoder->encode($qrCode, $version);
|
||||
|
||||
// Prüfe, dass das Ergebnis ein binärer String ist
|
||||
expect($encoded)->toBeString();
|
||||
|
||||
// Prüfe die Länge (sollte der vollen Datenkapazität entsprechen)
|
||||
$expectedLength = (new QrCodeVersion(1))->getDataCapacity(ErrorCorrectionLevel::M) * 8;
|
||||
expect(strlen($encoded))->toBe($expectedLength);
|
||||
|
||||
// Prüfe, ob Pad-Bytes vorhanden sind (11101100 oder 00010001)
|
||||
$containsPadBytes = str_contains($encoded, '11101100') || str_contains($encoded, '00010001');
|
||||
expect($containsPadBytes)->toBeTrue();
|
||||
});
|
||||
84
tests/Domain/QrCode/Service/ReedSolomonTest.php
Normal file
84
tests/Domain/QrCode/Service/ReedSolomonTest.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Domain\QrCode\Service\ReedSolomon;
|
||||
use App\Domain\QrCode\Service\ReedSolomonEncoder;
|
||||
use App\Domain\QrCode\ValueObject\ErrorCorrectionLevel;
|
||||
|
||||
test('ReedSolomon kann Fehlerkorrektur hinzufügen', function () {
|
||||
$rs = new ReedSolomon();
|
||||
|
||||
// Erstelle einen einfachen Testfall mit 4 Datenbytes
|
||||
$data = '00110011' . '01010101' . '11001100' . '10101010'; // Binär: 51, 85, 204, 170
|
||||
$dataCapacity = 4; // 4 Bytes
|
||||
$level = ErrorCorrectionLevel::M;
|
||||
|
||||
// Wende Reed-Solomon an
|
||||
$encoded = $rs->addErrorCorrection($data, $dataCapacity, $level);
|
||||
|
||||
// Überprüfe, dass das Ergebnis länger als die Eingabe ist (ECC wurde hinzugefügt)
|
||||
expect(strlen($encoded))->toBeGreaterThan(strlen($data));
|
||||
|
||||
// Überprüfe, dass die ursprünglichen Daten am Anfang vorhanden sind
|
||||
expect(substr($encoded, 0, strlen($data)))->toBe($data);
|
||||
});
|
||||
|
||||
test('ReedSolomonEncoder kann Bytes kodieren', function () {
|
||||
$encoder = new ReedSolomonEncoder();
|
||||
|
||||
// Testdaten: [0x32, 0x54, 0x67, 0x89]
|
||||
$data = [0x32, 0x54, 0x67, 0x89];
|
||||
$eccLength = 4; // 4 ECC Bytes hinzufügen
|
||||
|
||||
$encoded = $encoder->encode($data, $eccLength);
|
||||
|
||||
// Erwarte Originaldaten + ECC-Bytes
|
||||
expect(count($encoded))->toBe(count($data) + $eccLength);
|
||||
|
||||
// Überprüfe, dass die ursprünglichen Daten am Anfang vorhanden sind
|
||||
for ($i = 0; $i < count($data); $i++) {
|
||||
expect($encoded[$i])->toBe($data[$i]);
|
||||
}
|
||||
|
||||
// Überprüfe, dass die ECC-Bytes nicht alle 0 sind (echte Berechnung)
|
||||
$allZero = true;
|
||||
for ($i = count($data); $i < count($encoded); $i++) {
|
||||
if ($encoded[$i] !== 0) {
|
||||
$allZero = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
expect($allZero)->toBeFalse();
|
||||
});
|
||||
|
||||
test('ReedSolomon kann Daten in Blöcke organisieren', function () {
|
||||
$rs = new ReedSolomon();
|
||||
$method = new ReflectionMethod($rs, 'organizeDataBlocks');
|
||||
$method->setAccessible(true);
|
||||
|
||||
// Testdaten: 8 Bytes [1, 2, 3, 4, 5, 6, 7, 8]
|
||||
$data = [1, 2, 3, 4, 5, 6, 7, 8];
|
||||
$version = 1;
|
||||
$level = ErrorCorrectionLevel::M; // 1 Block für Version 1-M
|
||||
|
||||
$blocks = $method->invoke($rs, $data, $version, $level);
|
||||
|
||||
// Version 1-M hat 1 Block
|
||||
expect(count($blocks))->toBe(1);
|
||||
expect($blocks[0])->toBe($data);
|
||||
});
|
||||
|
||||
test('ReedSolomon kann Blöcke interleaven', function () {
|
||||
$rs = new ReedSolomon();
|
||||
$method = new ReflectionMethod($rs, 'interleaveBlocks');
|
||||
$method->setAccessible(true);
|
||||
|
||||
// 2 Blöcke: [1, 2, 3] und [4, 5, 6]
|
||||
$blocks = [[1, 2, 3], [4, 5, 6]];
|
||||
|
||||
$interleaved = $method->invoke($rs, $blocks);
|
||||
|
||||
// Erwartetes Ergebnis: [1, 4, 2, 5, 3, 6]
|
||||
expect($interleaved)->toBe([1, 4, 2, 5, 3, 6]);
|
||||
});
|
||||
59
tests/Domain/QrCode/ValueObject/GaloisFieldTest.php
Normal file
59
tests/Domain/QrCode/ValueObject/GaloisFieldTest.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Domain\QrCode\ValueObject\GaloisField;
|
||||
|
||||
test('GaloisField Arithmetik funktioniert korrekt', function () {
|
||||
$field = new GaloisField();
|
||||
|
||||
// Addition (XOR) Tests
|
||||
expect($field->add(0, 0))->toBe(0);
|
||||
expect($field->add(0, 1))->toBe(1);
|
||||
expect($field->add(1, 0))->toBe(1);
|
||||
expect($field->add(1, 1))->toBe(0);
|
||||
expect($field->add(15, 32))->toBe(47);
|
||||
|
||||
// Multiplikation Tests
|
||||
expect($field->multiply(0, 5))->toBe(0);
|
||||
expect($field->multiply(5, 0))->toBe(0);
|
||||
expect($field->multiply(1, 1))->toBe(1);
|
||||
expect($field->multiply(2, 3))->toBe(6);
|
||||
|
||||
// Division Tests
|
||||
expect($field->divide(0, 5))->toBe(0);
|
||||
expect($field->divide(5, 1))->toBe(5);
|
||||
expect($field->divide(6, 3))->toBe(2);
|
||||
|
||||
// Division durch Null sollte Exception werfen
|
||||
expect(fn() => $field->divide(5, 0))->toThrow(\DivisionByZeroError::class);
|
||||
|
||||
// Potenzen Tests
|
||||
expect($field->power(2, 0))->toBe(1); // 2^0 = 1
|
||||
expect($field->power(2, 1))->toBe(2); // 2^1 = 2
|
||||
expect($field->power(2, 2))->toBe(4); // 2^2 = 4
|
||||
expect($field->power(2, 3))->toBe(8); // 2^3 = 8
|
||||
});
|
||||
|
||||
test('GaloisField Tabellen sind korrekt initialisiert', function () {
|
||||
$field = new GaloisField();
|
||||
|
||||
$expTable = $field->getExpTable();
|
||||
$logTable = $field->getLogTable();
|
||||
|
||||
// Prüfe grundlegende Eigenschaften der Tabellen
|
||||
expect(count($expTable))->toBe(256);
|
||||
expect(count($logTable))->toBe(256);
|
||||
|
||||
// Prüfe spezifische Werte
|
||||
expect($expTable[0])->toBe(1);
|
||||
expect($expTable[1])->toBe(2);
|
||||
expect($expTable[2])->toBe(4);
|
||||
expect($expTable[3])->toBe(8);
|
||||
|
||||
// Prüfe Log-Tabelle
|
||||
expect($logTable[1])->toBe(0);
|
||||
expect($logTable[2])->toBe(1);
|
||||
expect($logTable[4])->toBe(2);
|
||||
expect($logTable[8])->toBe(3);
|
||||
});
|
||||
75
tests/Domain/QrCode/ValueObject/PolynomialTest.php
Normal file
75
tests/Domain/QrCode/ValueObject/PolynomialTest.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Domain\QrCode\ValueObject\GaloisField;
|
||||
use App\Domain\QrCode\ValueObject\Polynomial;
|
||||
|
||||
test('Polynomial kann erstellt werden', function () {
|
||||
$field = new GaloisField();
|
||||
$poly = new Polynomial($field, [1, 2, 3]); // x^2 + 2x + 3
|
||||
|
||||
expect($poly->getCoefficients())->toBe([1, 2, 3]);
|
||||
expect($poly->getDegree())->toBe(2);
|
||||
});
|
||||
|
||||
test('Polynomial entfernt führende Nullen', function () {
|
||||
$field = new GaloisField();
|
||||
$poly = new Polynomial($field, [0, 0, 1, 2]); // x + 2
|
||||
|
||||
expect($poly->getCoefficients())->toBe([1, 2]);
|
||||
expect($poly->getDegree())->toBe(1);
|
||||
});
|
||||
|
||||
test('Polynomial kann an Stelle x ausgewertet werden', function () {
|
||||
$field = new GaloisField();
|
||||
$poly = new Polynomial($field, [1, 0, 1]); // x^2 + 1
|
||||
|
||||
expect($poly->evaluateAt(0))->toBe(1);
|
||||
expect($poly->evaluateAt(1))->toBe(0); // 1^2 + 1 = 2 = 0 in GF(2)
|
||||
expect($poly->evaluateAt(2))->toBe(5); // 2^2 + 1 = 5
|
||||
});
|
||||
|
||||
test('Polynomial Addition funktioniert', function () {
|
||||
$field = new GaloisField();
|
||||
$poly1 = new Polynomial($field, [1, 2]); // x + 2
|
||||
$poly2 = new Polynomial($field, [3, 4]); // 3x + 4
|
||||
|
||||
$sum = $poly1->add($poly2);
|
||||
|
||||
// In GF(2^8) ist Addition = XOR, daher 1⊕3=2, 2⊕4=6
|
||||
expect($sum->getCoefficients())->toBe([2, 6]);
|
||||
});
|
||||
|
||||
test('Polynomial Multiplikation funktioniert', function () {
|
||||
$field = new GaloisField();
|
||||
$poly1 = new Polynomial($field, [1, 1]); // x + 1
|
||||
$poly2 = new Polynomial($field, [1, 0, 1]); // x^2 + 1
|
||||
|
||||
$product = $poly1->multiply($poly2);
|
||||
|
||||
// (x + 1)(x^2 + 1) = x^3 + x^2 + x + 1
|
||||
expect($product->getCoefficients())->toBe([1, 1, 1, 1]);
|
||||
});
|
||||
|
||||
test('Polynomial Division funktioniert', function () {
|
||||
$field = new GaloisField();
|
||||
$poly1 = new Polynomial($field, [1, 0, 1]); // x^2 + 1
|
||||
$poly2 = new Polynomial($field, [1, 1]); // x + 1
|
||||
|
||||
$result = $poly1->divideAndRemainder($poly2);
|
||||
|
||||
// (x^2 + 1) ÷ (x + 1) = x - 1 + 2/(x+1)
|
||||
// In GF(2^8): Quotient = x - 1 = x + 1, Rest = 2
|
||||
expect($result['quotient']->getCoefficients())->toEqual([1, 1]);
|
||||
expect($result['remainder']->getCoefficients())->toEqual([0]);
|
||||
});
|
||||
|
||||
test('Generator Polynom kann korrekt erstellt werden', function () {
|
||||
$field = new GaloisField();
|
||||
$generator = Polynomial::buildGenerator($field, 3);
|
||||
|
||||
// Erwartetes Ergebnis für Grad 3
|
||||
expect($generator->getDegree())->toBe(3);
|
||||
expect(count($generator->getCoefficients()))->toBe(4);
|
||||
});
|
||||
54
tests/Framework/DateTime/ClockInitializerTest.php
Normal file
54
tests/Framework/DateTime/ClockInitializerTest.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Framework\DateTime;
|
||||
|
||||
use App\Framework\DateTime\Clock;
|
||||
use App\Framework\DateTime\ClockInitializer;
|
||||
use App\Framework\DateTime\FrozenClock;
|
||||
use App\Framework\DateTime\SystemClock;
|
||||
|
||||
class ClockInitializerTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function testDefaultInitialization(): void
|
||||
{
|
||||
$initializer = new ClockInitializer();
|
||||
$clock = $initializer();
|
||||
|
||||
$this->assertInstanceOf(SystemClock::class, $clock);
|
||||
$this->assertEquals('UTC', $clock->now()->getTimezone()->getName());
|
||||
}
|
||||
|
||||
public function testCustomTimezone(): void
|
||||
{
|
||||
$initializer = new ClockInitializer('Europe/Berlin');
|
||||
$clock = $initializer();
|
||||
|
||||
$this->assertInstanceOf(SystemClock::class, $clock);
|
||||
$this->assertEquals('Europe/Berlin', $clock->now()->getTimezone()->getName());
|
||||
}
|
||||
|
||||
public function testFrozenClockInitialization(): void
|
||||
{
|
||||
$initializer = new ClockInitializer(
|
||||
useFrozenClock: true,
|
||||
frozenTime: '2021-01-01 12:00:00'
|
||||
);
|
||||
$clock = $initializer();
|
||||
|
||||
$this->assertInstanceOf(FrozenClock::class, $clock);
|
||||
$this->assertEquals('2021-01-01 12:00:00', $clock->now()->format('Y-m-d H:i:s'));
|
||||
}
|
||||
|
||||
public function testFrozenClockWithCustomTimezone(): void
|
||||
{
|
||||
$initializer = new ClockInitializer(
|
||||
timezone: 'Europe/Berlin',
|
||||
useFrozenClock: true,
|
||||
frozenTime: '2021-01-01 12:00:00'
|
||||
);
|
||||
$clock = $initializer();
|
||||
|
||||
$this->assertInstanceOf(FrozenClock::class, $clock);
|
||||
$this->assertEquals('Europe/Berlin', $clock->now()->getTimezone()->getName());
|
||||
}
|
||||
}
|
||||
101
tests/Framework/DateTime/DateRangeTest.php
Normal file
101
tests/Framework/DateTime/DateRangeTest.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Framework\DateTime;
|
||||
|
||||
use App\Framework\DateTime\DateRange;
|
||||
|
||||
class DateRangeTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function testConstructorWithValidDates(): void
|
||||
{
|
||||
$start = new \DateTimeImmutable('2021-01-01');
|
||||
$end = new \DateTimeImmutable('2021-01-31');
|
||||
|
||||
$range = new DateRange($start, $end);
|
||||
|
||||
$this->assertSame($start, $range->getStart());
|
||||
$this->assertSame($end, $range->getEnd());
|
||||
}
|
||||
|
||||
public function testConstructorWithInvalidDatesThrowsException(): void
|
||||
{
|
||||
$start = new \DateTimeImmutable('2021-01-31');
|
||||
$end = new \DateTimeImmutable('2021-01-01');
|
||||
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
new DateRange($start, $end);
|
||||
}
|
||||
|
||||
public function testFromStrings(): void
|
||||
{
|
||||
$range = DateRange::fromStrings('2021-01-01', '2021-01-31');
|
||||
|
||||
$this->assertEquals('2021-01-01', $range->getStart()->format('Y-m-d'));
|
||||
$this->assertEquals('2021-01-31', $range->getEnd()->format('Y-m-d'));
|
||||
}
|
||||
|
||||
public function testContains(): void
|
||||
{
|
||||
$range = DateRange::fromStrings('2021-01-01', '2021-01-31');
|
||||
|
||||
$inside = new \DateTimeImmutable('2021-01-15');
|
||||
$onStart = new \DateTimeImmutable('2021-01-01');
|
||||
$onEnd = new \DateTimeImmutable('2021-01-31');
|
||||
$before = new \DateTimeImmutable('2020-12-31');
|
||||
$after = new \DateTimeImmutable('2021-02-01');
|
||||
|
||||
$this->assertTrue($range->contains($inside));
|
||||
$this->assertTrue($range->contains($onStart));
|
||||
$this->assertTrue($range->contains($onEnd));
|
||||
$this->assertFalse($range->contains($before));
|
||||
$this->assertFalse($range->contains($after));
|
||||
}
|
||||
|
||||
public function testContainsRange(): void
|
||||
{
|
||||
$mainRange = DateRange::fromStrings('2021-01-01', '2021-01-31');
|
||||
|
||||
$inside = DateRange::fromStrings('2021-01-10', '2021-01-20');
|
||||
$sameRange = DateRange::fromStrings('2021-01-01', '2021-01-31');
|
||||
$overlapping = DateRange::fromStrings('2021-01-15', '2021-02-15');
|
||||
$outside = DateRange::fromStrings('2021-02-01', '2021-02-28');
|
||||
|
||||
$this->assertTrue($mainRange->containsRange($inside));
|
||||
$this->assertTrue($mainRange->containsRange($sameRange));
|
||||
$this->assertFalse($mainRange->containsRange($overlapping));
|
||||
$this->assertFalse($mainRange->containsRange($outside));
|
||||
}
|
||||
|
||||
public function testOverlaps(): void
|
||||
{
|
||||
$mainRange = DateRange::fromStrings('2021-01-01', '2021-01-31');
|
||||
|
||||
$inside = DateRange::fromStrings('2021-01-10', '2021-01-20');
|
||||
$overlappingStart = DateRange::fromStrings('2020-12-15', '2021-01-15');
|
||||
$overlappingEnd = DateRange::fromStrings('2021-01-15', '2021-02-15');
|
||||
$outside = DateRange::fromStrings('2021-02-01', '2021-02-28');
|
||||
|
||||
$this->assertTrue($mainRange->overlaps($inside));
|
||||
$this->assertTrue($mainRange->overlaps($overlappingStart));
|
||||
$this->assertTrue($mainRange->overlaps($overlappingEnd));
|
||||
$this->assertFalse($mainRange->overlaps($outside));
|
||||
}
|
||||
|
||||
public function testGetDuration(): void
|
||||
{
|
||||
$range = DateRange::fromStrings('2021-01-01', '2021-01-31');
|
||||
$duration = $range->getDuration();
|
||||
|
||||
$this->assertInstanceOf(\DateInterval::class, $duration);
|
||||
$this->assertEquals(30, $duration->days);
|
||||
}
|
||||
|
||||
public function testGetDurationInSeconds(): void
|
||||
{
|
||||
$range = DateRange::fromStrings('2021-01-01', '2021-01-02');
|
||||
$seconds = $range->getDurationInSeconds();
|
||||
|
||||
// Ein Tag hat 86400 Sekunden
|
||||
$this->assertEquals(86400, $seconds);
|
||||
}
|
||||
}
|
||||
64
tests/Framework/DateTime/DateTimeFormatterTest.php
Normal file
64
tests/Framework/DateTime/DateTimeFormatterTest.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Framework\DateTime;
|
||||
|
||||
use App\Framework\DateTime\DateTimeFormatter;
|
||||
|
||||
class DateTimeFormatterTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
private \DateTimeImmutable $sampleDate;
|
||||
private DateTimeFormatter $formatter;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->sampleDate = new \DateTimeImmutable('2021-01-01 12:34:56', new \DateTimeZone('UTC'));
|
||||
$this->formatter = new DateTimeFormatter();
|
||||
}
|
||||
|
||||
public function testFormatIso8601(): void
|
||||
{
|
||||
$formatted = $this->formatter->formatIso8601($this->sampleDate);
|
||||
$this->assertEquals('2021-01-01T12:34:56+00:00', $formatted);
|
||||
}
|
||||
|
||||
public function testFormatSql(): void
|
||||
{
|
||||
$formatted = $this->formatter->formatSql($this->sampleDate);
|
||||
$this->assertEquals('2021-01-01 12:34:56', $formatted);
|
||||
}
|
||||
|
||||
public function testFormatDate(): void
|
||||
{
|
||||
$formatted = $this->formatter->formatDate($this->sampleDate);
|
||||
$this->assertEquals('2021-01-01', $formatted);
|
||||
}
|
||||
|
||||
public function testFormatTime(): void
|
||||
{
|
||||
$formatted = $this->formatter->formatTime($this->sampleDate);
|
||||
$this->assertEquals('12:34:56', $formatted);
|
||||
}
|
||||
|
||||
public function testCustomFormat(): void
|
||||
{
|
||||
$formatted = $this->formatter->format($this->sampleDate, 'd.m.Y H:i');
|
||||
$this->assertEquals('01.01.2021 12:34', $formatted);
|
||||
}
|
||||
|
||||
public function testWithCustomTimezone(): void
|
||||
{
|
||||
$formatter = new DateTimeFormatter('Europe/Berlin');
|
||||
$formatted = $formatter->format($this->sampleDate, 'Y-m-d H:i:s T');
|
||||
|
||||
// UTC 12:34:56 sollte in Berlin 13:34:56 sein (während Standardzeit/Winterzeit)
|
||||
$this->assertEquals('2021-01-01 13:34:56 CET', $formatted);
|
||||
}
|
||||
|
||||
public function testWithDateTimeObject(): void
|
||||
{
|
||||
$dateTime = new \DateTime('2021-01-01 12:34:56', new \DateTimeZone('UTC'));
|
||||
$formatted = $this->formatter->formatIso8601($dateTime);
|
||||
|
||||
$this->assertEquals('2021-01-01T12:34:56+00:00', $formatted);
|
||||
}
|
||||
}
|
||||
138
tests/Framework/DateTime/DateTimeTest.php
Normal file
138
tests/Framework/DateTime/DateTimeTest.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Framework\DateTime;
|
||||
|
||||
use App\Framework\DateTime\DateTime;
|
||||
use App\Framework\DateTime\Exceptions\InvalidDateTimeException;
|
||||
use App\Framework\DateTime\Exceptions\InvalidTimezoneException;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class DateTimeTest extends TestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
// Sicherheitsvorkehrung: Default-Timezone vor jedem Test zurücksetzen
|
||||
if (method_exists(DateTime::class, 'setDefaultTimezone')) {
|
||||
DateTime::setDefaultTimezone('UTC');
|
||||
}
|
||||
}
|
||||
|
||||
public function testNowReturnsCurrentDateTime(): void
|
||||
{
|
||||
$now = DateTime::now();
|
||||
|
||||
$this->assertInstanceOf(\DateTimeImmutable::class, $now);
|
||||
$this->assertEquals('UTC', $now->getTimezone()->getName());
|
||||
$this->assertLessThanOrEqual(2, abs(time() - $now->getTimestamp()));
|
||||
}
|
||||
|
||||
public function testFromTimestamp(): void
|
||||
{
|
||||
$timestamp = 1609459200; // 2021-01-01 00:00:00 UTC
|
||||
$date = DateTime::fromTimestamp($timestamp);
|
||||
|
||||
$this->assertEquals($timestamp, $date->getTimestamp());
|
||||
$this->assertEquals('UTC', $date->getTimezone()->getName());
|
||||
}
|
||||
|
||||
public function testFromString(): void
|
||||
{
|
||||
$date = DateTime::fromString('2021-01-01 12:00:00');
|
||||
|
||||
$this->assertEquals('2021-01-01 12:00:00', $date->format('Y-m-d H:i:s'));
|
||||
$this->assertEquals('UTC', $date->getTimezone()->getName());
|
||||
}
|
||||
|
||||
public function testFromFormat(): void
|
||||
{
|
||||
$date = DateTime::fromFormat('01/01/2021', 'd/m/Y');
|
||||
|
||||
$this->assertEquals('2021-01-01', $date->format('Y-m-d'));
|
||||
}
|
||||
|
||||
public function testFromDateTime(): void
|
||||
{
|
||||
$originalDate = new \DateTime('2021-01-01 12:00:00');
|
||||
$immutableDate = DateTime::fromDateTime($originalDate);
|
||||
|
||||
$this->assertInstanceOf(\DateTimeImmutable::class, $immutableDate);
|
||||
$this->assertEquals($originalDate->format('Y-m-d H:i:s'), $immutableDate->format('Y-m-d H:i:s'));
|
||||
}
|
||||
|
||||
public function testCreateInterval(): void
|
||||
{
|
||||
$interval = DateTime::createInterval('P1D');
|
||||
|
||||
$this->assertInstanceOf(\DateInterval::class, $interval);
|
||||
$this->assertEquals(1, $interval->d);
|
||||
}
|
||||
|
||||
public function testCreateTimezone(): void
|
||||
{
|
||||
$timezone = DateTime::createTimezone('Europe/Berlin');
|
||||
|
||||
$this->assertInstanceOf(\DateTimeZone::class, $timezone);
|
||||
$this->assertEquals('Europe/Berlin', $timezone->getName());
|
||||
}
|
||||
|
||||
public function testInvalidTimezoneThrowsException(): void
|
||||
{
|
||||
$this->expectException(InvalidTimezoneException::class);
|
||||
DateTime::createTimezone('Invalid/Timezone');
|
||||
}
|
||||
|
||||
public function testInvalidDateTimeThrowsException(): void
|
||||
{
|
||||
$this->expectException(InvalidDateTimeException::class);
|
||||
DateTime::fromString('not a date');
|
||||
}
|
||||
|
||||
public function testInvalidFormatThrowsException(): void
|
||||
{
|
||||
$this->expectException(InvalidDateTimeException::class);
|
||||
DateTime::fromFormat('2021-01-01', 'invalid format');
|
||||
}
|
||||
|
||||
public function testInvalidIntervalThrowsException(): void
|
||||
{
|
||||
$this->expectException(InvalidDateTimeException::class);
|
||||
DateTime::createInterval('invalid interval');
|
||||
}
|
||||
|
||||
public function testSetDefaultTimezone(): void
|
||||
{
|
||||
DateTime::setDefaultTimezone('Europe/Berlin');
|
||||
$now = DateTime::now();
|
||||
|
||||
$this->assertEquals('Europe/Berlin', $now->getTimezone()->getName());
|
||||
}
|
||||
|
||||
public function testToday(): void
|
||||
{
|
||||
$today = DateTime::today();
|
||||
$expected = (new \DateTimeImmutable('today'))->format('Y-m-d');
|
||||
|
||||
$this->assertEquals($expected, $today->format('Y-m-d'));
|
||||
$this->assertEquals('00:00:00', $today->format('H:i:s'));
|
||||
}
|
||||
|
||||
public function testTomorrow(): void
|
||||
{
|
||||
$tomorrow = DateTime::tomorrow();
|
||||
$expected = (new \DateTimeImmutable('tomorrow'))->format('Y-m-d');
|
||||
|
||||
$this->assertEquals($expected, $tomorrow->format('Y-m-d'));
|
||||
$this->assertEquals('00:00:00', $tomorrow->format('H:i:s'));
|
||||
}
|
||||
|
||||
public function testYesterday(): void
|
||||
{
|
||||
$yesterday = DateTime::yesterday();
|
||||
$expected = (new \DateTimeImmutable('yesterday'))->format('Y-m-d');
|
||||
|
||||
$this->assertEquals($expected, $yesterday->format('Y-m-d'));
|
||||
$this->assertEquals('00:00:00', $yesterday->format('H:i:s'));
|
||||
}
|
||||
}
|
||||
82
tests/Framework/DateTime/FrozenClockTest.php
Normal file
82
tests/Framework/DateTime/FrozenClockTest.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Framework\DateTime;
|
||||
|
||||
use App\Framework\DateTime\FrozenClock;
|
||||
|
||||
class FrozenClockTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function testNowReturnsFrozenTime(): void
|
||||
{
|
||||
$frozenTime = new \DateTimeImmutable('2021-01-01 00:00:00');
|
||||
$clock = new FrozenClock($frozenTime);
|
||||
|
||||
$this->assertEquals($frozenTime, $clock->now());
|
||||
|
||||
// Überprüfen, dass die Zeit eingefroren ist
|
||||
sleep(1);
|
||||
$this->assertEquals($frozenTime, $clock->now());
|
||||
}
|
||||
|
||||
public function testFromTimestampReturnsCorrectDateTime(): void
|
||||
{
|
||||
$clock = new FrozenClock('2021-01-01 00:00:00');
|
||||
$timestamp = 1609459200; // 2021-01-01 00:00:00 UTC
|
||||
$date = $clock->fromTimestamp($timestamp);
|
||||
|
||||
$this->assertInstanceOf(\DateTimeImmutable::class, $date);
|
||||
$this->assertEquals($timestamp, $date->getTimestamp());
|
||||
}
|
||||
|
||||
public function testFromStringReturnsCorrectDateTime(): void
|
||||
{
|
||||
$clock = new FrozenClock('2021-01-01 00:00:00');
|
||||
$date = $clock->fromString('2021-02-01 00:00:00');
|
||||
|
||||
$this->assertInstanceOf(\DateTimeImmutable::class, $date);
|
||||
$this->assertEquals('2021-02-01', $date->format('Y-m-d'));
|
||||
$this->assertEquals('00:00:00', $date->format('H:i:s'));
|
||||
}
|
||||
|
||||
public function testSetToChangesTime(): void
|
||||
{
|
||||
$clock = new FrozenClock('2021-01-01 00:00:00');
|
||||
$newTime = new \DateTimeImmutable('2021-02-01 00:00:00');
|
||||
|
||||
$clock->setTo($newTime);
|
||||
$this->assertEquals($newTime, $clock->now());
|
||||
|
||||
$clock->setTo('2021-03-01 00:00:00');
|
||||
$this->assertEquals('2021-03-01', $clock->now()->format('Y-m-d'));
|
||||
}
|
||||
|
||||
public function testMoveForwardAdvancesTime(): void
|
||||
{
|
||||
$clock = new FrozenClock('2021-01-01 00:00:00');
|
||||
|
||||
$clock->moveForward('P1D'); // 1 Tag vorwärts
|
||||
$this->assertEquals('2021-01-02', $clock->now()->format('Y-m-d'));
|
||||
|
||||
$clock->moveForward('PT1H'); // 1 Stunde vorwärts
|
||||
$this->assertEquals('2021-01-02 01:00:00', $clock->now()->format('Y-m-d H:i:s'));
|
||||
}
|
||||
|
||||
public function testMoveBackwardReversesTime(): void
|
||||
{
|
||||
$clock = new FrozenClock('2021-01-10 10:00:00');
|
||||
|
||||
$clock->moveBackward('P5D'); // 5 Tage zurück
|
||||
$this->assertEquals('2021-01-05', $clock->now()->format('Y-m-d'));
|
||||
|
||||
$clock->moveBackward('PT5H'); // 5 Stunden zurück
|
||||
$this->assertEquals('2021-01-05 05:00:00', $clock->now()->format('Y-m-d H:i:s'));
|
||||
}
|
||||
|
||||
public function testCustomTimezone(): void
|
||||
{
|
||||
$clock = new FrozenClock('2021-01-01 00:00:00', 'Europe/Berlin');
|
||||
$now = $clock->now();
|
||||
|
||||
$this->assertEquals('Europe/Berlin', $now->getTimezone()->getName());
|
||||
}
|
||||
}
|
||||
66
tests/Framework/DateTime/SystemClockTest.php
Normal file
66
tests/Framework/DateTime/SystemClockTest.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Framework\DateTime;
|
||||
|
||||
use App\Framework\DateTime\SystemClock;
|
||||
|
||||
class SystemClockTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function testNowReturnsCurrentDateTime(): void
|
||||
{
|
||||
$clock = new SystemClock();
|
||||
$now = $clock->now();
|
||||
|
||||
$this->assertInstanceOf(\DateTimeImmutable::class, $now);
|
||||
$this->assertEquals('UTC', $now->getTimezone()->getName());
|
||||
|
||||
// Überprüfen, dass das Datum innerhalb von 2 Sekunden liegt (für Testlaufzeit)
|
||||
$this->assertLessThanOrEqual(2, abs(time() - $now->getTimestamp()));
|
||||
}
|
||||
|
||||
public function testFromTimestampReturnsCorrectDateTime(): void
|
||||
{
|
||||
$clock = new SystemClock();
|
||||
$timestamp = 1609459200; // 2021-01-01 00:00:00 UTC
|
||||
$date = $clock->fromTimestamp($timestamp);
|
||||
|
||||
$this->assertInstanceOf(\DateTimeImmutable::class, $date);
|
||||
$this->assertEquals($timestamp, $date->getTimestamp());
|
||||
$this->assertEquals('UTC', $date->getTimezone()->getName());
|
||||
}
|
||||
|
||||
public function testFromStringReturnsCorrectDateTime(): void
|
||||
{
|
||||
$clock = new SystemClock();
|
||||
$date = $clock->fromString('2021-01-01 00:00:00');
|
||||
|
||||
$this->assertInstanceOf(\DateTimeImmutable::class, $date);
|
||||
$this->assertEquals('2021-01-01', $date->format('Y-m-d'));
|
||||
$this->assertEquals('00:00:00', $date->format('H:i:s'));
|
||||
}
|
||||
|
||||
public function testFromStringWithFormatReturnsCorrectDateTime(): void
|
||||
{
|
||||
$clock = new SystemClock();
|
||||
$date = $clock->fromString('01/01/2021', 'd/m/Y');
|
||||
|
||||
$this->assertInstanceOf(\DateTimeImmutable::class, $date);
|
||||
$this->assertEquals('2021-01-01', $date->format('Y-m-d'));
|
||||
}
|
||||
|
||||
public function testFromStringWithInvalidFormatThrowsException(): void
|
||||
{
|
||||
$clock = new SystemClock();
|
||||
|
||||
$this->expectException(\Exception::class);
|
||||
$clock->fromString('not a date', 'Y-m-d');
|
||||
}
|
||||
|
||||
public function testClockWithCustomTimezone(): void
|
||||
{
|
||||
$clock = new SystemClock('Europe/Berlin');
|
||||
$now = $clock->now();
|
||||
|
||||
$this->assertEquals('Europe/Berlin', $now->getTimezone()->getName());
|
||||
}
|
||||
}
|
||||
70
tests/Framework/Filesystem/FileStorageTest.php
Normal file
70
tests/Framework/Filesystem/FileStorageTest.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Framework\Filesystem;
|
||||
|
||||
use App\Framework\Filesystem\Exceptions\FileNotFoundException;
|
||||
use App\Framework\Filesystem\FileStorage;
|
||||
use App\Framework\Filesystem\InMemoryStorage;
|
||||
|
||||
test('speichert und lädt Dateien', function () {
|
||||
$tempFile = tempnam(sys_get_temp_dir(), 'test_');
|
||||
$content = 'Testinhalt ' . uniqid();
|
||||
|
||||
$storage = new FileStorage();
|
||||
$storage->put($tempFile, $content);
|
||||
|
||||
expect($storage->exists($tempFile))->toBeTrue();
|
||||
expect($storage->get($tempFile))->toBe($content);
|
||||
expect($storage->size($tempFile))->toBe(strlen($content));
|
||||
|
||||
// Aufräumen
|
||||
$storage->delete($tempFile);
|
||||
expect($storage->exists($tempFile))->toBeFalse();
|
||||
});
|
||||
|
||||
test('wirft Exception bei nicht existierender Datei', function () {
|
||||
$storage = new FileStorage();
|
||||
$nonExistingFile = '/tmp/doesnt_exist_' . uniqid();
|
||||
|
||||
expect(fn() => $storage->get($nonExistingFile))
|
||||
->toThrow(FileNotFoundException::class);
|
||||
});
|
||||
|
||||
test('kopiert Dateien', function () {
|
||||
$tempFile = tempnam(sys_get_temp_dir(), 'src_');
|
||||
$destFile = tempnam(sys_get_temp_dir(), 'dest_');
|
||||
unlink($destFile); // Löschen, damit copy funktioniert
|
||||
|
||||
$content = 'Kopierinhalt ' . uniqid();
|
||||
|
||||
$storage = new FileStorage();
|
||||
$storage->put($tempFile, $content);
|
||||
$storage->copy($tempFile, $destFile);
|
||||
|
||||
expect($storage->exists($destFile))->toBeTrue();
|
||||
expect($storage->get($destFile))->toBe($content);
|
||||
|
||||
// Aufräumen
|
||||
$storage->delete($tempFile);
|
||||
$storage->delete($destFile);
|
||||
});
|
||||
|
||||
test('InMemoryStorage funktioniert wie FileStorage', function () {
|
||||
$storage = new InMemoryStorage();
|
||||
$path = '/virtual/test.txt';
|
||||
$content = 'Virtueller Inhalt';
|
||||
|
||||
$storage->put($path, $content);
|
||||
expect($storage->exists($path))->toBeTrue();
|
||||
expect($storage->get($path))->toBe($content);
|
||||
expect($storage->size($path))->toBe(strlen($content));
|
||||
|
||||
$copyPath = '/virtual/copy.txt';
|
||||
$storage->copy($path, $copyPath);
|
||||
expect($storage->get($copyPath))->toBe($content);
|
||||
|
||||
$storage->delete($path);
|
||||
expect($storage->exists($path))->toBeFalse();
|
||||
});
|
||||
121
tests/Framework/Filesystem/LazyLoadingTest.php
Normal file
121
tests/Framework/Filesystem/LazyLoadingTest.php
Normal file
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Framework\Filesystem;
|
||||
|
||||
use App\Framework\Filesystem\File;
|
||||
use App\Framework\Filesystem\Directory;
|
||||
use App\Framework\Filesystem\FilesystemFactory;
|
||||
use App\Framework\Filesystem\InMemoryStorage;
|
||||
use App\Framework\Filesystem\FileStorage;
|
||||
|
||||
it('lädt File-Properties erst bei Bedarf', function() {
|
||||
// Test-Storage mit Instrumentierung
|
||||
$storage = new class extends InMemoryStorage {
|
||||
public array $accessed = [];
|
||||
|
||||
public function get(string $path): string {
|
||||
$this->accessed[] = "get:{$path}";
|
||||
return parent::get($path);
|
||||
}
|
||||
|
||||
public function size(string $path): int {
|
||||
$this->accessed[] = "size:{$path}";
|
||||
return parent::size($path);
|
||||
}
|
||||
};
|
||||
|
||||
// Testdatei hinzufügen
|
||||
$storage->addFile('/test.txt', 'Testinhalt');
|
||||
|
||||
// Lazy File erstellen
|
||||
$file = $storage->file('/test.txt');
|
||||
|
||||
// Sollte noch keine Storage-Methoden aufgerufen haben
|
||||
expect($storage->accessed)->toBeEmpty();
|
||||
|
||||
// Zugriff auf path sollte kein Laden auslösen
|
||||
$path = $file->path;
|
||||
expect($storage->accessed)->toBeEmpty();
|
||||
|
||||
// Zugriff auf contents sollte get() auslösen
|
||||
$contents = $file->contents;
|
||||
expect($storage->accessed)->toContain('get:/test.txt');
|
||||
expect($contents)->toBe('Testinhalt');
|
||||
|
||||
// Zugriff auf size sollte size() auslösen
|
||||
$size = $file->size;
|
||||
expect($storage->accessed)->toContain('size:/test.txt');
|
||||
expect($size)->toBe(10); // Länge von 'Testinhalt'
|
||||
});
|
||||
|
||||
it('lädt Directory-Properties erst bei Bedarf', function() {
|
||||
// Test-Storage mit Instrumentierung
|
||||
$storage = new class extends InMemoryStorage {
|
||||
public array $accessed = [];
|
||||
|
||||
public function listDirectory(string $directory): array {
|
||||
$this->accessed[] = "list:{$directory}";
|
||||
return parent::listDirectory($directory);
|
||||
}
|
||||
};
|
||||
|
||||
// Testverzeichnis erstellen
|
||||
$storage->createDirectory('/test-dir');
|
||||
$storage->addFile('/test-dir/file1.txt', 'Datei 1');
|
||||
$storage->addFile('/test-dir/file2.txt', 'Datei 2');
|
||||
|
||||
// Lazy Directory erstellen
|
||||
$dir = $storage->directory('/test-dir');
|
||||
|
||||
// Sollte noch keine Storage-Methoden aufgerufen haben
|
||||
expect($storage->accessed)->toBeEmpty();
|
||||
|
||||
// Zugriff auf path sollte kein Laden auslösen
|
||||
$path = $dir->path;
|
||||
expect($storage->accessed)->toBeEmpty();
|
||||
|
||||
// Zugriff auf contents sollte listDirectory() auslösen
|
||||
$contents = $dir->contents;
|
||||
expect($storage->accessed)->toContain('list:/test-dir');
|
||||
expect($contents)->toHaveCount(2);
|
||||
});
|
||||
|
||||
it('kann mit echtem FileStorage arbeiten', function() {
|
||||
// Dieser Test kann übersprungen werden, wenn keine Schreibrechte im Temp-Verzeichnis vorhanden sind
|
||||
$tempDir = sys_get_temp_dir() . '/php-lazy-test-' . uniqid();
|
||||
@mkdir($tempDir, 0777, true);
|
||||
if (!is_dir($tempDir) || !is_writable($tempDir)) {
|
||||
$this->markTestSkipped('Kein Schreibzugriff im Temp-Verzeichnis');
|
||||
}
|
||||
|
||||
try {
|
||||
// Echten FileStorage verwenden
|
||||
$storage = new FileStorage();
|
||||
|
||||
// Testdatei erstellen
|
||||
$testFile = $tempDir . '/test.txt';
|
||||
file_put_contents($testFile, 'Lazy Loading Test');
|
||||
|
||||
// Lazy File erstellen
|
||||
$file = $storage->file($testFile);
|
||||
|
||||
// Properties testen
|
||||
expect($file->path)->toBe($testFile);
|
||||
expect($file->contents)->toBe('Lazy Loading Test');
|
||||
expect($file->size)->toBe(17); // Länge von 'Lazy Loading Test'
|
||||
expect($file->lastModified)->toBeGreaterThan(time() - 10);
|
||||
|
||||
// Directory testen
|
||||
$dir = $storage->directory($tempDir);
|
||||
expect($dir->exists())->toBeTrue();
|
||||
|
||||
$files = $dir->getFiles();
|
||||
expect($files)->toHaveCount(1);
|
||||
expect($files[0]->path)->toEndWith('/test.txt');
|
||||
} finally {
|
||||
// Aufräumen
|
||||
@unlink($testFile);
|
||||
@rmdir($tempDir);
|
||||
}
|
||||
});
|
||||
79
tests/Framework/StaticSite/RouteCollectorTest.php
Normal file
79
tests/Framework/StaticSite/RouteCollectorTest.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Framework\StaticSite;
|
||||
|
||||
use App\Framework\Router\HttpRouter;
|
||||
use App\Framework\Router\Route;
|
||||
use App\Framework\Router\RouteCollection;
|
||||
use App\Framework\StaticSite\RouteCollector;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class RouteCollectorTest extends TestCase
|
||||
{
|
||||
public function testCollectRoutes(): void
|
||||
{
|
||||
// Testdaten vorbereiten
|
||||
$routes = [
|
||||
new Route(path: '/', controller: 'TestController', action: 'index', methods: ['GET']),
|
||||
new Route(path: '/about', controller: 'TestController', action: 'about', methods: ['GET']),
|
||||
new Route(path: '/api/data', controller: 'ApiController', action: 'getData', methods: ['GET']),
|
||||
new Route(path: '/contact', controller: 'TestController', action: 'contact', methods: ['POST']),
|
||||
new Route(path: '/users/{id}', controller: 'UserController', action: 'show', methods: ['GET']),
|
||||
];
|
||||
|
||||
$routeCollection = $this->createMock(RouteCollection::class);
|
||||
$routeCollection->method('getAll')->willReturn($routes);
|
||||
|
||||
$router = $this->createMock(HttpRouter::class);
|
||||
$router->method('getRoutes')->willReturn($routeCollection);
|
||||
|
||||
// RouteCollector initialisieren
|
||||
$collector = new RouteCollector($router);
|
||||
|
||||
// Routen sammeln
|
||||
$collectedRoutes = $collector->collectRoutes();
|
||||
|
||||
// Prüfen, ob die richtigen Routen gesammelt wurden (nur GET-Methoden)
|
||||
$this->assertContains('/', $collectedRoutes);
|
||||
$this->assertContains('/about', $collectedRoutes);
|
||||
$this->assertContains('/api/data', $collectedRoutes);
|
||||
$this->assertContains('/users/{id}', $collectedRoutes);
|
||||
$this->assertNotContains('/contact', $collectedRoutes); // POST-Route sollte nicht enthalten sein
|
||||
}
|
||||
|
||||
public function testFilterRoutes(): void
|
||||
{
|
||||
// Testdaten vorbereiten
|
||||
$routes = [
|
||||
'/',
|
||||
'/about',
|
||||
'/api/data',
|
||||
'/api/users',
|
||||
'/admin/dashboard',
|
||||
'/users/{id}',
|
||||
'/products/{slug}',
|
||||
];
|
||||
|
||||
$excludePatterns = [
|
||||
'/\/api\/.*/', // API-Routen ausschließen
|
||||
'/\/admin\/.*/', // Admin-Routen ausschließen
|
||||
];
|
||||
|
||||
$router = $this->createMock(HttpRouter::class);
|
||||
$collector = new RouteCollector($router);
|
||||
|
||||
// Routen filtern
|
||||
$filteredRoutes = $collector->filterRoutes($routes, $excludePatterns);
|
||||
|
||||
// Prüfen, ob die richtigen Routen gefiltert wurden
|
||||
$this->assertContains('/', $filteredRoutes);
|
||||
$this->assertContains('/about', $filteredRoutes);
|
||||
$this->assertNotContains('/api/data', $filteredRoutes); // Sollte durch Pattern ausgeschlossen sein
|
||||
$this->assertNotContains('/api/users', $filteredRoutes); // Sollte durch Pattern ausgeschlossen sein
|
||||
$this->assertNotContains('/admin/dashboard', $filteredRoutes); // Sollte durch Pattern ausgeschlossen sein
|
||||
$this->assertNotContains('/users/{id}', $filteredRoutes); // Sollte durch Platzhalter ausgeschlossen sein
|
||||
$this->assertNotContains('/products/{slug}', $filteredRoutes); // Sollte durch Platzhalter ausgeschlossen sein
|
||||
}
|
||||
}
|
||||
102
tests/Framework/StaticSite/StaticPageCollectorTest.php
Normal file
102
tests/Framework/StaticSite/StaticPageCollectorTest.php
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Framework\StaticSite;
|
||||
|
||||
use App\Framework\Attributes\StaticPage;
|
||||
use App\Framework\Router\HttpRouter;
|
||||
use App\Framework\Router\Route;
|
||||
use App\Framework\Router\RouteCollection;
|
||||
use App\Framework\StaticSite\StaticPageCollector;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class StaticPageCollectorTest extends TestCase
|
||||
{
|
||||
public function testCollectStaticPages(): void
|
||||
{
|
||||
// Controller-Klasse mit StaticPage-Attribut simulieren
|
||||
$controllerClass = 'TestStaticPageController';
|
||||
$this->createTestControllerClass($controllerClass);
|
||||
|
||||
// Testdaten vorbereiten
|
||||
$routes = [
|
||||
new Route(path: '/', controller: $controllerClass, action: 'indexAction', methods: ['GET']),
|
||||
new Route(path: '/about', controller: $controllerClass, action: 'aboutAction', methods: ['GET']),
|
||||
new Route(path: '/contact', controller: $controllerClass, action: 'contactAction', methods: ['GET']),
|
||||
new Route(path: '/api/data', controller: 'ApiController', action: 'getData', methods: ['GET']),
|
||||
];
|
||||
|
||||
$routeCollection = $this->createMock(RouteCollection::class);
|
||||
$routeCollection->method('getAll')->willReturn($routes);
|
||||
|
||||
$router = $this->createMock(HttpRouter::class);
|
||||
$router->method('getRoutes')->willReturn($routeCollection);
|
||||
|
||||
// StaticPageCollector initialisieren
|
||||
$collector = new StaticPageCollector($router);
|
||||
|
||||
// Statische Seiten sammeln
|
||||
$staticPages = $collector->collectStaticPages();
|
||||
|
||||
// Prüfen, ob die richtigen Seiten gesammelt wurden
|
||||
$this->assertContains('/', $staticPages);
|
||||
$this->assertContains('/about', $staticPages);
|
||||
$this->assertNotContains('/contact', $staticPages); // Kein StaticPage-Attribut
|
||||
$this->assertNotContains('/api/data', $staticPages); // Anderer Controller ohne StaticPage-Attribut
|
||||
}
|
||||
|
||||
public function testCollectAllGetRoutes(): void
|
||||
{
|
||||
// Testdaten vorbereiten
|
||||
$routes = [
|
||||
new Route(path: '/', controller: 'TestController', action: 'index', methods: ['GET']),
|
||||
new Route(path: '/about', controller: 'TestController', action: 'about', methods: ['GET']),
|
||||
new Route(path: '/contact', controller: 'TestController', action: 'contact', methods: ['POST']),
|
||||
new Route(path: '/api/data', controller: 'ApiController', action: 'getData', methods: ['GET']),
|
||||
];
|
||||
|
||||
$routeCollection = $this->createMock(RouteCollection::class);
|
||||
$routeCollection->method('getAll')->willReturn($routes);
|
||||
|
||||
$router = $this->createMock(HttpRouter::class);
|
||||
$router->method('getRoutes')->willReturn($routeCollection);
|
||||
|
||||
// StaticPageCollector initialisieren
|
||||
$collector = new StaticPageCollector($router);
|
||||
|
||||
// Alle GET-Routen sammeln
|
||||
$allGetRoutes = $collector->collectAllGetRoutes();
|
||||
|
||||
// Prüfen, ob die richtigen Seiten gesammelt wurden
|
||||
$this->assertContains('/', $allGetRoutes);
|
||||
$this->assertContains('/about', $allGetRoutes);
|
||||
$this->assertContains('/api/data', $allGetRoutes);
|
||||
$this->assertNotContains('/contact', $allGetRoutes); // POST-Route sollte nicht enthalten sein
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt eine temporäre Controller-Klasse mit StaticPage-Attributen für Tests
|
||||
*/
|
||||
private function createTestControllerClass(string $className): void
|
||||
{
|
||||
if (class_exists($className)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$code = <<<EOT
|
||||
class {$className} {
|
||||
#[\App\Framework\Attributes\StaticPage]
|
||||
public function indexAction() {}
|
||||
|
||||
#[\App\Framework\Attributes\StaticPage(outputPath: 'custom-about')]
|
||||
public function aboutAction() {}
|
||||
|
||||
// Keine StaticPage-Annotation
|
||||
public function contactAction() {}
|
||||
}
|
||||
EOT;
|
||||
|
||||
eval($code);
|
||||
}
|
||||
}
|
||||
134
tests/Framework/StaticSite/StaticSiteGeneratorTest.php
Normal file
134
tests/Framework/StaticSite/StaticSiteGeneratorTest.php
Normal file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Framework\StaticSite;
|
||||
|
||||
use App\Framework\Core\Application;
|
||||
use App\Framework\Http\Method;
|
||||
use App\Framework\Http\HttpResponse;
|
||||
use App\Framework\Http\Request;
|
||||
use App\Framework\Http\Response;
|
||||
use App\Framework\StaticSite\StaticSiteGenerator;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class StaticSiteGeneratorTest extends TestCase
|
||||
{
|
||||
private $outputDir;
|
||||
private $app;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
// Temporäres Verzeichnis für Tests erstellen
|
||||
$this->outputDir = sys_get_temp_dir() . '/static-site-test-' . uniqid();
|
||||
mkdir($this->outputDir, 0755, true);
|
||||
|
||||
// Mock für Application erstellen
|
||||
$this->app = $this->createMock(Application::class);
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
parent::tearDown();
|
||||
|
||||
// Temporäres Verzeichnis nach dem Test löschen
|
||||
$this->removeDirectory($this->outputDir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hilfsfunktion zum rekursiven Löschen eines Verzeichnisses
|
||||
*/
|
||||
private function removeDirectory(string $dir): void
|
||||
{
|
||||
if (!is_dir($dir)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$files = array_diff(scandir($dir), ['.', '..']);
|
||||
|
||||
foreach ($files as $file) {
|
||||
$path = $dir . '/' . $file;
|
||||
is_dir($path) ? $this->removeDirectory($path) : unlink($path);
|
||||
}
|
||||
|
||||
rmdir($dir);
|
||||
}
|
||||
|
||||
public function testGenerateCreatesStaticFiles(): void
|
||||
{
|
||||
// Testdaten vorbereiten
|
||||
$routes = ['/', '/about', '/blog/post-1'];
|
||||
$responseBody = '<html><body>Test Content</body></html>';
|
||||
|
||||
// Mock für Response konfigurieren
|
||||
$response = $this->createMock(Response::class);
|
||||
$response->method('getBody')->willReturn($responseBody);
|
||||
|
||||
// App-Mock konfigurieren, um Response zurückzugeben
|
||||
$this->app->method('handleRequest')->willReturn($response);
|
||||
|
||||
// StaticSiteGenerator initialisieren
|
||||
$generator = new StaticSiteGenerator($this->app, $routes, $this->outputDir);
|
||||
|
||||
// Statische Seiten generieren
|
||||
$generator->generate();
|
||||
|
||||
// Prüfen, ob die erwarteten Dateien erstellt wurden
|
||||
$this->assertFileExists($this->outputDir . '/index.html');
|
||||
$this->assertFileExists($this->outputDir . '/about/index.html');
|
||||
$this->assertFileExists($this->outputDir . '/blog/post-1/index.html');
|
||||
|
||||
// Prüfen, ob der Inhalt korrekt ist
|
||||
$this->assertEquals($responseBody, file_get_contents($this->outputDir . '/index.html'));
|
||||
}
|
||||
|
||||
public function testGenerateHandlesExceptions(): void
|
||||
{
|
||||
// Testdaten vorbereiten
|
||||
$routes = ['/error-page'];
|
||||
|
||||
// App-Mock konfigurieren, um eine Exception zu werfen
|
||||
$this->app->method('handleRequest')->willThrowException(new \Exception('Test Exception'));
|
||||
|
||||
// StaticSiteGenerator initialisieren
|
||||
$generator = new StaticSiteGenerator($this->app, $routes, $this->outputDir);
|
||||
|
||||
// Output-Buffer verwenden, um die Echo-Ausgaben zu erfassen
|
||||
ob_start();
|
||||
$generator->generate();
|
||||
$output = ob_get_clean();
|
||||
|
||||
// Prüfen, ob die Fehlermeldung ausgegeben wurde
|
||||
$this->assertStringContainsString('Fehler beim Generieren von /error-page', $output);
|
||||
|
||||
// Prüfen, ob keine Datei erstellt wurde
|
||||
$this->assertFileDoesNotExist($this->outputDir . '/error-page/index.html');
|
||||
}
|
||||
|
||||
public function testGetFilePathForRoute(): void
|
||||
{
|
||||
// StaticSiteGenerator mit Reflection für private Methoden testen
|
||||
$generator = new StaticSiteGenerator($this->app, [], $this->outputDir);
|
||||
$reflection = new \ReflectionClass($generator);
|
||||
$method = $reflection->getMethod('getFilePathForRoute');
|
||||
$method->setAccessible(true);
|
||||
|
||||
// Verschiedene Routentypen testen
|
||||
$this->assertEquals(
|
||||
$this->outputDir . '/index.html',
|
||||
$method->invoke($generator, '/')
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
$this->outputDir . '/about/index.html',
|
||||
$method->invoke($generator, '/about')
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
$this->outputDir . '/api/data.json',
|
||||
$method->invoke($generator, '/api/data.json')
|
||||
);
|
||||
}
|
||||
}
|
||||
62
tests/Unit/QrCodeTest.php
Normal file
62
tests/Unit/QrCodeTest.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Application\Service\QrCodeService;
|
||||
use App\Domain\QrCode\Exception\QrCodeException;
|
||||
use App\Domain\QrCode\QrCode;
|
||||
use App\Domain\QrCode\ValueObject\ErrorCorrectionLevel;
|
||||
use App\Domain\QrCode\ValueObject\QrCodeVersion;
|
||||
|
||||
test('QR-Code kann mit grundlegenden Daten erstellt werden', function () {
|
||||
$qrCode = new QrCode('Hallo Welt');
|
||||
|
||||
expect($qrCode->getData())->toBe('Hallo Welt');
|
||||
expect($qrCode->getErrorCorrectionLevel())->toBe(ErrorCorrectionLevel::M);
|
||||
});
|
||||
|
||||
test('QR-Code wirft eine Exception bei leeren Daten', function () {
|
||||
expect(fn() => new QrCode(''))->toThrow(QrCodeException::class);
|
||||
});
|
||||
|
||||
test('QR-Code kann als SVG generiert werden', function () {
|
||||
$service = new QrCodeService();
|
||||
$svg = $service->generateSvg('Test');
|
||||
|
||||
expect($svg)->toContain('<svg');
|
||||
expect($svg)->toContain('</svg>');
|
||||
expect($svg)->toContain('fill="black"');
|
||||
});
|
||||
|
||||
test('QR-Code kann als PNG generiert werden', function () {
|
||||
$service = new QrCodeService();
|
||||
$png = $service->generatePng('Test');
|
||||
|
||||
expect($png)->toStartWith("\x89PNG");
|
||||
});
|
||||
|
||||
test('QR-Code kann als ASCII-Art generiert werden', function () {
|
||||
$service = new QrCodeService();
|
||||
$ascii = $service->generateAscii('Test');
|
||||
|
||||
expect($ascii)->toBeString();
|
||||
expect(strlen($ascii))->toBeGreaterThan(100);
|
||||
});
|
||||
|
||||
test('Fehlerkorrekturlevel beeinflusst die Generierung', function () {
|
||||
$service = new QrCodeService();
|
||||
|
||||
$lowMatrix = $service->generateQrCode('Test', ErrorCorrectionLevel::L);
|
||||
$highMatrix = $service->generateQrCode('Test', ErrorCorrectionLevel::H);
|
||||
|
||||
expect($lowMatrix->getSize())->toBeGreaterThan(0);
|
||||
expect($highMatrix->getSize())->toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test('QR-Code-Version bestimmt die Größe', function () {
|
||||
$version1 = new QrCodeVersion(1);
|
||||
$version10 = new QrCodeVersion(10);
|
||||
|
||||
expect($version1->getSize())->toBe(21);
|
||||
expect($version10->getSize())->toBe(57);
|
||||
});
|
||||
Reference in New Issue
Block a user