diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 98158df..0000000 --- a/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -language: php -php: - - 7.1 - - 7.2 - - 7.3 - - 7.4 -install: - - composer install -script: composer test \ No newline at end of file diff --git a/src/Containers/DocumentTags/BodyTag.php b/src/Containers/DocumentTags/BodyTag.php index 19964b9..2612ef0 100644 --- a/src/Containers/DocumentTags/BodyTag.php +++ b/src/Containers/DocumentTags/BodyTag.php @@ -6,8 +6,5 @@ use ByJoby\HTML\Tags\AbstractContainerTag; class BodyTag extends AbstractContainerTag implements BodyTagInterface { - public function tag(): string - { - return 'body'; - } + const TAG = 'body'; } diff --git a/src/Containers/DocumentTags/HeadTag.php b/src/Containers/DocumentTags/HeadTag.php index d626e94..2bf12f3 100644 --- a/src/Containers/DocumentTags/HeadTag.php +++ b/src/Containers/DocumentTags/HeadTag.php @@ -6,6 +6,8 @@ use ByJoby\HTML\Tags\AbstractContainerTag; class HeadTag extends AbstractContainerTag implements HeadTagInterface { + const TAG = 'head'; + /** @var TitleTagInterface */ protected $title; @@ -20,9 +22,4 @@ class HeadTag extends AbstractContainerTag implements HeadTagInterface { return $this->title; } - - public function tag(): string - { - return 'head'; - } } diff --git a/src/Containers/DocumentTags/HtmlTag.php b/src/Containers/DocumentTags/HtmlTag.php index 36e58d0..712e70a 100644 --- a/src/Containers/DocumentTags/HtmlTag.php +++ b/src/Containers/DocumentTags/HtmlTag.php @@ -6,6 +6,8 @@ use ByJoby\HTML\Tags\AbstractContainerTag; class HtmlTag extends AbstractContainerTag implements HtmlTagInterface { + const TAG = 'html'; + /** @var HeadTagInterface */ protected $head; /** @var BodyTagInterface */ @@ -26,11 +28,6 @@ class HtmlTag extends AbstractContainerTag implements HtmlTagInterface ]; } - public function tag(): string - { - return 'html'; - } - public function head(): HeadTagInterface { return $this->head; diff --git a/src/Containers/DocumentTags/TitleTag.php b/src/Containers/DocumentTags/TitleTag.php index 5e408a2..57efdb0 100644 --- a/src/Containers/DocumentTags/TitleTag.php +++ b/src/Containers/DocumentTags/TitleTag.php @@ -2,12 +2,13 @@ namespace ByJoby\HTML\Containers\DocumentTags; -use ByJoby\HTML\Tags\AbstractContainerTag; use ByJoby\HTML\Traits\NodeTrait; use Exception; class TitleTag implements TitleTagInterface { + const TAG = 'title'; + use NodeTrait; /** @var string */ diff --git a/src/Helpers/Attributes.php b/src/Helpers/Attributes.php index 3b36d06..07d76bb 100644 --- a/src/Helpers/Attributes.php +++ b/src/Helpers/Attributes.php @@ -47,7 +47,7 @@ class Attributes implements IteratorAggregate, ArrayAccess function offsetGet(mixed $offset): mixed { $offset = static::sanitizeOffset($offset); - return $this->array[$offset]; + return @$this->array[$offset]; } function offsetSet(mixed $offset, mixed $value): void diff --git a/src/Html5/Html5Document.php b/src/Html5/Html5Document.php new file mode 100644 index 0000000..e208b49 --- /dev/null +++ b/src/Html5/Html5Document.php @@ -0,0 +1,9 @@ +attributes()['href']; + } + + public function setHref(null|string $href): static + { + $this->attributes()['href'] = $href; + return $this; + } + + public function unsetHref(): static + { + unset($this->attributes()['href']); + return $this; + } + + public function target(): null|string + { + return $this->attributes()['target']; + } + + public function setTarget(null|string $target): static + { + $this->attributes()['target'] = $target; + return $this; + } + + public function unsetTarget(): static + { + unset($this->attributes()['target']); + return $this; + } +} diff --git a/src/Html5/Tags/LinkTag.php b/src/Html5/Tags/LinkTag.php new file mode 100644 index 0000000..8107a69 --- /dev/null +++ b/src/Html5/Tags/LinkTag.php @@ -0,0 +1,10 @@ +getMockForAbstractClass(AbstractContainerTag::class, [], '', true, true, true, ['tag']); + $tag->method('tag')->willReturn($name); + return $tag; + } + public function testConstruction() { $empty = new Fragment(); @@ -19,10 +26,8 @@ class FragmentTest extends TestCase public function testNestingDocument(): Fragment { $fragment = new Fragment(); - $div1 = $this->getMockForAbstractClass(AbstractContainerTag::class); - $div1->method('tag')->will($this->returnValue('div')); - $div2 = $this->getMockForAbstractClass(AbstractContainerTag::class); - $div2->method('tag')->will($this->returnValue('div')); + $div1 = $this->tag('div'); + $div2 = $this->tag('div'); // adding div1 to fragment sets its fragment $fragment->addChild($div1); $this->assertEquals($fragment, $div1->document()); @@ -40,8 +45,7 @@ class FragmentTest extends TestCase /** @var AbstractContainerTag */ $div2 = $div1->children()[0]; // add a span and verify it has the right parent - $span = $this->getMockForAbstractClass(AbstractTag::class); - $span->method('tag')->will($this->returnValue('span')); + $span = $this->tag('span'); $div2->addChild($span); $this->assertEquals($fragment, $span->document()); // detach and check document/parent of all nodes diff --git a/tests/Html5/Tags/BaseTagTest.php b/tests/Html5/Tags/BaseTagTest.php new file mode 100644 index 0000000..c4e12d0 --- /dev/null +++ b/tests/Html5/Tags/BaseTagTest.php @@ -0,0 +1,12 @@ +assertAttributeHelperMethods('href', BaseTag::class); + $this->assertAttributeHelperMethods('target', BaseTag::class); + } +} diff --git a/tests/Html5/Tags/TagTestCase.php b/tests/Html5/Tags/TagTestCase.php new file mode 100644 index 0000000..0a4424c --- /dev/null +++ b/tests/Html5/Tags/TagTestCase.php @@ -0,0 +1,46 @@ +assertTagRendersAttribute($tag, $attribute, $render_value); + // test getter + $this->assertEquals($render_value, call_user_func([$tag, $getFn])); + $this->assertEquals($render_value, $tag->attributes()[$attribute]); + // test unsetting via unset + call_user_func([$tag,$unsetFn]); + $this->assertNull(call_user_func([$tag,$getFn])); + } + + protected function assertTagRendersAttribute(TagInterface $tag, string $attribute, string $value) + { + if ($tag instanceof ContainerInterface) { + $this->assertEquals( + sprintf('<%s %s="%s">', $tag->tag(), $attribute, $value, $tag->tag()), + $tag->__toString(), + sprintf('Unexpected rendering of %s value %s is in %s tag', $attribute, $value, $tag->tag()) + ); + } else { + $this->assertEquals( + sprintf('<%s %s="%s"/>', $tag->tag(), $attribute, $value), + $tag->__toString(), + sprintf('Unexpected rendering of %s value %s is in %s tag', $attribute, $value, $tag->tag()) + ); + } + } +} diff --git a/tests/Tags/AbstractContainerTagTest.php b/tests/Tags/AbstractContainerTagTest.php index d07bc84..f797b1c 100644 --- a/tests/Tags/AbstractContainerTagTest.php +++ b/tests/Tags/AbstractContainerTagTest.php @@ -2,21 +2,24 @@ namespace ByJoby\HTML\Tags; -use ByJoby\HTML\Helpers\Attributes; -use ByJoby\HTML\Helpers\Classes; use ByJoby\HTML\Nodes\Text; use ByJoby\HTML\Nodes\UnsanitizedText; use PHPUnit\Framework\TestCase; class AbstractContainerTagTest extends TestCase { + public function tag(string $name): AbstractContainerTag + { + $tag = $this->getMockForAbstractClass(AbstractContainerTag::class, [], '', true, true, true, ['tag']); + $tag->method('tag')->willReturn($name); + return $tag; + } + public function testDIV(): AbstractContainerTag { - $div = $this->getMockForAbstractClass(AbstractContainerTag::class); - $div->method('tag')->will($this->returnValue('div')); + $div = $this->tag('div'); $this->assertEquals('
', $div->__toString()); - $span = $this->getMockForAbstractClass(AbstractContainerTag::class); - $span->method('tag')->will($this->returnValue('span')); + $span = $this->tag('span'); $div->addChild($span); $div->attributes()['a'] = 'b'; $this->assertEquals( @@ -34,9 +37,9 @@ class AbstractContainerTagTest extends TestCase /** @depends clone testDIV */ public function testMoreNesting(AbstractContainerTag $div): AbstractContainerTag { + /** @var AbstractContainerTag */ $span1 = $div->children()[0]; - $span2 = $this->getMockForAbstractClass(AbstractContainerTag::class); - $span2->method('tag')->will($this->returnValue('span')); + $span2 = $this->tag('span'); $span1->addChild($span2); $this->assertEquals( implode(PHP_EOL, [ @@ -54,8 +57,7 @@ class AbstractContainerTagTest extends TestCase /** @depends clone testDIV */ public function testRemoveChild(AbstractContainerTag $div): void { - $span2 = $this->getMockForAbstractClass(AbstractContainerTag::class); - $span2->method('tag')->will($this->returnValue('span')); + $span2 = $this->tag('span'); // add a second span and remove it using its object $div->addChild($span2); $this->assertCount(2, $div->children()); @@ -80,38 +82,36 @@ class AbstractContainerTagTest extends TestCase /** @depends clone testMoreNesting */ public function testDetach(AbstractContainerTag $div): void { - $span1 = $div->children()[0]; - $span2 = $span1->children()[0]; - $span1->detach(); + /** @var AbstractContainerTag */ + $span = $div->children()[0]; + $span->detach(); $this->assertEquals('
', $div->__toString()); - $this->assertNull($span1->parent()); + $this->assertNull($span->parent()); } /** @depends clone testMoreNesting */ public function testDetachCopy(AbstractContainerTag $div): void { - $span1 = $div->children()[0]; - $span2 = $span1->children()[0]; - $copy = $span1->detachCopy(); + /** @var AbstractContainerTag */ + $span = $div->children()[0]; + $copy = $span->detachCopy(); $this->assertNull($copy->parent()); - $this->assertEquals($div, $span1->parent()); + $this->assertEquals($div, $span->parent()); } public function testAddChildBefore(): void { - $div = $this->getMockForAbstractClass(AbstractContainerTag::class); - $div->method('tag')->will($this->returnValue('div')); + $div = $this->tag('div'); // add a string child $div->addChild('a'); $div->addChildBefore('b', 'a'); $this->assertEquals('b', $div->children()[0]->__toString()); // add an actual node object - $span1 = $this->getMockForAbstractClass(AbstractContainerTag::class); - $span1->method('tag')->will($this->returnValue('span')); - $div->addChildBefore($span1, 'a'); - $this->assertEquals($span1, $div->children()[1]->__toString()); + $span = $this->tag('span'); + $div->addChildBefore($span, 'a'); + $this->assertEquals($span, $div->children()[1]->__toString()); // add another object referencing the node object - $div->addChildBefore('c', $span1); + $div->addChildBefore('c', $span); $this->assertEquals('c', $div->children()[1]->__toString()); // should throw an exception if reference child is not found $this->expectExceptionMessage('Reference child not found in this container'); @@ -120,19 +120,17 @@ class AbstractContainerTagTest extends TestCase public function testAddChildAfter(): void { - $div = $this->getMockForAbstractClass(AbstractContainerTag::class); - $div->method('tag')->will($this->returnValue('div')); + $div = $this->tag('div'); // add a string child $div->addChild('a'); $div->addChildAfter('b', 'a'); $this->assertEquals('b', $div->children()[1]->__toString()); // add an actual node object - $span1 = $this->getMockForAbstractClass(AbstractContainerTag::class); - $span1->method('tag')->will($this->returnValue('span')); - $div->addChildAfter($span1, 'a'); - $this->assertEquals($span1, $div->children()[1]->__toString()); + $span = $this->tag('span'); + $div->addChildAfter($span, 'a'); + $this->assertEquals($span, $div->children()[1]->__toString()); // add another object referencing the node object - $div->addChildAfter('c', $span1); + $div->addChildAfter('c', $span); $this->assertEquals('c', $div->children()[2]->__toString()); // should throw an exception if reference child is not found $this->expectExceptionMessage('Reference child not found in this container'); diff --git a/tests/Tags/AbstractTagTest.php b/tests/Tags/AbstractTagTest.php index 5639161..b6b1920 100644 --- a/tests/Tags/AbstractTagTest.php +++ b/tests/Tags/AbstractTagTest.php @@ -8,10 +8,17 @@ use PHPUnit\Framework\TestCase; class AbstractTagTest extends TestCase { + + public function tag(string $name): AbstractTag + { + $tag = $this->getMockForAbstractClass(AbstractTag::class, [], '', true, true, true, ['tag']); + $tag->method('tag')->willReturn($name); + return $tag; + } + public function testBR(): AbstractTag { - $br = $this->getMockForAbstractClass(AbstractTag::class); - $br->method('tag')->will($this->returnValue('br')); + $br = $this->tag('br'); $this->assertEquals('
', $br->__toString()); $this->assertInstanceOf(Classes::class, $br->classes()); $this->assertInstanceOf(Attributes::class, $br->attributes());