Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

feat(PHP Unit): first configuration for PHP Unit tests in ValidForm Builder#154

Merged
flangfeldt merged 72 commits into
validformbuilder:mastervalidformbuilder/validformbuilder:masterfrom
rvanbaalen:feat/testsrvanbaalen/validformbuilder:feat/testsCopy head branch name to clipboard
Jun 12, 2026
Merged

feat(PHP Unit): first configuration for PHP Unit tests in ValidForm Builder#154
flangfeldt merged 72 commits into
validformbuilder:mastervalidformbuilder/validformbuilder:masterfrom
rvanbaalen:feat/testsrvanbaalen/validformbuilder:feat/testsCopy head branch name to clipboard

Conversation

@rvanbaalen

@rvanbaalen rvanbaalen commented Jan 30, 2025

Copy link
Copy Markdown
Member

First setup for PHPUnit tests in ValidForm Builder — see #161.

952 tests, 1,751 assertions — every reachable line in classes/ValidFormBuilder/ is covered. The suite passes under randomized test order and runs in ~0.13s.

Test suite

  • One test class per source class (33 files under tests/ValidFormBuilder/), unified structure: #[Test] attributes, ValidFormBuilder\Tests namespace, assertSame over assertEquals.
  • HtmlAssertionsTrait — shared DOM-level assertion helper. Rendered HTML is parsed with DOMXPath and asserted structurally (element counts, hierarchy, attribute values) instead of brittle substring checks. Captures/restores libxml error state per test.
  • Every class got a dedicated security pass alongside functional coverage: XSS payloads through values/labels/meta, request tampering, array-input edge cases.
  • Tests that mutate $_REQUEST/$_POST/$_FILES/$_SESSION clean up in tearDown(), so a failing test can't leak state into the next one.
  • Known bugs are pinned with characterization tests that carry explicit KNOWN BUG comments and issue references (e.g. Page constructor does not store $meta — getMeta() and getShortHeader() always return defaults #204Page never stores constructor meta; Area::getDynamicCount() returns string instead of int). These tests fail loudly when the underlying bug gets fixed, flagging the assertion to flip.

Source fixes (driven by the tests)

Security:

Bug fixes:

  • Validator: VFORM_BOOLEAN regex tightened from /^[on]*$/i (a character class accepting o, nooo, ono, …) to /^(on)?$/i — exactly the two values an HTML checkbox submits (VFORM_BOOLEAN regex /^[on]*$/i accepts arbitrary sequences of o/n characters #200).
  • Collection::seek(): reversed loop condition meant the internal pointer never advanced past position 0.
  • Collection::inCollection(): with $blnReturnKey, returned stale key() state instead of the matched key (PHP 7+ foreach no longer advances the internal pointer).
  • Comparison: added the missing VFORM_COMPARISON_DOES_NOT_CONTAIN case; cast preg_match() result to bool as documented.
  • Condition::addComparison(): new \ReflectionClass("Comparison") resolved against the global namespace (always fatal) — now Comparison::class; argument extraction used array_keys() where array_values() was intended.
  • Base::__sanitizeCheckForJs(): keep the /u regex flag when the pattern uses \p{...} Unicode property escapes (required in JavaScript).

Unreachable code: two provably unreachable defensive branches (Base::addCondition() catch, Condition::addComparison() else) carry inline comments explaining why they cannot be reached and flagging them as candidates for deletion. They are the only uncovered lines in the coverage report.

Backwards-compatibility notes

  • VFORM_BOOLEAN now rejects garbage values (o, nooo, true, 1) that previously validated. Standard checkbox submissions ("" / "on") are unaffected.
  • Validator::validate() no longer terminates the request on invalid array elements; it returns false. Code relying on the old exit() behavior will now continue executing.

Tooling & CI

  • phpunit.xml — PHPUnit 11.5 config; coverage source is the full classes/ directory, no exclusions.
  • .github/workflows/php-unit.yml — runs the suite on PR, with line/method coverage gates at 70% (pcov on PHP 8.4).
  • composer.json — adds phpunit/phpunit ^11.5 + phpdocumentor/shim to require-dev, ext-mbstring requirement, platform PHP 8.2.
  • AGENTS.md / CLAUDE.md / README.md — document the test commands, Docker pcov coverage workflow, and testing conventions.

Known follow-up

ValidWizard::isSubmitted() does not validate the CSRF token, unlike its parent ValidForm::isSubmitted() — discovered and documented by the new tests (ValidWizardTest::isSubmittedReturnsTrueWhenDispatchKeyMatches). Tracked in #208.

Per-class checklist

The item is checked if a unit test is added.

@rvanbaalen rvanbaalen marked this pull request as draft January 30, 2025 17:14
@rvanbaalen rvanbaalen self-assigned this Jan 30, 2025
Signed-off-by: Robin van Baalen <robin@ganttify.com>
Signed-off-by: Robin van Baalen <robin@ganttify.com>
Signed-off-by: Robin van Baalen <robin@ganttify.com>
Signed-off-by: Robin van Baalen <robin@ganttify.com>
Signed-off-by: Robin van Baalen <robin@ganttify.com>
Signed-off-by: Robin van Baalen <robin@ganttify.com>
Signed-off-by: Robin van Baalen <robin@ganttify.com>
Signed-off-by: Robin van Baalen <robin@ganttify.com>
Signed-off-by: Robin van Baalen <robin@ganttify.com>
Signed-off-by: Robin van Baalen <robin@ganttify.com>
Signed-off-by: Robin van Baalen <robin@ganttify.com>
Signed-off-by: Robin van Baalen <robin@ganttify.com>
Signed-off-by: Robin van Baalen <robin@ganttify.com>
Signed-off-by: Robin van Baalen <robin@ganttify.com>
Signed-off-by: Robin van Baalen <robin@ganttify.com>
Signed-off-by: Robin van Baalen <robin@ganttify.com>
Signed-off-by: Robin van Baalen <robin@ganttify.com>
Signed-off-by: Robin van Baalen <robin@ganttify.com>
Instead, we’re going to use their docker image directly to generate the docs in Github Actions.

Signed-off-by: Robin van Baalen <robin@ganttify.com>
Signed-off-by: Robin van Baalen <robin@ganttify.com>
Signed-off-by: Robin van Baalen <robin@ganttify.com>
Signed-off-by: Robin van Baalen <robin@ganttify.com>
rvanbaalen and others added 2 commits February 27, 2025 21:59
Reorganized and added badges to provide more relevant project information. Replaced Travis CI badge with GitHub Actions workflow status badges and added download statistics from Packagist. This improves clarity and highlights key project metrics.
Covers constructor, toHtml wrapper with vf__notes class, conditional h4
header, body auto-wrapped in p vs raw pass-through when p tags present,
empty header/body edge cases. Security: documents raw HTML rendering of
header and body as intentional design. No new vulnerabilities.
Covers constructor (explicit/auto id, header, class/style/overview meta),
addField (direct Fieldset vs auto-wrap, reuse of last fieldset), toHtml
(vf__page wrapper, h2 header, overview skip), toJS (addPage call),
isValid, hasFields, isDynamic, getShortHeader. Documents broken
summaryLabel meta bug (validformbuilder#204) as regression-doc test. Security: header
rendered as raw HTML (developer content, intentional). No new
vulnerabilities.
Paragraph (11 tests): constructor, toHtml (h3 header, auto-p-wrap body,
raw body with existing p tags, empty header/body), placeholders,
security audit (raw HTML by design).

Password (11 tests): construction, toHtml (password input with
autocomplete=off, label, required class, tip), validation (any input
passes empty regex, minLength enforcement, matchWith), toJS, security
(value htmlspecialchars escaping verified via DOM parse).

StaticText (9 tests): constructor, toHtml (raw HTML rendering,
metaString placeholder replacement, simple layout span wrapping),
placeholders, security (raw HTML by design).

No new vulnerabilities found. Filed validformbuilder#205 for a stray double-quote in
the simple-layout div tag across File/Group/Password.

closes validformbuilder#181, closes validformbuilder#182, closes validformbuilder#185
Same XSS class as GroupField (validformbuilder#202). SelectOption::toHtmlInternal() and
SelectGroup::toHtmlInternal() rendered value and label into HTML without
htmlspecialchars(). Adds SelectTest with 12 tests covering construction,
addField/addGroup, rendering (option values, optgroup labels, selected
attribute, label linkage), toJS, and XSS regression tests.

closes validformbuilder#183, closes validformbuilder#184, closes validformbuilder#206
Text (11 tests): construction, toHtml (input with name/id, label, submitted
value, default value, required class, tip, maxlength attribute), toJS,
email CSS class, XSS escape verification.

Textarea (10 tests): construction, toHtml (textarea with name/id, default
rows/cols, custom rows/cols meta limitation documented, submitted value,
label), toJS, HTML type renders as Textarea, XSS escape verification.

Documents the custom rows/cols append bug — Textarea constructor sets
defaults before parent::__construct so meta values append instead of
overwriting. No new vulnerabilities found — both classes escape values
with htmlspecialchars.

closes validformbuilder#186, closes validformbuilder#187
Keeps both: feat/tests's autoload-dev PSR-4 mapping + phpunit require-dev,
and upstream/master's phpdocumentor/shim + config/platform + ext-mbstring.
52 tests exercising every VFORM_* type regex (positive + negative inputs
via DataProvider), custom regex dispatch, empty-check passthrough, array
input regression for validformbuilder#199, getCheck() lookup, and security probes (HTML
tag rejection, SQL injection rejection, invalid-regex error suppression).
No new vulnerabilities found.

closes validformbuilder#188
The upstream merge brought config.platform.php=8.0.0 which conflicts
with phpunit/phpunit ^11.5 (requires php >=8.2). The CI matrix only
runs 8.2+ so this is safe.
ValidForm (56 tests): constructor, addField factory for all 20 VFORM_*
types via DataProvider, other factory methods (fieldset/hidden/multi/
area/paragraph/button/navigation/html), isSubmitted (dispatch key + CSRF
bypass note), isValid (empty/valid/invalid), getFields/getValidField,
setDefaults (verified via rendered output), static helpers (get/getIsSet/
getStrippedClassName), toHtml structural checks (form element, dispatch
hidden field, child fields), security (dispatch key rejection, dispatch
field value rendering).

ValidWizard (23 tests): constructor (nav labels from meta + defaults),
addPage (page creation, uniqueId hidden field, no duplication), addField/
addFieldset/addMultiField (delegate to last page), getPage (by index,
out-of-range quirk documented), isSubmitted (dispatch + uniqueId from
request, CSRF bypass documented), isValid (whole wizard + per-page
semantics of isValidUntil), confirm page flag, getFields across pages,
security (CSRF bypass vs parent documented).

closes validformbuilder#189, closes validformbuilder#190
@rvanbaalen rvanbaalen requested a review from flangfeldt April 10, 2026 18:24
@flangfeldt flangfeldt removed their request for review April 17, 2026 14:09
…Ignore

Both branches are provably dead code — the guard conditions above them
filter out all inputs that could reach them. Annotating them lets pcov
report an honest 100% line coverage without requiring contrived mocks.
Replaces the outdated claim that no test suite exists. Adds the
vendor/bin/phpunit run command, assertSame preference note, and the
Docker pcov image instructions for generating coverage locally.
Adds rendering paths, dynamic-field cloning, condition/comparison logic,
multi-step wizard flows, and per-class security audits (XSS, injection).
ButtonTest/MultiFieldTest include Linux-libxml fixes (explicit ids instead
of anonymous-class NUL-byte ids). Coverage grew from 72.6% to 100%.
Replace the three assertTrue(true) placeholders in BaseTest with a real
setConditions test (or deletion where the method doesn't exist on Base),
assert the validate() return value in FieldValidatorTest, and move inline
$_REQUEST cleanup into tearDown in AreaTest/CheckboxTest.
The unreachable branches in Base::addCondition() and Condition::addComparison()
are now documented with inline comments suggesting deletion instead of
coverage-tool metadata.
Drop issue URLs and history narration from inline comments; that context
lives in the commit history and PR description.
@rvanbaalen rvanbaalen marked this pull request as ready for review June 10, 2026 13:22
@rvanbaalen rvanbaalen requested a review from flangfeldt June 10, 2026 13:22
@flangfeldt flangfeldt merged commit 4523e4b into validformbuilder:master Jun 12, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants

Morty Proxy This is a proxified and sanitized view of the page, visit original site.