Skip to content

Commit

Permalink
Refactored function location parsing and added test cases for invalid…
Browse files Browse the repository at this point in the history
… fields

* Refactored the logic for parsing function locations to improve readability.
* Introduced tests to handle cases where field values are missing or incomplete.
  • Loading branch information
friedemannsommer committed Jun 14, 2024
1 parent 4249ac3 commit e34f032
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 20 deletions.
12 changes: 6 additions & 6 deletions src/lib/transform-result.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,12 +171,12 @@ export function transformFunctionLocation(result: ParseResult<Variant.FunctionLo
if (result.value !== null && result.value.length >= 2) {
lineStart = parseInteger(result.value[0])
lineEnd = parseInteger(result.value[1])
name =
lineEnd < lineStart || result.value.length === 2
? result.value[1]
: result.value.length >= 3
? result.value[2]
: ''

if (lineEnd < lineStart || result.value.length === 2) {
name = result.value[1]
} else if (result.value.length >= 3) {
name = result.value[2]
}
}

return {
Expand Down
17 changes: 10 additions & 7 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ import List from './lib/list.js'
import { type FieldOptions, generateFieldLookup } from './lib/lookup.js'
import type { FieldNames } from './typings/options.js'

/**
* A list of {@link ParseResult}s that have been flushed from the parser.
* This typing is used to make it clear that there will always be at least one result.
* @see {@link Parser#flush}
*/
export type FlushedResults = [ParseResult, ...ParseResult[]]

/**
* A parsed LCOV field entry.
* It may be incomplete, check the {@link ParseResult#done} and {@link ParseResult#incomplete} fields.
Expand Down Expand Up @@ -105,9 +112,9 @@ export class LcovParser {
/**
* Try to parse as many results as possible with the currently available chunks.
*/
public flush(): ParseResult[] {
public flush(): FlushedResults {
let result = this.read()
const parseResults: ParseResult[] = [result]
const parseResults: FlushedResults = [result]

while (!result.done && !result.incomplete) {
result = this.read()
Expand Down Expand Up @@ -214,18 +221,14 @@ export class LcovParser {
*/
private static _parseValue(buf: Buffer, offset: number, startAtOffset: boolean): ParseValueResult | null {
const length = buf.byteLength
let start = startAtOffset ? offset : -1
let start = offset

for (let index = offset; index < length; index++) {
const byte = buf[index]

if (!startAtOffset && byte === 58 /* ':' (colon) */) {
start = index + 1
} else if (byte === 10 /* '\n' (new line) */) {
if (start === -1) {
return null
}

return {
lastIndex: index,
value: LcovParser._parseSlice(buf, start, index)
Expand Down
9 changes: 5 additions & 4 deletions src/stream/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { defaultFieldNames } from '../constants.js'
import { type FunctionMap, createSection, handleResult } from '../lib/handle-result.js'
import { isBlankSpace } from '../lib/parse.js'
import transformResult from '../lib/transform-result.js'
import { LcovParser } from '../parser.js'
import { type FlushedResults, LcovParser } from '../parser.js'
import type { SectionSummary } from '../typings/file.js'
import type { StreamOptions } from '../typings/options.js'

Expand Down Expand Up @@ -49,7 +49,7 @@ export class LcovStreamParser extends Transform {
}

this._parser.write(chunk)
this._processResults()
this._processResults(this._parser.flush())

callback()
}
Expand All @@ -64,9 +64,10 @@ export class LcovStreamParser extends Transform {
const buffer = this._parser.getCurrentBuffer()

if (buffer !== null && !LcovStreamParser._isTrailingBlankSpace(buffer)) {
// write a trailing newline to ensure that the last line can be processed
this._parser.write(Buffer.from([10]))

if (!this._processResults()) {
if (!this._processResults(this._parser.flush())) {
callback(new Error('unexpected end of input.'))
return
}
Expand All @@ -93,7 +94,7 @@ export class LcovStreamParser extends Transform {
/**
* @internal
*/
private _processResults(results = this._parser.flush()): boolean {
private _processResults(results: FlushedResults): boolean {
for (const result of results) {
if (result.incomplete) {
return false
Expand Down
24 changes: 21 additions & 3 deletions src/tests/parser.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,7 @@ describe('LcovParser - Field names', (): void => {

parser.write(Buffer.from(chunk))

const result = parser.flush()

expect(result).to.eql([
expect(parser.flush()).to.eql([
getParseResult(
variant,
isEmptyFieldVariant ? null : variant === Variant.Comment ? [':test', 'data'] : ['test', 'data']
Expand All @@ -38,6 +36,26 @@ describe('LcovParser - Field names', (): void => {
}
})

describe('LcovParser - Invalid fields', (): void => {
for (const key of Object.keys(defaultFieldNames) as Array<keyof FieldNames>) {
const fieldName = defaultFieldNames[key]
const variant = FIELD_NAME_MAP[key]

if (isEmptyField(variant) || variant === Variant.Comment) {
// these fields either don't have a value, or a value is not required (comments)
continue
}

it(`should return incomplete result for "${fieldName}" (${key})"`, (): void => {
const parser = new LcovParser(defaultFieldNames)

parser.write(Buffer.from(`${fieldName}test,data\n`))

expect(parser.read()).to.eql(getParseResult(Variant.None, null, false, true))
})
}
})

describe('LcovParser - Chunks', (): void => {
it('should return `done: true` if there are no chunks and buffer available', (): void => {
const parser = new LcovParser(defaultFieldNames)
Expand Down

0 comments on commit e34f032

Please sign in to comment.