diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..44e5413 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +tests/fixtures diff --git a/package.json b/package.json index 463d0c4..c6e2fd5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nocuous", - "version": "0.4.0", + "version": "0.4.1", "description": "A static code analysis tool for JavaScript and TypeScript.", "main": "index.js", "bin": { @@ -34,6 +34,7 @@ "devDependencies": { "@types/node": "14.0.9", "@types/table": "5.0.0", + "@types/tmp": "^0.2.3", "@types/yargs": "15.0.5", "@typescript-eslint/eslint-plugin": "3.1.0", "@typescript-eslint/parser": "3.1.0", @@ -47,6 +48,7 @@ "prettier": "2.0.5", "pretty-quick": "2.0.1", "rimraf": "3.0.2", + "tmp": "^0.2.1", "ts-node": "8.10.2", "typescript": "3.9.3" }, diff --git a/src/reports/csv.ts b/src/reports/csv.ts index 72e1c8b..673bfc3 100644 --- a/src/reports/csv.ts +++ b/src/reports/csv.ts @@ -39,7 +39,7 @@ export function report( } } row.unshift(`"${path}"`); - row.length = headers.length; + row.length = headers.length + 1; // headers do not have "Path" rows.push(row.join(",")); } const titles = headers.map((h) => `"${labels[h]}"`); diff --git a/tests/fixtures/stats/cyclomaticComplexity.ts b/tests/fixtures/stats/cyclomaticComplexity.ts index b26d125..9d0d4b1 100644 --- a/tests/fixtures/stats/cyclomaticComplexity.ts +++ b/tests/fixtures/stats/cyclomaticComplexity.ts @@ -41,3 +41,24 @@ export function qux(a: string, b: string): string | number { } return 0; } + +export function foo(a: number) { + for (let i = 0; false; i++) { } // FoStatement without added complexity + for (let i = 0; i < 10; i++) { }// FoStatement with added complexity + while (false) { }; // WhileStatement with no added complexity + while (a < 5) { // WhileStatement with added complexity + do { a++ } while (a < 5); // DoStatement + }; + try {} catch {}; // CatchClause + a = a < 0 ? 0 : a; // ConditionalExpression + for (let x in []) {}; // ForInStatement + for (let x of []) {}; // ForOfStatement + function bar() {}; // FunctionDeclaration + const baz = function() {}; // FunctionExpression + const obj = { + foo() {}, // MethodDeclaration + get bar() { return null }, // GetAccessor + set bar(val) {}, // SetAccessor + }; + const Quux = class {}; // ClassExpression +}; diff --git a/tests/unit/reports/csv.ts b/tests/unit/reports/csv.ts new file mode 100644 index 0000000..25d0c66 --- /dev/null +++ b/tests/unit/reports/csv.ts @@ -0,0 +1,31 @@ +import test from "ava"; +import { fileSync } from "tmp"; +import { readFileSync } from "fs"; +import { fixtureAsSourceFile } from "../../util"; +import { stat } from "../../../src/stats/anonInnerLength"; +import { report } from "../../../src/reports/csv"; +import { StatResults } from "../../../src/interfaces"; + +test("reports/csv - works", async (t) => { + const sourceFile = fixtureAsSourceFile("stats/cyclomaticComplexity.ts"); + const results: StatResults = {}; + results["path1/file1"] = []; + results["path2/file2"] = []; + const stat1 = await stat(sourceFile, { threshold: 1 }); + const stat2 = await stat(sourceFile, { threshold: 100 }); + if (stat1) { + results["path1/file1"].push(stat1); + } + if (stat2) { + results["path2/file2"].push(stat2); + } + report(results); + const tempFile = fileSync(); + report(results, { output: tempFile.name }); + const expected = ` +"Path","Anonymous inner length" +"path1/file1",5 +"path2/file2", +`.trim(); + t.is(readFileSync(tempFile.name, "utf-8"), expected); +}); diff --git a/tests/unit/reports/table.ts b/tests/unit/reports/table.ts new file mode 100644 index 0000000..330aca9 --- /dev/null +++ b/tests/unit/reports/table.ts @@ -0,0 +1,22 @@ +import test from "ava"; +import { fixtureAsSourceFile } from "../../util"; +import { stat } from "../../../src/stats/anonInnerLength"; +import { report } from "../../../src/reports/table"; +import { StatResults } from "../../../src/interfaces"; + +test("reports/table - works", async (t) => { + const sourceFile = fixtureAsSourceFile("stats/cyclomaticComplexity.ts"); + const results: StatResults = {}; + results["path1/file1"] = []; + results["path2/file2"] = []; + const stat1 = await stat(sourceFile, { threshold: 1 }); + const stat2 = await stat(sourceFile, { threshold: 100 }); + if (stat1) { + results["path1/file1"].push(stat1); + } + if (stat2) { + results["path2/file2"].push(stat2); + } + report(results); + t.assert(true); +}); diff --git a/tests/unit/stats/cyclomaticComplexity.ts b/tests/unit/stats/cyclomaticComplexity.ts index 245521b..d670a95 100644 --- a/tests/unit/stats/cyclomaticComplexity.ts +++ b/tests/unit/stats/cyclomaticComplexity.ts @@ -14,7 +14,7 @@ test("stats/cyclomaticComplexity - counts functions and methods", async (t) => { const sourceFile = fixtureAsSourceFile("stats/cyclomaticComplexity.ts"); const actual = await stat(sourceFile, { threshold: 10 }); t.assert(actual); - t.is(actual?.count, 7); + t.is(actual?.count, 11); }); test("stats/cyclomaticComplexity - scores based on threshold", async (t) => { diff --git a/tests/unit/util.ts b/tests/unit/util.ts new file mode 100644 index 0000000..53c6697 --- /dev/null +++ b/tests/unit/util.ts @@ -0,0 +1,13 @@ +import test from "ava"; + +import { commonStartsWith, sortPaths } from "../../src/util"; + +test("util/commonStartsWith - no items", async (t) => { + const actual = commonStartsWith(["a/a", "a/b"]); + t.is(actual, "a/"); +}); + +test("util/sortPaths - no items", async (t) => { + const actual = sortPaths(["b/b", "a/b", "a/a"]); + t.deepEqual(actual, ["a/a", "a/b", "b/b"]); +}); diff --git a/yarn.lock b/yarn.lock index 6d15e1c..b9f31c9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -322,6 +322,11 @@ resolved "https://registry.yarnpkg.com/@types/table/-/table-5.0.0.tgz#67c3821138eb41d538c3d9286771c6cdeeac7172" integrity sha512-fQLtGLZXor264zUPWI95WNDsZ3QV43/c0lJpR/h1hhLJumXRmHNsrvBfEzW2YMhb0EWCsn4U6h82IgwsajAuTA== +"@types/tmp@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@types/tmp/-/tmp-0.2.3.tgz#908bfb113419fd6a42273674c00994d40902c165" + integrity sha512-dDZH/tXzwjutnuk4UacGgFRwV+JSLaXL1ikvidfJprkb7L9Nx1njcRHHmi3Dsvt7pgqqTEeucQuOrWHPFgzVHA== + "@types/yargs-parser@*": version "15.0.0" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d" @@ -3616,6 +3621,13 @@ tmp@^0.0.33: dependencies: os-tmpdir "~1.0.2" +tmp@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" + integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== + dependencies: + rimraf "^3.0.0" + to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"