Skip to content

Commit

Permalink
feat: create fixes on c-like and php files (#869)
Browse files Browse the repository at this point in the history
* feat: create fixes on c-like and php files

* fix: add e2e test for fixes
  • Loading branch information
thomasrockhu-codecov authored Sep 1, 2022
1 parent d73502c commit 29b240c
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,5 @@ codecov.exe
.coverage
# File genrated as part of XCode tests
coverage-report-test.json

*.coverage.txt
1 change: 1 addition & 0 deletions src/helpers/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ const args: ICLIArgument[] = [
name: 'feature',
type: 'string',
description: `Toggle functionalities. Separate multiple ones by comma: -X network,search
-X fixes Enable file fixes to ignore common lines from coverage (e.g. blank lines or empty brackets)
-X network Disable uploading the file network
-X search Disable searching for coverage files`,
},
Expand Down
70 changes: 70 additions & 0 deletions src/helpers/fixes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import fs from 'fs'
import readline from 'readline'

import { getAllFiles } from './files'
import { UploadLogger } from './logger'

export const FIXES_HEADER = '# path=fixes\n'

export async function generateFixes(projectRoot: string): Promise<string> {
// Fake out the UploaderArgs as they are not needed
const allFiles = await getAllFiles(projectRoot, projectRoot, {
flags: '',
slug: '',
upstream: '',
})

const allAdjustments: string[] = []
const EMPTYLINE = /^\s*$/mg
// { or }
const SYNTAXBRACKET = /^\s*[{}]\s*(\/\/.*)?$/m
// [ or ]
const SYNTAXLIST = /^\s*[[\]]\s*(\/\/.*)?$/m

for (const file of allFiles) {
let lineAdjustments: string[] = []

if (
file.match(/\.c$/) ||
file.match(/\.cpp$/) ||
file.match(/\.h$/) ||
file.match(/\.hpp$/) ||
file.match(/\.m$/) ||
file.match(/\.swift$/) ||
file.match(/\.vala$/)
) {
lineAdjustments = await getMatchedLines(file, [EMPTYLINE, SYNTAXBRACKET])
} else if (
file.match(/\.php$/)
) {
lineAdjustments = await getMatchedLines(file, [SYNTAXBRACKET, SYNTAXLIST])
}

if (lineAdjustments.length > 0) {
UploadLogger.verbose(`Matched file ${file} for adjustments: ${lineAdjustments.join(',')}`)
allAdjustments.push(`${file}:${lineAdjustments.join(',')}\n`)
}
}
return allAdjustments.join('')
}

async function getMatchedLines(file: string, matchers: RegExp[]): Promise<string[]> {
const fileStream = fs.createReadStream(file)
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
});

const matchedLines: string[] = []
let lineNumber = 1

for await (const line of rl) {
for (const matcher of matchers) {
if (line.match(matcher)) {
matchedLines.push(lineNumber.toString())
}
}
lineNumber++
}
return matchedLines
}
11 changes: 11 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
removeFile,
} from './helpers/files'
import { generateCoveragePyFile } from './helpers/coveragepy'
import { generateFixes, FIXES_HEADER } from './helpers/fixes'
import { generateGcovCoverageFiles } from './helpers/gcov'
import { generateXcodeCoverageFiles } from './helpers/xcode'
import { argAsArray } from './helpers/util'
Expand Down Expand Up @@ -322,6 +323,16 @@ export async function main(
uploadFileChunks.push(Buffer.from(MARKER_ENV_END))
}

// Fixes
if (args.feature && args.feature.split(',').includes('fixes') === true) {
info('Generating file fixes...')
const fixes = await generateFixes(projectRoot)
uploadFileChunks.push(Buffer.from(FIXES_HEADER))
uploadFileChunks.push(Buffer.from(fixes))
uploadFileChunks.push(Buffer.from(MARKER_ENV_END))
info('Finished generating file fixes')
}

const uploadFile = Buffer.concat(uploadFileChunks)
const gzippedFile = zlib.gzipSync(uploadFile)

Expand Down
20 changes: 20 additions & 0 deletions test/fixtures/fixes/example.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php namespace Example;

class Example
{
public static function go()
{
$test_array = [
1,
2,
3,
]

if (false) {
return true;
}

return false;

}
}
66 changes: 66 additions & 0 deletions test/helpers/fixes.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import td from 'testdouble'
import childProcess from 'child_process'

import * as fixesHelpers from '../../src/helpers/fixes'

describe('Fixes Helpers', () => {
afterEach(() => {
td.reset()
})

it('provides no fixes if none are applicable', async () => {
const files = ['package.json']
td.replace(childProcess, 'spawnSync', () => {
return {
stdout: files.join('\n'),
status: 0,
error: undefined,
}
})
expect(
await fixesHelpers.generateFixes('.')
).toBe('')
})

it('provides proper fixes for c-like files', async () => {
const files = ['test/fixtures/gcov/main.c']
td.replace(childProcess, 'spawnSync', () => {
return {
stdout: files.join('\n'),
status: 0,
error: undefined,
}
})
expect(
await fixesHelpers.generateFixes('.')
).toBe('test/fixtures/gcov/main.c:2,4,11,12,13,14,16,20\n')
})

it('provides proper fixes for php-like files', async () => {
const files = ['test/fixtures/fixes/example.php']
td.replace(childProcess, 'spawnSync', () => {
return {
stdout: files.join('\n'),
status: 0,
error: undefined,
}
})
expect(
await fixesHelpers.generateFixes('.')
).toBe('test/fixtures/fixes/example.php:4,6,11,15,19,20\n')
})

it('provides multiple fixes for files', async () => {
const files = ['test/fixtures/fixes/example.php', 'test/fixtures/gcov/main.c']
td.replace(childProcess, 'spawnSync', () => {
return {
stdout: files.join('\n'),
status: 0,
error: undefined,
}
})
expect(
await fixesHelpers.generateFixes('.')
).toBe('test/fixtures/fixes/example.php:4,6,11,15,19,20\ntest/fixtures/gcov/main.c:2,4,11,12,13,14,16,20\n')
})
})
16 changes: 16 additions & 0 deletions test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -509,4 +509,20 @@ describe('Uploader Core', () => {
expect.stringMatching(/<<<<<< network/),
)
})

it('Can create fixes', async () => {
await app.main({
name: 'customname',
token: 'abcdefg',
url: 'https://codecov.io',
dryRun: 'true',
feature: 'fixes',
flags: '',
slug: '',
upstream: ''
})
expect(console.log).toHaveBeenCalledWith(
expect.stringMatching(/# path=fixes\ntest\/fixtures\/fixes\/example.php:4,6,11,15,19,20\ntest\/fixtures\/gcov\/main.c:2,4,11,12,13,14,16,20/)
)
})
})

0 comments on commit 29b240c

Please sign in to comment.