@diffblue/java-combiner
Advanced tools
Comparing version 0.1.3 to 0.1.4
@@ -15,2 +15,16 @@ import { IClangStyle } from './clangFormat'; | ||
/** | ||
* Split a java file into an array at points where a test or import can be inserted | ||
* | ||
* @param {string} fileContents | ||
*/ | ||
export declare function splitExistingCode(fileContents: string): { | ||
splitCode: string[]; | ||
functionLocations: [string, number][]; | ||
importLocations: [string, number][]; | ||
classAnnotationLocations: [string, number][]; | ||
pkgLocation: number; | ||
classLocation: number; | ||
pkg: string; | ||
}; | ||
/** | ||
* Given an array of names that may end with a number, return a map of names | ||
@@ -41,1 +55,46 @@ * with numbers stripped to the highest number found | ||
export declare function mergeTests(fileContents: string, tests: ILooseTestData[], clangStyle?: IClangStyle): Promise<string>; | ||
/** | ||
* Get type of import. | ||
* | ||
* Returns: | ||
* 0 for static imports | ||
* 2 for static java imports | ||
* 3 for java imports | ||
* 1 for other imports | ||
* | ||
* @param {string} importName | ||
* @returns | ||
*/ | ||
export declare function getImportGroup(importName: string): number; | ||
/** | ||
* | ||
* Comparator for sorting imports | ||
* Sorts by import group (from getImportGroup), then alphabetically | ||
* | ||
* @param {string} a | ||
* @param {string} b | ||
* @returns | ||
*/ | ||
export declare function cmpImports(a: string, b: string): 0 | 1 | -1; | ||
/** | ||
* Insert imports into split code array (by mutating the array) | ||
* | ||
* @param {string[]} splitCode Existing code, as split into chunks with splitExistingCode | ||
* @param {number} pkgLocation Location of "package" keyword in splitCode (to insert | ||
* imports if there are none already) | ||
* @param {Array<[string, number]>} importLocations Array listing existing imports and their locations in the | ||
* splitCode | ||
* @param {string[]} importsToAdd Array of imports to be added | ||
* @param {string[]} staticImportsToAdd Array of static imports to be added | ||
*/ | ||
export declare function insertImports(splitCode: string[], pkgLocation: number, importLocations: Array<[string, number]>, importsToAdd: string[], staticImportsToAdd: string[]): void; | ||
/** | ||
* insert import at location | ||
* | ||
* @export | ||
* @param {number} loc | ||
* @param {string[]} splitCode | ||
* @param {string} codeToAdd | ||
* @param {number} pkg | ||
*/ | ||
export declare function spliceCode(loc: number, splitCode: string[], codeToAdd: string, newlineBefore: number, newlineAfter: number): void; |
@@ -7,3 +7,2 @@ "use strict"; | ||
const parse_1 = require("./parse"); | ||
const testCombiner_1 = require("./testCombiner"); | ||
const utils_1 = require("./utils"); | ||
@@ -129,3 +128,3 @@ /** | ||
else if (char === ';' && depth === 0) { | ||
const importRegexMatch = curChunk.match(/import\s+(?:static\s+)?(.*)$/); | ||
const importRegexMatch = curChunk.match(/import\s+?(.*)$/); | ||
if (importRegexMatch) { | ||
@@ -155,2 +154,3 @@ importLocations.push([importRegexMatch[1], splitCode.length]); | ||
} | ||
exports.splitExistingCode = splitExistingCode; | ||
/** | ||
@@ -263,7 +263,7 @@ * Given an array of names that may end with a number, return a map of names | ||
// We should insert at the end | ||
splitCode.splice(functionLocations[currFunc - 1][1] + 1, 0, `\n\n${testBody}`); | ||
spliceCode(functionLocations[currFunc - 1][1] + 1, splitCode, testBody, 2, 1); | ||
} | ||
else { | ||
// Inserting after a test, add newlines before the body | ||
splitCode.splice(functionLocations[currFunc][1], 0, `\n\n${testBody}`); | ||
spliceCode(functionLocations[currFunc][1], splitCode, testBody, 2, 2); | ||
} | ||
@@ -301,2 +301,41 @@ } | ||
/** | ||
* Get type of import. | ||
* | ||
* Returns: | ||
* 0 for static imports | ||
* 2 for static java imports | ||
* 3 for java imports | ||
* 1 for other imports | ||
* | ||
* @param {string} importName | ||
* @returns | ||
*/ | ||
function getImportGroup(importName) { | ||
importName = importName || ''; | ||
if (importName.match(/^static\s+javax?\./)) { | ||
return 2; | ||
} | ||
if (importName.match(/^static($|\s)/)) { | ||
return 0; | ||
} | ||
if (importName.match(/^(javax?)\./)) { | ||
return 3; | ||
} | ||
return 1; | ||
} | ||
exports.getImportGroup = getImportGroup; | ||
/** | ||
* | ||
* Comparator for sorting imports | ||
* Sorts by import group (from getImportGroup), then alphabetically | ||
* | ||
* @param {string} a | ||
* @param {string} b | ||
* @returns | ||
*/ | ||
function cmpImports(a, b) { | ||
return utils_1.cmp(getImportGroup(a), getImportGroup(b)) || utils_1.cmp(a, b); | ||
} | ||
exports.cmpImports = cmpImports; | ||
/** | ||
* Insert imports into split code array (by mutating the array) | ||
@@ -313,11 +352,132 @@ * | ||
function insertImports(splitCode, pkgLocation, importLocations, importsToAdd, staticImportsToAdd) { | ||
let importInsertLocation = pkgLocation + 1; | ||
if (importLocations.length && importLocations[importLocations.length - 1]) { | ||
importInsertLocation = importLocations[importLocations.length - 1][1] + 1; | ||
const existingImports = new Set(importLocations.map((q) => q[0])); | ||
const allImports = [...importsToAdd, ...staticImportsToAdd.map((i) => `static ${i}`)].filter((i) => !(i in existingImports)); | ||
allImports.sort(cmpImports); | ||
let locationCounter = importLocations.length - 1; | ||
let addCounter = allImports.length - 1; | ||
while (locationCounter >= 0 && addCounter >= 0) { | ||
const location = importLocations[locationCounter]; | ||
const importToAdd = allImports[addCounter]; | ||
if (cmpImports(importToAdd, location[0]) === 1) { | ||
// Insert after location | ||
const [newlinesBefore, newlinesAfter] = pickNewlines(location[1] + 1, importLocations, `import ${importToAdd}`, splitCode, pkgLocation); | ||
spliceCode(location[1] + 1, splitCode, `import ${importToAdd};`, newlinesBefore, newlinesAfter); | ||
importLocations.forEach((i) => { | ||
if (i[1] >= location[1] + 1) { | ||
i[1]++; | ||
} | ||
}); | ||
importLocations.push([importToAdd, location[1] + 1]); | ||
addCounter -= 1; | ||
} | ||
else { | ||
locationCounter -= 1; | ||
} | ||
} | ||
if (importsToAdd.length || staticImportsToAdd.length) { | ||
const additionalImportsString = testCombiner_1.createImportString(importsToAdd.concat(staticImportsToAdd.map((i) => `static ${i}`)), true); | ||
splitCode.splice(importInsertLocation, 0, `\n${additionalImportsString}`); | ||
// Insert any remaining imports after package statement | ||
while (addCounter > -1) { | ||
const importToAdd = allImports[addCounter]; | ||
const [newlinesBefore, newlinesAfter] = pickNewlines(pkgLocation + 1, importLocations, `import ${importToAdd}`, splitCode, pkgLocation); | ||
spliceCode(pkgLocation + 1, splitCode, `import ${importToAdd};`, newlinesBefore, newlinesAfter); | ||
importLocations.splice(0, 0, [importToAdd, pkgLocation + 1]); | ||
addCounter--; | ||
} | ||
} | ||
exports.insertImports = insertImports; | ||
/** | ||
* Count newlines | ||
* | ||
* @param {string} input | ||
* @returns | ||
*/ | ||
function nlc(input) { | ||
const matches = input.match(/^(\n+)((.|$)+$)/); | ||
return matches ? matches[1].length : 0; | ||
} | ||
/** | ||
* Leave string with only one preceeding newline | ||
* | ||
* @param {string} input string | ||
* @returns | ||
*/ | ||
function oneNewline(input) { | ||
// leaves one newline in place | ||
const split = input.match(/^(\n+)((.|\n|$)+)/); | ||
return split ? `\n${split[2]}` : `\n${input}`; | ||
} | ||
/** | ||
* determine whether an import should be surrounded by newliens | ||
* | ||
* @param {number} loc location of import | ||
* @param {string[]} splitCode splitCode | ||
* @param {string} importToAdd import being added | ||
* @returns | ||
*/ | ||
function pickNewlines(loc, importLocations, importToAdd, splitCode, pkg) { | ||
let newlineAfter = 0; | ||
let newlineBefore = 1; | ||
const addition = getImportGroup(importToAdd.trim().split(' ')[1]); | ||
// the line after the current import | ||
const afterImport = importLocations.filter((i) => i[1] === loc); | ||
let afterImportGroup; | ||
if (afterImport[0] && afterImport[0][0]) { | ||
afterImportGroup = getImportGroup(afterImport[0] && afterImport[0][0]); | ||
} | ||
// the line before the current import | ||
const beforeImport = importLocations.filter((i) => i[1] === loc - 1); | ||
const beforeImportGroup = getImportGroup(beforeImport[0] && beforeImport[0][0]); | ||
// if import types are dissimilar, there must be a blank line between them | ||
if (addition !== beforeImportGroup) { | ||
newlineBefore = 2; | ||
} | ||
if (beforeImport.length === 0 && pkg === -1) { | ||
// we're at the beginning, there's no package | ||
newlineBefore = 0; | ||
} | ||
// a space should be added if the next line isn't an import | ||
if (addition !== afterImportGroup) { | ||
let a = afterImport[0] ? afterImport[0][1] : undefined; | ||
if (!a) { | ||
a = loc; | ||
} | ||
let nl; | ||
if (a) { | ||
nl = nlc(splitCode[a]); | ||
} | ||
newlineAfter = nl && nl > 2 ? nl : 2; | ||
} | ||
// same type no gap | ||
if (addition === afterImportGroup) { | ||
newlineAfter = 1; | ||
} | ||
// a newline should be added if we're at package | ||
if ((loc - 1 === pkg) && pkg !== -1) { | ||
newlineBefore = 2; | ||
} | ||
return [newlineBefore, newlineAfter]; | ||
} | ||
/** | ||
* insert import at location | ||
* | ||
* @export | ||
* @param {number} loc | ||
* @param {string[]} splitCode | ||
* @param {string} codeToAdd | ||
* @param {number} pkg | ||
*/ | ||
function spliceCode(loc, splitCode, codeToAdd, newlineBefore, newlineAfter) { | ||
// set newlines before addition | ||
let codeString = codeToAdd; | ||
for (let i = newlineBefore; i > 0; i--) { | ||
codeString = `\n${codeString}`; | ||
} | ||
splitCode.splice(loc, 0, codeString); | ||
// Set newlines after addition | ||
let nextLine = oneNewline(splitCode[loc + 1]).slice(1); | ||
for (let i = newlineAfter; i > 0; i--) { | ||
nextLine = `\n${nextLine}`; | ||
} | ||
splitCode[loc + 1] = nextLine; | ||
} | ||
exports.spliceCode = spliceCode; | ||
//# sourceMappingURL=mergeTests.js.map |
@@ -19,6 +19,6 @@ import { ILooseTestData, ITestData } from './test'; | ||
* @param {string} className The desired name of the class | ||
* @param {string} testedClasses The list of classes the test covers | ||
* @param {string} packageName The desired package name of the class | ||
* @param {string} [legacyPackageName] Override pacakagename if supplied. Deprecated. For backwards compatibility only. | ||
* @returns {ClangStyle} | ||
*/ | ||
export declare function genTestClass(tests: ILooseTestData[], className: string, testedClasses: string, packageName: string): string; | ||
export declare function genTestClass(tests: ILooseTestData[], className: string, packageName: string, legacyPackageName?: string): string; |
@@ -25,2 +25,3 @@ "use strict"; | ||
function createImportString(imports, newLines) { | ||
const importSet = new Set(imports); | ||
const javaImports = []; | ||
@@ -30,3 +31,3 @@ const javaStaticImports = []; | ||
const staticImports = []; | ||
imports.forEach((i) => { | ||
importSet.forEach((i) => { | ||
if (i.match(/^java./)) { | ||
@@ -81,7 +82,11 @@ javaImports.push(`import ${i};`); | ||
* @param {string} className The desired name of the class | ||
* @param {string} testedClasses The list of classes the test covers | ||
* @param {string} packageName The desired package name of the class | ||
* @param {string} [legacyPackageName] Override pacakagename if supplied. Deprecated. For backwards compatibility only. | ||
* @returns {ClangStyle} | ||
*/ | ||
function genTestClass(tests, className, testedClasses, packageName) { | ||
function genTestClass(tests, className, packageName, legacyPackageName) { | ||
if (legacyPackageName) { | ||
// Deprecated 3rd parameter (testedClasses) used; overwrite packageName with 4th parameter | ||
packageName = legacyPackageName; | ||
} | ||
const classNameModified = className.replace(/\$/g, '_'); | ||
@@ -128,3 +133,2 @@ // Merge all tests' classAnnotation arrays into a single Set | ||
/* testedClasses: ${testedClasses} */ | ||
${content} | ||
@@ -131,0 +135,0 @@ } |
import { ILooseTestData, ITestData } from './test'; | ||
/** | ||
* cmp | ||
* | ||
* Returns 0 if inputs are equal, -1 if first is less, 1 if first is greater. | ||
* | ||
* Like cmp in every language where it appears as a built in. | ||
*/ | ||
export declare function cmp<T>(a: T, b: T): 0 | 1 | -1; | ||
export declare function standardiseTests(tests: ILooseTestData[]): ITestData[]; |
@@ -5,2 +5,13 @@ "use strict"; | ||
/** | ||
* cmp | ||
* | ||
* Returns 0 if inputs are equal, -1 if first is less, 1 if first is greater. | ||
* | ||
* Like cmp in every language where it appears as a built in. | ||
*/ | ||
function cmp(a, b) { | ||
return a < b ? -1 : a > b ? 1 : 0; | ||
} | ||
exports.cmp = cmp; | ||
/** | ||
* Function whose signature claims to return a given type, but in practise always just throws an error. | ||
@@ -7,0 +18,0 @@ * Used to satisfy types during conversion from loose test to strict test |
@@ -0,1 +1,12 @@ | ||
0.1.4 (2019-07-25) | ||
================== | ||
* Test debug infrastructure improvements #25 | ||
* Add import order regression tests [TG-7926] #26, #33, #27 | ||
* Remove testedClasses comment [TG-8388] #10 | ||
* Fix linting of unit tests and verify on CircleCI #30 | ||
* Upgrade dependencies #29 & remove unused #28, #31 | ||
* Order imports and newline appropriately #32 | ||
* Deduplicate imports in Test Combiner #35 | ||
0.1.3 (2019-06-19) | ||
@@ -2,0 +13,0 @@ ================== |
{ | ||
"name": "@diffblue/java-combiner", | ||
"description": "Java test combining library", | ||
"version": "0.1.3", | ||
"version": "0.1.4", | ||
"main": "build/index.js", | ||
@@ -14,4 +14,4 @@ "types": "build/index.d.ts", | ||
"repository": { | ||
"type" : "git", | ||
"url" : "https://github.com/diffblue/cover-test-combiner-js" | ||
"type": "git", | ||
"url": "https://github.com/diffblue/cover-test-combiner-js" | ||
}, | ||
@@ -25,2 +25,3 @@ "author": "DiffBlue Limited", | ||
"lint": "tslint --project tsconfig.json", | ||
"lint-tests": "tslint test/**/*.ts", | ||
"mutate": "stryker run", | ||
@@ -57,27 +58,20 @@ "test": "mocha", | ||
"devDependencies": { | ||
"@stryker-mutator/core": "2.0.0", | ||
"@stryker-mutator/html-reporter": "2.0.0", | ||
"@stryker-mutator/mocha-framework": "2.0.0", | ||
"@stryker-mutator/mocha-runner": "2.0.0", | ||
"@stryker-mutator/typescript": "2.0.0", | ||
"@types/body-parser": "1.17.0", | ||
"@types/chai": "4.1.7", | ||
"@types/cookie": "0.3.2", | ||
"@types/cors": "2.8.4", | ||
"@types/dotenv-safe": "5.0.3", | ||
"@types/express": "4.16.1", | ||
"@types/lodash": "4.14.123", | ||
"@types/mocha": "5.2.6", | ||
"@types/source-map-support": "0.5.0", | ||
"chai": "4.2.0", | ||
"git-hooks": "git://github.com/rjmunro/git-hooks-js#4b1ac7ca6dd87c24deb60613a56d435921a17154", | ||
"mocha": "6.0.2", | ||
"nodemon": "1.18.10", | ||
"nyc": "13.3.0", | ||
"ts-node": "8.0.3", | ||
"tsc-watch": "2.1.2", | ||
"tslint": "5.14.0", | ||
"@stryker-mutator/core": "2.0.2", | ||
"@stryker-mutator/html-reporter": "2.0.2", | ||
"@stryker-mutator/mocha-framework": "2.0.2", | ||
"@stryker-mutator/mocha-runner": "2.0.2", | ||
"@stryker-mutator/typescript": "2.0.2", | ||
"@types/fs-extra": "8.0.0", | ||
"@types/mocha": "5.2.7", | ||
"fs-extra": "8.1.0", | ||
"git-hooks": "1.1.10", | ||
"mocha": "6.1.4", | ||
"nodemon": "1.19.1", | ||
"nyc": "14.1.1", | ||
"ts-node": "8.3.0", | ||
"tsc-watch": "2.2.1", | ||
"tslint": "5.18.0", | ||
"tslint-eslint-rules": "5.4.0", | ||
"typescript": "3.3.3333" | ||
"typescript": "3.5.3" | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
89487
17
1476