Skip to content

Commit f04c9f3

Browse files
committed
feat: increase coverage
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
1 parent c7a35a0 commit f04c9f3

2 files changed

Lines changed: 370 additions & 1 deletion

File tree

tests/Unit/Pdf/Svg/SvgArcConverterTest.php

Lines changed: 326 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,88 @@
77

88
namespace LibreSign\XObjectTemplate\Tests\Unit\Pdf\Svg;
99

10+
use LibreSign\XObjectTemplate\Pdf\Svg\ArcParams;
1011
use LibreSign\XObjectTemplate\Pdf\Svg\SvgArcConverter;
1112
use PHPUnit\Framework\Attributes\DataProvider;
1213
use PHPUnit\Framework\TestCase;
1314

1415
final class SvgArcConverterTest extends TestCase
1516
{
17+
/**
18+
* @param array<int, float> $expected
19+
* @param array<int, float> $actual
20+
*/
21+
private static function assertCurveMatches(array $expected, array $actual, float $delta = 0.0001): void
22+
{
23+
self::assertCount(count($expected), $actual);
24+
25+
foreach ($expected as $index => $expectedValue) {
26+
self::assertEqualsWithDelta(
27+
$expectedValue,
28+
$actual[$index],
29+
$delta,
30+
sprintf('Curve index %d differs.', $index),
31+
);
32+
}
33+
}
34+
35+
/**
36+
* @param list<mixed> $arguments
37+
*/
38+
private static function invokePrivateMethod(SvgArcConverter $converter, string $methodName, array $arguments): mixed
39+
{
40+
$reflection = new \ReflectionClass($converter);
41+
$method = $reflection->getMethod($methodName);
42+
$method->setAccessible(true);
43+
44+
return $method->invokeArgs($converter, $arguments);
45+
}
46+
1647
public function testArcToBezierCurvesReturnsEmptyArrayWhenStartAndEndPointsMatch(): void
1748
{
1849
$converter = new SvgArcConverter();
1950

2051
self::assertSame([], $converter->arcToBezierCurves(10.0, 10.0, 5.0, 6.0, 30.0, 0, 1, 10.0, 10.0));
2152
}
2253

54+
public function testArcToBezierCurvesReturnsEmptyArrayWhenBothAxisDeltasStayBelowTolerance(): void
55+
{
56+
$converter = new SvgArcConverter();
57+
58+
self::assertSame(
59+
[],
60+
$converter->arcToBezierCurves(10.0, 10.0, 5.0, 6.0, 30.0, 0, 1, 10.0 + 5.0e-11, 10.0 - 5.0e-11),
61+
);
62+
}
63+
64+
public function testArcToBezierCurvesDoesNotTreatSingleAxisDeltaAsSamePoint(): void
65+
{
66+
$converter = new SvgArcConverter();
67+
68+
$curves = $converter->arcToBezierCurves(10.0, 10.0, 5.0, 6.0, 30.0, 0, 1, 10.0, 14.0);
69+
70+
self::assertNotSame([], $curves);
71+
}
72+
73+
public function testArcToBezierCurvesDoesNotTreatExactToleranceDeltaAsSamePoint(): void
74+
{
75+
$converter = new SvgArcConverter();
76+
77+
$curves = $converter->arcToBezierCurves(
78+
10.0,
79+
10.0,
80+
5.0,
81+
6.0,
82+
30.0,
83+
0,
84+
1,
85+
10.0 + 1.0e-10,
86+
10.0,
87+
);
88+
89+
self::assertNotSame([], $curves);
90+
}
91+
2392
public function testArcToBezierCurvesFallsBackToDegenerateLineWhenAnyRadiusIsZero(): void
2493
{
2594
$converter = new SvgArcConverter();
@@ -30,6 +99,251 @@ public function testArcToBezierCurvesFallsBackToDegenerateLineWhenAnyRadiusIsZer
3099
);
31100
}
32101

102+
public function testArcToBezierCurvesFallsBackToDegenerateLineWhenRadiusYIsTiny(): void
103+
{
104+
$converter = new SvgArcConverter();
105+
106+
self::assertSame(
107+
[[20.0, 30.0, 20.0, 30.0, 20.0, 30.0]],
108+
$converter->arcToBezierCurves(0.0, 0.0, 5.0, 1.0e-12, 0.0, 0, 1, 20.0, 30.0),
109+
);
110+
}
111+
112+
public function testArcToBezierCurvesDoesNotDegenerateWhenRadiiAreJustAboveTolerance(): void
113+
{
114+
$converter = new SvgArcConverter();
115+
116+
$curves = $converter->arcToBezierCurves(0.0, 0.0, 1.1e-10, 2.2e-10, 0.0, 0, 1, 20.0, 30.0);
117+
118+
self::assertNotSame([], $curves);
119+
self::assertNotSame([[20.0, 30.0, 20.0, 30.0, 20.0, 30.0]], $curves);
120+
}
121+
122+
public function testArcToBezierCurvesDoesNotDegenerateAtExactRadiusTolerance(): void
123+
{
124+
$converter = new SvgArcConverter();
125+
126+
$curves = $converter->arcToBezierCurves(
127+
0.0,
128+
0.0,
129+
1.0e-10,
130+
2.0e-10,
131+
0.0,
132+
0,
133+
1,
134+
20.0,
135+
30.0,
136+
);
137+
138+
self::assertNotSame([], $curves);
139+
self::assertNotSame([[20.0, 30.0, 20.0, 30.0, 20.0, 30.0]], $curves);
140+
}
141+
142+
public function testArcToBezierCurvesUsesSweepAndLargeArcFlagsToChooseDifferentSolutions(): void
143+
{
144+
$converter = new SvgArcConverter();
145+
146+
$smallSweep = $converter->arcToBezierCurves(10.0, 0.0, 10.0, 10.0, 0.0, 0, 1, 0.0, 10.0);
147+
$smallReverseSweep = $converter->arcToBezierCurves(10.0, 0.0, 10.0, 10.0, 0.0, 0, 0, 0.0, 10.0);
148+
$largeSweep = $converter->arcToBezierCurves(10.0, 0.0, 10.0, 10.0, 0.0, 1, 1, 0.0, 10.0);
149+
150+
self::assertNotSame([], $smallSweep);
151+
self::assertNotSame([], $smallReverseSweep);
152+
self::assertNotSame([], $largeSweep);
153+
self::assertNotEquals($smallSweep, $smallReverseSweep);
154+
self::assertNotEquals($smallSweep, $largeSweep);
155+
}
156+
157+
public function testArcToBezierCurvesReturnsFiniteControlPointsForNormalizedRotatedArc(): void
158+
{
159+
$converter = new SvgArcConverter();
160+
161+
$curves = $converter->arcToBezierCurves(0.0, 0.0, 4.0, 3.0, 35.0, 1, 0, 25.0, 8.0);
162+
163+
self::assertNotSame([], $curves);
164+
165+
foreach ($curves as $curve) {
166+
foreach ($curve as $value) {
167+
self::assertTrue(is_finite($value));
168+
}
169+
}
170+
}
171+
172+
public function testArcToBezierCurvesMatchesExpectedHalfEllipseControlPoints(): void
173+
{
174+
$converter = new SvgArcConverter();
175+
176+
$curves = $converter->arcToBezierCurves(0.0, 5.0, 10.0, 5.0, 0.0, 0, 1, 20.0, 5.0);
177+
178+
self::assertCount(2, $curves);
179+
self::assertCurveMatches(
180+
[
181+
-6.7182135842927015E-16,
182+
2.257081148225684,
183+
4.514162296451365,
184+
5.038660188219526E-16,
185+
9.999999999999998,
186+
0.0,
187+
],
188+
$curves[0],
189+
);
190+
self::assertCurveMatches(
191+
[
192+
15.485837703548633,
193+
-5.038660188219526E-16,
194+
20.0,
195+
2.2570811482256823,
196+
20.0,
197+
4.999999999999999,
198+
],
199+
$curves[1],
200+
);
201+
}
202+
203+
public function testArcToBezierCurvesMatchesExpectedNormalizedArcControlPoints(): void
204+
{
205+
$converter = new SvgArcConverter();
206+
207+
$curves = $converter->arcToBezierCurves(0.0, 0.0, 5.0, 5.0, 0.0, 0, 1, 30.0, 0.0);
208+
209+
self::assertCount(2, $curves);
210+
self::assertCurveMatches(
211+
[
212+
-1.0077320376439053E-15,
213+
-8.22875655532295,
214+
6.7712434446770455,
215+
-14.999999999999998,
216+
14.999999999999996,
217+
-15.0,
218+
],
219+
$curves[0],
220+
);
221+
self::assertCurveMatches(
222+
[
223+
23.228756555322946,
224+
-15.000000000000002,
225+
29.999999999999996,
226+
-8.228756555322954,
227+
30.0,
228+
-3.67394039744206E-15,
229+
],
230+
$curves[1],
231+
);
232+
}
233+
234+
public function testArcToBezierCurvesMatchesExpectedQuarterArcSolutionsForFlagVariants(): void
235+
{
236+
$converter = new SvgArcConverter();
237+
238+
$largeSweep = $converter->arcToBezierCurves(10.0, 0.0, 10.0, 10.0, 0.0, 1, 1, 0.0, 10.0);
239+
$smallSweep = $converter->arcToBezierCurves(10.0, 0.0, 10.0, 10.0, 0.0, 0, 1, 0.0, 10.0);
240+
241+
self::assertCount(2, $largeSweep);
242+
self::assertCount(2, $smallSweep);
243+
self::assertCurveMatches(
244+
[
245+
20.95014085253355,
246+
6.808005228802601,
247+
20.95014085253355,
248+
13.191994771197399,
249+
17.071067811865476,
250+
17.071067811865476,
251+
],
252+
$largeSweep[0],
253+
);
254+
self::assertCurveMatches(
255+
[
256+
10.95014085253355,
257+
-3.191994771197398,
258+
10.95014085253355,
259+
3.191994771197398,
260+
7.0710678118654755,
261+
7.071067811865475,
262+
],
263+
$smallSweep[0],
264+
);
265+
}
266+
267+
public function testCalculatePrimeCoordinatesMatchesExpectedRotatedValues(): void
268+
{
269+
$converter = new SvgArcConverter();
270+
$params = new ArcParams(
271+
0.0,
272+
0.0,
273+
60.0,
274+
0.0,
275+
40.0,
276+
20.0,
277+
cos(deg2rad(45.0)),
278+
sin(deg2rad(45.0)),
279+
1,
280+
1,
281+
);
282+
283+
$primeCoordinates = self::invokePrivateMethod($converter, 'calculatePrimeCoordinates', [$params]);
284+
285+
self::assertSame([-21.213203435596427, 21.213203435596423], $primeCoordinates);
286+
}
287+
288+
public function testGenerateArcCurvesUsesSingleSegmentBelowNinetyDegrees(): void
289+
{
290+
$converter = new SvgArcConverter();
291+
292+
$curves = self::invokePrivateMethod(
293+
$converter,
294+
'generateArcCurves',
295+
[0.0, 0.0, 10.0, 10.0, 1.0, 0.0, 0.0, M_PI / 4.0],
296+
);
297+
298+
self::assertCount(1, $curves);
299+
self::assertCurveMatches(
300+
[
301+
10.0,
302+
2.6511477349130246,
303+
8.94571235314983,
304+
5.1964232705811195,
305+
7.0710678118654755,
306+
7.071067811865475,
307+
],
308+
$curves[0],
309+
);
310+
}
311+
312+
public function testGenerateArcCurvesSplitsLargerAnglesIntoExpectedSegments(): void
313+
{
314+
$converter = new SvgArcConverter();
315+
316+
$curves = self::invokePrivateMethod(
317+
$converter,
318+
'generateArcCurves',
319+
[0.0, 0.0, 10.0, 10.0, 1.0, 0.0, 0.0, 3.0 * M_PI / 4.0],
320+
);
321+
322+
self::assertCount(2, $curves);
323+
self::assertCurveMatches(
324+
[
325+
10.0,
326+
4.036465386317128,
327+
7.556042077759557,
328+
7.6941068964541515,
329+
3.8268343236508984,
330+
9.238795325112868,
331+
],
332+
$curves[0],
333+
);
334+
self::assertCurveMatches(
335+
[
336+
0.09762656954223958,
337+
10.783483753771584,
338+
-4.216855765175856,
339+
9.925279858555093,
340+
-7.071067811865475,
341+
7.0710678118654755,
342+
],
343+
$curves[1],
344+
);
345+
}
346+
33347
#[DataProvider('provideArcScenarios')]
34348
public function testArcToBezierCurvesGeneratesExpectedCurveShape(
35349
float $fromX,
@@ -69,7 +383,18 @@ public function testArcToBezierCurvesGeneratesExpectedCurveShape(
69383
}
70384

71385
/**
72-
* @return iterable<string, array{fromX: float, fromY: float, radiusX: float, radiusY: float, rotation: float, largeArc: int, sweep: int, toX: float, toY: float, expectedSegmentCount: int}>
386+
* @return iterable<string, array{
387+
* fromX: float,
388+
* fromY: float,
389+
* radiusX: float,
390+
* radiusY: float,
391+
* rotation: float,
392+
* largeArc: int,
393+
* sweep: int,
394+
* toX: float,
395+
* toY: float,
396+
* expectedSegmentCount: int,
397+
* }>
73398
*/
74399
public static function provideArcScenarios(): iterable
75400
{

0 commit comments

Comments
 (0)