Skip to content

Commit cee2087

Browse files
committed
test: improve test coverage
1 parent 4412156 commit cee2087

11 files changed

Lines changed: 266 additions & 6 deletions

.codacy.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
exclude_paths:
2+
- ".github/**"
3+
- "example/**"
4+
- "test/**"
5+

src/TableBinder.php

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,6 @@
77
use Traversable;
88

99
class TableBinder {
10-
/**
11-
* @noinspection PhpPropertyOnlyWrittenInspection
12-
* @phpstan-ignore-next-line
13-
*/
1410
private ListBinder $listBinder;
1511
private ListElementCollection $templateCollection;
1612
private ElementBinder $elementBinder;
@@ -45,12 +41,12 @@ public function bindTableData(
4541
?string $bindKey = null
4642
):void {
4743
$tableData = $this->normaliseTableData($tableData);
44+
$this->initBinders($context);
4845

4946
if($context instanceof Document) {
5047
$context = $context->documentElement;
5148
}
5249

53-
$this->initBinders();
5450
$tableArray = $this->findMatchingTables($context, $bindKey);
5551
if(empty($tableArray)) {
5652
throw new TableElementNotFoundInContextException();
@@ -493,7 +489,11 @@ private function normalizeDoubleHeader(array $bindValue):array {
493489
];
494490
}
495491

496-
private function initBinders():void {
492+
private function initBinders(Document|Element $context):void {
493+
$document = $context instanceof Document
494+
? $context
495+
: $context->ownerDocument;
496+
497497
if(!isset($this->htmlAttributeBinder)) {
498498
$this->htmlAttributeBinder = new HTMLAttributeBinder();
499499
}
@@ -506,5 +506,24 @@ private function initBinders():void {
506506
if(!isset($this->elementBinder)) {
507507
$this->elementBinder = new ElementBinder();
508508
}
509+
if(!isset($this->templateCollection)) {
510+
$this->templateCollection = new ListElementCollection($document);
511+
}
512+
if(!isset($this->listBinder)) {
513+
$this->listBinder = new ListBinder();
514+
}
515+
516+
$this->htmlAttributeBinder->setDependencies($this->listBinder, $this);
517+
$this->elementBinder->setDependencies(
518+
$this->htmlAttributeBinder,
519+
$this->htmlAttributeCollection,
520+
$this->placeholderBinder,
521+
);
522+
$this->listBinder->setDependencies(
523+
$this->elementBinder,
524+
$this->templateCollection,
525+
new BindableCache(),
526+
$this,
527+
);
509528
}
510529
}

test/phpunit/BindableCacheTest.php

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,4 +213,65 @@ public function testConvertToKvp_nestedNullProperty():void {
213213
self::assertNull($kvpList[$i]["address.country.name"]);
214214
}
215215
}
216+
217+
public function testReadNestedObjectValue_privatePropertyReturnsNull():void {
218+
$sut = new BindableCache();
219+
$address = new Address(
220+
"123 Example Street",
221+
"Apt 4",
222+
"Example City",
223+
"AB1 2CD",
224+
new \Gt\DomTemplate\Test\TestHelper\Model\Country("GB"),
225+
);
226+
$object = new class($address) {
227+
public function __construct(private readonly Address $address) {}
228+
};
229+
230+
self::assertNull(
231+
$this->invokeBindableCacheMethod($sut, "readNestedObjectValue", $object, "address"),
232+
);
233+
}
234+
235+
public function testReadNestedObjectValue_uninitializedTypedPropertyReturnsNull():void {
236+
$sut = new BindableCache();
237+
$object = new class {
238+
public Address $address;
239+
};
240+
241+
self::assertNull(
242+
$this->invokeBindableCacheMethod($sut, "readNestedObjectValue", $object, "address"),
243+
);
244+
}
245+
246+
public function testReadNestedObjectValue_missingPropertyReturnsNull():void {
247+
$sut = new BindableCache();
248+
$object = new class {};
249+
250+
self::assertNull(
251+
$this->invokeBindableCacheMethod($sut, "readNestedObjectValue", $object, "address"),
252+
);
253+
}
254+
255+
public function testNullableStringOrIterable_missingMemberReturnsNull():void {
256+
$sut = new BindableCache();
257+
$object = new class {};
258+
259+
self::assertNull(
260+
$this->invokeBindableCacheMethod($sut, "nullableStringOrIterable", $object, "missing"),
261+
);
262+
}
263+
264+
private function invokeBindableCacheMethod(
265+
BindableCache $sut,
266+
string $methodName,
267+
object $object,
268+
string $propertyName,
269+
):mixed {
270+
$invokeMethod = \Closure::bind(
271+
fn(object $target, string $member):mixed => $this->$methodName($target, $member),
272+
$sut,
273+
BindableCache::class,
274+
);
275+
return $invokeMethod($object, $propertyName);
276+
}
216277
}

test/phpunit/ComponentBinderTest.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,4 +213,26 @@ public function testBindValue_stringContext():void {
213213
$sut->bindValue("2", "#subcomponent-2");
214214
$sut->bindValue("3");
215215
}
216+
217+
public function testBindValue_callable():void {
218+
$document = new HTMLDocument(HTMLPageContent::HTML_TODO_CUSTOM_ELEMENT_ALREADY_EXPANDED);
219+
$componentElement = $document->querySelector("todo-list");
220+
$elementBinder = self::createMock(ElementBinder::class);
221+
$elementBinder->expects(self::once())
222+
->method("bind")
223+
->with(null, "computed value", $componentElement);
224+
225+
$sut = new ComponentBinder($document);
226+
$sut->setDependencies(
227+
$elementBinder,
228+
self::createStub(PlaceholderBinder::class),
229+
self::createStub(TableBinder::class),
230+
self::createStub(ListBinder::class),
231+
self::createStub(ListElementCollection::class),
232+
self::createStub(BindableCache::class),
233+
);
234+
$sut->setComponentBinderDependencies($componentElement);
235+
236+
$sut->bindValue(fn():string => "computed value");
237+
}
216238
}

test/phpunit/DocumentBinderTest.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,23 @@ public function testBindTable():void {
511511
}
512512
}
513513

514+
public function testBindTable_stringContext():void {
515+
$document = new HTMLDocument(HTMLPageContent::HTML_TABLES);
516+
$sut = new DocumentBinder($document);
517+
$sut->setDependencies(...$this->documentBinderDependencies($document));
518+
519+
$tableData = [
520+
["Name", "Position"],
521+
["Alan Statham", "Head of Radiology"],
522+
["Sue White", "Staff Liason Officer"],
523+
];
524+
525+
$sut->bindTable($tableData, "#tbl1", "tableData");
526+
$table = $document->getElementById("tbl1");
527+
self::assertSame("Alan Statham", $table->rows[1]->cells[0]->textContent);
528+
self::assertSame("Staff Liason Officer", $table->rows[2]->cells[1]->textContent);
529+
}
530+
514531
public function testBindTable_withNullData():void {
515532
$document = new HTMLDocument(HTMLPageContent::HTML_TABLES);
516533
$sut = new DocumentBinder($document);

test/phpunit/HTMLAttributeBinderTest.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,4 +158,24 @@ public function testExpandAttributes_atCharacter():void {
158158
self::assertSame("London", $fromInput->value);
159159
self::assertSame("Derby", $toInput->value);
160160
}
161+
162+
public function testExpandAttributes_atCharacterDefaultsToName():void {
163+
$document = new HTMLDocument(
164+
"<!doctype html><html><body><input name='email' data-bind:value='@' /></body></html>"
165+
);
166+
$input = $document->querySelector("input");
167+
$sut = new HTMLAttributeBinder();
168+
$sut->expandAttributes($input);
169+
self::assertSame("email", $input->getAttribute("data-bind:value"));
170+
}
171+
172+
public function testExpandAttributes_listUsesTagNameWhenNoHyphen():void {
173+
$document = new HTMLDocument(
174+
"<!doctype html><html><body><ul data-bind:list=''></ul></body></html>"
175+
);
176+
$list = $document->querySelector("ul");
177+
$sut = new HTMLAttributeBinder();
178+
$sut->expandAttributes($list);
179+
self::assertSame("ul", $list->getAttribute("data-bind:list"));
180+
}
161181
}

test/phpunit/ListElementCollectionTest.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,17 @@ public function testGet_noName_noMatch():void {
2424
$sut->get($document->querySelector("ol"));
2525
}
2626

27+
public function testGet_noName_noMatchIncludesContextDescription():void {
28+
$document = new HTMLDocument(
29+
"<!doctype html><html><body><div id='example' class='one two'></div></body></html>"
30+
);
31+
$sut = new ListElementCollection($document);
32+
33+
self::expectException(ListElementNotFoundInContextException::class);
34+
self::expectExceptionMessage("div.one.two#example");
35+
$sut->get($document->querySelector("div"));
36+
}
37+
2738
public function testGet_noName():void {
2839
$document = new HTMLDocument(HTMLPageContent::HTML_LIST);
2940
$ul = $document->querySelector("ul");

test/phpunit/ListElementTest.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,29 @@ public function testInsertListItem():void {
3939
$inserted = $sut->insertListItem();
4040
self::assertSame($originalElementNextElementSibling, $inserted->nextElementSibling);
4141
}
42+
43+
public function testGetListItemName_dataTemplate():void {
44+
$document = new HTMLDocument(HTMLPageContent::HTML_EMPTY);
45+
$originalElement = $document->createElement("template");
46+
$originalElement->setAttribute("data-template", "example-template");
47+
$document->body->appendChild($originalElement);
48+
$sut = new ListElement($originalElement);
49+
self::assertSame("example-template", $sut->getListItemName());
50+
}
51+
52+
public function testFinalizeListItem_noParentDoesNothing():void {
53+
$document = new HTMLDocument(HTMLPageContent::HTML_EMPTY);
54+
$template = $document->createElement("template");
55+
$template->setAttribute("data-list", "example");
56+
$template->innerHTML = "<li>Example</li>";
57+
$document->body->appendChild($template);
58+
59+
$sut = new ListElement($template);
60+
$sut->removeOriginalElement();
61+
$proxy = $sut->insertListItem();
62+
$proxy->remove();
63+
64+
$sut->finalizeListItem($proxy);
65+
self::assertCount(0, $document->body->children);
66+
}
4267
}

test/phpunit/PartialContentTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,18 @@ public function testGetContent():void {
4949
);
5050
}
5151

52+
public function testGetContent_src():void {
53+
$expectedContent = "Nested test file contents";
54+
$dir = $this->baseDir . "/" . uniqid("_partial");
55+
mkdir("$dir/component", 0775, true);
56+
file_put_contents("$dir/component/variant.html", $expectedContent);
57+
$sut = new PartialContent($dir);
58+
self::assertSame(
59+
$expectedContent,
60+
$sut->getContent("component", src: "variant")
61+
);
62+
}
63+
5264
public function testGetHTMLDocument():void {
5365
$expectedContent = "<!doctype html><h1>Test file contents</h1>";
5466
$dir = $this->baseDir . "/" . uniqid("_partial");

test/phpunit/PlaceholderBinderTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,12 @@ public function testBind_multipleAttribute():void {
8282
$sut->bind("tierId", "47297", $link);
8383
self::assertSame("https://github.com/sponsors/PhpGt/sponsorships?tier_id=47297", $link->href);
8484
}
85+
86+
public function testBind_keyMismatchDoesNothing():void {
87+
$document = new HTMLDocument(HTMLPageContent::HTML_PLACEHOLDER);
88+
$sut = new PlaceholderBinder();
89+
$greeting = $document->querySelector("#test2 .greeting");
90+
$sut->bind("otherKey", "Cody", $greeting);
91+
self::assertSame("Hello, {{name ?? you}}!", $greeting->textContent);
92+
}
8593
}

0 commit comments

Comments
 (0)