Repository navigation
Bugfix Issue 773 Exec GetOptions EWarning
Bugfix — Issue #773: exec.inc.php:182 E_WARNING on every execution save (testprojects.options NULL/empty)
Issue: #773
Branch: fix/issue-773-exec-options-warning · Commits: 9469bc3f5 (fix), 1b9eecd23 (regression suite)
Status: FIXED & VERIFIED (2026-08-29)
Every write_execution() save (Execute Tests → Save Steps WIP / any manual single
execution save, incl. POST /api/execute/?action=save) writes one E_WARNING event into
the Event Viewer (events table) whenever the owning test project has no options blob:
E_WARNING
Undefined property: stdClass::$requirementsEnabled - in lib/functions/exec.inc.php - Line 182
-
api/execute/index.php:874(and legacylib/execute/execSetResults.php) callwrite_execution()→lib/functions/exec.inc.php:181:$topt = $tprojectMgr->getOptions($execSign->tproject_id); -
lib/functions/exec.inc.php:182:if( $topt->requirementsEnabled ) {— unguarded property read. -
lib/functions/testproject.class.php:3904 getOptions()returns(object)[]— an object with zero properties — whenevertestprojects.optionsis NULL, an empty string, not serialized PHP, orunserialize()fails (guards at lines 3911-3924, added by the #581/#564 hardening).requirementsEnabledonly exists when the persisted blob actually contains it. - Reading a non-existent property on a plain object raises the PHP
E_WARNING, which the framework's handler writes to theeventstable (Event Viewer).
Triggering DB state: testprojects.options IS NULL — legacy projects, projects created
through paths that never wrote an options blob, DB restored from an old dump.
Why only this call site breaks: every sibling read of requirementsEnabled already
guards it (common.php:361-362 isset(...) &&, resultsNavigator.php:24-25 isset,
printDocOptions.php:159-160 isset, tcEdit.php:409 !empty(...) && isset(...)).
exec.inc.php:182 was the single unguarded read in the executor family.
lib/functions/exec.inc.php:182 now reads:
$topt = $tprojectMgr->getOptions($execSign->tproject_id);
if( isset($topt->requirementsEnabled) && $topt->requirementsEnabled ) {Missing requirementsEnabled ⇒ treated as requirements disabled, i.e. the req-link
freeze branch is skipped — exactly the legacy semantics for a project whose blob is NULL
(the option_reqs column defaults 0 anyway).
Alternatives rejected:
- Make
getOptions()return a fully-defaulted options object: larger blast radius (every caller iterates the returned object;setOptions()attestproject.class.php:3929foreach ($itemOpt as $prop => $value)would then persist defaults on unrelated updates) and does not remove the need for the same guard pattern at the other call sites.
| File | Change |
|---|---|
lib/functions/exec.inc.php |
+1: guard requirementsEnabled read in write_execution() with isset()
|
tmp/TLU_Test_Cases.md |
+Suite 773 (4 test cases, 4/4 PASS) |
-
php -l lib/functions/exec.inc.php→ no syntax errors. -
Primary: truncated
events; withtestprojects.options=NULLranPOST /api/execute/?action=save→ HTTP 200saved:true,SELECT COUNT(*) FROM events= 0 (pre-fix: exactly theexec.inc.php Line 182E_WARNING row). -
Regression matrix:
- options=NULL → save → 0 events ✅
- full blob
requirementsEnabled=0→ save → 0 events, freeze branch skipped ✅ - full blob
requirementsEnabled=1+ realreq_coveragerow withlink_status=1(OPEN) linked to the tcversion → save →req_coverage.link_status1→2 (CLOSED_BY_EXEC) andreq_versions.is_open1→0 (freeze works ⇒ branch NOT skipped) ✅ - Event Viewer shows no new Error/Warning (only the login AUDIT row) ✅
