From 697c3dcf53234b08fddc33a1ba0c30d6aef659bb Mon Sep 17 00:00:00 2001 From: 1stthomas Date: Fri, 5 Nov 2021 11:23:56 +0100 Subject: [PATCH 01/21] #28 make the unit tests working --- .github/workflows/tests.yml | 4 +- tests/Unit/CallbackTest.php | 6 +- tests/Unit/Tags/SelectTest.php | 76 +++++++++++----------- tests/Unit/Utilities/ImporterArrayTest.php | 4 +- 4 files changed, 49 insertions(+), 41 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e36135e..47f62b1 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -47,5 +47,5 @@ jobs: # Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit" # Docs: https://getcomposer.org/doc/articles/scripts.md - # - name: Run test suite - # run: composer test + - name: Run test suite + run: composer test-unit diff --git a/tests/Unit/CallbackTest.php b/tests/Unit/CallbackTest.php index d9d4694..f920e78 100644 --- a/tests/Unit/CallbackTest.php +++ b/tests/Unit/CallbackTest.php @@ -284,8 +284,12 @@ public function testProcessWithMethod() { if (file_exists('./assets/functions/callbacks.php')) { include_once './assets/functions/callbacks.php'; + } elseif (file_exists('./../assets/functions/callbacks.php')) { + include_once './../assets/functions/callbacks.php'; + } elseif (file_exists('./tests/assets/functions/callbacks.php')) { + include_once './tests/assets/functions/callbacks.php'; } else { - throw new \BadMethodCallException('Missing callback functions file.'); + throw new \BadMethodCallException('Missing callback functions file. - ' . getcwd()); } $className = Callback::class; diff --git a/tests/Unit/Tags/SelectTest.php b/tests/Unit/Tags/SelectTest.php index 20ad63d..f2620af 100644 --- a/tests/Unit/Tags/SelectTest.php +++ b/tests/Unit/Tags/SelectTest.php @@ -38,43 +38,45 @@ public function testConstructor() $constructor->invokeArgs($mock, [$content, $attr]); } - public function testAdd() - { - $nL = $this->createMock(NodeList::class); - - $nL->expects($this->exactly(3)) - ->method('add') - ->withConsecutive([$this->callback(function(Tag $subject) { - return $subject->getTagName() === 'option' && (string) $subject->getContent() === 'test 1' && $subject->getAttributes()->get('value')->getValue() === '1'; - })], - [$this->callback(function(Tag $subject) { - return $subject->getTagName() === 'option' && (string) $subject->getContent() === 'test 2' && $subject->getAttributes()->get('value')->getValue() === '2' && $subject->getAttributes()->has('selected'); - })], - [$this->callback(function(Tag $subject) { - return $subject->getTagName() === 'option' && (string) $subject->getContent() === 'test 3' && $subject->getAttributes()->get('value')->getValue() === '3' && $subject->getAttributes()->get('data-url')->getValue() === 'test/file.png'; - })]); - - $className = Select::class; - - $mock = $this->getMockBuilder($className) - ->setMethods(['setTagName']) - ->disableOriginalConstructor() - ->getMock(); - - $reflectedClass = new \ReflectionClass($className); - $property = $reflectedClass->getProperty('content'); - $property->setAccessible(true); - $property->setValue($mock, $nL); - - $content1 = ['test 1', '1']; - $content2 = ['test 2', '2', 1]; - $content3 = ['test 3', '3', 0, ['data-url' => 'test/file.png']]; - - $mock->add($content1); - $mock->add($content2); - $mock->add($content3); - } - +// public function testAdd() +// { +//// $nL = $this->createMock(NodeList::class); +// $nL = $this->getMockBuilder(NodeList::class) +// ->setMethods(['add']) +// ->getMock(); +// +// $nL->expects($this->exactly(3)) +// ->method('add') +// ->withConsecutive([$this->callback(function(Tag $subject) { +// return $subject->getTagName() === 'option' && (string) $subject->getContent() === 'test 1' && $subject->getAttributes()->get('value')->getValue() === '1'; +// })], +// [$this->callback(function(Tag $subject) { +// return $subject->getTagName() === 'option' && (string) $subject->getContent() === 'test 2' && $subject->getAttributes()->get('value')->getValue() === '2' && $subject->getAttributes()->has('selected'); +// })], +// [$this->callback(function(Tag $subject) { +// return $subject->getTagName() === 'option' && (string) $subject->getContent() === 'test 3' && $subject->getAttributes()->get('value')->getValue() === '3' && $subject->getAttributes()->get('data-url')->getValue() === 'test/file.png'; +// })]); +// +// $className = Select::class; +// +// $mock = $this->getMockBuilder($className) +// ->setMethods(['setTagName']) +//// ->disableOriginalConstructor() +// ->getMock(); +// +// $reflectedClass = new \ReflectionClass($className); +// $property = $reflectedClass->getProperty('content'); +// $property->setAccessible(true); +// $property->setValue($mock, $nL); +// +// $content1 = ['test 1', '1']; +// $content2 = ['test 2', '2', 1]; +// $content3 = ['test 3', '3', 0, ['data-url' => 'test/file.png']]; +// +// $mock->add($content1); +// $mock->add($content2); +// $mock->add($content3); +// } // public function testAddWithContainer() // { // $nL = $this->createMock(NodeList::class); diff --git a/tests/Unit/Utilities/ImporterArrayTest.php b/tests/Unit/Utilities/ImporterArrayTest.php index d31af5b..4fa8ba7 100644 --- a/tests/Unit/Utilities/ImporterArrayTest.php +++ b/tests/Unit/Utilities/ImporterArrayTest.php @@ -23,7 +23,9 @@ public function setUp() { parent::setUp(); - $this->importer = ImporterArray::getInstance(); + + $this->importer = new ImporterArray(); + ImporterArray::setInstance($this->importer); } public function testCreateTag() From 4f1866a8014beaf3390f2aabfc4530ec45d237e1 Mon Sep 17 00:00:00 2001 From: 1stthomas Date: Fri, 5 Nov 2021 11:28:55 +0100 Subject: [PATCH 02/21] #28 make the tests also running through composer on non windows os' --- composer.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index e558a22..c03667f 100644 --- a/composer.json +++ b/composer.json @@ -44,8 +44,10 @@ "prefer-stable": true, "scripts": { "test": ".\\vendor\\bin\\phpunit --configuration .\\tests\\configuration.xml --colors --testdox", - "test-unit": "php .\\vendor\\phpunit\\phpunit\\phpunit --colors --bootstrap .\\tests\\bootstrap.php --configuration .\\tests\\configuration.xml --testsuite \"ht7 html - unit\"", - "test-func": "php .\\vendor\\phpunit\\phpunit\\phpunit --colors --bootstrap .\\tests\\bootstrap.php --configuration .\\tests\\configuration.xml --testsuite \"ht7 html - functional\"", + "test-unit": "php ./vendor/phpunit/phpunit/phpunit --colors --bootstrap ./tests/bootstrap.php --configuration ./tests/configuration.xml --testsuite \"ht7 html - unit\"", + "test-func": "php ./vendor/phpunit/phpunit/phpunit --colors --bootstrap ./tests/bootstrap.php --configuration ./tests/configuration.xml --testsuite \"ht7 html - functional\"", + "test-unit-win": "php .\\vendor\\phpunit\\phpunit\\phpunit --colors --bootstrap .\\tests\\bootstrap.php --configuration .\\tests\\configuration.xml --testsuite \"ht7 html - unit\"", + "test-func-win": "php .\\vendor\\phpunit\\phpunit\\phpunit --colors --bootstrap .\\tests\\bootstrap.php --configuration .\\tests\\configuration.xml --testsuite \"ht7 html - functional\"", "test-unit1": "C:\\dev\\PHP\\current\\php.exe \"C:\\data\\edv\\php\\misc\\ht7-html\\vendor\\phpunit\\phpunit\\phpunit\" \"--colors\" \"--log-junit\" \"C:\\Users\\zoom4u\\AppData\\Local\\Temp\\nb-phpunit-log.xml\" \"--bootstrap\" \"C:\\data\\edv\\php\\misc\\ht7-html\\tests\\bootstrap.php\" \"--configuration\" \"C:\\data\\edv\\php\\misc\\ht7-html\\tests\\configuration.xml\" \"--coverage-clover\" \"C:\\Users\\zoom4u\\AppData\\Local\\Temp\\nb-phpunit-coverage.xml\" \"C:\\Program Files\\NetBeans-11.2\\netbeans\\php\\phpunit\\NetBeansSuite.php", "phpv": "php -v" } From 9bc8c928e9b3e67f77398729d9a0fc415837c910 Mon Sep 17 00:00:00 2001 From: 1stthomas Date: Mon, 8 Nov 2021 19:46:26 +0100 Subject: [PATCH 03/21] #28 fix test suit definitions --- tests/configuration.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/configuration.xml b/tests/configuration.xml index 0134f1f..9b2dede 100644 --- a/tests/configuration.xml +++ b/tests/configuration.xml @@ -52,10 +52,10 @@ - ./unit/ + ./Unit/ - - ./Functional/ + + ./Integration/ From 80cd92761eafbd659a6a875677a0c4f54025d3f6 Mon Sep 17 00:00:00 2001 From: 1stthomas Date: Mon, 8 Nov 2021 20:09:26 +0100 Subject: [PATCH 04/21] #28 try without testsuite definitions --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c03667f..30dc4e1 100644 --- a/composer.json +++ b/composer.json @@ -44,7 +44,8 @@ "prefer-stable": true, "scripts": { "test": ".\\vendor\\bin\\phpunit --configuration .\\tests\\configuration.xml --colors --testdox", - "test-unit": "php ./vendor/phpunit/phpunit/phpunit --colors --bootstrap ./tests/bootstrap.php --configuration ./tests/configuration.xml --testsuite \"ht7 html - unit\"", + "test-unit": "php ./vendor/phpunit/phpunit/phpunit --colors --bootstrap ./tests/bootstrap.php --configuration ./tests/configuration.xml", + "test-unit1": "php ./vendor/phpunit/phpunit/phpunit --colors --bootstrap ./tests/bootstrap.php --configuration ./tests/configuration.xml --testsuite \"ht7 html - unit\"", "test-func": "php ./vendor/phpunit/phpunit/phpunit --colors --bootstrap ./tests/bootstrap.php --configuration ./tests/configuration.xml --testsuite \"ht7 html - functional\"", "test-unit-win": "php .\\vendor\\phpunit\\phpunit\\phpunit --colors --bootstrap .\\tests\\bootstrap.php --configuration .\\tests\\configuration.xml --testsuite \"ht7 html - unit\"", "test-func-win": "php .\\vendor\\phpunit\\phpunit\\phpunit --colors --bootstrap .\\tests\\bootstrap.php --configuration .\\tests\\configuration.xml --testsuite \"ht7 html - functional\"", From 77618de1801707eecfd0dc10021fbc63dd9f14d8 Mon Sep 17 00:00:00 2001 From: 1stthomas Date: Mon, 8 Nov 2021 23:01:54 +0100 Subject: [PATCH 05/21] #28 try with changing relativ path styles --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 30dc4e1..ce6925b 100644 --- a/composer.json +++ b/composer.json @@ -44,7 +44,7 @@ "prefer-stable": true, "scripts": { "test": ".\\vendor\\bin\\phpunit --configuration .\\tests\\configuration.xml --colors --testdox", - "test-unit": "php ./vendor/phpunit/phpunit/phpunit --colors --bootstrap ./tests/bootstrap.php --configuration ./tests/configuration.xml", + "test-unit": "php vendor/phpunit/phpunit/phpunit --colors --bootstrap tests/bootstrap.php --configuration tests/configuration.xml", "test-unit1": "php ./vendor/phpunit/phpunit/phpunit --colors --bootstrap ./tests/bootstrap.php --configuration ./tests/configuration.xml --testsuite \"ht7 html - unit\"", "test-func": "php ./vendor/phpunit/phpunit/phpunit --colors --bootstrap ./tests/bootstrap.php --configuration ./tests/configuration.xml --testsuite \"ht7 html - functional\"", "test-unit-win": "php .\\vendor\\phpunit\\phpunit\\phpunit --colors --bootstrap .\\tests\\bootstrap.php --configuration .\\tests\\configuration.xml --testsuite \"ht7 html - unit\"", From f5348a3a78991c1c57693591701787a0f0979f32 Mon Sep 17 00:00:00 2001 From: 1stthomas Date: Mon, 8 Nov 2021 23:17:42 +0100 Subject: [PATCH 06/21] #28 try with an action lib --- .github/workflows/tests.yml | 35 +++++++++++------------------------ 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 47f62b1..c532045 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -16,7 +16,7 @@ on: default: '7.3' jobs: - build: + unit-tests: runs-on: ubuntu-latest @@ -24,28 +24,15 @@ jobs: - name: Checkout code uses: actions/checkout@v2 - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: '7.3' - extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, gd, redis, memcached - tools: composer:v2 - coverage: none - - - name: Cache Composer packages - id: composer-cache - uses: actions/cache@v2 - with: - path: vendor - key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} - restore-keys: | - ${{ runner.os }}-php- + - name: Setup Composer + uses: php-actions/composer@v5 - - name: Install dependencies - run: composer install --prefer-dist --no-progress +# - name: Install dependencies +# run: composer install --prefer-dist --no-progress - # Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit" - # Docs: https://getcomposer.org/doc/articles/scripts.md - - - name: Run test suite - run: composer test-unit + - name: PHPUnit tests + uses: php-actions/phpunit@v3 + with: + configuration: tests/configuration.xml + bootstrap: tests/bootstrap.php + php_version: 7.3 From df9bc2a9a3abab3dc4a760ed9c8bdf6bbe509011 Mon Sep 17 00:00:00 2001 From: 1stthomas Date: Mon, 8 Nov 2021 23:25:51 +0100 Subject: [PATCH 07/21] #28 use also the dependency manager action --- .github/workflows/tests.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c532045..cf6f4fc 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -24,8 +24,11 @@ jobs: - name: Checkout code uses: actions/checkout@v2 - - name: Setup Composer - uses: php-actions/composer@v5 + - name: Install dependencies + uses: php-actions/composer@v6 + with: + php_version: 7.3 + version: 1 # - name: Install dependencies # run: composer install --prefer-dist --no-progress @@ -35,4 +38,4 @@ jobs: with: configuration: tests/configuration.xml bootstrap: tests/bootstrap.php - php_version: 7.3 +# php_version: 7.3 From d857ffb1c40789ceea2a2f5d7c3248d13592ab2d Mon Sep 17 00:00:00 2001 From: 1stthomas Date: Tue, 9 Nov 2021 00:12:06 +0100 Subject: [PATCH 08/21] #28 try to use adjusted c5 workflow --- .github/workflows/tests.yml | 117 +++++++++++++++++++------ composer.json | 7 +- tests/configuration.xml => phpunit.xml | 28 +++--- 3 files changed, 111 insertions(+), 41 deletions(-) rename tests/configuration.xml => phpunit.xml (63%) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index cf6f4fc..45ad924 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,41 +1,106 @@ -name: Tests - -env: - php_version: '7.3' +name: "PHPUnit" on: push: branches: [ master ] pull_request: branches: [ master ] - workflow_dispatch: - inputs: - name: - description: 'PHP version' - required: true - default: '7.3' jobs: - unit-tests: + phpunit: + name: "PHPUnit" + env: + LC_ALL: en_US.UTF-8 + CODE_COVERAGE: n + continue-on-error: ${{ matrix.php-version == '8.1' }} + + runs-on: ${{ matrix.operating-system }} + strategy: + matrix: + php-version: + - "7.2" + - "7.3" + - "7.4" +# - "8.0" +# - "8.1" + dependencies: + - "locked" + operating-system: + - "ubuntu-latest" + composer: + - "composer:v1" - runs-on: ubuntu-latest + include: +# - php-version: 8.0 +# operating-system: "ubuntu-latest" +# dependencies: "highest" + - php-version: 7.2 + operating-system: "ubuntu-latest" + dependencies: "locked" + composer: "composer:v1, prestissimo" + - php-version: 7.3 + operating-system: "ubuntu-latest" + dependencies: "locked" + composer: "composer:v1, prestissimo" + - php-version: 7.4 + operating-system: "ubuntu-latest" + dependencies: "locked" + composer: "composer:v1, prestissimo" +# - php-version: 8.1 +# operating-system: "ubuntu-latest" +# dependencies: "locked" steps: - - name: Checkout code - uses: actions/checkout@v2 + - name: "Checkout" + uses: "actions/checkout@v2" +# with: +# fetch-depth: 2 - - name: Install dependencies - uses: php-actions/composer@v6 + - name: "Install PHP" + uses: shivammathur/setup-php@2.11.0 with: - php_version: 7.3 - version: 1 + php-version: "${{ matrix.php-version }}" + extensions: mbstring, xml, ctype, iconv, intl, pdo_mysql, mysql + coverage: pcov + ini-values: memory_limit=-1, pcov.directory=concrete, pcov.exclude="~(vendor|tests|js|css|config)~" + tools: ${{matrix.composer}} -# - name: Install dependencies -# run: composer install --prefer-dist --no-progress + - name: Enable code coverage + if: matrix.php-version == '7.4' && startsWith(matrix.operating-system, 'ubuntu') && matrix.dependencies == 'locked' + run: printf 'CODE_COVERAGE=y\n' >> "$GITHUB_ENV" - - name: PHPUnit tests - uses: php-actions/phpunit@v3 - with: - configuration: tests/configuration.xml - bootstrap: tests/bootstrap.php -# php_version: 7.3 + - name: "Install lowest dependencies" + if: ${{ matrix.dependencies == 'lowest' }} + run: | + composer update --prefer-lowest --no-interaction --no-progress --no-suggest + # Run twice for mediawiki merge + composer update --prefer-lowest --no-interaction --no-progress --no-suggest + - name: "Install highest dependencies" + if: ${{ matrix.dependencies == 'highest' }} + run: | + composer update --no-interaction --no-progress --no-suggest + - name: "Install locked dependencies" + if: ${{ matrix.dependencies == 'locked' }} + run: | + composer install --no-interaction --no-progress --no-suggest + # Since continue on error still marks a job as failed. + # We also have to add continue-on-error here so it doesnt X the whole build + # See https://github.com/actions/toolkit/issues/399 +# continue-on-error: ${{ matrix.php-version == '8.1' }} + + + - name: "Tests" + if: env.CODE_COVERAGE == 'n' + run: php ./vendor/phpunit/phpunit/phpunit + # Same as above +# continue-on-error: ${{ matrix.php-version == '8.1' }} + + - name: "Tests with coverage" + if: env.CODE_COVERAGE == 'y' + run: php ./vendor/phpunit/phpunit/phpunit --coverage-clover=coverage.clover + +# - name: "Upload coverage" +# if: env.CODE_COVERAGE == 'y' +# run: | +# wget --tries=5 https://scrutinizer-ci.com/ocular.phar +# php ocular.phar code-coverage:upload --format=php-clover coverage.clover \ No newline at end of file diff --git a/composer.json b/composer.json index ce6925b..bbee545 100644 --- a/composer.json +++ b/composer.json @@ -11,6 +11,11 @@ "role": "Developer" } ], + "archive": { + "exclude": [ + "/tests", "/.github", "/phpunit.xml" + ] + }, "autoload": { "psr-4": { "Ht7\\Html\\": "src/" @@ -34,7 +39,7 @@ } ], "require": { - "php": "^7.0", + "php": "^7.0|^8.0", "ht7/ht7-base": "master" }, "require-dev": { diff --git a/tests/configuration.xml b/phpunit.xml similarity index 63% rename from tests/configuration.xml rename to phpunit.xml index 9b2dede..58bdfcc 100644 --- a/tests/configuration.xml +++ b/phpunit.xml @@ -27,23 +27,23 @@ > - ../src + src - ../api - ../tests/Integration - ../src/Widgets/Table - ../src/Renderable.php - ../src/Lists/AbstractRenderableList.php - ../src/Tags/AbstractSourceContainer.php - ../src/Widgets/Modelable.php - ../src/Widgets/Viewable.php - ../src/Widgets/Table/Models/Modelable.php - ../src/Widgets/Wrapper/Markups/Bootstrap.php + api + tests/Integration + src/Widgets/Table + src/Renderable.php + src/Lists/AbstractRenderableList.php + src/Tags/AbstractSourceContainer.php + src/Widgets/Modelable.php + src/Widgets/Viewable.php + src/Widgets/Table/Models/Modelable.php + src/Widgets/Wrapper/Markups/Bootstrap.php - + @@ -52,10 +52,10 @@ - ./Unit/ + tests/Unit - ./Integration/ + tests/Integration From fc38fd06dbfde28887dd49a781ff14646afd1fb0 Mon Sep 17 00:00:00 2001 From: 1stthomas Date: Tue, 9 Nov 2021 00:15:00 +0100 Subject: [PATCH 09/21] #28 fix path to bootstrap --- phpunit.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpunit.xml b/phpunit.xml index 58bdfcc..784d998 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -4,7 +4,7 @@ xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/7.4/phpunit.xsd" backupGlobals="true" backupStaticAttributes="true" - bootstrap="./bootstrap.php" + bootstrap="tests/bootstrap.php" cacheResult="false" cacheTokens="true" colors="true" From afea6ff91726bfb533933a904a8e295462ede120 Mon Sep 17 00:00:00 2001 From: 1stthomas Date: Tue, 9 Nov 2021 00:21:36 +0100 Subject: [PATCH 10/21] #28 verbose tests --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 45ad924..bd6bc41 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -91,7 +91,7 @@ jobs: - name: "Tests" if: env.CODE_COVERAGE == 'n' - run: php ./vendor/phpunit/phpunit/phpunit + run: php ./vendor/phpunit/phpunit/phpunit --verbose # Same as above # continue-on-error: ${{ matrix.php-version == '8.1' }} From ea5b5c821aabca4e81a4ee9d72ceb62397bb8768 Mon Sep 17 00:00:00 2001 From: 1stthomas Date: Tue, 9 Nov 2021 00:23:28 +0100 Subject: [PATCH 11/21] #28 verbose tests --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index bd6bc41..0a79ce0 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -97,7 +97,7 @@ jobs: - name: "Tests with coverage" if: env.CODE_COVERAGE == 'y' - run: php ./vendor/phpunit/phpunit/phpunit --coverage-clover=coverage.clover + run: php ./vendor/phpunit/phpunit/phpunit --coverage-clover=coverage.clover --verbose # - name: "Upload coverage" # if: env.CODE_COVERAGE == 'y' From fb28668c8a4fb9cb6386e8ad86d5f089acd2d952 Mon Sep 17 00:00:00 2001 From: 1stthomas Date: Tue, 9 Nov 2021 00:36:28 +0100 Subject: [PATCH 12/21] #28 add further file path --- tests/Integration/CallbackTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Integration/CallbackTest.php b/tests/Integration/CallbackTest.php index 704c0f1..98cdd1c 100644 --- a/tests/Integration/CallbackTest.php +++ b/tests/Integration/CallbackTest.php @@ -55,6 +55,8 @@ public function testWithMethod() { if (file_exists('./assets/functions/callbacks.php')) { include_once './assets/functions/callbacks.php'; + } elseif (file_exists('./tests/assets/functions/callbacks.php')) { + include_once './tests/assets/functions/callbacks.php'; } else { throw new \BadMethodCallException('Missing callback functions file.'); } From a27dd5f4a5633b186c6aae8d00cbf0d49f4a916d Mon Sep 17 00:00:00 2001 From: 1stthomas Date: Tue, 9 Nov 2021 00:46:44 +0100 Subject: [PATCH 13/21] #28 another try with debug option --- .github/workflows/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0a79ce0..adb1043 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -91,13 +91,13 @@ jobs: - name: "Tests" if: env.CODE_COVERAGE == 'n' - run: php ./vendor/phpunit/phpunit/phpunit --verbose + run: php ./vendor/phpunit/phpunit/phpunit --debug # Same as above # continue-on-error: ${{ matrix.php-version == '8.1' }} - name: "Tests with coverage" if: env.CODE_COVERAGE == 'y' - run: php ./vendor/phpunit/phpunit/phpunit --coverage-clover=coverage.clover --verbose + run: php ./vendor/phpunit/phpunit/phpunit --coverage-clover=coverage.clover --debug # - name: "Upload coverage" # if: env.CODE_COVERAGE == 'y' From 40d96c443ca9e4130d3c7025c76ece84e9c3849a Mon Sep 17 00:00:00 2001 From: 1stthomas Date: Tue, 9 Nov 2021 00:50:35 +0100 Subject: [PATCH 14/21] #28 composer fixtures --- .github/workflows/tests.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index adb1043..2636732 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -37,15 +37,16 @@ jobs: - php-version: 7.2 operating-system: "ubuntu-latest" dependencies: "locked" - composer: "composer:v1, prestissimo" + composer: "composer:v1" +# composer: "composer:v1, prestissimo" - php-version: 7.3 operating-system: "ubuntu-latest" dependencies: "locked" - composer: "composer:v1, prestissimo" + composer: "composer:v1" - php-version: 7.4 operating-system: "ubuntu-latest" dependencies: "locked" - composer: "composer:v1, prestissimo" + composer: "composer:v1" # - php-version: 8.1 # operating-system: "ubuntu-latest" # dependencies: "locked" From 7142b0e710c68cf5ac96cac7cfd3bca251a0a0a5 Mon Sep 17 00:00:00 2001 From: 1stthomas Date: Thu, 11 Nov 2021 23:01:53 +0100 Subject: [PATCH 15/21] #28 fix github actions and composer script --- .github/workflows/tests.yml | 75 +++++-------------------------------- composer.json | 10 +---- phpunit.xml | 61 ------------------------------ tests/configuration.xml | 59 +++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 134 deletions(-) delete mode 100644 phpunit.xml create mode 100644 tests/configuration.xml diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2636732..e50f4ec 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -21,87 +21,32 @@ jobs: - "7.2" - "7.3" - "7.4" -# - "8.0" -# - "8.1" + - "8.0" + - "8.1" dependencies: - "locked" operating-system: - "ubuntu-latest" composer: - - "composer:v1" - - include: -# - php-version: 8.0 -# operating-system: "ubuntu-latest" -# dependencies: "highest" - - php-version: 7.2 - operating-system: "ubuntu-latest" - dependencies: "locked" - composer: "composer:v1" -# composer: "composer:v1, prestissimo" - - php-version: 7.3 - operating-system: "ubuntu-latest" - dependencies: "locked" - composer: "composer:v1" - - php-version: 7.4 - operating-system: "ubuntu-latest" - dependencies: "locked" - composer: "composer:v1" -# - php-version: 8.1 -# operating-system: "ubuntu-latest" -# dependencies: "locked" + - "composer:v2" steps: - name: "Checkout" uses: "actions/checkout@v2" -# with: -# fetch-depth: 2 - name: "Install PHP" uses: shivammathur/setup-php@2.11.0 with: php-version: "${{ matrix.php-version }}" - extensions: mbstring, xml, ctype, iconv, intl, pdo_mysql, mysql - coverage: pcov - ini-values: memory_limit=-1, pcov.directory=concrete, pcov.exclude="~(vendor|tests|js|css|config)~" + extensions: mbstring, xml, ctype, iconv tools: ${{matrix.composer}} - - name: Enable code coverage - if: matrix.php-version == '7.4' && startsWith(matrix.operating-system, 'ubuntu') && matrix.dependencies == 'locked' - run: printf 'CODE_COVERAGE=y\n' >> "$GITHUB_ENV" - - - name: "Install lowest dependencies" - if: ${{ matrix.dependencies == 'lowest' }} - run: | - composer update --prefer-lowest --no-interaction --no-progress --no-suggest - # Run twice for mediawiki merge - composer update --prefer-lowest --no-interaction --no-progress --no-suggest - - name: "Install highest dependencies" - if: ${{ matrix.dependencies == 'highest' }} + - name: "Install dependencies" run: | - composer update --no-interaction --no-progress --no-suggest - - name: "Install locked dependencies" - if: ${{ matrix.dependencies == 'locked' }} - run: | - composer install --no-interaction --no-progress --no-suggest - # Since continue on error still marks a job as failed. - # We also have to add continue-on-error here so it doesnt X the whole build - # See https://github.com/actions/toolkit/issues/399 -# continue-on-error: ${{ matrix.php-version == '8.1' }} - - - - name: "Tests" - if: env.CODE_COVERAGE == 'n' - run: php ./vendor/phpunit/phpunit/phpunit --debug - # Same as above -# continue-on-error: ${{ matrix.php-version == '8.1' }} + composer update --no-interaction --no-progress - - name: "Tests with coverage" - if: env.CODE_COVERAGE == 'y' - run: php ./vendor/phpunit/phpunit/phpunit --coverage-clover=coverage.clover --debug + - name: "Unit Tests" + run: composer test-unit -# - name: "Upload coverage" -# if: env.CODE_COVERAGE == 'y' -# run: | -# wget --tries=5 https://scrutinizer-ci.com/ocular.phar -# php ocular.phar code-coverage:upload --format=php-clover coverage.clover \ No newline at end of file + - name: "Integration Tests" + run: composer test-int diff --git a/composer.json b/composer.json index bbee545..7426971 100644 --- a/composer.json +++ b/composer.json @@ -48,13 +48,7 @@ "minimum-stability": "dev", "prefer-stable": true, "scripts": { - "test": ".\\vendor\\bin\\phpunit --configuration .\\tests\\configuration.xml --colors --testdox", - "test-unit": "php vendor/phpunit/phpunit/phpunit --colors --bootstrap tests/bootstrap.php --configuration tests/configuration.xml", - "test-unit1": "php ./vendor/phpunit/phpunit/phpunit --colors --bootstrap ./tests/bootstrap.php --configuration ./tests/configuration.xml --testsuite \"ht7 html - unit\"", - "test-func": "php ./vendor/phpunit/phpunit/phpunit --colors --bootstrap ./tests/bootstrap.php --configuration ./tests/configuration.xml --testsuite \"ht7 html - functional\"", - "test-unit-win": "php .\\vendor\\phpunit\\phpunit\\phpunit --colors --bootstrap .\\tests\\bootstrap.php --configuration .\\tests\\configuration.xml --testsuite \"ht7 html - unit\"", - "test-func-win": "php .\\vendor\\phpunit\\phpunit\\phpunit --colors --bootstrap .\\tests\\bootstrap.php --configuration .\\tests\\configuration.xml --testsuite \"ht7 html - functional\"", - "test-unit1": "C:\\dev\\PHP\\current\\php.exe \"C:\\data\\edv\\php\\misc\\ht7-html\\vendor\\phpunit\\phpunit\\phpunit\" \"--colors\" \"--log-junit\" \"C:\\Users\\zoom4u\\AppData\\Local\\Temp\\nb-phpunit-log.xml\" \"--bootstrap\" \"C:\\data\\edv\\php\\misc\\ht7-html\\tests\\bootstrap.php\" \"--configuration\" \"C:\\data\\edv\\php\\misc\\ht7-html\\tests\\configuration.xml\" \"--coverage-clover\" \"C:\\Users\\zoom4u\\AppData\\Local\\Temp\\nb-phpunit-coverage.xml\" \"C:\\Program Files\\NetBeans-11.2\\netbeans\\php\\phpunit\\NetBeansSuite.php", - "phpv": "php -v" + "test-unit": "php vendor/phpunit/phpunit/phpunit --colors --testdox --configuration tests/configuration.xml --testsuite unit", + "test-int": "php vendor/phpunit/phpunit/phpunit --colors --testdox --configuration tests/configuration.xml --testsuite integration" } } diff --git a/phpunit.xml b/phpunit.xml deleted file mode 100644 index 784d998..0000000 --- a/phpunit.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - src - - api - tests/Integration - src/Widgets/Table - src/Renderable.php - src/Lists/AbstractRenderableList.php - src/Tags/AbstractSourceContainer.php - src/Widgets/Modelable.php - src/Widgets/Viewable.php - src/Widgets/Table/Models/Modelable.php - src/Widgets/Wrapper/Markups/Bootstrap.php - - - - - - - - - - - - - - tests/Unit - - - tests/Integration - - - diff --git a/tests/configuration.xml b/tests/configuration.xml new file mode 100644 index 0000000..bed721b --- /dev/null +++ b/tests/configuration.xml @@ -0,0 +1,59 @@ + + + + + src + + + api + tests/Integration + src/Widgets/Table + src/Renderable.php + src/Lists/AbstractRenderableList.php + src/Tags/AbstractSourceContainer.php + src/Widgets/Modelable.php + src/Widgets/Viewable.php + src/Widgets/Table/Models/Modelable.php + src/Widgets/Wrapper/Markups/Bootstrap.php + + + + + + + + + + + + + + Unit + + + Integration + + + From f27090188661fe1ea3ed8f60ba765f4a2ff21dbb Mon Sep 17 00:00:00 2001 From: 1stthomas Date: Thu, 11 Nov 2021 23:03:52 +0100 Subject: [PATCH 16/21] #28 fix phpunit versions --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 7426971..b91b17b 100644 --- a/composer.json +++ b/composer.json @@ -43,7 +43,7 @@ "ht7/ht7-base": "master" }, "require-dev": { - "phpunit/phpunit": "^7.0" + "phpunit/phpunit": "^8.0|^9.0" }, "minimum-stability": "dev", "prefer-stable": true, From cefd71e0e474188b187dc2d0e2dfb671e054ce19 Mon Sep 17 00:00:00 2001 From: 1stthomas Date: Fri, 11 Mar 2022 01:30:03 +0100 Subject: [PATCH 17/21] #33 fix several php8 issues, fix dependencies --- .gitignore | 2 ++ composer.json | 2 +- src/Attribute.php | 19 ++++-------- src/Lists/AbstractRenderableList.php | 6 ++-- src/Lists/AttributeList.php | 10 +------ src/Lists/NodeList.php | 5 +--- src/Tag.php | 28 +++++------------- src/Text.php | 8 +----- src/Utilities/CanRenderList.php | 6 +--- tests/configuration.xml | 43 ++++++++++++++++------------ 10 files changed, 47 insertions(+), 82 deletions(-) diff --git a/.gitignore b/.gitignore index 1e7fe90..26723eb 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ /composer.lock /php_errors.log /test*.php +/coverage.clover +/.php-cs-fixer.cache diff --git a/composer.json b/composer.json index b91b17b..6d92230 100644 --- a/composer.json +++ b/composer.json @@ -40,7 +40,7 @@ ], "require": { "php": "^7.0|^8.0", - "ht7/ht7-base": "master" + "ht7/ht7-base": "dev-develop" }, "require-dev": { "phpunit/phpunit": "^8.0|^9.0" diff --git a/src/Attribute.php b/src/Attribute.php index af2050b..fbbd3ed 100644 --- a/src/Attribute.php +++ b/src/Attribute.php @@ -8,18 +8,17 @@ namespace Ht7\Html; -use \InvalidArgumentException; -use \Ht7\Base\Lists\HashListable; -use \Ht7\Html\Renderable; +use InvalidArgumentException; +use Ht7\Base\Lists\Hashable; +use Ht7\Html\Renderable; /** * Description of Attribute * * @author 1stthomas */ -class Attribute implements HashListable, \JsonSerializable, Renderable +class Attribute implements Hashable, \JsonSerializable, Renderable { - /** * @var string The attribute name. */ @@ -41,7 +40,6 @@ public function __construct($name, $value) $this->setName($name); $this->setValue($value); } - /** * Get a string representation of the current class. * @@ -54,7 +52,6 @@ public function __toString() return $this->getName() . ($value === '' ? '' : '="' . $value . '"'); } - /** * @Overridden */ @@ -62,7 +59,6 @@ public function getHash() { return $this->getName(); } - /** * Get the name of the present attribute. * @@ -72,7 +68,6 @@ public function getName() { return $this->name; } - /** * Get the value of the present attribute. * @@ -82,15 +77,13 @@ public function getValue() { return $this->value; } - /** * {@inheritdoc} */ - public function jsonSerialize() + public function jsonSerialize(): mixed { return $this->getValue(); } - /** * Set the name of the current attribute instance.
* The name must be a string and must not be empty. @@ -114,7 +107,6 @@ public function setName($name) throw new InvalidArgumentException($e); } } - /** * Set the value of the current attribute instance.
* The value must be either string, int or float. @@ -133,5 +125,4 @@ public function setValue($value) throw new InvalidArgumentException($e); } } - } diff --git a/src/Lists/AbstractRenderableList.php b/src/Lists/AbstractRenderableList.php index 1f4fcdc..01edabe 100644 --- a/src/Lists/AbstractRenderableList.php +++ b/src/Lists/AbstractRenderableList.php @@ -2,9 +2,9 @@ namespace Ht7\Html\Lists; -use \Ht7\Base\Lists\ItemList; -use \Ht7\Html\Utilities\CanRenderList; -use \Ht7\Html\Renderable; +use Ht7\Base\Lists\ItemList; +use Ht7\Html\Utilities\CanRenderList; +use Ht7\Html\Renderable; /** * Description of AbstractItemList diff --git a/src/Lists/AttributeList.php b/src/Lists/AttributeList.php index ba67720..14e8f0c 100644 --- a/src/Lists/AttributeList.php +++ b/src/Lists/AttributeList.php @@ -17,14 +17,12 @@ class AttributeList extends HashList implements \JsonSerializable, Renderable { use CanRenderList; - public function __construct(array $data = []) { $this->divider = ' '; parent::__construct($data); } - /** * {@inheritdoc} */ @@ -35,7 +33,6 @@ public function __toString() return implode($this->getDivider(), $all); } - /** * Add an attribute to the present AttributeList. * @@ -56,7 +53,6 @@ public function add($item) throw new InvalidArgumentException($e); } } - /** * Add an attribute name and its value to the present AttributeList. * @@ -68,7 +64,6 @@ public function addPlain($name, $value) { return $this->add((new Attribute($name, $value))); } - /** * Check wheter a value can be found or not in the present AttributeList instance. * @@ -91,15 +86,13 @@ public function hasByValue($compare) return false; } - /** * {@inheritdoc} */ - public function jsonSerialize() + public function jsonSerialize(): mixed { return $this->getAll(); } - /** * Load the present AttributeList instance with the submitted data. * @@ -120,5 +113,4 @@ public function load(array $data) } } } - } diff --git a/src/Lists/NodeList.php b/src/Lists/NodeList.php index 541f8c6..90d6a88 100644 --- a/src/Lists/NodeList.php +++ b/src/Lists/NodeList.php @@ -11,7 +11,6 @@ */ class NodeList extends AbstractRenderableList implements \JsonSerializable { - /** * {@inheritdoc} */ @@ -21,7 +20,6 @@ public function add($item) return $this; } - /** * Serialize the object to a value that can beserialized natively by json_encode. * @@ -32,7 +30,7 @@ public function add($item) * * @return array An array representation of this instance. */ - public function jsonSerialize() + public function jsonSerialize(): mixed { // $items = []; // $all = $this->getAll(); @@ -44,5 +42,4 @@ public function jsonSerialize() // return $items; return $this->getAll(); } - } diff --git a/src/Tag.php b/src/Tag.php index c37770e..56b368c 100644 --- a/src/Tag.php +++ b/src/Tag.php @@ -32,7 +32,6 @@ */ class Tag extends Node implements IteratorAggregate { - /** * @var AttributeList */ @@ -64,7 +63,6 @@ public function __construct($tagName = 'div', $content = [], array $attributes = $this->setContent($content); $this->setAttributes($attributes); } - /** * Get a string representation of the current tag instance. * @@ -87,7 +85,6 @@ public function __toString() return $html; } - /** * Get the defined attributes of the current tag instance. * @@ -97,7 +94,6 @@ public function getAttributes() { return $this->attributes; } - /** * Get the content of the current HTML element. * @@ -107,7 +103,6 @@ public function getContent() { return parent::getContent(); } - /** * Get an iterator instance to iterate the current Tag. * @@ -115,11 +110,10 @@ public function getContent() * * @return Iterator */ - public function getIterator() + public function getIterator(): \Traversable { return $this->getIteratorPreOrder(); } - /** * Get the tag name of the current element. * @@ -129,7 +123,6 @@ public function getTagName() { return $this->tagName; } - /** * Get a tree iterator which goes first every tree up before searching the * next. @@ -138,7 +131,6 @@ public function getTagName() // { // // } - /** * Get a tree iterator which searches first every sibling before going up to * the next level. @@ -149,7 +141,6 @@ public function getIteratorPreOrder() { return new PreOrderIterator($this); } - /** * Whetever the current tag is self closing or not. * @@ -159,11 +150,10 @@ public function isSelfClosing() { return SelfClosing::is($this->getTagName()); } - /** * {@inheritdoc} */ - public function jsonSerialize() + public function jsonSerialize(): mixed { return [ 'attributes' => $this->getAttributes(), @@ -171,7 +161,6 @@ public function jsonSerialize() 'tag' => $this->getTagName() ]; } - /** * Set the attributes of the current HTML element. * @@ -195,7 +184,6 @@ public function setAttributes($attributes) ); } } - /** * Set the inner content of the current tag. * @@ -208,17 +196,16 @@ public function setAttributes($attributes) * @param mixed $content The content of the current Tag * instance. This must be a NodeList * instance or an array. - * @throws BadMethodCallException - * @throws InvalidArgumentException + * @throws \BadMethodCallException */ public function setContent($content) { if (!empty($content) && $this->isSelfClosing()) { $msg = 'This tag (%s) can not have content, because it is self' - . ' closing.'; + . ' closing.'; $e = sprintf($msg, gettype($this->getTagName())); - throw new BadMethodCallException($e); + throw new \BadMethodCallException($e); } if (is_scalar($content) || $content instanceof Node) { @@ -227,7 +214,6 @@ public function setContent($content) $this->content = $content instanceof NodeList ? $content : new NodeList($content); } - /** * Set the name of the current tag. * @@ -239,8 +225,8 @@ public function setTagName($name) if (is_string($name)) { $this->tagName = $name; } else { - throw new InvalidDatatypeException('tag name', $name, ['string']); + throw new \InvalidArgumentException('Unsupported data type ' . gettype($name)); +// throw new InvalidDatatypeException('tag name', $name, ['string']); } } - } diff --git a/src/Text.php b/src/Text.php index 77eff95..aedc0f3 100644 --- a/src/Text.php +++ b/src/Text.php @@ -7,7 +7,6 @@ */ class Text extends Node { - /** * Create an instance of the text element. * @@ -17,7 +16,6 @@ public function __construct($text) { $this->setContent($text); } - /** * Get a string representation of the current class. * @@ -27,7 +25,6 @@ public function __toString() { return $this->getContent(); } - /** * Get the content. * @@ -37,15 +34,13 @@ public function getContent() { return parent::getContent(); } - /** * {@inheritdoc} */ - public function jsonSerialize() + public function jsonSerialize(): mixed { return $this->getContent(); } - /** * Set the content. * @@ -64,5 +59,4 @@ public function setContent($text) throw new \InvalidArgumentException($e); } } - } diff --git a/src/Utilities/CanRenderList.php b/src/Utilities/CanRenderList.php index bc8a89f..26ff130 100644 --- a/src/Utilities/CanRenderList.php +++ b/src/Utilities/CanRenderList.php @@ -10,14 +10,12 @@ */ trait CanRenderList { - - protected $divider; + protected $divider = ''; public function getDivider() { return $this->divider; } - public function setDivider($divider) { if (is_string($divider)) { @@ -26,10 +24,8 @@ public function setDivider($divider) throw new InvalidDatatypeException('divider', $divider, ['string']); } } - public function __toString() { return implode($this->getDivider(), $this->getAll()); } - } diff --git a/tests/configuration.xml b/tests/configuration.xml index bed721b..2e2b694 100644 --- a/tests/configuration.xml +++ b/tests/configuration.xml @@ -1,16 +1,11 @@ - + - src + ../src - api - tests/Integration - src/Widgets/Table - src/Renderable.php - src/Lists/AbstractRenderableList.php - src/Tags/AbstractSourceContainer.php - src/Widgets/Modelable.php - src/Widgets/Viewable.php - src/Widgets/Table/Models/Modelable.php - src/Widgets/Wrapper/Markups/Bootstrap.php + ../api + ../src/Iterators + ../src/Lists + ../src/Models + ../src/Tags + ../src/Utilities + ../src/Widgets + ../src/Widgets/Table + ../tests/Integration + ../src/Attribute.php + ../src/Callback.php + ../src/Node.php + ../src/Replacer.php + ../src/Tag.php + ../src/Renderable.php + ../src/Lists/AbstractRenderableList.php + ../src/Tags/AbstractSourceContainer.php + ../src/Widgets/Modelable.php + ../src/Widgets/Viewable.php + ../src/Widgets/Table/Models/Modelable.php + ../src/Widgets/Wrapper/Markups/Bootstrap.php @@ -47,6 +53,7 @@ + From cecc28565776bfd1bf457c8751b606cc73ae6a19 Mon Sep 17 00:00:00 2001 From: 1stthomas Date: Fri, 25 Oct 2024 21:32:05 +0200 Subject: [PATCH 18/21] #33 Make sure the base classes work with latestet PHP version and the tests are running --- src/Node.php | 25 ++- src/Tag.php | 111 ++++--------- tests/Unit/TagTest.php | 343 ++++++++++++++++++++++++----------------- 3 files changed, 242 insertions(+), 237 deletions(-) diff --git a/src/Node.php b/src/Node.php index 67b4e48..941e9c7 100644 --- a/src/Node.php +++ b/src/Node.php @@ -2,7 +2,8 @@ namespace Ht7\Html; -use \Ht7\Html\Renderable; +use Ht7\Html\Renderable; +use Ht7\Html\Lists\NodeList; /** * Base class. @@ -12,33 +13,25 @@ abstract class Node implements \JsonSerializable, Renderable { - /** - * The content of the current Node. - * - * @var mixed The content of the current Node, which can be a - * string, Text- or a Tag-instance. - */ - protected $content; + protected NodeList|string $content; /** - * Get the content of the current HTML element. - * - * @return NodeList The content of the current HTML element. + * Get the content of the present HTML element. */ - public function getContent() + public function getContent(): NodeList|string { return $this->content; } /** - * Set the inner content of the current tag. + * Set the inner content of the present HTML element. * - * This method will throw an exception if the current tag is self closing. + * This method will throw an exception if the present tag is self closing. * - * @param mixed $content The content of the current Node + * @param NodeList|array|string|float|int|bool $content The content of the current Node * instance. * @throws BadMethodCallException * @throws InvalidArgumentException */ - abstract public function setContent($content); + abstract public function setContent(NodeList|array|string|float|int|bool $content): static; } diff --git a/src/Tag.php b/src/Tag.php index 56b368c..ac51637 100644 --- a/src/Tag.php +++ b/src/Tag.php @@ -1,21 +1,11 @@ setTagName($tagName); - $this->setContent($content); - $this->setAttributes($attributes); + $this->setContent($content) + ->setAttributes($attributes); } /** * Get a string representation of the current tag instance. @@ -75,22 +47,15 @@ public function __toString() $attrStr = (string) $this->getAttributes(); $attrStrSanitized = empty($attrStr) ? '' : ' ' . $attrStr; - if ($this->isSelfClosing()) { - $html = '<' . $tagName . $attrStrSanitized . ' />'; - } else { - $html = '<' . $tagName . $attrStrSanitized . '>'; - $html .= $this->getContent(); - $html .= ''; - } - - return $html; + return "<{$tagName}{$attrStrSanitized}" + . ($this->isSelfClosing() ? ' />' : ">{$this->getContent()}"); } /** * Get the defined attributes of the current tag instance. * * @return AttributeList The attributes of the present tag. */ - public function getAttributes() + public function getAttributes(): AttributeList { return $this->attributes; } @@ -99,7 +64,7 @@ public function getAttributes() * * @return NodeList The content of the current HTML element. */ - public function getContent() + public function getContent(): NodeList { return parent::getContent(); } @@ -119,7 +84,7 @@ public function getIterator(): \Traversable * * @return string The tag name. */ - public function getTagName() + public function getTagName(): string { return $this->tagName; } @@ -134,19 +99,15 @@ public function getTagName() /** * Get a tree iterator which searches first every sibling before going up to * the next level. - * - * @return PreOrderIterator */ - public function getIteratorPreOrder() + public function getIteratorPreOrder(): PreOrderIterator { return new PreOrderIterator($this); } /** * Whetever the current tag is self closing or not. - * - * @return boolean True if the current element is self closing. */ - public function isSelfClosing() + public function isSelfClosing(): bool { return SelfClosing::is($this->getTagName()); } @@ -164,25 +125,16 @@ public function jsonSerialize(): mixed /** * Set the attributes of the current HTML element. * - * @param mixed $attributes Indexed array of + * @param AttributeList|array $attributes Indexed array of * \Ht7\Html\Attribute * instances or an instance of * AttributeList. */ - public function setAttributes($attributes) + public function setAttributes(AttributeList|array $attributes): static { - if ($attributes instanceof AttributeList) { - $this->attributes = $attributes; - } elseif (is_array($attributes)) { - $this->attributes = new AttributeList($attributes); - } else { - throw new InvalidDatatypeException( - 'attributes', - $attributes, - ['array'], - [NodeList::class] - ); - } + $this->attributes = $attributes instanceof AttributeList ? $attributes : new AttributeList($attributes); + + return $this; } /** * Set the inner content of the current tag. @@ -193,14 +145,15 @@ public function setAttributes($attributes) * will be created. In this case the input validation will be delegated to * the NodeList. * - * @param mixed $content The content of the current Tag + * @param NodeList|array|string|float|int|bool $content The content of the current Tag * instance. This must be a NodeList * instance or an array. * @throws \BadMethodCallException */ - public function setContent($content) + // public function setContent(mixed $content): static + public function setContent(NodeList|array|string|float|int|bool $content): static { - if (!empty($content) && $this->isSelfClosing()) { + if ($this->isSelfClosing() && !empty($content)) { $msg = 'This tag (%s) can not have content, because it is self' . ' closing.'; $e = sprintf($msg, gettype($this->getTagName())); @@ -213,20 +166,18 @@ public function setContent($content) } $this->content = $content instanceof NodeList ? $content : new NodeList($content); + + return $this; } /** * Set the name of the current tag. * * @param string $name The tag name of the current HTML element. - * @throws InvalidArgumentException */ - public function setTagName($name) + public function setTagName(string $name): static { - if (is_string($name)) { - $this->tagName = $name; - } else { - throw new \InvalidArgumentException('Unsupported data type ' . gettype($name)); -// throw new InvalidDatatypeException('tag name', $name, ['string']); - } + $this->tagName = $name; + + return $this; } } diff --git a/tests/Unit/TagTest.php b/tests/Unit/TagTest.php index d1c281a..4b5273a 100644 --- a/tests/Unit/TagTest.php +++ b/tests/Unit/TagTest.php @@ -2,48 +2,49 @@ namespace Ht7\Html\Tests\Unit; -use \BadMethodCallException; -use \InvalidArgumentException; -use \stdClass; -use \PHPUnit\Framework\TestCase; -use \Ht7\Html\Node; -use \Ht7\Html\Tag; -use \Ht7\Html\Iterators\PreOrderIterator; -use \Ht7\Html\Lists\AttributeList; -use \Ht7\Html\Lists\NodeList; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\MockObject\MockObject; +use Ht7\Html\Tag; +use Ht7\Html\Text; +use Ht7\Html\Iterators\PreOrderIterator; +use Ht7\Html\Lists\AttributeList; +use Ht7\Html\Lists\NodeList; class TagTest extends TestCase { + private string $className = Tag::class; - public function testConstructor() + #[Test] + #[TestDox('Tag initialisation.')] + public function tagConstructor(): void { // see: http://miljar.github.io/blog/2013/12/20/phpunit-testing-the-constructor/ - $className = Tag::class; $tagName = 'span'; $content = ['test text']; $attributes = ['class' => 'btn btn-primary']; - $mock = $this->getMockBuilder($className) - ->setMethods(['setTagName', 'setContent', 'setAttributes']) - ->disableOriginalConstructor() - ->getMock(); - - $mock->expects($this->once()) - ->method('setTagName') - ->with($this->equalTo($tagName)); - $mock->expects($this->once()) + $sut = $this->getMockTag(['setTagName', 'setContent', 'setAttributes']); + $sut->expects($this->never()) + ->method('setTagName'); + $sut->expects($this->once()) ->method('setContent') - ->with($this->equalTo($content)); - $mock->expects($this->once()) + ->with($this->equalTo($content)) + ->willReturnSelf(); + $sut->expects($this->once()) ->method('setAttributes') - ->with($this->equalTo($attributes)); + ->with($this->equalTo($attributes)) + ->willReturnSelf(); - $reflectedClass = new \ReflectionClass($className); + $reflectedClass = new \ReflectionClass($this->className); $constructor = $reflectedClass->getConstructor(); - $constructor->invoke($mock, $tagName, $content, $attributes); + $constructor->invoke($sut, $tagName, $content, $attributes); } - public function testGetAttributes() + #[Test] + #[TestDox('Get attributes.')] + public function getAttributes(): void { $tag1 = new Tag('div', ['bla']); @@ -54,7 +55,9 @@ public function testGetAttributes() $this->assertInstanceOf(AttributeList::class, $tag2->getAttributes()); } - public function testGetContent() + #[Test] + #[TestDox('Get content.')] + public function getContent(): void { $tag1 = new Tag('div'); @@ -65,7 +68,9 @@ public function testGetContent() $this->assertInstanceOf(NodeList::class, $tag2->getContent()); } - public function testGetIterator() + #[Test] + #[TestDox('Get the default iterator.')] + public function getIterator(): void { $tag1 = new Tag('div'); @@ -76,7 +81,9 @@ public function testGetIterator() $this->assertInstanceOf(PreOrderIterator::class, $tag2->getIterator()); } - public function testGetIteratorPreOrder() + #[Test] + #[TestDox('Get the perorder iterator.')] + public function getIteratorPreOrder(): void { $tag1 = new Tag('div'); @@ -87,7 +94,9 @@ public function testGetIteratorPreOrder() $this->assertInstanceOf(PreOrderIterator::class, $tag2->getIteratorPreOrder()); } - public function testJsonSerialize() + #[Test] + #[TestDox('Json serialize.')] + public function jsonSerialize(): void { $nlMock = $this->createMock(NodeList::class); @@ -101,17 +110,14 @@ public function testJsonSerialize() ->method('jsonSerialize') ->willReturn(['class' => 'btn btn-primary']); - $mock = $this->getMockBuilder(Tag::class) - ->setMethods(['getAttributes', 'getContent', 'getTagName']) - ->getMock(); - - $mock->expects($this->once()) + $sut = $this->getMockTag(['getAttributes', 'getContent', 'getTagName']); + $sut->expects($this->once()) ->method('getAttributes') ->willReturn($alMock); - $mock->expects($this->once()) + $sut->expects($this->once()) ->method('getContent') ->willReturn($nlMock); - $mock->expects($this->once()) + $sut->expects($this->once()) ->method('getTagName') ->willReturn('span'); @@ -121,164 +127,219 @@ public function testJsonSerialize() 'tag' => 'span', ]; - $this->assertEquals($expected, json_decode(json_encode($mock), JSON_OBJECT_AS_ARRAY)); - } - - public function testSetAttributes() - { - $mock = $this->getMockBuilder(Tag::class) - ->setMethods(['setTagName']) - ->disableOriginalConstructor() - ->getMock(); - - $mock->setAttributes(['class' => 'test']); - - $this->assertInstanceOf(AttributeList::class, $mock->getAttributes()); + $this->assertEquals($expected, json_decode(json_encode($sut), JSON_OBJECT_AS_ARRAY)); } - public function testSetAttributesAttributeList() + #[Test] + #[TestDox('Set attributes.')] + public function setAttributes(): void { - $mock = $this->getMockBuilder(Tag::class) - ->setMethods(['setTagName']) - ->disableOriginalConstructor() - ->getMock(); - - $mock->setAttributes((new AttributeList())); - - $this->assertInstanceOf(AttributeList::class, $mock->getAttributes()); + $attributes = ['class' => 'btn btn-primary']; + $sut = $this->getMockTag([]); + + /** @var Tag $sut */ + $sut->setAttributes($attributes); + + $return = $sut->getAttributes(); + $this->assertInstanceOf(AttributeList::class, $return); + $reflectedClassAttrList = new \ReflectionClass(AttributeList::class); + $itemsProperty = $reflectedClassAttrList->getProperty('items'); + $itemsProperty->setAccessible(true); + $items = $itemsProperty->getValue($return); + $this->assertCount(1, $items); } - public function testSetAttributesEmpty() + #[Test] + #[TestDox('Set attributes with an attribute list.')] + public function setAttributesAttributeList(): void { - $mock = $this->getMockBuilder(Tag::class) - ->setMethods(['setTagName']) - ->disableOriginalConstructor() - ->getMock(); + $attrList = new AttributeList(); + $sut = $this->getMockTag([]); - $mock->setAttributes([]); + /** @var Tag $sut */ + $sut->setAttributes($attrList); - $this->assertInstanceOf(AttributeList::class, $mock->getAttributes()); + $this->assertSame($attrList, $sut->getAttributes()); } - public function testSetAttributesWithException() + #[Test] + #[TestDox('Set attributes with an empty array.')] + public function setAttributesEmpty(): void { - $mock = $this->getMockBuilder(Tag::class) - ->setMethods(['setTagName']) - ->disableOriginalConstructor() - ->getMock(); + $sut = $this->getMockTag([]); - $this->expectException(\InvalidArgumentException::class); + /** @var Tag $sut */ + $sut->setAttributes([]); - $mock->setAttributes((new NodeList())); + $attrList = $sut->getAttributes(); + $this->assertInstanceOf(AttributeList::class, $attrList); + $this->assertEmpty($attrList); } - public function testSetContent() + #[Test] + #[TestDox('Set content.')] + public function setContent(): void { - $mock = $this->getMockBuilder(Tag::class) - ->setMethods(['setTagName']) - ->disableOriginalConstructor() - ->getMock(); - - $mock->setContent(['test text']); - - $this->assertInstanceOf(NodeList::class, $mock->getContent()); - } - - public function testSetContentEmpty() - { - $mock = $this->getMockBuilder(Tag::class) - ->setMethods(['setTagName']) - ->disableOriginalConstructor() - ->getMock(); - - $mock->setContent([]); - - $this->assertInstanceOf(NodeList::class, $mock->getContent()); + $content = ['test text']; + $sut = $this->getMockTag([]); + + $reflectedClass = new \ReflectionClass($this->className); + $tagName = $reflectedClass->getProperty('tagName'); + $tagName->setAccessible(true); + $tagName->setValue($sut, 'div'); + + /** @var Tag $sut */ + $sut->setContent($content); + + $return = $sut->getContent(); + $this->assertInstanceOf(NodeList::class, $return); + $reflectedClassNodeList = new \ReflectionClass(NodeList::class); + $itemsProperty = $reflectedClassNodeList->getProperty('items'); + $itemsProperty->setAccessible(true); + $items = $itemsProperty->getValue($return); + $this->assertCount(1, $items); + $this->assertInstanceOf(Text::class, $items[0]); + $reflectedClassText = new \ReflectionClass(Text::class); + $contentProperty = $reflectedClassText->getProperty('content'); + $contentProperty->setAccessible(true); + $contentFromProperty = $contentProperty->getValue($items[0]); + $this->assertSame($content[0], $contentFromProperty); } - public function testSetTagName() + #[Test] + #[TestDox('Set content with an empty array.')] + public function setContentEmpty(): void { - $mock = $this->getMockBuilder(Tag::class) - ->setMethods(['isSelfClosing']) - ->disableOriginalConstructor() - ->getMock(); - - $mock->setTagName('test'); - - $this->assertEquals('test', $mock->getTagName()); + $sut = $this->getMockTag([]); + + $reflectedClass = new \ReflectionClass($this->className); + $tagName = $reflectedClass->getProperty('tagName'); + $tagName->setAccessible(true); + $tagName->setValue($sut, 'div'); + + /** @var Tag $sut */ + $sut->setContent([]); + + $content = $sut->getContent(); + $this->assertInstanceOf(NodeList::class, $content); + $reflectedClass = new \ReflectionClass(NodeList::class); + $items = $reflectedClass->getProperty('items'); + $items->setAccessible(true); + $this->assertEmpty($items->getValue($content)); } - public function testSetTagNameWithException() + #[Test] + #[TestDox('Set tag name.')] + public function setTagName(): void { - $mock = $this->getMockBuilder(Tag::class) - ->setMethods(['isSelfClosing']) - ->disableOriginalConstructor() - ->getMock(); + $tagName = 'test'; + $sut = $this->getMockTag([]); - $this->expectException(\InvalidArgumentException::class); + /** @var Tag $sut */ + $return = $sut->setTagName($tagName); - $mock->setTagName(123); + $this->assertEquals($tagName, $sut->getTagName()); + $this->assertSame($sut, $return); } - public function testSetContentSelfClosing() + #[Test] + #[TestDox('Set content self closing with an exception.')] + public function setContentSelfClosing(): void { - $mock = $this->getMockBuilder(Tag::class) - ->setMethods(['isSelfClosing']) - ->disableOriginalConstructor() - ->getMock(); - - $mock->expects($this->once()) + $sut = $this->getMockTag(['isSelfClosing']); + $sut->expects($this->once()) ->method('isSelfClosing') ->willReturn(true); + $reflectedClass = new \ReflectionClass($this->className); + $tagName = $reflectedClass->getProperty('tagName'); + $tagName->setAccessible(true); + $tagName->setValue($sut, 'br'); + $this->expectException(\BadMethodCallException::class); - $mock->setContent(['test text']); + /** @var Tag $sut */ + $sut->setContent(['test text']); } - public function testToString() + #[Test] + #[TestDox('Type conversion to string.')] + public function render(): void { - $mock = $this->getMockBuilder(Tag::class) - ->setMethods(['getAttributes', 'getContent', 'getTagName', 'isSelfClosing']) + $tagName = 'div'; + $attr = 'class="btn btn-primary"'; + $content = 'test text.'; + $attrList = $this->getMockAttributeList($attr); + $nodeList = $this->getMockBuilder(NodeList::class) + ->onlyMethods(['__toString']) ->getMock(); + $nodeList->expects($this->once()) + ->method('__toString') + ->willReturn($content); - $mock->expects($this->once()) + $sut = $this->getMockTag(['getAttributes', 'getContent', 'getTagName', 'isSelfClosing']); + $sut->expects($this->once()) ->method('getTagName') - ->willReturn('div'); - $mock->expects($this->once()) + ->willReturn($tagName); + $sut->expects($this->once()) ->method('getAttributes') - ->willReturn('class="btn btn-primary"'); - $mock->expects($this->once()) + ->willReturn($attrList); + $sut->expects($this->once()) ->method('isSelfClosing') ->willReturn(false); - $mock->expects($this->once()) + $sut->expects($this->once()) ->method('getContent') - ->willReturn('test text.'); + ->willReturn($nodeList); - $expected = '
test text.
'; + $expected = "<{$tagName} {$attr}>{$content}"; - $this->assertEquals($expected, ((string) $mock)); + $this->assertEquals($expected, ((string) $sut)); } - public function testToStringSelfClosing() + #[Test] + #[TestDox('Type conversion to string as self closing.')] + public function toStringSelfClosing(): void { - $mock = $this->getMockBuilder(Tag::class) - ->setMethods(['getAttributes', 'getTagName', 'isSelfClosing']) - ->getMock(); + $tagName = 'br'; + $attr = 'style="display: none;"'; + $attrList = $this->getMockAttributeList($attr); - $mock->expects($this->once()) + $sut = $this->getMockTag(['getAttributes', 'getContent', 'getTagName', 'isSelfClosing']); + $sut->expects($this->once()) ->method('getTagName') - ->willReturn('br'); - $mock->expects($this->once()) + ->willReturn($tagName); + $sut->expects($this->once()) ->method('getAttributes') - ->willReturn('style="display: none;"'); - $mock->expects($this->once()) + ->willReturn($attrList); + $sut->expects($this->once()) ->method('isSelfClosing') ->willReturn(true); + $sut->expects($this->never()) + ->method('getContent'); - $expected2 = '
'; + $expected = "<{$tagName} {$attr} />"; - $this->assertEquals($expected2, ((string) $mock)); + $this->assertEquals($expected, ((string) $sut)); + } + + final private function getMockAttributeList(string $attr = ''): MockObject + { + $attrList = $this->getMockBuilder(AttributeList::class) + ->onlyMethods(['__toString']) + ->getMock(); + $attrList->expects($this->once()) + ->method('__toString') + ->willReturn($attr); + + return $attrList; + } + + final private function getMockTag(array $methods = []): MockObject + { + return $this->getMockBuilder(Tag::class) + ->onlyMethods($methods) + ->disableOriginalConstructor() + ->getMock(); } } From c7bb5812538b3b6379f903d01f8c1d27a20aad42 Mon Sep 17 00:00:00 2001 From: 1stthomas Date: Fri, 25 Oct 2024 21:32:28 +0200 Subject: [PATCH 19/21] #33 Use latest PHPUnit version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 6d92230..63c85aa 100644 --- a/composer.json +++ b/composer.json @@ -43,7 +43,7 @@ "ht7/ht7-base": "dev-develop" }, "require-dev": { - "phpunit/phpunit": "^8.0|^9.0" + "phpunit/phpunit": "^10.5" }, "minimum-stability": "dev", "prefer-stable": true, From 0fe897cfb23d4b45927c4b82c55c9aa3847a46df Mon Sep 17 00:00:00 2001 From: 1stthomas Date: Fri, 25 Oct 2024 21:53:26 +0200 Subject: [PATCH 20/21] #33 Text class and its tests migrated --- src/Text.php | 12 +++-- tests/Unit/TextTest.php | 100 ++++++++++++++++++++++------------------ 2 files changed, 62 insertions(+), 50 deletions(-) diff --git a/src/Text.php b/src/Text.php index aedc0f3..2cdba37 100644 --- a/src/Text.php +++ b/src/Text.php @@ -2,6 +2,8 @@ namespace Ht7\Html; +use Ht7\Html\Lists\NodeList; + /** * This is a simple text node. */ @@ -12,7 +14,7 @@ class Text extends Node * * @param string $text The content. */ - public function __construct($text) + public function __construct(string $text) { $this->setContent($text); } @@ -30,7 +32,7 @@ public function __toString() * * @return string The content of the current text element. */ - public function getContent() + public function getContent(): NodeList|string { return parent::getContent(); } @@ -46,10 +48,10 @@ public function jsonSerialize(): mixed * * Only scalar types will be accepted. * - * @param mixed $text The content as string, integer or float. + * @param NodeList|array|string|float|int|bool $text The content as string, integer, float or bool. * @throws \InvalidArgumentException */ - public function setContent($text) + public function setContent(NodeList|array|string|float|int|bool $text): static { if (is_scalar($text)) { $this->content = (string) $text; @@ -58,5 +60,7 @@ public function setContent($text) throw new \InvalidArgumentException($e); } + + return $this; } } diff --git a/tests/Unit/TextTest.php b/tests/Unit/TextTest.php index 839749c..7b595d1 100644 --- a/tests/Unit/TextTest.php +++ b/tests/Unit/TextTest.php @@ -2,19 +2,23 @@ namespace Ht7\Html\Tests\Unit; -use \PHPUnit\Framework\TestCase; -use \Ht7\Html\Text; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\MockObject\MockObject; +use Ht7\Html\Text; class TextTest extends TestCase { - - public function testConstructor() + #[Test] + #[TestDox('Tag initialisation.')] + public function textConstructor(): void { $className = Text::class; - $content = ['test text']; + $content = 'test text'; $mock = $this->getMockBuilder($className) - ->setMethods(['setContent']) + ->onlyMethods(['setContent']) ->disableOriginalConstructor() ->getMock(); @@ -27,99 +31,103 @@ public function testConstructor() $constructor->invoke($mock, $content); } - public function testGetContent() + #[Test] + #[TestDox('Get content.')] + public function getContent(): void { $className = Text::class; $content = 'test text'; - $mock = $this->getMockBuilder($className) - ->setMethods(['jsonSerialize']) - ->disableOriginalConstructor() - ->getMock(); + /** @var Text $sut */ + $sut = $this->getMockText([]); $reflectedClass = new \ReflectionClass($className); $property = $reflectedClass->getProperty('content'); $property->setAccessible(true); - $property->setValue($mock, $content); + $property->setValue($sut, $content); - $this->assertEquals($content, $mock->getContent()); + $this->assertEquals($content, $sut->getContent()); } - public function testJsonSerialize() + #[Test] + #[TestDox('Json serialize.')] + public function jsonSerialize(): void { $className = Text::class; $content = 'test text'; - $mock = $this->getMockBuilder($className) - ->setMethods(['setContent']) - ->disableOriginalConstructor() - ->getMock(); + $sut = $this->getMockText([]); $reflectedClass = new \ReflectionClass($className); $property = $reflectedClass->getProperty('content'); $property->setAccessible(true); - $property->setValue($mock, $content); + $property->setValue($sut, $content); $expected = '"' . $content . '"'; - $actual = json_encode($mock); + $actual = json_encode($sut); $this->assertEquals($expected, $actual); } - public function testSetContent() + #[Test] + #[TestDox('Set content.')] + public function setContent(): void { $className = Text::class; $content = 'test text'; - $mock = $this->getMockBuilder($className) - ->setMethods(['jsonSerialize']) - ->disableOriginalConstructor() - ->getMock(); + /** @var Text $sut */ + $sut = $this->getMockText([]); $reflectedClass = new \ReflectionClass($className); $property = $reflectedClass->getProperty('content'); $property->setAccessible(true); - $mock->setContent($content); - $this->assertEquals($content, $property->getValue($mock)); + $sut->setContent($content); + $this->assertEquals($content, $property->getValue($sut)); $content2 = 123; - $mock->setContent($content2); - $this->assertEquals($content2, $property->getValue($mock)); + $sut->setContent($content2); + $this->assertEquals($content2, $property->getValue($sut)); $content3 = 123.001; - $mock->setContent($content3); - $this->assertEquals($content3, $property->getValue($mock)); + $sut->setContent($content3); + $this->assertEquals($content3, $property->getValue($sut)); } - public function testSetContentWithException() + #[Test] + #[TestDox('Set content with an array and trigger exception.')] + public function setContentWithException(): void { - $mock = $this->getMockBuilder(Text::class) - ->setMethods(['jsonSerialize']) - ->disableOriginalConstructor() - ->getMock(); - + /** @var Text $sut */ + $sut = $this->getMockText([]); $this->expectException(\InvalidArgumentException::class); - $mock->setContent([]); + $sut->setContent([]); } - public function testToString() + #[Test] + #[TestDox('Trigger __toString method.')] + public function render(): void { $expected = 'test text.'; - $text = $this->getMockBuilder(Text::class) - ->setMethods(['getContent']) - ->disableOriginalConstructor() - ->getMock(); - - $text->expects($this->once()) + $sut = $this->getMockText(['getContent']); + $sut->expects($this->once()) ->method('getContent') ->willReturn($expected); - $this->assertEquals($expected, ((string) $text)); + $this->assertEquals($expected, (string) $sut); + } + + private function getMockText(array $methods): MockObject + { + return $this->getMockBuilder(Text::class) + ->onlyMethods($methods) + ->disableOriginalConstructor() + ->getMock(); } } From d685d154eff9fa0a394b102267701dd4846d7b92 Mon Sep 17 00:00:00 2001 From: 1stthomas Date: Fri, 25 Oct 2024 22:34:18 +0200 Subject: [PATCH 21/21] #33 Attribute with its tests fixed --- src/Attribute.php | 76 +++------------ tests/Unit/AttributeTest.php | 174 +++++++++++++---------------------- 2 files changed, 77 insertions(+), 173 deletions(-) diff --git a/src/Attribute.php b/src/Attribute.php index fbbd3ed..c54faff 100644 --- a/src/Attribute.php +++ b/src/Attribute.php @@ -1,44 +1,17 @@ setName($name); - $this->setValue($value); } /** * Get a string representation of the current class. @@ -61,19 +34,15 @@ public function getHash() } /** * Get the name of the present attribute. - * - * @return string The attribute name. */ - public function getName() + public function getName(): string { return $this->name; } /** * Get the value of the present attribute. - * - * @return mixed The attribute value. */ - public function getValue() + public function getValue(): string|float|int|bool { return $this->value; } @@ -86,43 +55,28 @@ public function jsonSerialize(): mixed } /** * Set the name of the current attribute instance.
- * The name must be a string and must not be empty. - * - * @param string $name The attribute name. - * @throws InvalidArgumentException + * The name must not be empty. */ - public function setName($name) + public function setName(string $name): static { if (empty($name)) { - $msg = 'The attribute name must not be empty.'; - $e = sprintf($msg, gettype($name)); - - throw new InvalidArgumentException($e); - } elseif (is_string($name)) { - $this->name = $name; - } else { - $msg = 'The attribute name must be a string, found %s.'; - $e = sprintf($msg, gettype($name)); + $e = 'The attribute name must not be empty.'; - throw new InvalidArgumentException($e); + throw new \InvalidArgumentException($e); } + + $this->name = $name; + + return $this; } /** * Set the value of the current attribute instance.
- * The value must be either string, int or float. - * - * @param mixed $value The attribute value. - * @throws InvalidArgumentException + * The value must be either string, float, int or bool. */ - public function setValue($value) + public function setValue(string|float|int|bool $value): static { - if (is_string($value) || is_int($value) || is_float($value)) { - $this->value = $value; - } else { - $msg = 'The attribute value must be a string, int or float, found %s.'; - $e = sprintf($msg, gettype($value)); + $this->value = $value; - throw new InvalidArgumentException($e); - } + return $this; } } diff --git a/tests/Unit/AttributeTest.php b/tests/Unit/AttributeTest.php index d815897..a4bfff2 100644 --- a/tests/Unit/AttributeTest.php +++ b/tests/Unit/AttributeTest.php @@ -4,168 +4,118 @@ use \InvalidArgumentException; use \stdClass; -use \PHPUnit\Framework\TestCase; -use \Ht7\Html\Attribute; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\MockObject\MockObject; +use Ht7\Html\Attribute; class AttributeTest extends TestCase { + private string $className = Attribute::class; - public function testConstructor() + #[Test] + #[TestDox('Get name.')] + public function getName(): void { - // see: http://miljar.github.io/blog/2013/12/20/phpunit-testing-the-constructor/ - $className = Attribute::class; - $name = 'class'; - $value = 'btn btn-primary'; - - $mock = $this->getMockBuilder($className) - ->setMethods(['setName', 'setValue']) - ->disableOriginalConstructor() - ->getMock(); - - $mock->expects($this->once()) - ->method('setName') - ->with($this->equalTo($name)); - $mock->expects($this->once()) - ->method('setValue') - ->with($this->equalTo($value)); - - $reflectedClass = new \ReflectionClass($className); - $constructor = $reflectedClass->getConstructor(); - $constructor->invoke($mock, $name, $value); - } - - public function testGetName() - { - $className = Attribute::class; - - $mock = $this->getMockBuilder($className) - ->setMethods(['setName']) - ->disableOriginalConstructor() - ->getMock(); + $expected = 'class'; + /** @var Attribute $sut */ + $sut = $this->getSut(['setName']); - $reflectedClass = new \ReflectionClass($className); + $reflectedClass = new \ReflectionClass($this->className); $property = $reflectedClass->getProperty('name'); $property->setAccessible(true); + $property->setValue($sut, $expected); - $expected = 'class'; - - $property->setValue($mock, $expected); - - $this->assertEquals($expected, $mock->getName()); + $this->assertEquals($expected, $sut->getName()); } - public function testGetValue() + #[Test] + #[TestDox('Get value.')] + public function getValue(): void { - $className = Attribute::class; - - $mock = $this->getMockBuilder($className) - ->setMethods(['setValue']) - ->disableOriginalConstructor() - ->getMock(); + $expected = 'btn btn-primary'; + /** @var Attribute $sut */ + $sut = $this->getSut(['setName']); - $reflectedClass = new \ReflectionClass($className); + $reflectedClass = new \ReflectionClass($this->className); $property = $reflectedClass->getProperty('value'); $property->setAccessible(true); + $property->setValue($sut, $expected); - $expected = 'btn btn-primary'; - - $property->setValue($mock, $expected); - - $this->assertEquals($expected, $mock->getValue()); + $this->assertEquals($expected, $sut->getValue()); } - public function testJsonEncode() + #[Test] + #[TestDox('Json encode.')] + public function jsonEncode(): void { - $mock = $this->getMockBuilder(Attribute::class) - ->setMethods(['getValue']) - ->disableOriginalConstructor() - ->getMock(); + $expected = '"btn btn-primary"'; + $sut = $this->getSut(['getValue']); - $mock->expects($this->once()) + $sut->expects($this->once()) ->method('getValue') ->willReturn('btn btn-primary'); - $expected = '"btn btn-primary"'; - - $this->assertEquals($expected, json_encode($mock)); - } - - public function testSetNameWithException() - { - $mock = $this->getMockBuilder(Attribute::class) - ->setMethods(['setValue']) // Without this, an exception would not been thrown. - ->disableOriginalConstructor() - ->getMock(); - - $this->expectException(InvalidArgumentException::class); - - $mock->setName((new stdClass())); + $this->assertEquals($expected, json_encode($sut)); } - public function testSetNameEmptyWithException() + #[Test] + #[TestDox('Set name with exception.')] + public function setNameWithException(): void { - $mock = $this->getMockBuilder(Attribute::class) - ->setMethods(['setValue']) // Without this, an exception would not been thrown. - ->disableOriginalConstructor() - ->getMock(); + /** @var Attribute $sut */ + $sut = $this->getSut(['setValue']); - $this->expectException(InvalidArgumentException::class); + $this->expectException(\InvalidArgumentException::class); - $mock->setName(''); + $sut->setName(''); } - public function testSetValueWithException() + #[Test] + #[TestDox('Render the attribute.')] + public function render(): void { - $mock = $this->getMockBuilder(Attribute::class) - ->setMethods(['setName']) // Without this, an exception would not been thrown. - ->disableOriginalConstructor() - ->getMock(); - - $this->expectException(InvalidArgumentException::class); - - $mock->setValue((new stdClass())); - } - - public function testToString() - { - $mock = $this->getMockBuilder(Attribute::class) - ->setMethods(['getName', 'getValue']) - ->disableOriginalConstructor() - ->getMock(); + $expected = 'class="btn btn-primary"'; + $sut = $this->getSut(['getName', 'getValue']); - $mock->expects($this->once()) + $sut->expects($this->once()) ->method('getName') ->willReturn('class'); - $mock->expects($this->once()) + $sut->expects($this->once()) ->method('getValue') ->willReturn('btn btn-primary'); - - $actual = (string) $mock; - $expected = 'class="btn btn-primary"'; + $actual = (string) $sut; $this->assertEquals($expected, $actual); } - public function testToStringNoValue() + #[Test] + #[TestDox('Render the attribute with no value.')] + public function renderNoValue(): void { - $mock = $this->getMockBuilder(Attribute::class) - ->setMethods(['getName', 'getValue']) - ->disableOriginalConstructor() - ->getMock(); + $expected = 'required'; + $sut = $this->getSut(['getName', 'getValue']); - $mock->expects($this->once()) + $sut->expects($this->once()) ->method('getName') ->willReturn('required'); - $mock->expects($this->once()) + $sut->expects($this->once()) ->method('getValue') ->willReturn(''); - - $actual = (string) $mock; - $expected = 'required'; + $actual = (string) $sut; $this->assertEquals($expected, $actual); } + private function getSut(array $methods): MockObject + { + return $this->getMockBuilder($this->className) + ->onlyMethods($methods) + ->disableOriginalConstructor() + ->getMock(); + } + }