Passed
Pull Request — master (#4368)
by Owen
13:28
created

ExactFontTest::setUp()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 18
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 14
dl 0
loc 18
rs 9.7998
c 0
b 0
f 0
cc 3
nc 3
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace PhpOffice\PhpSpreadsheetTests\Shared;
6
7
use PhpOffice\PhpSpreadsheet\RichText\RichText;
8
use PhpOffice\PhpSpreadsheet\RichText\Run;
9
use PhpOffice\PhpSpreadsheet\Shared\Font;
10
use PhpOffice\PhpSpreadsheet\Style\Font as StyleFont;
11
use PHPUnit\Framework\TestCase;
12
13
class ExactFontTest extends TestCase
14
{
15
    // Results from this test are not necessarily portable between
16
    //   systems and Php Releases.
17
    // See https://github.com/php/php-src/issues/9073
18
    // Extra tests are added to determine if test should
19
    //   be marked incomplete.
20
    const EXTRA_FONTS = [
21
        'DejaVu Sans' => [
22
            'x' => 'DejaVuSans.ttf',
23
            'xb' => 'DejaVuSans-Bold.ttf',
24
            'xi' => 'DejaVuSans-Oblique.ttf',
25
            'xbi' => 'DejaVuSans-BoldOblique.ttf',
26
        ],
27
        'DejaVu Sans Mono' => [
28
            'x' => 'DejaVuSansMono.ttf',
29
            'xb' => 'DejaVuSansMono-Bold.ttf',
30
            'xi' => 'DejaVuSansMono-Oblique.ttf',
31
            'xbi' => 'DejaVuSansMono-BoldOblique.ttf',
32
        ],
33
        'DejaVu Serif Condensed' => [
34
            'x' => 'DejaVuSerifCondensed.ttf',
35
            'xb' => 'DejaVuSerifCondensed-Bold.ttf',
36
            'xi' => 'DejaVuSerifCondensed-Italic.ttf',
37
            'xbi' => 'DejaVuSerifCondensed-BoldItalic.ttf',
38
        ],
39
    ];
40
41
    private string $holdDirectory;
42
43
    private string $holdAutoSizeMethod;
44
45
    private string $directoryName = '';
46
47
    private string $incompleteMessage = '';
48
49
    private const KNOWN_MD5 = [
50
        '6a15e0a7c0367ba77a959ea27ebf11cf',
51
        'b0e31de57cd5307954a3c54136ce68ae',
52
        'be189a7e2711cdf2a7f6275c60cbc7e2',
53
    ];
54
55
    private float|int|null $paddingAmountExact;
56
57
    protected function setUp(): void
58
    {
59
        $this->paddingAmountExact = Font::getPaddingAmountExact();
60
        $this->holdDirectory = Font::getTrueTypeFontPath();
61
        $this->holdAutoSizeMethod = Font::getAutoSizeMethod();
62
        $direc = realpath('vendor/mpdf/mpdf/ttfonts') . DIRECTORY_SEPARATOR;
63
        $fontFile = 'DejaVuSans.ttf';
64
        $fontPath = $direc . $fontFile;
65
        $this->incompleteMessage = '';
66
        if (@is_readable($fontPath)) {
67
            $hash = md5_file($fontPath);
68
            if (!in_array($hash, self::KNOWN_MD5, true)) {
69
                $this->incompleteMessage = "Unrecognized Font file MD5 hash $hash";
70
            }
71
        } else {
72
            $this->incompleteMessage = 'Unable to locate font file';
73
        }
74
        $this->directoryName = $direc;
75
    }
76
77
    protected function tearDown(): void
78
    {
79
        Font::setTrueTypeFontPath($this->holdDirectory);
80
        Font::setAutoSizeMethod($this->holdAutoSizeMethod);
81
        Font::setPaddingAmountExact($this->paddingAmountExact);
82
        $this->directoryName = '';
83
    }
84
85
    #[\PHPUnit\Framework\Attributes\DataProvider('providerFontData')]
86
    public function testExact(string $fontName, float $excelWidth, float $xmlWidth, float $winWidth, float $ubuntuWidth): void
87
    {
88
        if ($this->incompleteMessage !== '') {
89
            self::markTestIncomplete($this->incompleteMessage);
90
        }
91
        $font = new StyleFont();
92
        $font->setName($fontName);
93
        $font->setSize(11);
94
        Font::setTrueTypeFontPath($this->directoryName);
95
        Font::setExtraFontArray(self::EXTRA_FONTS);
96
        Font::setAutoSizeMethod(Font::AUTOSIZE_METHOD_EXACT);
97
        $exactWidth = Font::calculateColumnWidth($font, "This is $fontName");
98
        Font::setAutoSizeMethod(Font::AUTOSIZE_METHOD_APPROX);
99
        $approxWidth = Font::calculateColumnWidth($font, "This is $fontName");
100
        if ($excelWidth > 0) {
101
            self::assertGreaterThanOrEqual(max($excelWidth, $xmlWidth), $exactWidth);
102
            // Give ourselves a little wiggle room on upper bound.
103
            self::assertLessThanOrEqual(1.05 * max($winWidth, $ubuntuWidth), $exactWidth);
104
            self::assertNotEquals($exactWidth, $approxWidth);
105
        } else {
106
            self::assertEquals($exactWidth, $approxWidth, 'Use approx when exact font file not found');
107
        }
108
    }
109
110
    public static function providerFontData(): array
111
    {
112
        return [
113
            ['DejaVu Sans', 19.82, 20.453125, 22.5659, 21.709],
114
            ['DejaVu Sans Mono', 29.18, 29.81640625, 31.9922, 31.8494],
115
            ['DejaVu Serif Condensed', 29.55, 30.1796875, 31.9922, 31.1353],
116
            ['Arial', -29.55, 30.1796875, 31.9922, 31.1353],
117
        ];
118
    }
119
120
    public function testRichText(): void
121
    {
122
        // RichText treated as text, using Cell font, not Run Font
123
        $courier = new StyleFont();
124
        $courier->setName('Courier New');
125
        $courier->setSize(11);
126
        Font::setAutoSizeMethod(Font::AUTOSIZE_METHOD_APPROX);
127
        $element1 = new Run('A');
128
        $element2 = new Run('B');
129
        $element3 = new Run('C');
130
        $element1->setFont($courier);
131
        $element2->setFont($courier);
132
        $element3->setFont($courier);
133
        $richText = new RichText();
134
        $richText->setRichTextElements([$element1, $element2, $element3]);
135
        $arial = new StyleFont();
136
        $arial->setName('Arial');
137
        $arial->setSize(9);
138
        $widthRich = Font::calculateColumnWidth($arial, $richText);
139
        $widthText = Font::calculateColumnWidth($arial, 'ABC');
140
        self::assertSame($widthRich, $widthText);
141
    }
142
143
    public function testIssue3626NoPad(): void
144
    {
145
        $fontName = 'DejaVu Sans';
146
        if ($this->incompleteMessage !== '') {
147
            self::markTestIncomplete($this->incompleteMessage);
148
        }
149
        Font::setTrueTypeFontPath($this->directoryName);
150
        Font::setExtraFontArray(self::EXTRA_FONTS);
151
        Font::setAutoSizeMethod(Font::AUTOSIZE_METHOD_EXACT);
152
        Font::setPaddingAmountExact(0);
153
154
        $font = new StyleFont();
155
        $font->setName($fontName);
156
        $font->setSize(20);
157
        $exactWidth = Font::calculateColumnWidth($font, 'Column2');
158
        $expectedWidth = 16.853;
159
        self::assertTrue(
160
            $exactWidth > 0.95 * $expectedWidth && $exactWidth < 1.05 * $expectedWidth,
161
            "$exactWidth is not within 5% of expected $expectedWidth"
162
        );
163
164
        $font = new StyleFont();
165
        $font->setName($fontName);
166
        $exactWidth = Font::calculateColumnWidth($font, 'Col3');
167
        $expectedWidth = 4.5703;
168
        self::assertTrue(
169
            $exactWidth > 0.95 * $expectedWidth && $exactWidth < 1.05 * $expectedWidth,
170
            "$exactWidth is not within 5% of expected $expectedWidth"
171
        );
172
173
        $font = new StyleFont();
174
        $font->setName($fontName);
175
        $exactWidth = Font::calculateColumnWidth($font, 'Big Column in 4 position');
176
        $expectedWidth = 26.2793;
177
        self::assertTrue(
178
            $exactWidth > 0.95 * $expectedWidth && $exactWidth < 1.05 * $expectedWidth,
179
            "$exactWidth is not within 5% of expected $expectedWidth"
180
        );
181
    }
182
183
    public function testIssue3626Pad(): void
184
    {
185
        $fontName = 'DejaVu Sans';
186
        if ($this->incompleteMessage !== '') {
187
            self::markTestIncomplete($this->incompleteMessage);
188
        }
189
        Font::setTrueTypeFontPath($this->directoryName);
190
        Font::setExtraFontArray(self::EXTRA_FONTS);
191
        Font::setAutoSizeMethod(Font::AUTOSIZE_METHOD_EXACT);
192
        //Font::setPaddingAmountExact(null); // default - not needed
193
194
        $font = new StyleFont();
195
        $font->setName($fontName);
196
        $font->setSize(20);
197
        $exactWidth = Font::calculateColumnWidth($font, 'Column2');
198
        $expectedWidth = 18.8525;
199
        self::assertTrue(
200
            $exactWidth > 0.95 * $expectedWidth && $exactWidth < 1.05 * $expectedWidth,
201
            "$exactWidth is not within 5% of expected $expectedWidth"
202
        );
203
204
        $font = new StyleFont();
205
        $font->setName($fontName);
206
        $exactWidth = Font::calculateColumnWidth($font, 'Col3');
207
        $expectedWidth = 5.8557;
208
        self::assertTrue(
209
            $exactWidth > 0.95 * $expectedWidth && $exactWidth < 1.05 * $expectedWidth,
210
            "$exactWidth is not within 5% of expected $expectedWidth"
211
        );
212
213
        $font = new StyleFont();
214
        $font->setName($fontName);
215
        $exactWidth = Font::calculateColumnWidth($font, 'Big Column in 4 position');
216
        $expectedWidth = 27.5647;
217
        self::assertTrue(
218
            $exactWidth > 0.95 * $expectedWidth && $exactWidth < 1.05 * $expectedWidth,
219
            "$exactWidth is not within 5% of expected $expectedWidth"
220
        );
221
    }
222
}
223