- Add comprehensive health check system with multiple endpoints - Add Prometheus metrics endpoint - Add production logging configurations (5 strategies) - Add complete deployment documentation suite: * QUICKSTART.md - 30-minute deployment guide * DEPLOYMENT_CHECKLIST.md - Printable verification checklist * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference * production-logging.md - Logging configuration guide * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation * README.md - Navigation hub * DEPLOYMENT_SUMMARY.md - Executive summary - Add deployment scripts and automation - Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment - Update README with production-ready features All production infrastructure is now complete and ready for deployment.
200 lines
5.6 KiB
PHP
200 lines
5.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Framework\QrCode\QrCodeGenerator;
|
|
use App\Framework\QrCode\QrCodeRenderer;
|
|
use App\Framework\QrCode\ValueObjects\QrCodeStyle;
|
|
use App\Framework\Svg\ValueObjects\Styling\SvgColor;
|
|
|
|
test('can render QR code to SVG', function () {
|
|
$data = 'Test';
|
|
$matrix = QrCodeGenerator::generate($data);
|
|
$renderer = new QrCodeRenderer();
|
|
|
|
$svg = $renderer->renderSvg($matrix);
|
|
|
|
expect($svg)->toBeString()
|
|
->and($svg)->toContain('<?xml')
|
|
->and($svg)->toContain('<svg')
|
|
->and($svg)->toContain('</svg>');
|
|
});
|
|
|
|
test('can render QR code to inline SVG', function () {
|
|
$data = 'Test';
|
|
$matrix = QrCodeGenerator::generate($data);
|
|
$renderer = new QrCodeRenderer();
|
|
|
|
$svg = $renderer->renderInlineSvg($matrix);
|
|
|
|
expect($svg)->toBeString()
|
|
->and($svg)->not->toContain('<?xml')
|
|
->and($svg)->toContain('<svg')
|
|
->and($svg)->toContain('</svg>');
|
|
});
|
|
|
|
test('renders with default style', function () {
|
|
$data = 'Test';
|
|
$matrix = QrCodeGenerator::generate($data);
|
|
$renderer = new QrCodeRenderer();
|
|
|
|
$svg = $renderer->renderSvg($matrix);
|
|
|
|
// Should contain rectangles for modules
|
|
expect($svg)->toContain('<rect')
|
|
->and($svg)->toContain('width=')
|
|
->and($svg)->toContain('height=');
|
|
});
|
|
|
|
test('renders with custom style', function () {
|
|
$data = 'Test';
|
|
$matrix = QrCodeGenerator::generate($data);
|
|
$renderer = new QrCodeRenderer();
|
|
|
|
$style = QrCodeStyle::withColors(
|
|
SvgColor::fromHex('#0000ff'), // Blue dark modules
|
|
SvgColor::fromHex('#ffff00') // Yellow light modules
|
|
);
|
|
|
|
$svg = $renderer->renderCustom($matrix, $style);
|
|
|
|
expect($svg)->toBeString()
|
|
->and($svg)->toContain('<rect');
|
|
});
|
|
|
|
test('renders with compact style', function () {
|
|
$data = 'Test';
|
|
$matrix = QrCodeGenerator::generate($data);
|
|
$renderer = new QrCodeRenderer();
|
|
|
|
$style = QrCodeStyle::compact();
|
|
$svg = $renderer->renderSvg($matrix, $style);
|
|
|
|
// Compact style has smaller modules (5px)
|
|
expect($svg)->toContain('<svg')
|
|
->and($svg)->toContain('width=');
|
|
});
|
|
|
|
test('renders with large style', function () {
|
|
$data = 'Test';
|
|
$matrix = QrCodeGenerator::generate($data);
|
|
$renderer = new QrCodeRenderer();
|
|
|
|
$style = QrCodeStyle::large();
|
|
$svg = $renderer->renderSvg($matrix, $style);
|
|
|
|
// Large style has bigger modules (20px)
|
|
expect($svg)->toContain('<svg')
|
|
->and($svg)->toContain('width=');
|
|
});
|
|
|
|
test('renders with inverted style', function () {
|
|
$data = 'Test';
|
|
$matrix = QrCodeGenerator::generate($data);
|
|
$renderer = new QrCodeRenderer();
|
|
|
|
$style = QrCodeStyle::inverted();
|
|
$svg = $renderer->renderSvg($matrix, $style);
|
|
|
|
// Should render (white modules on black background)
|
|
expect($svg)->toContain('<rect');
|
|
});
|
|
|
|
test('can generate data URL', function () {
|
|
$data = 'Test';
|
|
$matrix = QrCodeGenerator::generate($data);
|
|
$renderer = new QrCodeRenderer();
|
|
|
|
$dataUrl = $renderer->toDataUrl($matrix);
|
|
|
|
expect($dataUrl)->toBeString()
|
|
->and($dataUrl)->toStartWith('data:image/svg+xml;base64,')
|
|
->and(strlen($dataUrl))->toBeGreaterThan(100);
|
|
});
|
|
|
|
test('data URL contains valid base64', function () {
|
|
$data = 'Test';
|
|
$matrix = QrCodeGenerator::generate($data);
|
|
$renderer = new QrCodeRenderer();
|
|
|
|
$dataUrl = $renderer->toDataUrl($matrix);
|
|
$base64 = substr($dataUrl, strlen('data:image/svg+xml;base64,'));
|
|
|
|
$decoded = base64_decode($base64, true);
|
|
|
|
expect($decoded)->not->toBeFalse()
|
|
->and($decoded)->toContain('<svg');
|
|
});
|
|
|
|
test('renders QR code with title and description', function () {
|
|
$data = 'Test';
|
|
$matrix = QrCodeGenerator::generate($data);
|
|
$renderer = new QrCodeRenderer();
|
|
|
|
$svg = $renderer->renderSvg($matrix);
|
|
|
|
expect($svg)->toContain('<title>QR Code</title>')
|
|
->and($svg)->toContain('<desc>QR Code Version');
|
|
});
|
|
|
|
test('renders different sizes correctly', function () {
|
|
$data = 'Test';
|
|
|
|
$matrix1 = QrCodeGenerator::generate($data, \App\Framework\QrCode\ValueObjects\QrCodeConfig::withVersion(1));
|
|
$matrix2 = QrCodeGenerator::generate($data, \App\Framework\QrCode\ValueObjects\QrCodeConfig::withVersion(2));
|
|
|
|
$renderer = new QrCodeRenderer();
|
|
$style = QrCodeStyle::default();
|
|
|
|
$svg1 = $renderer->renderSvg($matrix1, $style);
|
|
$svg2 = $renderer->renderSvg($matrix2, $style);
|
|
|
|
// Larger version should have larger SVG
|
|
expect(strlen($svg2))->toBeGreaterThan(strlen($svg1));
|
|
});
|
|
|
|
test('can render to file', function () {
|
|
$data = 'Test';
|
|
$matrix = QrCodeGenerator::generate($data);
|
|
$renderer = new QrCodeRenderer();
|
|
|
|
$filepath = __DIR__ . '/../../../../tests/tmp/test-qrcode.svg';
|
|
|
|
// Ensure directory exists
|
|
if (!is_dir(dirname($filepath))) {
|
|
mkdir(dirname($filepath), 0777, true);
|
|
}
|
|
|
|
$renderer->renderToFile($matrix, $filepath);
|
|
|
|
expect(file_exists($filepath))->toBeTrue()
|
|
->and(filesize($filepath))->toBeGreaterThan(0);
|
|
|
|
// Cleanup
|
|
if (file_exists($filepath)) {
|
|
unlink($filepath);
|
|
}
|
|
});
|
|
|
|
test('rendered SVG has correct viewBox', function () {
|
|
$data = 'Test';
|
|
$matrix = QrCodeGenerator::generate($data);
|
|
$renderer = new QrCodeRenderer();
|
|
|
|
$svg = $renderer->renderSvg($matrix);
|
|
|
|
// Should contain viewBox attribute
|
|
expect($svg)->toContain('viewBox=');
|
|
});
|
|
|
|
test('renders consistent output for same input', function () {
|
|
$data = 'Test123';
|
|
$matrix = QrCodeGenerator::generate($data);
|
|
$renderer = new QrCodeRenderer();
|
|
|
|
$svg1 = $renderer->renderSvg($matrix);
|
|
$svg2 = $renderer->renderSvg($matrix);
|
|
|
|
expect($svg1)->toBe($svg2);
|
|
});
|