diff --git a/test/phpunit/ListBinderTest.php b/test/phpunit/ListBinderTest.php index eb668b6..c82170e 100644 --- a/test/phpunit/ListBinderTest.php +++ b/test/phpunit/ListBinderTest.php @@ -9,6 +9,7 @@ use Gt\Dom\HTMLDocument; use Gt\DomTemplate\Bind; use Gt\DomTemplate\BindableCache; +use Gt\DomTemplate\BindGetter; use Gt\DomTemplate\ElementBinder; use Gt\DomTemplate\HTMLAttributeBinder; use Gt\DomTemplate\HTMLAttributeCollection; @@ -20,6 +21,8 @@ use Gt\DomTemplate\ListElementCollection; use Gt\DomTemplate\ListElement; use Gt\DomTemplate\Test\TestHelper\HTMLPageContent; +use Gt\DomTemplate\Test\TestHelper\Model\IteratorAggregate\Music\MusicFactory; +use Gt\DomTemplate\Test\TestHelper\Model\IteratorAggregate\Student\StudentFactory; use Gt\DomTemplate\Test\TestHelper\Model\Student; use Gt\DomTemplate\Test\TestHelper\TestData; use PHPUnit\Framework\TestCase; @@ -821,4 +824,105 @@ private function listBinderDependencies(HTMLDocument $document, mixed...$otherOb ]; } + public function testBindListData_objectWithPublicIterable():void { + $obj1 = new class("First") { + public function __construct(public string $name) {} + #[BindGetter] + public function getLettersOfName():array { + return str_split($this->name, 1); + } + }; + $obj2 = new class("Second") { + public function __construct(public string $name) {} + #[BindGetter] + public function getLettersOfName():array { + return str_split($this->name, 1); + } + }; + + $document = new HTMLDocument(HTMLPageContent::HTML_LIST_BIND_NAME); + $sut = new ListBinder(); + $sut->setDependencies(...$this->listBinderDependencies($document)); + $sut->bindListData([ + $obj1, + $obj2, + ], $document); + + $nodeList = $document->querySelectorAll("ul li"); + self::assertCount(2, $nodeList); + self::assertSame("First", $nodeList[0]->textContent); + self::assertSame("Second", $nodeList[1]->textContent); + } + + public function testBindListData_iteratorAggregate():void { + $testData = (new MusicFactory())->buildArtistArray(TestData::MUSIC); + $document = new HTMLDocument(HTMLPageContent::HTML_MUSIC_NO_TEMPLATE_NAMES); + $sut = new ListBinder(); + $sut->setDependencies(...$this->listBinderDependencies($document)); + $sut->bindListData($testData, $document); + + $arrayArtistData = TestData::MUSIC; + + foreach($document->querySelectorAll("body>ul>li") as $artistLi) { + $artistName = key($arrayArtistData); + $arrayAlbumData = current($arrayArtistData); + + self::assertSame($artistName, $artistLi->querySelector("h2")->textContent); + + foreach($artistLi->querySelectorAll("ul>li") as $albumLi) { + $albumName = key($arrayAlbumData); + $arrayTrackData = current($arrayAlbumData); + + self::assertSame($albumName, $albumLi->querySelector("h3")->textContent); + + foreach($albumLi->querySelectorAll("ol>li") as $trackLi) { + $trackName = current($arrayTrackData); + self::assertSame($trackName, $trackLi->textContent); + next($arrayTrackData); + } + + next($arrayAlbumData); + } + + next($arrayArtistData); + } + } + + /** + * This test asserts that the outer element has its data bound correctly. + * We know that the nested sub-lists are bound correctly from the music examples, + * but there's a bug where the outer element (representing the Student in this case) + * does not have its data bound correctly. + */ + public function testBindListData_iteratorAggregate_outerBinds():void { + $testData = (new StudentFactory())->buildStudentArray(TestData::STUDENTS); + $document = new HTMLDocument(HTMLPageContent::HTML_STUDENT_LIST_EXPLICIT_BINDS); + $sut = new ListBinder(); + $sut->setDependencies(...$this->listBinderDependencies($document)); + $sut->bindListData($testData, $document); + + $arrayStudentData = TestData::STUDENTS; + + foreach($document->querySelectorAll("body>ul>li") as $studentLi) { + $arrayStudent = current($arrayStudentData); + $firstName = $arrayStudent["firstName"]; + $lastName = $arrayStudent["lastName"]; + + self::assertSame( + "$firstName $lastName", + trim(preg_replace("/\s+/", " ", $studentLi->querySelector("dd.name")->textContent)) + ); + + $arrayModuleData = $arrayStudent["modules"]; + foreach($studentLi->querySelectorAll(".modules ul>li") as $moduleLi) { + $moduleTitle = current($arrayModuleData); + + self::assertSame($moduleTitle, $moduleLi->textContent); + + next($arrayModuleData); + } + + next($arrayStudentData); + } + } } diff --git a/test/phpunit/TestHelper/HTMLPageContent.php b/test/phpunit/TestHelper/HTMLPageContent.php index c7ccb55..4adfba9 100644 --- a/test/phpunit/TestHelper/HTMLPageContent.php +++ b/test/phpunit/TestHelper/HTMLPageContent.php @@ -1067,6 +1067,39 @@ class HTMLPageContent { HTML; + const HTML_LIST_BIND_NAME = << + +
    +
  1. This doesn't have a data template attribute
  2. +
+

Text message goes here

+HTML; + + const HTML_STUDENT_LIST_EXPLICIT_BINDS = << +

List of students:

+ +HTML; public static function createHTML(string $html = ""):HTMLDocument { return new HTMLDocument($html); diff --git a/test/phpunit/TestHelper/Model/IteratorAggregate/Music/Album.php b/test/phpunit/TestHelper/Model/IteratorAggregate/Music/Album.php new file mode 100644 index 0000000..3999b84 --- /dev/null +++ b/test/phpunit/TestHelper/Model/IteratorAggregate/Music/Album.php @@ -0,0 +1,18 @@ + $trackList */ + public function __construct( + public readonly string $name, + public readonly array $trackList, + ) {} + + public function getIterator():Traversable { + return new ArrayIterator($this->trackList); + } +} diff --git a/test/phpunit/TestHelper/Model/IteratorAggregate/Music/Artist.php b/test/phpunit/TestHelper/Model/IteratorAggregate/Music/Artist.php new file mode 100644 index 0000000..d0043ef --- /dev/null +++ b/test/phpunit/TestHelper/Model/IteratorAggregate/Music/Artist.php @@ -0,0 +1,19 @@ + $albumList */ + public function __construct( + public readonly string $name, + public readonly array $albumList, + ) { + } + + public function getIterator():Traversable { + return new ArrayIterator($this->albumList); + } +} diff --git a/test/phpunit/TestHelper/Model/IteratorAggregate/Music/MusicFactory.php b/test/phpunit/TestHelper/Model/IteratorAggregate/Music/MusicFactory.php new file mode 100644 index 0000000..3850dd7 --- /dev/null +++ b/test/phpunit/TestHelper/Model/IteratorAggregate/Music/MusicFactory.php @@ -0,0 +1,28 @@ +>> $input + * @return array + */ + public function buildArtistArray(array $input):array { + $artistArray = []; + + foreach($input as $artistName => $inputAlbums) { + $albumList = []; + foreach($inputAlbums as $albumName => $inputTracks) { + $trackList = []; + foreach($inputTracks as $trackName) { + $trackList[$trackName] = new Track($trackName, rand(20, 300)); + } + + $albumList[$albumName] = new Album($albumName, $trackList); + } + + $artistArray[$artistName] = new Artist($artistName, $albumList); + } + + return $artistArray; + } +} diff --git a/test/phpunit/TestHelper/Model/IteratorAggregate/Music/Track.php b/test/phpunit/TestHelper/Model/IteratorAggregate/Music/Track.php new file mode 100644 index 0000000..a782ed7 --- /dev/null +++ b/test/phpunit/TestHelper/Model/IteratorAggregate/Music/Track.php @@ -0,0 +1,10 @@ + $moduleList */ + public function __construct( + public readonly Name $name, + public readonly array $moduleList, + ) {} + + public function getIterator():Traversable { + return new \ArrayIterator($this->moduleList); + } +} diff --git a/test/phpunit/TestHelper/Model/IteratorAggregate/Student/StudentFactory.php b/test/phpunit/TestHelper/Model/IteratorAggregate/Student/StudentFactory.php new file mode 100644 index 0000000..0336b5a --- /dev/null +++ b/test/phpunit/TestHelper/Model/IteratorAggregate/Student/StudentFactory.php @@ -0,0 +1,35 @@ +>> $input + * @return array + */ + public function buildStudentArray(array $input):array { + $studentArray = []; + + foreach($input as $inputStudent) { + $moduleList = []; + foreach($inputStudent["modules"] as $moduleName) { + array_push( + $moduleList, + new Module($moduleName), + ); + } + + $name = new Name($inputStudent["firstName"], $inputStudent["lastName"]); + + array_push( + $studentArray, + new Student( + $name, + $moduleList, + ), + ); + } + + return $studentArray; + } +}