UNPKG

code-complexity

Version:

Measure the churn/complexity score. Higher values mean hotspots where refactorings should happen.

469 lines (426 loc) 11.9 kB
import { sep } from "node:path"; import { tmpdir } from "node:os"; import { expect } from "chai"; import { Options } from "../../src/lib/types"; import Statistics from "../../src/lib"; import TestRepositoryFixture from "../fixtures/test-repository.fixture"; describe("Statistics", () => { const defaultOptions: Options = { directory: tmpdir() + sep + TestRepositoryFixture.testRepositoryName, target: tmpdir() + sep + TestRepositoryFixture.testRepositoryName, format: "json", filter: [], limit: 3, since: undefined, sort: "score", }; context("options.limit", () => { it("returns the appropriate number of elements", async () => { // Given const options: Options = { ...defaultOptions, limit: 3 }; new TestRepositoryFixture() .addFile({ name: "a.js" }) .addFile({ name: "b.js" }) .addFile({ name: "c.js" }) .addFile({ name: "d.js" }) .writeOnDisk(); // When const result = (await Statistics.compute(options)).list(); // Then expect(result).to.have.length(3); }); }); context("options.filter", () => { it("returns the appropriate elements", async () => { // Given const options: Options = { ...defaultOptions, filter: ["*.js"], }; new TestRepositoryFixture() .addFile({ name: "a.js" }) .addFile({ name: "b.md" }) .addFile({ name: "c.js" }) .writeOnDisk(); // When const result = (await Statistics.compute(options)).list(); // Then expect(result).to.deep.equal([ { churn: 1, complexity: 1, path: "a.js", score: 1, }, { churn: 1, complexity: 1, path: "c.js", score: 1, }, ]); }); }); context("options.since", () => { it("returns the appropriate elements", async () => { // Given const options: Options = { ...defaultOptions, since: "2010-01-01" }; new TestRepositoryFixture() .addFile({ name: "a.js", date: "2000-01-01T00:00:00" }) .addFile({ name: "b.js", date: "2020-01-01T00:00:00" }) .addFile({ name: "c.js", date: "2020-01-01T00:00:00" }) .writeOnDisk(); // When const result = (await Statistics.compute(options)).list(); // Then expect(result).to.deep.equal([ { churn: 1, complexity: 1, path: "b.js", score: 1, }, { churn: 1, complexity: 1, path: "c.js", score: 1, }, ]); }); }); context("options.until", () => { it("returns the appropriate elements", async () => { // Given const options: Options = { ...defaultOptions, until: "2010-01-01" }; new TestRepositoryFixture() .addFile({ name: "a.js", date: "2000-01-01T00:00:00" }) .addFile({ name: "b.js", date: "2020-01-01T00:00:00" }) .addFile({ name: "c.js", date: "2020-01-01T00:00:00" }) .writeOnDisk(); // When const result = (await Statistics.compute(options)).list(); // Then expect(result).to.deep.equal([ { churn: 1, complexity: 1, path: "a.js", score: 1, }, ]); }); }); context("options.sort=score", () => { it("returns the appropriate elements", async () => { // Given const options: Options = { ...defaultOptions, sort: "score" }; new TestRepositoryFixture() .addFile({ name: "a.js", lines: 1, commits: 4 }) .addFile({ name: "b.js", lines: 3, commits: 3 }) .addFile({ name: "c.js", lines: 3, commits: 2 }) .addFile({ name: "d.js", lines: 4, commits: 2 }) .writeOnDisk(); // When const result = (await Statistics.compute(options)).list(); // Then expect(result).to.deep.equal([ { churn: 3, complexity: 3, path: "b.js", score: 9, }, { churn: 2, complexity: 4, path: "d.js", score: 8, }, { churn: 2, complexity: 3, path: "c.js", score: 6, }, ]); }); }); context("options.sort=complexity", () => { context("when using cyclomatic strategy", () => { it("returns the appropriate elements", async () => { // Given const options: Options = { ...defaultOptions, sort: "complexity", complexityStrategy: "cyclomatic", }; new TestRepositoryFixture() .addFile({ name: "a.ts", content: "if (true) if (true) console.log();", }) .addFile({ name: "b.js", content: "if (true) if (true) console.log();", }) .writeOnDisk(); // When const result = (await Statistics.compute(options)).list(); // Then expect(result).to.deep.equal([ { churn: 1, complexity: 3, path: "a.ts", score: 3, }, { churn: 1, complexity: 3, path: "b.js", score: 3, }, ]); }); }); context("when using halstead strategy", () => { it("returns the appropriate elements", async () => { // Given const options: Options = { ...defaultOptions, sort: "complexity", complexityStrategy: "halstead", }; new TestRepositoryFixture() .addFile({ name: "a.ts", content: "if (true) if (true) console.log();", }) .addFile({ name: "b.js", content: "if (true) if (true) console.log();", }) .writeOnDisk(); // When const result = (await Statistics.compute(options)).list(); // Then expect(result).to.deep.equal([ { churn: 1, complexity: 25.26619429851844, path: "a.ts", score: 25.26619429851844, }, { churn: 1, complexity: 25.26619429851844, path: "b.js", score: 25.26619429851844, }, ]); }); }); context("when using sloc strategy", () => { context("when analyzed file is supported by node-sloc", () => { it("returns the appropriate elements", async () => { // Given const options: Options = { ...defaultOptions, complexityStrategy: "sloc", sort: "complexity", }; new TestRepositoryFixture() .addFile({ name: "a.js", lines: 8 }) .addFile({ name: "b.js", lines: 6 }) .addFile({ name: "c.js", lines: 2 }) .addFile({ name: "d.js", lines: 4 }) .writeOnDisk(); // When const result = (await Statistics.compute(options)).list(); // Then expect(result).to.deep.equal([ { churn: 1, complexity: 8, path: "a.js", score: 8, }, { churn: 1, complexity: 6, path: "b.js", score: 6, }, { churn: 1, complexity: 4, path: "d.js", score: 4, }, ]); }); }); context("when analyzed file is not supported by node-sloc", () => { it("returns the appropriate elements", async () => { // Given const options: Options = { ...defaultOptions, complexityStrategy: "sloc", sort: "complexity", }; new TestRepositoryFixture() .addFile({ name: "a.txt", lines: 8 }) .writeOnDisk(); // When const result = (await Statistics.compute(options)).list(); // Then expect(result).to.deep.equal([ { churn: 1, complexity: 7, path: "a.txt", score: 7, }, ]); }); }); }); }); context("options.sort=churn", () => { it("returns the appropriate elements", async () => { // Given const options: Options = { ...defaultOptions, sort: "churn" }; new TestRepositoryFixture() .addFile({ name: "a.js", commits: 7 }) .addFile({ name: "b.js", commits: 3 }) .addFile({ name: "c.js", commits: 5 }) .addFile({ name: "d.js", commits: 2 }) .writeOnDisk(); // When const result = (await Statistics.compute(options)).list(); // Then expect(result).to.deep.equal([ { churn: 7, complexity: 1, path: "a.js", score: 7, }, { churn: 5, complexity: 1, path: "c.js", score: 5, }, { churn: 3, complexity: 1, path: "b.js", score: 3, }, ]); }); }); context("options.sort=file", () => { it("returns the appropriate elements", async () => { // Given const options: Options = { ...defaultOptions, sort: "file" }; new TestRepositoryFixture() .addFile({ name: "d.js", lines: 1, commits: 4 }) .addFile({ name: "a.js", lines: 2, commits: 3 }) .addFile({ name: "c.js", lines: 3, commits: 2 }) .addFile({ name: "b.js", lines: 4, commits: 1 }) .writeOnDisk(); // When const result = (await Statistics.compute(options)).list(); // Then expect(result).to.deep.equal([ { churn: 3, complexity: 2, path: "a.js", score: 6, }, { churn: 1, complexity: 4, path: "b.js", score: 4, }, { churn: 2, complexity: 3, path: "c.js", score: 6, }, ]); }); }); context("options.directories=true", () => { it("returns the appropriate elements", async () => { // Given const options: Options = { ...defaultOptions, limit: 4, directories: true, }; new TestRepositoryFixture() .addFile({ name: "test/a.js" }) .addFile({ name: "test/foo/b.js" }) .addFile({ name: "test/foo/c.js" }) .addFile({ name: "test/bar/qux/d.js" }) .writeOnDisk(); // When const result = (await Statistics.compute(options)).list(); // Then expect(result).to.deep.equal([ { path: "test", churn: 4, complexity: 4, score: 16, }, { path: "test/foo", churn: 2, complexity: 2, score: 4, }, { path: "test/bar", churn: 1, complexity: 1, score: 1, }, { path: "test/bar/qux", churn: 1, complexity: 1, score: 1, }, ]); }); }); context("when file no longer exists", () => { it("it is ignored", async () => { // Given const options: Options = { ...defaultOptions, sort: "file" }; new TestRepositoryFixture() .addFile({ name: "a.js", removed: true }) .addFile({ name: "b.ts" }) .writeOnDisk(); // When const result = (await Statistics.compute(options)).list(); // Then expect(result).to.deep.equal([ { churn: 1, complexity: 1, path: "b.ts", score: 1, }, ]); }); }); });