Issue 583 TlTestPlanMetrics TSuiteDepth2 Empty Plan Null Guard Fix - sebiboga/testlink-upgraded GitHub Wiki
tlTestPlanMetrics TSuite Depth-2 Empty-Plan Null Guard Fix
Issue #583
Fixed: opening lib/results/resultsByTSuite.php?tplan_id=<plan-without-linked-test-cases>&format=0
on PHP 8.3 produced HTTP 500 / zero-byte body:
E_WARNING Attempt to read property "colDefinition" on null - tlTestPlanMetrics.class.php - Line 3389
PHP Fatal: Uncaught TypeError: array_keys(): Argument #1 ($array) must be of
type array, null given - tlTestPlanMetrics.class.php Line 3403
Root Cause
Exactly the pattern flagged during the #579 review, on the sibling method that was not covered by that fix:
getStatusTotalsTSuiteDepth2ForRender()callsgetStatusTotalsByItemForRender($id,'tsuite',β¦). For a plan whose builds exist but which has zero linked test cases, that inner method returns[null, staircase](the null contract documented in #579).- The depth-2 renderer then dereferenced
$rx->colDefinition(:3389) and β because resultsByTSuite.php passesgroupByPlatform=1βarray_keys($rx->info)(:3403) without a null check. On PHP 8, reading a property on null is an E_WARNING andarray_keys(null)is an uncaught TypeError β fatal.
Note: the build-less empty plan never reaches this code because
helperGetExecCounters() throws "Can not work with empty build set"
first; the reported path needs at least one build.
The Fix β approach
One minimal guard in lib/functions/tlTestPlanMetrics.class.php,
identical in shape to the #579 fix:
// getStatusTotalsTSuiteDepth2ForRender(), right after the list() call
if( is_null($rx) ) {
return null;
}
Why this shape:
- Returning
nullmatches the method's existing contract β its only callerresultsByTSuite.php:33already handles it:if(is_null($tsInf) || empty($tsInf->infoL2))renders the "no test suites defined" report branch. - An early return is preferred over fabricating an empty render object because every consumer treats null as "nothing to report on".
- Alternatives rejected: always setting
$exec['tsuites'] = array()inside the metrics hot path (cosmetic key, wide blast radius), or guarding only the two dereference sites (leaves a half-initialised stdClass flowing into the caller).
Verification
| Step | Result |
|---|---|
| Pre-fix repro on fixture plan (build present, zero linked TCs) | HTTP 500, harness shows exactly the warning + TypeError above |
| Post-fix same URL | HTTP 200, "There are no Test Suites definedβ¦no report can be created" branch |
| Positive regression: link one TC under nested suites, reload | full "Metrics by Level 1 & Level 2 Test Suites" table (Top/Child rows, Not Run column) |
Sibling screens sharing the inner metrics call (resultsGeneral.php, mainPage.php) |
HTTP 200, zero new warnings/events |
| Event Viewer | no new Error/Warning events from the touched code path |
Regression suite: Regression β Issue #583 in tmp/TLU_Test_Cases.md.
Follow-up bug discovered during verification
Filed separately with repro steps, root cause and suggested fix:
- #586 pChart declares only a PHP4-style constructor
(
function pChart()), which PHP 8 no longer calls implicitly β$this->Picturestays null and every chart screen (topLevelSuitesBarChart etc.) fatals with an imagecolorallocate TypeError even on fully populated plans.
Files changed
lib/functions/tlTestPlanMetrics.class.phpβ early null return ingetStatusTotalsTSuiteDepth2ForRender()(~3376)
Screenshots

