Skip to content

Commit bfed9a7

Browse files
ehennestadclaude
andcommitted
fix: count a release as tested when only skipped tests remain
Tests filtered by an unmet assumption - an absent optional dependency, a documented gap - are reported as skipped rather than failed. Requiring zero skips meant a suite that passed everything it actually ran still disqualified its release. Errors and failures still disqualify a release. When no release qualified, the task returned without writing the badge and without reporting anything, so the caller only found out when a later step tripped over the missing file. Assert instead, and point at the reports. Co-Authored-By: Claude Opus 5 <[email protected]>
1 parent 2df5ccb commit bfed9a7

2 files changed

Lines changed: 102 additions & 17 deletions

File tree

code/+matbox/+tasks/createTestedWithBadgeforToolbox.m

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,12 @@ function createTestedWithBadgeforToolbox(versionNumber, projectRootDirectory)
4545
% Read the test results file
4646
testResults = readstruct(currentFile);
4747

48-
% If no tests failed, errors, or were skipped, then add it to the list
48+
% A release counts as tested when nothing errored or failed. Skipped
49+
% tests are deliberately filtered by test assumptions (an optional
50+
% dependency that is absent, a documented gap), so they say nothing
51+
% about whether the toolbox works on that release.
4952
if sum([testResults.testsuite.errorsAttribute]) == 0 ...
50-
&& sum([testResults.testsuite.failuresAttribute]) == 0 ...
51-
&& sum([testResults.testsuite.skippedAttribute]) == 0
53+
&& sum([testResults.testsuite.failuresAttribute]) == 0
5254
if releasesTestedWith ~= ""
5355
% Insert the separator between released after the first one
5456
releasesTestedWith = releasesTestedWith + " | ";
@@ -58,22 +60,28 @@ function createTestedWithBadgeforToolbox(versionNumber, projectRootDirectory)
5860
releasesFailed = releasesFailed + 1;
5961
end
6062
end
61-
if releasesTestedWith ~= ""
62-
switch releasesFailed
63-
case 0
64-
badgecolor = "green";
65-
case 1
66-
badgecolor = "orange";
67-
case 2
68-
badgecolor = "yellow";
69-
otherwise
70-
badgecolor = "red";
71-
end
7263

73-
outputDirectory = fullfile(projectRootDirectory, '.github', 'badges', versionNumber);
74-
matbox.utility.writeBadgeJSONFile("tested with", releasesTestedWith, badgecolor,...
75-
"OutputFolder", outputDirectory)
64+
% Fail loudly rather than leaving the caller with a missing badge file.
65+
assert( releasesTestedWith ~= "", ...
66+
'MATBOX:BadgeCreation:NoReleasePassed', ...
67+
['No release passed its tests, so no "tested with" badge was ', ...
68+
'created. Inspect the test reports under docs/reports and fix the ', ...
69+
'failing tests.\n'] )
70+
71+
switch releasesFailed
72+
case 0
73+
badgecolor = "green";
74+
case 1
75+
badgecolor = "orange";
76+
case 2
77+
badgecolor = "yellow";
78+
otherwise
79+
badgecolor = "red";
7680
end
81+
82+
outputDirectory = fullfile(projectRootDirectory, '.github', 'badges', versionNumber);
83+
matbox.utility.writeBadgeJSONFile("tested with", releasesTestedWith, badgecolor,...
84+
"OutputFolder", outputDirectory)
7785
end
7886

7987
function result = getReleaseNamesFromFolderPaths(folderPaths)

tools/tests/+matboxtools/+unittest/TasksTest.m

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,5 +122,82 @@ function testPackageToolboxShadowedRootFile(testCase)
122122
testCase.verifyEqual(fileread(packagedLicenseFile), shadowText)
123123
testCase.verifyTrue(isfile(fullfile(pwd, 'code', 'LICENSE')))
124124
end
125+
126+
function testTestedWithBadgeCountsReleaseWithSkippedTests(testCase)
127+
% Tests filtered by an unmet assumption are reported as skipped
128+
% rather than failed, so the release is still tested with.
129+
writeTestResultsReport(pwd, "R2024a", "Skipped", 4);
130+
writeTestResultsReport(pwd, "R2024b");
131+
132+
matbox.tasks.createTestedWithBadgeforToolbox("v1.2.3", pwd);
133+
134+
badgeInfo = readTestedWithBadge(testCase, pwd, "v1.2.3");
135+
testCase.verifyEqual(string(badgeInfo.message), "R2024a | R2024b")
136+
testCase.verifyEqual(string(badgeInfo.color), "green")
137+
end
138+
139+
function testTestedWithBadgeExcludesFailingRelease(testCase)
140+
% Errors and failures still disqualify a release, and the badge
141+
% turns orange once a single release is left out.
142+
writeTestResultsReport(pwd, "R2024a", "Failures", 1);
143+
writeTestResultsReport(pwd, "R2024b", "Skipped", 2);
144+
145+
matbox.tasks.createTestedWithBadgeforToolbox("v1.2.3", pwd);
146+
147+
badgeInfo = readTestedWithBadge(testCase, pwd, "v1.2.3");
148+
testCase.verifyEqual(string(badgeInfo.message), "R2024b")
149+
testCase.verifyEqual(string(badgeInfo.color), "orange")
150+
end
151+
152+
function testTestedWithBadgeErrorsWhenNoReleasePassed(testCase)
153+
% Writing no badge at all would surface much later as a missing
154+
% file, so the task has to report the problem itself.
155+
writeTestResultsReport(pwd, "R2024a", "Errors", 1);
156+
writeTestResultsReport(pwd, "R2024b", "Failures", 1);
157+
158+
testCase.verifyError( ...
159+
@() matbox.tasks.createTestedWithBadgeforToolbox("v1.2.3", pwd), ...
160+
"MATBOX:BadgeCreation:NoReleasePassed")
161+
end
125162
end
126163
end
164+
165+
function writeTestResultsReport(projectRootDirectory, releaseName, options)
166+
% writeTestResultsReport - Write a minimal JUnit-style report for one release
167+
%
168+
% The report holds a single test suite whose error, failure and skip counts
169+
% are given by the optional arguments. It mirrors the layout that the release
170+
% workflow produces by downloading one report artifact per MATLAB release.
171+
172+
arguments
173+
projectRootDirectory (1,1) string
174+
releaseName (1,1) string
175+
options.Errors (1,1) double = 0
176+
options.Failures (1,1) double = 0
177+
options.Skipped (1,1) double = 0
178+
end
179+
180+
reportFolder = fullfile(projectRootDirectory, "docs", "reports", "reports-" + releaseName);
181+
if ~isfolder(reportFolder)
182+
mkdir(reportFolder)
183+
end
184+
185+
reportXml = sprintf([...
186+
'<?xml version="1.0" encoding="UTF-8" standalone="no" ?>\n' ...
187+
'<testsuites>\n' ...
188+
' <testsuite errors="%d" failures="%d" name="ExampleTest" skipped="%d" tests="%d" time="1.0"/>\n' ...
189+
'</testsuites>\n'], ...
190+
options.Errors, options.Failures, options.Skipped, ...
191+
options.Errors + options.Failures + options.Skipped + 1);
192+
193+
matbox.utility.filewrite(fullfile(reportFolder, "test-results.xml"), reportXml);
194+
end
195+
196+
function badgeInfo = readTestedWithBadge(testCase, projectRootDirectory, versionNumber)
197+
% readTestedWithBadge - Read back the badge written for a given version
198+
199+
badgeFile = fullfile(projectRootDirectory, ".github", "badges", versionNumber, "tested_with.json");
200+
testCase.assertTrue(isfile(badgeFile), ...
201+
"Expected 'tested with' badge file was not created.")
202+
badgeInfo = jsondecode(fileread(badgeFile));
203+
end

0 commit comments

Comments
 (0)