mirror of
https://github.com/dorny/test-reporter.git
synced 2025-12-17 06:47:09 +01:00
Merge 2c5485e682 into 5edc9e96e2
This commit is contained in:
commit
60a394a30d
13 changed files with 593 additions and 0 deletions
21
__tests__/__outputs__/lcov-report-results.md
Normal file
21
__tests__/__outputs__/lcov-report-results.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||

|
||||
## ❌ <a id="user-content-r0" href="#r0">fixtures/lcov.info</a>
|
||||
**6** tests were completed in **0ms** with **4** passed, **2** failed and **0** skipped.
|
||||
|Test suite|Passed|Failed|Skipped|Time|
|
||||
|:---|---:|---:|---:|---:|
|
||||
|[src/services/notifier/NotifierService.js](#r0s0)|2✅|1❌||0ms|
|
||||
|[src/services/notifier/providers/DiscordNotifierProvider.js](#r0s1)|2✅|1❌||0ms|
|
||||
### ❌ <a id="user-content-r0s0" href="#r0s0">src/services/notifier/NotifierService.js</a>
|
||||
```
|
||||
src/services/notifier/NotifierService.js
|
||||
✅ lines 100% (21/21)
|
||||
✅ functions 100% (10/10)
|
||||
❌ branches 50% (3/6)
|
||||
```
|
||||
### ❌ <a id="user-content-r0s1" href="#r0s1">src/services/notifier/providers/DiscordNotifierProvider.js</a>
|
||||
```
|
||||
src/services/notifier/providers/DiscordNotifierProvider.js
|
||||
✅ lines 100% (17/17)
|
||||
✅ functions 100% (3/3)
|
||||
❌ branches 75% (3/4)
|
||||
```
|
||||
62
__tests__/__snapshots__/lcov.test.ts.snap
Normal file
62
__tests__/__snapshots__/lcov.test.ts.snap
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`lcov report coverage report from facebook/jest test results matches snapshot 1`] = `
|
||||
TestRunResult {
|
||||
"path": "fixtures/lcov.info",
|
||||
"suites": [
|
||||
TestSuiteResult {
|
||||
"groups": [
|
||||
TestGroupResult {
|
||||
"name": "src/services/notifier/NotifierService.js",
|
||||
"tests": [
|
||||
{
|
||||
"name": "lines 100% (21/21)",
|
||||
"result": "success",
|
||||
"time": 0,
|
||||
},
|
||||
{
|
||||
"name": "functions 100% (10/10)",
|
||||
"result": "success",
|
||||
"time": 0,
|
||||
},
|
||||
{
|
||||
"name": "branches 50% (3/6)",
|
||||
"result": "failed",
|
||||
"time": 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
"name": "src/services/notifier/NotifierService.js",
|
||||
"totalTime": undefined,
|
||||
},
|
||||
TestSuiteResult {
|
||||
"groups": [
|
||||
TestGroupResult {
|
||||
"name": "src/services/notifier/providers/DiscordNotifierProvider.js",
|
||||
"tests": [
|
||||
{
|
||||
"name": "lines 100% (17/17)",
|
||||
"result": "success",
|
||||
"time": 0,
|
||||
},
|
||||
{
|
||||
"name": "functions 100% (3/3)",
|
||||
"result": "success",
|
||||
"time": 0,
|
||||
},
|
||||
{
|
||||
"name": "branches 75% (3/4)",
|
||||
"result": "failed",
|
||||
"time": 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
"name": "src/services/notifier/providers/DiscordNotifierProvider.js",
|
||||
"totalTime": undefined,
|
||||
},
|
||||
],
|
||||
"totalTime": undefined,
|
||||
}
|
||||
`;
|
||||
92
__tests__/fixtures/lcov.info
Normal file
92
__tests__/fixtures/lcov.info
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
TN:
|
||||
SF:src/services/notifier/NotifierService.js
|
||||
FN:9,(anonymous_0)
|
||||
FN:10,(anonymous_1)
|
||||
FN:26,(anonymous_2)
|
||||
FN:27,(anonymous_3)
|
||||
FN:29,(anonymous_4)
|
||||
FN:30,(anonymous_5)
|
||||
FN:46,(anonymous_6)
|
||||
FN:47,(anonymous_7)
|
||||
FN:48,(anonymous_8)
|
||||
FN:49,(anonymous_9)
|
||||
FNF:10
|
||||
FNH:10
|
||||
FNDA:1,(anonymous_0)
|
||||
FNDA:1,(anonymous_1)
|
||||
FNDA:1,(anonymous_2)
|
||||
FNDA:3,(anonymous_3)
|
||||
FNDA:3,(anonymous_4)
|
||||
FNDA:3,(anonymous_5)
|
||||
FNDA:1,(anonymous_6)
|
||||
FNDA:3,(anonymous_7)
|
||||
FNDA:3,(anonymous_8)
|
||||
FNDA:3,(anonymous_9)
|
||||
DA:9,1
|
||||
DA:10,1
|
||||
DA:11,1
|
||||
DA:13,1
|
||||
DA:14,1
|
||||
DA:26,1
|
||||
DA:27,3
|
||||
DA:29,1
|
||||
DA:30,3
|
||||
DA:31,3
|
||||
DA:33,3
|
||||
DA:34,3
|
||||
DA:46,1
|
||||
DA:47,3
|
||||
DA:48,3
|
||||
DA:51,3
|
||||
DA:53,3
|
||||
DA:54,3
|
||||
DA:58,3
|
||||
DA:61,1
|
||||
DA:64,1
|
||||
LF:21
|
||||
LH:21
|
||||
BRDA:11,0,0,1
|
||||
BRDA:11,0,1,0
|
||||
BRDA:31,1,0,3
|
||||
BRDA:31,1,1,0
|
||||
BRDA:51,2,0,3
|
||||
BRDA:51,2,1,0
|
||||
BRF:6
|
||||
BRH:3
|
||||
end_of_record
|
||||
TN:
|
||||
SF:src/services/notifier/providers/DiscordNotifierProvider.js
|
||||
FN:12,(anonymous_0)
|
||||
FN:33,(anonymous_1)
|
||||
FN:51,(anonymous_2)
|
||||
FNF:3
|
||||
FNH:3
|
||||
FNDA:1,(anonymous_0)
|
||||
FNDA:1,(anonymous_1)
|
||||
FNDA:1,(anonymous_2)
|
||||
DA:3,1
|
||||
DA:12,1
|
||||
DA:13,1
|
||||
DA:14,1
|
||||
DA:22,1
|
||||
DA:23,1
|
||||
DA:33,1
|
||||
DA:34,1
|
||||
DA:35,1
|
||||
DA:40,1
|
||||
DA:41,1
|
||||
DA:51,1
|
||||
DA:52,1
|
||||
DA:53,1
|
||||
DA:58,1
|
||||
DA:59,1
|
||||
DA:62,1
|
||||
LF:17
|
||||
LH:17
|
||||
BRDA:18,0,0,0
|
||||
BRDA:18,0,1,1
|
||||
BRDA:20,1,0,1
|
||||
BRDA:20,1,1,1
|
||||
BRF:4
|
||||
BRH:3
|
||||
end_of_record
|
||||
23
__tests__/lcov.test.ts
Normal file
23
__tests__/lcov.test.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
|
||||
import {getReport} from '../src/report/get-report'
|
||||
import {normalizeFilePath} from '../src/utils/path-utils'
|
||||
import {LcovParser} from '../src/parsers/lcov/lcov-parser'
|
||||
|
||||
describe('lcov report coverage', () => {
|
||||
it('report from facebook/jest test results matches snapshot', async () => {
|
||||
const fixturePath = path.join(__dirname, 'fixtures', 'lcov.info')
|
||||
const outputPath = path.join(__dirname, '__outputs__', 'lcov-report-results.md')
|
||||
const filePath = normalizeFilePath(path.relative(__dirname, fixturePath))
|
||||
const fileContent = fs.readFileSync(fixturePath, {encoding: 'utf8'})
|
||||
|
||||
const parser = new LcovParser({parseErrors: true, trackedFiles: []})
|
||||
const result = await parser.parse(filePath, fileContent)
|
||||
expect(result).toMatchSnapshot()
|
||||
|
||||
const report = getReport([result])
|
||||
fs.mkdirSync(path.dirname(outputPath), {recursive: true})
|
||||
fs.writeFileSync(outputPath, report)
|
||||
})
|
||||
})
|
||||
|
|
@ -32,6 +32,7 @@ inputs:
|
|||
- jest-junit
|
||||
- mocha-json
|
||||
- swift-xunit
|
||||
- lcov
|
||||
required: true
|
||||
list-suites:
|
||||
description: |
|
||||
|
|
|
|||
250
dist/index.js
generated
vendored
250
dist/index.js
generated
vendored
|
|
@ -268,6 +268,7 @@ const mocha_json_parser_1 = __nccwpck_require__(6043);
|
|||
const swift_xunit_parser_1 = __nccwpck_require__(5366);
|
||||
const path_utils_1 = __nccwpck_require__(4070);
|
||||
const github_utils_1 = __nccwpck_require__(3522);
|
||||
const lcov_parser_1 = __nccwpck_require__(5698);
|
||||
function main() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
try {
|
||||
|
|
@ -436,6 +437,8 @@ class TestReporter {
|
|||
return new mocha_json_parser_1.MochaJsonParser(options);
|
||||
case 'swift-xunit':
|
||||
return new swift_xunit_parser_1.SwiftXunitParser(options);
|
||||
case 'lcov':
|
||||
return new lcov_parser_1.LcovParser(options);
|
||||
default:
|
||||
throw new Error(`Input variable 'reporter' is set to invalid value '${reporter}'`);
|
||||
}
|
||||
|
|
@ -1290,6 +1293,120 @@ class JestJunitParser {
|
|||
exports.JestJunitParser = JestJunitParser;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 5698:
|
||||
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
||||
|
||||
"use strict";
|
||||
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.LcovParser = void 0;
|
||||
const test_results_1 = __nccwpck_require__(2768);
|
||||
const lcov_utils_1 = __nccwpck_require__(4750);
|
||||
class LcovParser {
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
}
|
||||
parse(path, content) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const report = yield this.parseFile(path, content);
|
||||
return this.getTestRunResult(path, report);
|
||||
});
|
||||
}
|
||||
parseFile(path, content) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
try {
|
||||
return (0, lcov_utils_1.parseProm)(content);
|
||||
//return JSON.parse(content) as LcovReport
|
||||
}
|
||||
catch (e) {
|
||||
throw new Error(`Invalid JSON at ${path}\n\n${e}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
getTestRunResult(path, report) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const suites = [];
|
||||
for (const reportElement of report) {
|
||||
const fileName = reportElement.file;
|
||||
const statementCaseResult = {
|
||||
name: `lines ${this.getPartInfo(reportElement.lines)}`,
|
||||
time: 0,
|
||||
result: this.getPercentage(reportElement.lines) >= 80 ? 'success' : 'failed'
|
||||
};
|
||||
const fonctionCaseResult = {
|
||||
name: `functions ${this.getPartInfo(reportElement.functions)}`,
|
||||
time: 0,
|
||||
result: this.getPercentage(reportElement.functions) >= 80 ? 'success' : 'failed'
|
||||
};
|
||||
const brancheCaseResult = {
|
||||
name: `branches ${this.getPartInfo(reportElement.branches)}`,
|
||||
time: 0,
|
||||
result: this.getPercentage(reportElement.branches) >= 80 ? 'success' : 'failed'
|
||||
};
|
||||
const testCases = [statementCaseResult, fonctionCaseResult, brancheCaseResult];
|
||||
const groups = [new test_results_1.TestGroupResult(fileName, testCases)];
|
||||
const suite = new test_results_1.TestSuiteResult(fileName, groups);
|
||||
suites.push(suite);
|
||||
}
|
||||
return new test_results_1.TestRunResult(path, suites);
|
||||
});
|
||||
}
|
||||
getPercentage(stat) {
|
||||
return stat ? (stat.hit / stat.found) * 100 : 100;
|
||||
}
|
||||
getPartInfo(stat) {
|
||||
return `${this.getPercentage(stat)}% (${stat.hit}/${stat.found})`;
|
||||
}
|
||||
}
|
||||
exports.LcovParser = LcovParser;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 4750:
|
||||
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
||||
|
||||
"use strict";
|
||||
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.parseProm = void 0;
|
||||
const lcov_parse_1 = __importDefault(__nccwpck_require__(7454));
|
||||
const parseProm = (pathOrStr) => __awaiter(void 0, void 0, void 0, function* () {
|
||||
return new Promise((resolve, reject) => {
|
||||
(0, lcov_parse_1.default)(pathOrStr, (err, data) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
resolve(data !== null && data !== void 0 ? data : []);
|
||||
});
|
||||
});
|
||||
});
|
||||
exports.parseProm = parseProm;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 6043:
|
||||
|
|
@ -23434,6 +23551,139 @@ class Keyv extends EventEmitter {
|
|||
module.exports = Keyv;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 7454:
|
||||
/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
|
||||
|
||||
/*
|
||||
Copyright (c) 2012, Yahoo! Inc. All rights reserved.
|
||||
Code licensed under the BSD License:
|
||||
http://yuilibrary.com/license/
|
||||
*/
|
||||
|
||||
var fs = __nccwpck_require__(7147),
|
||||
path = __nccwpck_require__(1017);
|
||||
|
||||
/* istanbul ignore next */
|
||||
var exists = fs.exists || path.exists;
|
||||
|
||||
var walkFile = function(str, cb) {
|
||||
var data = [], item;
|
||||
|
||||
[ 'end_of_record' ].concat(str.split('\n')).forEach(function(line) {
|
||||
line = line.trim();
|
||||
var allparts = line.split(':'),
|
||||
parts = [allparts.shift(), allparts.join(':')],
|
||||
lines, fn;
|
||||
|
||||
switch (parts[0].toUpperCase()) {
|
||||
case 'TN':
|
||||
item.title = parts[1].trim();
|
||||
break;
|
||||
case 'SF':
|
||||
item.file = parts.slice(1).join(':').trim();
|
||||
break;
|
||||
case 'FNF':
|
||||
item.functions.found = Number(parts[1].trim());
|
||||
break;
|
||||
case 'FNH':
|
||||
item.functions.hit = Number(parts[1].trim());
|
||||
break;
|
||||
case 'LF':
|
||||
item.lines.found = Number(parts[1].trim());
|
||||
break;
|
||||
case 'LH':
|
||||
item.lines.hit = Number(parts[1].trim());
|
||||
break;
|
||||
case 'DA':
|
||||
lines = parts[1].split(',');
|
||||
item.lines.details.push({
|
||||
line: Number(lines[0]),
|
||||
hit: Number(lines[1])
|
||||
});
|
||||
break;
|
||||
case 'FN':
|
||||
fn = parts[1].split(',');
|
||||
item.functions.details.push({
|
||||
name: fn[1],
|
||||
line: Number(fn[0])
|
||||
});
|
||||
break;
|
||||
case 'FNDA':
|
||||
fn = parts[1].split(',');
|
||||
item.functions.details.some(function(i, k) {
|
||||
if (i.name === fn[1] && i.hit === undefined) {
|
||||
item.functions.details[k].hit = Number(fn[0]);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
break;
|
||||
case 'BRDA':
|
||||
fn = parts[1].split(',');
|
||||
item.branches.details.push({
|
||||
line: Number(fn[0]),
|
||||
block: Number(fn[1]),
|
||||
branch: Number(fn[2]),
|
||||
taken: ((fn[3] === '-') ? 0 : Number(fn[3]))
|
||||
});
|
||||
break;
|
||||
case 'BRF':
|
||||
item.branches.found = Number(parts[1]);
|
||||
break;
|
||||
case 'BRH':
|
||||
item.branches.hit = Number(parts[1]);
|
||||
break;
|
||||
}
|
||||
|
||||
if (line.indexOf('end_of_record') > -1) {
|
||||
data.push(item);
|
||||
item = {
|
||||
lines: {
|
||||
found: 0,
|
||||
hit: 0,
|
||||
details: []
|
||||
},
|
||||
functions: {
|
||||
hit: 0,
|
||||
found: 0,
|
||||
details: []
|
||||
},
|
||||
branches: {
|
||||
hit: 0,
|
||||
found: 0,
|
||||
details: []
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
data.shift();
|
||||
|
||||
if (data.length) {
|
||||
cb(null, data);
|
||||
} else {
|
||||
cb('Failed to parse string');
|
||||
}
|
||||
};
|
||||
|
||||
var parse = function(file, cb) {
|
||||
exists(file, function(x) {
|
||||
if (!x) {
|
||||
return walkFile(file, cb);
|
||||
}
|
||||
fs.readFile(file, 'utf8', function(err, str) {
|
||||
walkFile(str, cb);
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
|
||||
module.exports = parse;
|
||||
module.exports.source = walkFile;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 9662:
|
||||
|
|
|
|||
29
dist/licenses.txt
generated
vendored
29
dist/licenses.txt
generated
vendored
|
|
@ -1053,6 +1053,35 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
keyv
|
||||
MIT
|
||||
|
||||
lcov-parse
|
||||
BSD-3-Clause
|
||||
Copyright 2012 Yahoo! Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Yahoo! Inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL YAHOO! INC. BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
|
||||
lowercase-keys
|
||||
MIT
|
||||
MIT License
|
||||
|
|
|
|||
16
package-lock.json
generated
16
package-lock.json
generated
|
|
@ -15,6 +15,7 @@
|
|||
"adm-zip": "^0.5.10",
|
||||
"fast-glob": "^3.3.2",
|
||||
"got": "^11.8.2",
|
||||
"lcov-parse": "^1.0.0",
|
||||
"picomatch": "^3.0.1",
|
||||
"xml2js": "^0.6.2"
|
||||
},
|
||||
|
|
@ -25,6 +26,7 @@
|
|||
"@types/adm-zip": "^0.5.5",
|
||||
"@types/github-slugger": "^1.3.0",
|
||||
"@types/jest": "^29.5.11",
|
||||
"@types/lcov-parse": "^1.0.2",
|
||||
"@types/node": "^20.10.4",
|
||||
"@types/picomatch": "^2.3.3",
|
||||
"@types/xml2js": "^0.4.14",
|
||||
|
|
@ -1702,6 +1704,12 @@
|
|||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/lcov-parse": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/lcov-parse/-/lcov-parse-1.0.2.tgz",
|
||||
"integrity": "sha512-tdoxiYm04XdDEdR7UMwkWj78UAVo9U2IOcxI6tmX2/s9TK/ue/9T8gbpS/07yeWyVkVO0UumFQ5EUIBQbVejzQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.10.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.4.tgz",
|
||||
|
|
@ -5858,6 +5866,14 @@
|
|||
"language-subtag-registry": "~0.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/lcov-parse": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-1.0.0.tgz",
|
||||
"integrity": "sha512-aprLII/vPzuQvYZnDRU78Fns9I2Ag3gi4Ipga/hxnVMCZC8DnR2nI7XBqrPoywGfxqIx/DgarGvDJZAD3YBTgQ==",
|
||||
"bin": {
|
||||
"lcov-parse": "bin/cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/leven": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
"adm-zip": "^0.5.10",
|
||||
"fast-glob": "^3.3.2",
|
||||
"got": "^11.8.2",
|
||||
"lcov-parse": "^1.0.0",
|
||||
"picomatch": "^3.0.1",
|
||||
"xml2js": "^0.6.2"
|
||||
},
|
||||
|
|
@ -48,6 +49,7 @@
|
|||
"@types/adm-zip": "^0.5.5",
|
||||
"@types/github-slugger": "^1.3.0",
|
||||
"@types/jest": "^29.5.11",
|
||||
"@types/lcov-parse": "^1.0.2",
|
||||
"@types/node": "^20.10.4",
|
||||
"@types/picomatch": "^2.3.3",
|
||||
"@types/xml2js": "^0.4.14",
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import {SwiftXunitParser} from './parsers/swift-xunit/swift-xunit-parser'
|
|||
|
||||
import {normalizeDirPath, normalizeFilePath} from './utils/path-utils'
|
||||
import {getCheckRunContext} from './utils/github-utils'
|
||||
import {LcovParser} from './parsers/lcov/lcov-parser'
|
||||
|
||||
async function main(): Promise<void> {
|
||||
try {
|
||||
|
|
@ -225,6 +226,8 @@ class TestReporter {
|
|||
return new MochaJsonParser(options)
|
||||
case 'swift-xunit':
|
||||
return new SwiftXunitParser(options)
|
||||
case 'lcov':
|
||||
return new LcovParser(options)
|
||||
default:
|
||||
throw new Error(`Input variable 'reporter' is set to invalid value '${reporter}'`)
|
||||
}
|
||||
|
|
|
|||
59
src/parsers/lcov/lcov-parser.ts
Normal file
59
src/parsers/lcov/lcov-parser.ts
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
import {ParseOptions, TestParser} from '../../test-parser'
|
||||
|
||||
import {TestCaseResult, TestGroupResult, TestRunResult, TestSuiteResult} from '../../test-results'
|
||||
import {parseProm} from './lcov-utils'
|
||||
import {LcovBranch, LcovFile, LcovFunc, LcovLine, LcovPart} from 'lcov-parse'
|
||||
|
||||
export class LcovParser implements TestParser {
|
||||
constructor(readonly options: ParseOptions) {}
|
||||
async parse(path: string, content: string): Promise<TestRunResult> {
|
||||
const report = await this.parseFile(path, content)
|
||||
return this.getTestRunResult(path, report)
|
||||
}
|
||||
|
||||
private async parseFile(path: string, content: string): Promise<LcovFile[]> {
|
||||
try {
|
||||
return parseProm(content)
|
||||
//return JSON.parse(content) as LcovReport
|
||||
} catch (e) {
|
||||
throw new Error(`Invalid JSON at ${path}\n\n${e}`)
|
||||
}
|
||||
}
|
||||
private async getTestRunResult(path: string, report: LcovFile[]): Promise<TestRunResult> {
|
||||
const suites: TestSuiteResult[] = []
|
||||
|
||||
for (const reportElement of report) {
|
||||
const fileName = reportElement.file
|
||||
|
||||
const statementCaseResult: TestCaseResult = {
|
||||
name: `lines ${this.getPartInfo(reportElement.lines)}`,
|
||||
time: 0,
|
||||
result: this.getPercentage(reportElement.lines) >= 80 ? 'success' : 'failed'
|
||||
}
|
||||
const fonctionCaseResult: TestCaseResult = {
|
||||
name: `functions ${this.getPartInfo(reportElement.functions)}`,
|
||||
time: 0,
|
||||
result: this.getPercentage(reportElement.functions) >= 80 ? 'success' : 'failed'
|
||||
}
|
||||
const brancheCaseResult: TestCaseResult = {
|
||||
name: `branches ${this.getPartInfo(reportElement.branches)}`,
|
||||
time: 0,
|
||||
result: this.getPercentage(reportElement.branches) >= 80 ? 'success' : 'failed'
|
||||
}
|
||||
|
||||
const testCases: TestCaseResult[] = [statementCaseResult, fonctionCaseResult, brancheCaseResult]
|
||||
const groups: TestGroupResult[] = [new TestGroupResult(fileName, testCases)]
|
||||
const suite: TestSuiteResult = new TestSuiteResult(fileName, groups)
|
||||
|
||||
suites.push(suite)
|
||||
}
|
||||
return new TestRunResult(path, suites)
|
||||
}
|
||||
|
||||
private getPercentage(stat: LcovPart<LcovLine | LcovFunc | LcovBranch>): number {
|
||||
return stat ? (stat.hit / stat.found) * 100 : 100
|
||||
}
|
||||
private getPartInfo(stat: LcovPart<LcovLine | LcovFunc | LcovBranch>): string {
|
||||
return `${this.getPercentage(stat)}% (${stat.hit}/${stat.found})`
|
||||
}
|
||||
}
|
||||
21
src/parsers/lcov/lcov-types.ts
Normal file
21
src/parsers/lcov/lcov-types.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
export interface LcovReport {
|
||||
[str: string]: {
|
||||
path: string
|
||||
statementMap: unknown
|
||||
fnMap: unknown
|
||||
branchMap: unknown
|
||||
s: CovStats
|
||||
f: CovStats
|
||||
b: CovStats
|
||||
}
|
||||
}
|
||||
|
||||
export interface CovStats {
|
||||
[str: string]: number
|
||||
}
|
||||
|
||||
export interface CovParsedStat {
|
||||
max: number
|
||||
nonCovered: number
|
||||
percentage: number
|
||||
}
|
||||
14
src/parsers/lcov/lcov-utils.ts
Normal file
14
src/parsers/lcov/lcov-utils.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import parse, {LcovFile} from 'lcov-parse'
|
||||
|
||||
const parseProm = async (pathOrStr: string): Promise<LcovFile[]> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
parse(pathOrStr, (err, data) => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
}
|
||||
resolve(data ?? [])
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export {parseProm}
|
||||
Loading…
Add table
Add a link
Reference in a new issue