Skip to content

Commit d835adc

Browse files
author
Timm Ortloff
committed
Add CloneTest
1 parent 292ef03 commit d835adc

File tree

1 file changed

+155
-0
lines changed

1 file changed

+155
-0
lines changed

tests/CloneTest.php

+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
<?php
2+
3+
namespace ipl\Tests\Html;
4+
5+
use Closure;
6+
use ipl\Html\Attribute;
7+
use ipl\Html\Attributes;
8+
use ipl\Tests\Html\Lib\CloningDummyElement;
9+
use ReflectionFunction;
10+
use ReflectionProperty;
11+
12+
class CloneTest extends TestCase
13+
{
14+
public function testHtmlOutput(): void
15+
{
16+
$original = new CloningDummyElement();
17+
$original->getAttributes()->set('class', 'original_class');
18+
19+
$firstClone = clone $original;
20+
$firstClone->getAttributes()->set('class', 'first_clone_class');
21+
22+
$secondClone = clone $firstClone;
23+
$secondClone->getAttributes()->set('class', 'second_clone_class');
24+
25+
$originalHtml = <<<'HTML'
26+
<p class="original_class"
27+
test-instance-scope-noop-inline="inline"
28+
test-instance-noop-attribute="static_callback"
29+
test-closure-static-scope-noop="static_callback"
30+
test-closure-instance-scope-noop="static_callback">
31+
</p>
32+
HTML;
33+
34+
$firstCloneHtml = <<<'HTML'
35+
<p class="first_clone_class"
36+
test-instance-scope-noop-inline="inline"
37+
test-instance-noop-attribute="static_callback"
38+
test-closure-static-scope-noop="static_callback"
39+
test-closure-instance-scope-noop="static_callback">
40+
</p>
41+
HTML;
42+
43+
44+
$secondCloneHtml = <<<'HTML'
45+
<p class="second_clone_class"
46+
test-instance-scope-noop-inline="inline"
47+
test-instance-noop-attribute="static_callback"
48+
test-closure-static-scope-noop="static_callback"
49+
test-closure-instance-scope-noop="static_callback">
50+
</p>
51+
HTML;
52+
53+
$this->assertHtml($originalHtml, $original);
54+
$this->assertHtml($firstCloneHtml, $firstClone);
55+
$this->assertHtml($secondCloneHtml, $secondClone);
56+
}
57+
58+
public function testElementCallbacksCloning(): void
59+
{
60+
$element = new CloningDummyElement();
61+
$element->getAttributes();
62+
63+
$clone = clone $element;
64+
65+
$this->assertCallbacksFor($element);
66+
$this->assertCallbacksFor($clone);
67+
}
68+
69+
public function testCloningAttributes(): void
70+
{
71+
$original = Attributes::create([Attribute::create('class', 'class01')]);
72+
73+
$clone = clone $original;
74+
foreach ($clone->getAttributes() as $attribute) {
75+
if ($attribute->getName() === 'class') {
76+
$attribute->setValue('class02');
77+
}
78+
}
79+
80+
$this->assertSame($original->get('class')->getValue(), 'class01');
81+
$this->assertSame($clone->get('class')->getValue(), 'class02');
82+
}
83+
84+
protected function getCallbackThis(callable $callback): ?object
85+
{
86+
if (! $callback instanceof Closure) {
87+
if (is_array($callback) && ! is_string($callback[0])) {
88+
return $callback[0];
89+
} else {
90+
return null;
91+
}
92+
}
93+
94+
return (new ReflectionFunction($callback))
95+
->getClosureThis();
96+
}
97+
98+
protected function isCallbackGlobalOrStatic(callable $callback): bool
99+
{
100+
if (! $callback instanceof Closure) {
101+
if (is_array($callback) && ! is_string($callback[0])) {
102+
return false;
103+
}
104+
} else {
105+
$closureThis = (new ReflectionFunction($callback))
106+
->getClosureThis();
107+
108+
if ($closureThis) {
109+
return false;
110+
}
111+
}
112+
113+
return true;
114+
}
115+
116+
protected function getAttributeCallback(Attributes $attributes, string $name): callable
117+
{
118+
$callbacksProperty = new ReflectionProperty(get_class($attributes), 'callbacks');
119+
$callbacksProperty->setAccessible(true);
120+
$callbacks = $callbacksProperty->getValue($attributes);
121+
122+
return $callbacks[$name];
123+
}
124+
125+
protected function assertCallbacksFor(CloningDummyElement $element)
126+
{
127+
$this->assertCallbackBelongsTo($element->getAttributes(), 'test-instance-scope-noop-inline', $element);
128+
$this->assertCallbackBelongsTo(
129+
$element->getAttributes(),
130+
'test-instance-noop-attribute',
131+
$element
132+
);
133+
$this->assertGlobalOrStaticCallback(
134+
$element->getAttributes(),
135+
'test-closure-static-scope-noop'
136+
);
137+
$this->assertGlobalOrStaticCallback(
138+
$element->getAttributes(),
139+
'test-closure-instance-scope-noop'
140+
);
141+
}
142+
143+
protected function assertGlobalOrStaticCallback(Attributes $attributes, string $callbackName)
144+
{
145+
$callback = $this->getAttributeCallback($attributes, $callbackName);
146+
$this->assertTrue($this->isCallbackGlobalOrStatic($callback));
147+
}
148+
149+
protected function assertCallbackBelongsTo(Attributes $attributes, string $callbackName, object $owner)
150+
{
151+
$callback = $this->getAttributeCallback($attributes, $callbackName);
152+
$callbackThis = $this->getCallbackThis($callback);
153+
$this->assertSame($callbackThis, $owner);
154+
}
155+
}

0 commit comments

Comments
 (0)