feat(lcov) use really lcov.info file

This commit is contained in:
Julien Catania 2024-01-12 16:10:04 +01:00
parent 61007344dd
commit fb59f4f91d
11 changed files with 204 additions and 113 deletions

View file

@ -1,45 +1,21 @@
![Tests failed](https://img.shields.io/badge/tests-7%20passed%2C%208%20failed-critical) ![Tests failed](https://img.shields.io/badge/tests-4%20passed%2C%202%20failed-critical)
## ❌ <a id="user-content-r0" href="#r0">fixtures/lcov.json</a> ## ❌ <a id="user-content-r0" href="#r0">fixtures/lcov.info</a>
**15** tests were completed in **0ms** with **7** passed, **8** failed and **0** skipped. **6** tests were completed in **0ms** with **4** passed, **2** failed and **0** skipped.
|Test suite|Passed|Failed|Skipped|Time| |Test suite|Passed|Failed|Skipped|Time|
|:---|---:|---:|---:|---:| |:---|---:|---:|---:|---:|
|[src/core/dao.service.ts](#r0s0)|3✅|||0ms| |[src/services/notifier/NotifierService.js](#r0s0)|2✅|1❌||0ms|
|[src/domains/auth/auth.controller.ts](#r0s1)|2✅|1❌||0ms| |[src/services/notifier/providers/DiscordNotifierProvider.js](#r0s1)|2✅|1❌||0ms|
|[src/shared/notif/providers/fcm/fcm.service.spec.ts](#r0s2)||3❌||0ms| ### ❌ <a id="user-content-r0s0" href="#r0s0">src/services/notifier/NotifierService.js</a>
|[src/shared/notif/providers/fcm/fcm.service.ts](#r0s3)|1✅|2❌||0ms|
|[src/shared/notif/providers/mail/mail-service.ts](#r0s4)|1✅|2❌||0ms|
### ✅ <a id="user-content-r0s0" href="#r0s0">src/core/dao.service.ts</a>
``` ```
src/core/dao.service.ts src/services/notifier/NotifierService.js
statement ✅ lines 100% (21/21)
✅ fonction ✅ functions 100% (10/10)
✅ branche ❌ branches 50% (3/6)
``` ```
### ❌ <a id="user-content-r0s1" href="#r0s1">src/domains/auth/auth.controller.ts</a> ### ❌ <a id="user-content-r0s1" href="#r0s1">src/services/notifier/providers/DiscordNotifierProvider.js</a>
``` ```
src/domains/auth/auth.controller.ts src/services/notifier/providers/DiscordNotifierProvider.js
✅ statement ✅ lines 100% (17/17)
❌ fonction ✅ functions 100% (3/3)
✅ branche ❌ branches 75% (3/4)
```
### ❌ <a id="user-content-r0s2" href="#r0s2">src/shared/notif/providers/fcm/fcm.service.spec.ts</a>
```
src/shared/notif/providers/fcm/fcm.service.spec.ts
❌ statement
❌ fonction
❌ branche
```
### ❌ <a id="user-content-r0s3" href="#r0s3">src/shared/notif/providers/fcm/fcm.service.ts</a>
```
src/shared/notif/providers/fcm/fcm.service.ts
❌ statement
❌ fonction
✅ branche
```
### ❌ <a id="user-content-r0s4" href="#r0s4">src/shared/notif/providers/mail/mail-service.ts</a>
```
src/shared/notif/providers/mail/mail-service.ts
❌ statement
❌ fonction
✅ branche
``` ```

View 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

File diff suppressed because one or more lines are too long

View file

@ -3,12 +3,12 @@ import * as path from 'path'
import {getReport} from '../src/report/get-report' import {getReport} from '../src/report/get-report'
import {normalizeFilePath} from '../src/utils/path-utils' import {normalizeFilePath} from '../src/utils/path-utils'
import { LcovParser } from "../src/parsers/lcov-json/lcov-parser"; import { LcovParser } from "../src/parsers/lcov/lcov-parser";
describe('lcov report coverage', () => { describe('lcov report coverage', () => {
it('report from facebook/jest test results matches snapshot', async () => { it('report from facebook/jest test results matches snapshot', async () => {
const fixturePath = path.join(__dirname, 'fixtures', 'lcov.json') const fixturePath = path.join(__dirname, 'fixtures', 'lcov.info')
const outputPath = path.join(__dirname, '__outputs__', 'lcov-report-results.md') const outputPath = path.join(__dirname, '__outputs__', 'lcov-report-results.md')
const filePath = normalizeFilePath(path.relative(__dirname, fixturePath)) const filePath = normalizeFilePath(path.relative(__dirname, fixturePath))
const fileContent = fs.readFileSync(fixturePath, {encoding: 'utf8'}) const fileContent = fs.readFileSync(fixturePath, {encoding: 'utf8'})

16
package-lock.json generated
View file

@ -15,6 +15,7 @@
"adm-zip": "^0.5.3", "adm-zip": "^0.5.3",
"fast-glob": "^3.2.5", "fast-glob": "^3.2.5",
"got": "^11.8.2", "got": "^11.8.2",
"lcov-parse": "^1.0.0",
"picomatch": "^2.2.2", "picomatch": "^2.2.2",
"xml2js": "^0.5.0" "xml2js": "^0.5.0"
}, },
@ -25,6 +26,7 @@
"@types/adm-zip": "^0.5.0", "@types/adm-zip": "^0.5.0",
"@types/github-slugger": "^1.3.0", "@types/github-slugger": "^1.3.0",
"@types/jest": "^28.1.7", "@types/jest": "^28.1.7",
"@types/lcov-parse": "^1.0.2",
"@types/node": "^18.7.7", "@types/node": "^18.7.7",
"@types/picomatch": "^2.2.1", "@types/picomatch": "^2.2.1",
"@types/xml2js": "^0.4.8", "@types/xml2js": "^0.4.8",
@ -1790,6 +1792,12 @@
"@types/node": "*" "@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": { "node_modules/@types/node": {
"version": "18.17.17", "version": "18.17.17",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.17.17.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.17.17.tgz",
@ -5807,6 +5815,14 @@
"language-subtag-registry": "~0.3.2" "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": { "node_modules/leven": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",

View file

@ -36,6 +36,7 @@
"adm-zip": "^0.5.3", "adm-zip": "^0.5.3",
"fast-glob": "^3.2.5", "fast-glob": "^3.2.5",
"got": "^11.8.2", "got": "^11.8.2",
"lcov-parse": "^1.0.0",
"picomatch": "^2.2.2", "picomatch": "^2.2.2",
"xml2js": "^0.5.0" "xml2js": "^0.5.0"
}, },
@ -46,6 +47,7 @@
"@types/adm-zip": "^0.5.0", "@types/adm-zip": "^0.5.0",
"@types/github-slugger": "^1.3.0", "@types/github-slugger": "^1.3.0",
"@types/jest": "^28.1.7", "@types/jest": "^28.1.7",
"@types/lcov-parse": "^1.0.2",
"@types/node": "^18.7.7", "@types/node": "^18.7.7",
"@types/picomatch": "^2.2.1", "@types/picomatch": "^2.2.1",
"@types/xml2js": "^0.4.8", "@types/xml2js": "^0.4.8",

View file

@ -20,7 +20,7 @@ import {SwiftXunitParser} from './parsers/swift-xunit/swift-xunit-parser'
import {normalizeDirPath, normalizeFilePath} from './utils/path-utils' import {normalizeDirPath, normalizeFilePath} from './utils/path-utils'
import {getCheckRunContext} from './utils/github-utils' import {getCheckRunContext} from './utils/github-utils'
import {Icon} from './utils/markdown-utils' import {Icon} from './utils/markdown-utils'
import {LcovParser} from './parsers/lcov-json/lcov-parser' import {LcovParser} from './parsers/lcov/lcov-parser'
async function main(): Promise<void> { async function main(): Promise<void> {
try { try {

View file

@ -1,65 +0,0 @@
import {ParseOptions, TestParser} from '../../test-parser'
import {TestCaseResult, TestGroupResult, TestRunResult, TestSuiteResult} from '../../test-results'
import {CovParsedStat, CovStats, LcovReport} from './lcov-types'
export class LcovParser implements TestParser {
constructor(readonly options: ParseOptions) {}
async parse(path: string, content: string): Promise<TestRunResult> {
const report = this.parseFile(path, content)
return this.getTestRunResult(path, report)
}
private parseFile(path: string, content: string): LcovReport {
try {
return JSON.parse(content) as LcovReport
} catch (e) {
throw new Error(`Invalid JSON at ${path}\n\n${e}`)
}
}
private async getTestRunResult(path: string, report: LcovReport): Promise<TestRunResult> {
const suites: TestSuiteResult[] = []
for (const key of Object.keys(report)) {
const s: CovParsedStat = this.getParsedStat(report[key].s)
const f: CovParsedStat = this.getParsedStat(report[key].f)
const b: CovParsedStat = this.getParsedStat(report[key].b)
const statementCaseResult: TestCaseResult = {
name: 'statement',
time: 0,
result: s.percentage >= 80 ? 'success' : 'failed'
}
const fonctionCaseResult: TestCaseResult = {
name: 'fonction',
time: 0,
result: f.percentage >= 80 ? 'success' : 'failed'
}
const brancheCaseResult: TestCaseResult = {
name: 'branche',
time: 0,
result: b.percentage >= 80 ? 'success' : 'failed'
}
const testCases: TestCaseResult[] = [statementCaseResult, fonctionCaseResult, brancheCaseResult]
const goups: TestGroupResult[] = [new TestGroupResult(key, testCases)]
const suite: TestSuiteResult = new TestSuiteResult(key, goups)
suites.push(suite)
console.log({key, s, f, b})
}
return new TestRunResult(path, suites)
}
private getParsedStat(stat: CovStats): CovParsedStat {
const max = Object.keys(stat).length
const nonCovered = this.zeroLength(stat)
const percentage = ((max - nonCovered) / max) * 100
return {max, nonCovered, percentage}
}
private zeroLength(report: CovStats): number {
return Object.keys(report).filter(key => report[key] === 0).length
}
}

View file

@ -0,0 +1,62 @@
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 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 (let 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})`;
}
}

View file

@ -0,0 +1,14 @@
import parse, {LcovFile} from 'lcov-parse'
const parseProm = (pathOrStr: string): Promise<LcovFile[]> => {
return new Promise((resolve, reject) => {
parse(pathOrStr, (err, data) => {
if (err) {
reject(err);
}
resolve(data ?? []);
});
});
};
export {parseProm}