Skip to content

Add PHPUnit contract tests for Object and ObjectHandler#1700

Open
fiammybe wants to merge 12 commits into
ImpressCMS:mainfrom
fiammybe:phpunit-base-test-ipf
Open

Add PHPUnit contract tests for Object and ObjectHandler#1700
fiammybe wants to merge 12 commits into
ImpressCMS:mainfrom
fiammybe:phpunit-base-test-ipf

Conversation

@fiammybe

Copy link
Copy Markdown
Member

Starting out with unit tests for the base IPF classes, on which everything is built. I'm looking for improvements and suggestions to this starting point. Once there is a solid base for these classes, I want to expand it to cover as much of IPF as possible. This will help us tremendously in PHP version updates and internal refactorings.

@fiammybe
fiammybe requested review from MekDrop and skenow May 18, 2026 09:23
@fiammybe fiammybe self-assigned this May 18, 2026
@qodo-code-review

Copy link
Copy Markdown

Review Summary by Qodo

Add PHPUnit contract tests for core Object and ObjectHandler classes

🧪 Tests

Grey Divider

Walkthroughs

Description
• Add comprehensive PHPUnit test suite for core ImpressCMS base classes
• Create isolated test bootstrap with minimal CMS dependencies and mock database
• Implement contract tests for icms_core_Object with data providers
• Add tests for icms_core_ObjectHandler and icms_ipf_Object classes
• Configure PHPUnit with separate test suites for core and IPF modules
Diagram
flowchart LR
  A["Test Bootstrap<br/>tests/bootstrap.php"] -->|defines constants| B["PHPUnit Tests"]
  C["Core Object Tests<br/>ObjectTest.php"] -->|tests| D["icms_core_Object"]
  E["ObjectHandler Tests<br/>ObjectHandlerTest.php"] -->|tests| F["icms_core_ObjectHandler"]
  G["IPF Object Tests<br/>IpfObjectTest.php"] -->|tests| H["icms_ipf_Object"]
  B -->|runs| C
  B -->|runs| E
  B -->|runs| G
  I["PHPUnit Config<br/>phpunit.xml.dist"] -->|configures| B
  J["Composer Config<br/>composer.json"] -->|defines scripts| B
Loading

Grey Divider

File Changes

1. tests/bootstrap.php 🧪 Tests +156/-0

Minimal PHPUnit bootstrap for ImpressCMS base classes

• Defines core ImpressCMS constants required by base classes
• Registers legacy autoloader for icms_* classes
• Provides mock database layer (icms_db_legacy_Database)
• Implements mock global functions and configuration
• Sets stable timezone and locale for test reproducibility

tests/bootstrap.php


2. tests/icms/core/ObjectTest.php 🧪 Tests +257/-0

Comprehensive tests for icms_core_Object class

• Tests lifecycle of new, dirty, and config flags
• Validates setVars() and setFormVars() with prefix handling
• Tests variable formatting for different data types (textbox, textarea, options)
• Includes data providers for scalar casting, URL normalization, email validation
• Tests array and timestamp normalization in cleanVars()
• Validates textbox field requirements and max length constraints

tests/icms/core/ObjectTest.php


3. tests/icms/core/ObjectHandlerTest.php 🧪 Tests +85/-0

Contract tests for icms_core_ObjectHandler class

• Tests database reference storage in constructor
• Validates create() and get() return objects by reference
• Tests insert() and delete() receive objects by reference
• Uses test double to verify handler behavior without full implementation

tests/icms/core/ObjectHandlerTest.php


View more (5)
4. tests/icms/ipf/ObjectTest.php 🧪 Tests +105/-0

Baseline tests for icms_ipf_Object class

• Tests IPF object construction with handler parameter
• Validates initVar() adds IPF-specific metadata fields
• Tests control setting and retrieval for form fields
• Validates id() and title() methods use handler key and identifier fields
• Tests toArray() output and skips controller links when no identifier

tests/icms/ipf/ObjectTest.php


5. phpunit.xml.dist ⚙️ Configuration changes +19/-0

PHPUnit configuration with test suites

• Configures PHPUnit with bootstrap file reference
• Defines two test suites: icms-core and icms-ipf
• Sets output colors and cache directory
• Uses PHPUnit 11.5 schema

phpunit.xml.dist


6. composer.json Dependencies +23/-0

Composer configuration with PHPUnit dependency

• Adds PHPUnit 11.5 as dev dependency
• Defines npm-style test scripts for running all tests or specific suites
• Includes project metadata and author information

composer.json


7. tests/icms/core/README.md 📝 Documentation +16/-0

Documentation for core class tests

• Documents scope of core class tests as characterization tests
• Explains no full CMS bootstrap or database dependency required
• Provides command to run core test suite

tests/icms/core/README.md


8. tests/icms/ipf/README.md 📝 Documentation +10/-0

Documentation for IPF class tests

• Documents IPF test suite purpose and location
• Provides command to run IPF test suite

tests/icms/ipf/README.md


Grey Divider

Qodo Logo

@qodo-code-review

qodo-code-review Bot commented May 18, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (2) 📎 Requirement gaps (0)

Grey Divider


Action required

1. tests/bootstrap.php uses tabs ✓ Resolved 📘 Rule violation ✧ Quality
Description
New PHP code uses hard tab indentation (e.g., in define(...) blocks), which violates PSR-12 and
will fail PSR-12 linters/formatters. This increases formatting drift and CI lint failures on changed
files.
Code

tests/bootstrap.php[R12-23]

Evidence
PSR-12 requires spaces (no hard tabs) for indentation. The added lines in tests/bootstrap.php (and
other new tests) visibly use tab-indented statements like define(...) and other blocks.

Rule 259066: Enforce PSR-12 coding style for all new and modified PHP code
tests/bootstrap.php[12-23]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
New/modified PHP files include hard tabs for indentation, which violates PSR-12.

## Issue Context
PSR-12 requires 4 spaces and forbids hard tabs for indentation; this can cause `phpcs --standard=PSR12` (or equivalent) to fail.

## Fix Focus Areas
- tests/bootstrap.php[12-23]
- tests/icms/core/ObjectHandlerTest.php[9-14]
- tests/icms/core/ObjectTest.php[10-15]
- tests/icms/ipf/ObjectTest.php[9-18]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. #[DataProvider] attribute used 📘 Rule violation ≡ Correctness
Description
tests/icms/core/ObjectTest.php uses the #[DataProvider(...)] attribute syntax which requires PHP
8.0+, so the test code is not compatible with PHP 7.4. This breaks the stated requirement to keep
PHP code runnable on PHP 7.4–8.4.
Code

tests/icms/core/ObjectTest.php[R92-106]

Evidence
The compliance rule requires code to parse and run on PHP 7.4. The added #[DataProvider('...')]
lines are PHP 8.0+ syntax and will cause parse errors on PHP 7.4.

Rule 259067: Ensure PHP syntax is compatible with PHP 7.4–8.4
tests/icms/core/ObjectTest.php[92-116]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The test file uses PHP 8 attributes (`#[DataProvider(...)]`), which is not valid syntax on PHP 7.4.

## Issue Context
The project compliance requires PHP syntax compatibility with PHP 7.4 through 8.4.

## Fix Focus Areas
- tests/icms/core/ObjectTest.php[92-116]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. phpunit/phpunit requires PHP 8.2+ 📘 Rule violation ≡ Correctness
Description
composer.json adds phpunit/phpunit ^11.5, which requires a higher minimum PHP version than
7.4. This prevents running the test suite under PHP 7.4 as required.
Code

composer.json[R20-22]

Evidence
The rule requires that code and supporting configuration (including dependencies) work on PHP 7.4.
The PR introduces a require-dev constraint for phpunit/phpunit ^11.5, which cannot be used on
PHP 7.4 due to PHPUnit's PHP version requirements.

Rule 259067: Ensure PHP syntax is compatible with PHP 7.4–8.4
composer.json[20-22]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`composer.json` requires PHPUnit 11.x, which is not compatible with PHP 7.4.

## Issue Context
Compliance requires support for PHP 7.4–8.4. PHPUnit 11 requires PHP >= 8.2, so it cannot be installed/executed on PHP 7.4.

## Fix Focus Areas
- composer.json[20-22]
- phpunit.xml.dist[1-8]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

4. Bootstrap shadows DB class ✓ Resolved 🐞 Bug ⚙ Maintainability
Description
tests/bootstrap.php declares a concrete class named icms_db_legacy_Database, but ImpressCMS already
defines icms_db_legacy_Database as an abstract class; loading the real DB base later will fatally
conflict and also makes future DB-related tests harder to add.
Code

tests/bootstrap.php[R87-108]

Evidence
The PR bootstrap introduces a concrete icms_db_legacy_Database, but the codebase already defines
icms_db_legacy_Database as an abstract class; defining both in one runtime will produce a fatal
class redeclaration.

tests/bootstrap.php[84-108]
htdocs/libraries/icms/db/legacy/Database.php[46-60]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The PHPUnit bootstrap defines `class icms_db_legacy_Database`, which collides with the real ImpressCMS `abstract class icms_db_legacy_Database`. If any code under test ends up loading the real database base class, PHP will fatally error.

### Issue Context
ImpressCMS already ships an abstract `icms_db_legacy_Database` in `htdocs/libraries/icms/db/legacy/Database.php`. The test suite should avoid taking ownership of the same symbol.

### Fix Focus Areas
- Prefer renaming the mock to a test-specific name (e.g. `IcmsTestDatabase`) and update tests + `$GLOBALS['xoopsDB']` assignments accordingly
- Alternatively, only declare the mock when the real symbol is absent, and ensure tests don’t depend on instantiating an abstract base

- tests/bootstrap.php[84-108]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Bootstrap function redeclare risk ✓ Resolved 🐞 Bug ☼ Reliability
Description
tests/bootstrap.php defines icms_loadLanguageFile() and icms_getConfig() unconditionally, so any
future inclusion of htdocs/include/functions.php (which defines the same functions) will cause a
fatal "Cannot redeclare" error and stop the test suite.
Code

tests/bootstrap.php[R112-121]

Evidence
The bootstrap defines these functions in the global namespace with no guard, while the core already
provides the same symbols in htdocs/include/functions.php; loading both in one PHP process will
fatal.

tests/bootstrap.php[110-121]
htdocs/include/functions.php[571-650]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`tests/bootstrap.php` declares `icms_loadLanguageFile()` and `icms_getConfig()` without `function_exists()` guards. If later tests (or autoloaded code) include `htdocs/include/functions.php`, PHP will fatally error due to function redeclaration.

### Issue Context
The real ImpressCMS implementations already exist in `htdocs/include/functions.php`, so the bootstrap should defensively avoid redefining them.

### Fix Focus Areas
- Wrap the mock function definitions with `if (!function_exists(...)) { ... }`
- Ensure the mock signatures are compatible with the real ones to avoid surprising callsites

- tests/bootstrap.php[112-121]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Invalid Composer license id ✓ Resolved 🐞 Bug ⚙ Maintainability
Description
composer.json sets "license": "gpl-2.0", which is not an SPDX license identifier format and can
break Composer validation/publishing workflows that expect SPDX values.
Code

composer.json[R4-6]

Evidence
The new Composer package metadata explicitly declares license as gpl-2.0; this is the value
tooling will consume.

composer.json[1-6]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`composer.json` uses a non-standard license string (`gpl-2.0`). Composer ecosystems commonly expect SPDX identifiers.

### Issue Context
This repo’s source headers indicate GPL v2; Composer metadata should reflect that using an SPDX-compatible value.

### Fix Focus Areas
- Update `license` to an SPDX identifier like `GPL-2.0-only` or `GPL-2.0-or-later` (pick the correct one for the project)

- composer.json[1-6]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread tests/bootstrap.php
Comment on lines +92 to +106
#[DataProvider('scalarCastingProvider')]
public function testCleanVarsCastsScalarTypes(int $dataType, $input, int $expected): void
{
$object = new icms_core_Object();
$object->initVar('value', $dataType, 0);
$object->setVar('value', $input);

$this->assertTrue($object->cleanVars());
$this->assertSame($expected, $object->cleanVars['value']);
$this->assertFalse($object->isDirty());
}

#[DataProvider('urlNormalizationProvider')]
public function testCleanVarsNormalizesUrls(string $input, string $expected): void
{

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. #[dataprovider] attribute used 📘 Rule violation ≡ Correctness

tests/icms/core/ObjectTest.php uses the #[DataProvider(...)] attribute syntax which requires PHP
8.0+, so the test code is not compatible with PHP 7.4. This breaks the stated requirement to keep
PHP code runnable on PHP 7.4–8.4.
Agent Prompt
## Issue description
The test file uses PHP 8 attributes (`#[DataProvider(...)]`), which is not valid syntax on PHP 7.4.

## Issue Context
The project compliance requires PHP syntax compatibility with PHP 7.4 through 8.4.

## Fix Focus Areas
- tests/icms/core/ObjectTest.php[92-116]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread composer.json Outdated
Comment on lines +20 to +22
"require-dev": {
"phpunit/phpunit": "^11.5"
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

3. phpunit/phpunit requires php 8.2+ 📘 Rule violation ≡ Correctness

composer.json adds phpunit/phpunit ^11.5, which requires a higher minimum PHP version than
7.4. This prevents running the test suite under PHP 7.4 as required.
Agent Prompt
## Issue description
`composer.json` requires PHPUnit 11.x, which is not compatible with PHP 7.4.

## Issue Context
Compliance requires support for PHP 7.4–8.4. PHPUnit 11 requires PHP >= 8.2, so it cannot be installed/executed on PHP 7.4.

## Fix Focus Areas
- composer.json[20-22]
- phpunit.xml.dist[1-8]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@fiammybe fiammybe linked an issue May 18, 2026 that may be closed by this pull request
Comment thread tests/icms/core/ObjectHandlerTest.php Outdated
}
}

final class CoreObjectHandlerTestDouble extends icms_core_ObjectHandler

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

multiple classes per file I think is bad idea; you can use fixture classes or anonymous classes if that really is required; or better use mocking - AI really can help with that

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that should be taken into account now.

Comment thread tests/icms/core/README.md Outdated
Comment thread tests/icms/ipf/HandlerTest.php Outdated
Comment on lines +14 to +22
if (!class_exists('icms_core_Filesystem', false)) {
class icms_core_Filesystem
{
public static function mkdir($target, $mode = 0777, $base = ICMS_ROOT_PATH, $metachars = []): bool
{
return true;
}
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can generate false positive results if runned with some other tests; use mocking for such things

Comment thread tests/icms/ipf/HandlerTest.php Outdated
}

if (!defined('ICMS_UPLOAD_PATH')) {
define('ICMS_UPLOAD_PATH', sys_get_temp_dir());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use https://github.com/bovigo/vfsStream to not generate file spam after tests

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the suggestion, I'll look into integrating this package

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment thread tests/bootstrap.php Outdated
Comment on lines +113 to +117
function icms_loadLanguageFile($name, $module = null)
{
// No-op for tests
return true;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another trait

Comment thread tests/bootstrap.php Outdated
Comment on lines +121 to +124
function icms_getConfig($key)
{
return null;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another trait

Comment thread tests/bootstrap.php Outdated
Comment on lines +128 to +131
class icms
{
public static $config;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another trait that helps to work with icms config

Comment thread tests/bootstrap.php Outdated
Comment on lines +148 to +151
function icms_currency($value)
{
return (float) $value;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another trait

Comment thread composer.json
Comment on lines +17 to +18
"test:core": "phpunit --configuration phpunit.xml.dist --testsuite icms-core",
"test:ipf": "phpunit --configuration phpunit.xml.dist --testsuite icms-ipf"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's point in separating?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the tested classes are in different subfolders of the icms library folder. In the future, a 'test:db' or 'test:view' could be added as well. I admit that for 4 classes, it is overkill

fiammybe added 6 commits May 30, 2026 09:47
composer.json now includes the upstream package name mikey179/vfsstream in require-dev even though the source repo is bovigo/vfsStream. In tests\icms\ipf\HandlerTest.php, each test now gets a fresh vfsStream root, getImagePath() is pointed at that virtual upload path, and the test asserts the directory is actually created there. I also updated tests\fixtures\IcmsCoreFilesystemStub.php so the test helper performs a real recursive mkdir() in the virtual filesystem instead of returning success unconditionally. The full PHPUnit suite still passes.
…efixingDatabaseMock(). I removed the trait, had tests\icms\ipf\HandlerTest.php require the mock class directly, and put the small createMockDb() helper back on the test class. The focused handler test still passes, and the extra trait file is gone
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add PHP unit testing

2 participants