100 lines
4.0 KiB
PHP
100 lines
4.0 KiB
PHP
<?php
|
||
|
||
namespace Tests\Unit;
|
||
|
||
use App\Models\Business\CourierQuoteVersion;
|
||
use DOMElement;
|
||
use Dompdf\FrameDecorator\Text;
|
||
use FontLib\Font;
|
||
use Illuminate\Foundation\Testing\TestCase;
|
||
use Tests\CreatesApplication;
|
||
|
||
class CourierQuotePdfWhitespaceTest extends TestCase
|
||
{
|
||
use CreatesApplication;
|
||
|
||
public function test_pasted_quote_rules_render_without_missing_glyphs_and_keep_separate_lines(): void
|
||
{
|
||
$html = view('business.pdf.courier-quote', [
|
||
'version' => new CourierQuoteVersion([
|
||
'version_code' => 'QB-TEST', 'carrier_name' => '示例快递',
|
||
'quote_type' => '普通报价', 'effective_date' => '2026-11-01',
|
||
]),
|
||
'change' => null,
|
||
'values' => [['地区', '费用'], ['江苏', '6.50']],
|
||
'formulas' => [],
|
||
'partyA' => '示例甲方', 'expiryDate' => '长期',
|
||
'faceFee' => '0.50', 'bubbleCoefficient' => '1.2',
|
||
'billingRules' => "1、\u{00A0}计费重 > 0.5kg,费用6.50元。\t\t\t\r\n2、\u{00A0}轻抛比1:10000。\t\t\t\r3、保留末行。",
|
||
'signatureDate' => '2026年11月7日', 'generatedAt' => now(),
|
||
'fontPath' => str_replace('\\', '/', resource_path('fonts/DroidSansFallback.ttf')),
|
||
])->render();
|
||
|
||
$pdf = app('dompdf.wrapper');
|
||
$frames = [];
|
||
$pdf->getDomPDF()->setCallbacks([[
|
||
'event' => 'end_frame',
|
||
'f' => static function ($frame) use (&$frames): void {
|
||
if (! $frame instanceof Text) {
|
||
return;
|
||
}
|
||
|
||
$isSummary = false;
|
||
for ($node = $frame->get_node()->parentNode; $node; $node = $node->parentNode) {
|
||
if ($node instanceof DOMElement && $node->getAttribute('class') === 'summary') {
|
||
$isSummary = true;
|
||
break;
|
||
}
|
||
}
|
||
$frames[] = [
|
||
'text' => $frame->get_text(),
|
||
'font' => $frame->get_style()->font_family,
|
||
'y' => $frame->get_position()['y'],
|
||
'summary' => $isSummary,
|
||
];
|
||
},
|
||
]]);
|
||
$pdf->setPaper('a4', 'landscape');
|
||
$pdf->loadHTML($html, 'UTF-8');
|
||
$this->assertStringStartsWith('%PDF-', $pdf->output());
|
||
$this->assertNotEmpty($frames);
|
||
|
||
$characterMaps = [];
|
||
foreach ($frames as $frame) {
|
||
if (! isset($characterMaps[$frame['font']])) {
|
||
$font = Font::load($frame['font'] . '.ttf');
|
||
$font->parse();
|
||
$characterMaps[$frame['font']] = $font->getUnicodeCharMap();
|
||
$font->close();
|
||
}
|
||
foreach (mb_str_split($frame['text']) as $character) {
|
||
if ($character === "\n" || $character === "\r") {
|
||
continue;
|
||
}
|
||
$codepoint = mb_ord($character);
|
||
$this->assertNotEmpty(
|
||
$characterMaps[$frame['font']][$codepoint] ?? null,
|
||
sprintf('Quote PDF would display a missing glyph for U+%04X.', $codepoint)
|
||
);
|
||
}
|
||
}
|
||
|
||
$ruleFrames = array_values(array_filter($frames, fn ($frame) => $frame['summary']));
|
||
$renderedText = implode('', array_column($ruleFrames, 'text'));
|
||
$this->assertStringContainsString('计费重 > 0.5kg,费用6.50元。', $renderedText);
|
||
$this->assertStringContainsString('轻抛比1:10000。', $renderedText);
|
||
$this->assertStringContainsString('保留末行。', $renderedText);
|
||
$lineY = [];
|
||
foreach ($ruleFrames as $frame) {
|
||
foreach (['1', '2', '3'] as $number) {
|
||
if (str_starts_with($frame['text'], $number)) {
|
||
$lineY[$number] ??= $frame['y'];
|
||
}
|
||
}
|
||
}
|
||
$this->assertCount(3, $lineY);
|
||
$this->assertGreaterThan($lineY['1'], $lineY['2']);
|
||
$this->assertGreaterThan($lineY['2'], $lineY['3']);
|
||
}
|
||
}
|