Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | 1x 1x 12x 1x 1x 1x 1x 13x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x | 'use strict';
const fs = require('fs');
const path = require('path');
function nullToEmpty(s) {
return s == null ? '' : String(s);
}
function truncate(s, max) {
if (s.length <= max) return s;
return s.slice(0, max) + '...';
}
function toSeconds(duration) {
const d = Number(duration) || 0;
Iif (d <= 0) return 0.0;
Iif (d > 1000) return d / 1000.0;
return d;
}
function xmlEscape(s) {
return String(s)
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
/**
* @param {object} summary — same shape as ShiftLeftRunSummary (plain object for JSON)
*/
function writeJsonSummary(outDir, relativePath, summary) {
const full = path.join(outDir, relativePath);
fs.mkdirSync(path.dirname(full), { recursive: true });
const forJson = { ...summary };
delete forJson.jsonSummaryRelativePath;
delete forJson.testResultsXmlRelativePath;
fs.writeFileSync(full, JSON.stringify(forJson, null, 2), 'utf8');
return full;
}
/**
* JUnit-style testsuite XML for Azure Pipelines Publish Test Results.
*/
function writeXmlTestResults(outDir, relativePath, summary, results) {
const suiteName = `ShiftLeft Test Pack ${nullToEmpty(summary.packId)}`;
const timestamp = new Date().toISOString();
const tests = Math.max(summary.total || 0, results.resultsCount || 0);
const failures = Math.max(0, summary.failed || 0);
const errors = Math.max(0, summary.error || 0);
let xml = '<?xml version="1.0" encoding="UTF-8"?>\n';
xml += `<testsuite name="${xmlEscape(suiteName)}" tests="${tests}" failures="${failures}" errors="${errors}" timestamp="${xmlEscape(timestamp)}">\n`;
xml += ' <properties>\n';
xml += ` <property name="serverUrl" value="${xmlEscape(nullToEmpty(summary.serverUrl))}"/>\n`;
xml += ` <property name="tenantId" value="${xmlEscape(nullToEmpty(summary.tenantId))}"/>\n`;
xml += ` <property name="packId" value="${xmlEscape(nullToEmpty(summary.packId))}"/>\n`;
xml += ` <property name="executionId" value="${xmlEscape(nullToEmpty(summary.executionId))}"/>\n`;
xml += ` <property name="resultsPackName" value="${xmlEscape(nullToEmpty(results.packName))}"/>\n`;
xml += ` <property name="resultsPackId" value="${xmlEscape(nullToEmpty(results.packId))}"/>\n`;
xml += ` <property name="resultsExecutionId" value="${xmlEscape(nullToEmpty(results.executionId))}"/>\n`;
xml += ` <property name="resultsStartTime" value="${xmlEscape(nullToEmpty(results.startTimeIso))}"/>\n`;
xml += ` <property name="resultsEndTime" value="${xmlEscape(nullToEmpty(results.endTimeIso))}"/>\n`;
xml += ' </properties>\n';
for (const item of results.results) {
const testName = item.testName != null ? item.testName : nullToEmpty(item.testId);
const status = (item.status || '').trim().toUpperCase();
const seconds = toSeconds(item.duration);
xml += ` <testcase classname="ShiftLeft" name="${xmlEscape(testName)}" time="${seconds.toFixed(3)}">\n`;
Iif (status === 'FAILED') {
const err = nullToEmpty(item.error);
xml += ` <failure message="${xmlEscape(truncate(err, 500))}">${xmlEscape(truncate(err, 2000))}</failure>\n`;
} else Iif (status === 'ERROR') {
const err = nullToEmpty(item.error);
xml += ` <error message="${xmlEscape(truncate(err, 500))}">${xmlEscape(truncate(err, 2000))}</error>\n`;
}
const shiftleftMeta = `shiftleft.responseTimeMs=${item.responseTime} shiftleft.startTime=${nullToEmpty(item.startTimeIso)} shiftleft.endTime=${nullToEmpty(item.endTimeIso)}`;
xml += ` <system-out>${xmlEscape(shiftleftMeta)}</system-out>\n`;
xml += ' </testcase>\n';
}
xml += '</testsuite>\n';
const full = path.join(outDir, relativePath);
fs.mkdirSync(path.dirname(full), { recursive: true });
fs.writeFileSync(full, xml, 'utf8');
return full;
}
module.exports = { writeJsonSummary, writeXmlTestResults };
|