mirror of
https://github.com/samiyev/puaros.git
synced 2025-12-27 23:06:54 +05:00
feat(guardian): add guardian package - code quality analyzer
Add @puaros/guardian package v0.1.0 - code quality guardian for vibe coders and enterprise teams. Features: - Hardcode detection (magic numbers, magic strings) - Circular dependency detection - Naming convention enforcement (Clean Architecture) - Architecture violation detection - CLI tool with comprehensive reporting - 159 tests with 80%+ coverage - Smart suggestions for fixes - Built for AI-assisted development Built with Clean Architecture and DDD principles. Works with Claude, GPT, Copilot, Cursor, and any AI coding assistant.
This commit is contained in:
46
packages/guardian/tests/unit/domain/BaseEntity.test.ts
Normal file
46
packages/guardian/tests/unit/domain/BaseEntity.test.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { describe, it, expect } from "vitest"
|
||||
import { BaseEntity } from "../../../src/domain/entities/BaseEntity"
|
||||
|
||||
class TestEntity extends BaseEntity {
|
||||
constructor(id?: string) {
|
||||
super(id)
|
||||
}
|
||||
}
|
||||
|
||||
describe("BaseEntity", () => {
|
||||
it("should create an entity with generated id", () => {
|
||||
const entity = new TestEntity()
|
||||
expect(entity.id).toBeDefined()
|
||||
expect(typeof entity.id).toBe("string")
|
||||
})
|
||||
|
||||
it("should create an entity with provided id", () => {
|
||||
const customId = "custom-id-123"
|
||||
const entity = new TestEntity(customId)
|
||||
expect(entity.id).toBe(customId)
|
||||
})
|
||||
|
||||
it("should have createdAt and updatedAt timestamps", () => {
|
||||
const entity = new TestEntity()
|
||||
expect(entity.createdAt).toBeInstanceOf(Date)
|
||||
expect(entity.updatedAt).toBeInstanceOf(Date)
|
||||
})
|
||||
|
||||
it("should return true when comparing same entity", () => {
|
||||
const entity = new TestEntity()
|
||||
expect(entity.equals(entity)).toBe(true)
|
||||
})
|
||||
|
||||
it("should return true when comparing entities with same id", () => {
|
||||
const id = "same-id"
|
||||
const entity1 = new TestEntity(id)
|
||||
const entity2 = new TestEntity(id)
|
||||
expect(entity1.equals(entity2)).toBe(true)
|
||||
})
|
||||
|
||||
it("should return false when comparing entities with different ids", () => {
|
||||
const entity1 = new TestEntity()
|
||||
const entity2 = new TestEntity()
|
||||
expect(entity1.equals(entity2)).toBe(false)
|
||||
})
|
||||
})
|
||||
234
packages/guardian/tests/unit/domain/DependencyGraph.test.ts
Normal file
234
packages/guardian/tests/unit/domain/DependencyGraph.test.ts
Normal file
@@ -0,0 +1,234 @@
|
||||
import { describe, it, expect } from "vitest"
|
||||
import { DependencyGraph } from "../../../src/domain/entities/DependencyGraph"
|
||||
import { SourceFile } from "../../../src/domain/entities/SourceFile"
|
||||
import { ProjectPath } from "../../../src/domain/value-objects/ProjectPath"
|
||||
|
||||
describe("DependencyGraph", () => {
|
||||
describe("basic operations", () => {
|
||||
it("should create an empty dependency graph", () => {
|
||||
const graph = new DependencyGraph()
|
||||
expect(graph.getAllNodes()).toHaveLength(0)
|
||||
})
|
||||
|
||||
it("should add a file to the graph", () => {
|
||||
const graph = new DependencyGraph()
|
||||
const path = ProjectPath.create("/project/src/file.ts", "/project")
|
||||
const file = new SourceFile(path, "const x = 1")
|
||||
|
||||
graph.addFile(file)
|
||||
|
||||
expect(graph.getAllNodes()).toHaveLength(1)
|
||||
expect(graph.getNode("src/file.ts")).toBeDefined()
|
||||
})
|
||||
|
||||
it("should add dependencies between files", () => {
|
||||
const graph = new DependencyGraph()
|
||||
const path1 = ProjectPath.create("/project/src/file1.ts", "/project")
|
||||
const path2 = ProjectPath.create("/project/src/file2.ts", "/project")
|
||||
const file1 = new SourceFile(path1, "import { x } from './file2'")
|
||||
const file2 = new SourceFile(path2, "export const x = 1")
|
||||
|
||||
graph.addFile(file1)
|
||||
graph.addFile(file2)
|
||||
graph.addDependency("src/file1.ts", "src/file2.ts")
|
||||
|
||||
const node1 = graph.getNode("src/file1.ts")
|
||||
expect(node1?.dependencies).toContain("src/file2.ts")
|
||||
|
||||
const node2 = graph.getNode("src/file2.ts")
|
||||
expect(node2?.dependents).toContain("src/file1.ts")
|
||||
})
|
||||
|
||||
it("should get metrics", () => {
|
||||
const graph = new DependencyGraph()
|
||||
const path1 = ProjectPath.create("/project/src/file1.ts", "/project")
|
||||
const path2 = ProjectPath.create("/project/src/file2.ts", "/project")
|
||||
const file1 = new SourceFile(path1, "")
|
||||
const file2 = new SourceFile(path2, "")
|
||||
|
||||
graph.addFile(file1)
|
||||
graph.addFile(file2)
|
||||
graph.addDependency("src/file1.ts", "src/file2.ts")
|
||||
|
||||
const metrics = graph.getMetrics()
|
||||
expect(metrics.totalFiles).toBe(2)
|
||||
expect(metrics.totalDependencies).toBe(1)
|
||||
})
|
||||
})
|
||||
|
||||
describe("findCycles", () => {
|
||||
it("should return empty array when no cycles exist", () => {
|
||||
const graph = new DependencyGraph()
|
||||
const path1 = ProjectPath.create("/project/src/a.ts", "/project")
|
||||
const path2 = ProjectPath.create("/project/src/b.ts", "/project")
|
||||
const path3 = ProjectPath.create("/project/src/c.ts", "/project")
|
||||
|
||||
const fileA = new SourceFile(path1, "")
|
||||
const fileB = new SourceFile(path2, "")
|
||||
const fileC = new SourceFile(path3, "")
|
||||
|
||||
graph.addFile(fileA)
|
||||
graph.addFile(fileB)
|
||||
graph.addFile(fileC)
|
||||
|
||||
graph.addDependency("src/a.ts", "src/b.ts")
|
||||
graph.addDependency("src/b.ts", "src/c.ts")
|
||||
|
||||
const cycles = graph.findCycles()
|
||||
expect(cycles).toHaveLength(0)
|
||||
})
|
||||
|
||||
it("should detect simple two-file cycle (A → B → A)", () => {
|
||||
const graph = new DependencyGraph()
|
||||
const pathA = ProjectPath.create("/project/src/a.ts", "/project")
|
||||
const pathB = ProjectPath.create("/project/src/b.ts", "/project")
|
||||
|
||||
const fileA = new SourceFile(pathA, "import { b } from './b'")
|
||||
const fileB = new SourceFile(pathB, "import { a } from './a'")
|
||||
|
||||
graph.addFile(fileA)
|
||||
graph.addFile(fileB)
|
||||
graph.addDependency("src/a.ts", "src/b.ts")
|
||||
graph.addDependency("src/b.ts", "src/a.ts")
|
||||
|
||||
const cycles = graph.findCycles()
|
||||
expect(cycles.length).toBeGreaterThan(0)
|
||||
|
||||
const cycle = cycles[0]
|
||||
expect(cycle).toContain("src/a.ts")
|
||||
expect(cycle).toContain("src/b.ts")
|
||||
})
|
||||
|
||||
it("should detect three-file cycle (A → B → C → A)", () => {
|
||||
const graph = new DependencyGraph()
|
||||
const pathA = ProjectPath.create("/project/src/a.ts", "/project")
|
||||
const pathB = ProjectPath.create("/project/src/b.ts", "/project")
|
||||
const pathC = ProjectPath.create("/project/src/c.ts", "/project")
|
||||
|
||||
const fileA = new SourceFile(pathA, "")
|
||||
const fileB = new SourceFile(pathB, "")
|
||||
const fileC = new SourceFile(pathC, "")
|
||||
|
||||
graph.addFile(fileA)
|
||||
graph.addFile(fileB)
|
||||
graph.addFile(fileC)
|
||||
|
||||
graph.addDependency("src/a.ts", "src/b.ts")
|
||||
graph.addDependency("src/b.ts", "src/c.ts")
|
||||
graph.addDependency("src/c.ts", "src/a.ts")
|
||||
|
||||
const cycles = graph.findCycles()
|
||||
expect(cycles.length).toBeGreaterThan(0)
|
||||
|
||||
const cycle = cycles[0]
|
||||
expect(cycle).toContain("src/a.ts")
|
||||
expect(cycle).toContain("src/b.ts")
|
||||
expect(cycle).toContain("src/c.ts")
|
||||
})
|
||||
|
||||
it("should detect longer cycles (A → B → C → D → A)", () => {
|
||||
const graph = new DependencyGraph()
|
||||
const pathA = ProjectPath.create("/project/src/a.ts", "/project")
|
||||
const pathB = ProjectPath.create("/project/src/b.ts", "/project")
|
||||
const pathC = ProjectPath.create("/project/src/c.ts", "/project")
|
||||
const pathD = ProjectPath.create("/project/src/d.ts", "/project")
|
||||
|
||||
const fileA = new SourceFile(pathA, "")
|
||||
const fileB = new SourceFile(pathB, "")
|
||||
const fileC = new SourceFile(pathC, "")
|
||||
const fileD = new SourceFile(pathD, "")
|
||||
|
||||
graph.addFile(fileA)
|
||||
graph.addFile(fileB)
|
||||
graph.addFile(fileC)
|
||||
graph.addFile(fileD)
|
||||
|
||||
graph.addDependency("src/a.ts", "src/b.ts")
|
||||
graph.addDependency("src/b.ts", "src/c.ts")
|
||||
graph.addDependency("src/c.ts", "src/d.ts")
|
||||
graph.addDependency("src/d.ts", "src/a.ts")
|
||||
|
||||
const cycles = graph.findCycles()
|
||||
expect(cycles.length).toBeGreaterThan(0)
|
||||
|
||||
const cycle = cycles[0]
|
||||
expect(cycle.length).toBe(4)
|
||||
expect(cycle).toContain("src/a.ts")
|
||||
expect(cycle).toContain("src/b.ts")
|
||||
expect(cycle).toContain("src/c.ts")
|
||||
expect(cycle).toContain("src/d.ts")
|
||||
})
|
||||
|
||||
it("should detect multiple independent cycles", () => {
|
||||
const graph = new DependencyGraph()
|
||||
|
||||
const pathA = ProjectPath.create("/project/src/a.ts", "/project")
|
||||
const pathB = ProjectPath.create("/project/src/b.ts", "/project")
|
||||
const pathC = ProjectPath.create("/project/src/c.ts", "/project")
|
||||
const pathD = ProjectPath.create("/project/src/d.ts", "/project")
|
||||
|
||||
const fileA = new SourceFile(pathA, "")
|
||||
const fileB = new SourceFile(pathB, "")
|
||||
const fileC = new SourceFile(pathC, "")
|
||||
const fileD = new SourceFile(pathD, "")
|
||||
|
||||
graph.addFile(fileA)
|
||||
graph.addFile(fileB)
|
||||
graph.addFile(fileC)
|
||||
graph.addFile(fileD)
|
||||
|
||||
graph.addDependency("src/a.ts", "src/b.ts")
|
||||
graph.addDependency("src/b.ts", "src/a.ts")
|
||||
|
||||
graph.addDependency("src/c.ts", "src/d.ts")
|
||||
graph.addDependency("src/d.ts", "src/c.ts")
|
||||
|
||||
const cycles = graph.findCycles()
|
||||
expect(cycles.length).toBeGreaterThanOrEqual(2)
|
||||
})
|
||||
|
||||
it("should handle complex graph with cycle and acyclic parts", () => {
|
||||
const graph = new DependencyGraph()
|
||||
|
||||
const pathA = ProjectPath.create("/project/src/a.ts", "/project")
|
||||
const pathB = ProjectPath.create("/project/src/b.ts", "/project")
|
||||
const pathC = ProjectPath.create("/project/src/c.ts", "/project")
|
||||
const pathD = ProjectPath.create("/project/src/d.ts", "/project")
|
||||
|
||||
const fileA = new SourceFile(pathA, "")
|
||||
const fileB = new SourceFile(pathB, "")
|
||||
const fileC = new SourceFile(pathC, "")
|
||||
const fileD = new SourceFile(pathD, "")
|
||||
|
||||
graph.addFile(fileA)
|
||||
graph.addFile(fileB)
|
||||
graph.addFile(fileC)
|
||||
graph.addFile(fileD)
|
||||
|
||||
graph.addDependency("src/a.ts", "src/b.ts")
|
||||
graph.addDependency("src/b.ts", "src/a.ts")
|
||||
|
||||
graph.addDependency("src/c.ts", "src/d.ts")
|
||||
|
||||
const cycles = graph.findCycles()
|
||||
expect(cycles.length).toBeGreaterThan(0)
|
||||
|
||||
const cycle = cycles[0]
|
||||
expect(cycle).toContain("src/a.ts")
|
||||
expect(cycle).toContain("src/b.ts")
|
||||
expect(cycle).not.toContain("src/c.ts")
|
||||
expect(cycle).not.toContain("src/d.ts")
|
||||
})
|
||||
|
||||
it("should handle single file without dependencies", () => {
|
||||
const graph = new DependencyGraph()
|
||||
const path = ProjectPath.create("/project/src/a.ts", "/project")
|
||||
const file = new SourceFile(path, "")
|
||||
|
||||
graph.addFile(file)
|
||||
|
||||
const cycles = graph.findCycles()
|
||||
expect(cycles).toHaveLength(0)
|
||||
})
|
||||
})
|
||||
})
|
||||
358
packages/guardian/tests/unit/domain/HardcodedValue.test.ts
Normal file
358
packages/guardian/tests/unit/domain/HardcodedValue.test.ts
Normal file
@@ -0,0 +1,358 @@
|
||||
import { describe, it, expect } from "vitest"
|
||||
import { HardcodedValue } from "../../../src/domain/value-objects/HardcodedValue"
|
||||
import { HARDCODE_TYPES } from "../../../src/shared/constants"
|
||||
|
||||
describe("HardcodedValue", () => {
|
||||
describe("create", () => {
|
||||
it("should create a magic number value", () => {
|
||||
const value = HardcodedValue.create(
|
||||
5000,
|
||||
HARDCODE_TYPES.MAGIC_NUMBER,
|
||||
10,
|
||||
20,
|
||||
"setTimeout(() => {}, 5000)",
|
||||
)
|
||||
|
||||
expect(value.value).toBe(5000)
|
||||
expect(value.type).toBe(HARDCODE_TYPES.MAGIC_NUMBER)
|
||||
expect(value.line).toBe(10)
|
||||
expect(value.column).toBe(20)
|
||||
expect(value.context).toBe("setTimeout(() => {}, 5000)")
|
||||
})
|
||||
|
||||
it("should create a magic string value", () => {
|
||||
const value = HardcodedValue.create(
|
||||
"http://localhost:8080",
|
||||
HARDCODE_TYPES.MAGIC_STRING,
|
||||
5,
|
||||
15,
|
||||
'const url = "http://localhost:8080"',
|
||||
)
|
||||
|
||||
expect(value.value).toBe("http://localhost:8080")
|
||||
expect(value.type).toBe(HARDCODE_TYPES.MAGIC_STRING)
|
||||
})
|
||||
})
|
||||
|
||||
describe("isMagicNumber", () => {
|
||||
it("should return true for magic numbers", () => {
|
||||
const value = HardcodedValue.create(
|
||||
3000,
|
||||
HARDCODE_TYPES.MAGIC_NUMBER,
|
||||
1,
|
||||
1,
|
||||
"timeout = 3000",
|
||||
)
|
||||
|
||||
expect(value.isMagicNumber()).toBe(true)
|
||||
})
|
||||
|
||||
it("should return false for magic strings", () => {
|
||||
const value = HardcodedValue.create(
|
||||
"some string",
|
||||
HARDCODE_TYPES.MAGIC_STRING,
|
||||
1,
|
||||
1,
|
||||
"const str = 'some string'",
|
||||
)
|
||||
|
||||
expect(value.isMagicNumber()).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe("isMagicString", () => {
|
||||
it("should return true for magic strings", () => {
|
||||
const value = HardcodedValue.create(
|
||||
"http://localhost",
|
||||
HARDCODE_TYPES.MAGIC_STRING,
|
||||
1,
|
||||
1,
|
||||
'url = "http://localhost"',
|
||||
)
|
||||
|
||||
expect(value.isMagicString()).toBe(true)
|
||||
})
|
||||
|
||||
it("should return false for magic numbers", () => {
|
||||
const value = HardcodedValue.create(
|
||||
8080,
|
||||
HARDCODE_TYPES.MAGIC_NUMBER,
|
||||
1,
|
||||
1,
|
||||
"port = 8080",
|
||||
)
|
||||
|
||||
expect(value.isMagicString()).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe("suggestConstantName for numbers", () => {
|
||||
it("should suggest TIMEOUT_MS for timeout context", () => {
|
||||
const value = HardcodedValue.create(
|
||||
5000,
|
||||
HARDCODE_TYPES.MAGIC_NUMBER,
|
||||
1,
|
||||
1,
|
||||
"const timeout = 5000",
|
||||
)
|
||||
|
||||
expect(value.suggestConstantName()).toBe("TIMEOUT_MS")
|
||||
})
|
||||
|
||||
it("should suggest MAX_RETRIES for retry context", () => {
|
||||
const value = HardcodedValue.create(
|
||||
3,
|
||||
HARDCODE_TYPES.MAGIC_NUMBER,
|
||||
1,
|
||||
1,
|
||||
"const retry = 3",
|
||||
)
|
||||
|
||||
expect(value.suggestConstantName()).toBe("MAX_RETRIES")
|
||||
})
|
||||
|
||||
it("should suggest MAX_RETRIES for attempts context", () => {
|
||||
const value = HardcodedValue.create(
|
||||
5,
|
||||
HARDCODE_TYPES.MAGIC_NUMBER,
|
||||
1,
|
||||
1,
|
||||
"const attempts = 5",
|
||||
)
|
||||
|
||||
expect(value.suggestConstantName()).toBe("MAX_RETRIES")
|
||||
})
|
||||
|
||||
it("should suggest MAX_LIMIT for limit context", () => {
|
||||
const value = HardcodedValue.create(
|
||||
100,
|
||||
HARDCODE_TYPES.MAGIC_NUMBER,
|
||||
1,
|
||||
1,
|
||||
"const limit = 100",
|
||||
)
|
||||
|
||||
expect(value.suggestConstantName()).toBe("MAX_LIMIT")
|
||||
})
|
||||
|
||||
it("should suggest MAX_LIMIT for max context", () => {
|
||||
const value = HardcodedValue.create(
|
||||
50,
|
||||
HARDCODE_TYPES.MAGIC_NUMBER,
|
||||
1,
|
||||
1,
|
||||
"const max = 50",
|
||||
)
|
||||
|
||||
expect(value.suggestConstantName()).toBe("MAX_LIMIT")
|
||||
})
|
||||
|
||||
it("should suggest DEFAULT_PORT for port context", () => {
|
||||
const value = HardcodedValue.create(
|
||||
8080,
|
||||
HARDCODE_TYPES.MAGIC_NUMBER,
|
||||
1,
|
||||
1,
|
||||
"const port = 8080",
|
||||
)
|
||||
|
||||
expect(value.suggestConstantName()).toBe("DEFAULT_PORT")
|
||||
})
|
||||
|
||||
it("should suggest DELAY_MS for delay context", () => {
|
||||
const value = HardcodedValue.create(
|
||||
1000,
|
||||
HARDCODE_TYPES.MAGIC_NUMBER,
|
||||
1,
|
||||
1,
|
||||
"const delay = 1000",
|
||||
)
|
||||
|
||||
expect(value.suggestConstantName()).toBe("DELAY_MS")
|
||||
})
|
||||
|
||||
it("should suggest MAGIC_NUMBER_<value> for unknown context", () => {
|
||||
const value = HardcodedValue.create(
|
||||
999,
|
||||
HARDCODE_TYPES.MAGIC_NUMBER,
|
||||
1,
|
||||
1,
|
||||
"const x = 999",
|
||||
)
|
||||
|
||||
expect(value.suggestConstantName()).toBe("MAGIC_NUMBER_999")
|
||||
})
|
||||
})
|
||||
|
||||
describe("suggestConstantName for strings", () => {
|
||||
it("should suggest API_BASE_URL for http URLs", () => {
|
||||
const value = HardcodedValue.create(
|
||||
"http://localhost:3000",
|
||||
HARDCODE_TYPES.MAGIC_STRING,
|
||||
1,
|
||||
1,
|
||||
'const url = "http://localhost:3000"',
|
||||
)
|
||||
|
||||
expect(value.suggestConstantName()).toBe("API_BASE_URL")
|
||||
})
|
||||
|
||||
it("should suggest API_BASE_URL for https URLs", () => {
|
||||
const value = HardcodedValue.create(
|
||||
"https://api.example.com",
|
||||
HARDCODE_TYPES.MAGIC_STRING,
|
||||
1,
|
||||
1,
|
||||
'const url = "https://api.example.com"',
|
||||
)
|
||||
|
||||
expect(value.suggestConstantName()).toBe("API_BASE_URL")
|
||||
})
|
||||
|
||||
it("should suggest DEFAULT_DOMAIN for domain-like strings", () => {
|
||||
const value = HardcodedValue.create(
|
||||
"example.com",
|
||||
HARDCODE_TYPES.MAGIC_STRING,
|
||||
1,
|
||||
1,
|
||||
'const domain = "example.com"',
|
||||
)
|
||||
|
||||
expect(value.suggestConstantName()).toBe("DEFAULT_DOMAIN")
|
||||
})
|
||||
|
||||
it("should suggest DEFAULT_PATH for path-like strings", () => {
|
||||
const value = HardcodedValue.create(
|
||||
"api.example.com/users",
|
||||
HARDCODE_TYPES.MAGIC_STRING,
|
||||
1,
|
||||
1,
|
||||
'const path = "api.example.com/users"',
|
||||
)
|
||||
|
||||
expect(value.suggestConstantName()).toBe("DEFAULT_PATH")
|
||||
})
|
||||
|
||||
it("should suggest ERROR_MESSAGE for error context", () => {
|
||||
const value = HardcodedValue.create(
|
||||
"Something went wrong",
|
||||
HARDCODE_TYPES.MAGIC_STRING,
|
||||
1,
|
||||
1,
|
||||
'const error = "Something went wrong"',
|
||||
)
|
||||
|
||||
expect(value.suggestConstantName()).toBe("ERROR_MESSAGE")
|
||||
})
|
||||
|
||||
it("should suggest ERROR_MESSAGE for message context", () => {
|
||||
const value = HardcodedValue.create(
|
||||
"Invalid input",
|
||||
HARDCODE_TYPES.MAGIC_STRING,
|
||||
1,
|
||||
1,
|
||||
'const message = "Invalid input"',
|
||||
)
|
||||
|
||||
expect(value.suggestConstantName()).toBe("ERROR_MESSAGE")
|
||||
})
|
||||
|
||||
it("should suggest DEFAULT_VALUE for default context", () => {
|
||||
const value = HardcodedValue.create(
|
||||
"default value",
|
||||
HARDCODE_TYPES.MAGIC_STRING,
|
||||
1,
|
||||
1,
|
||||
'const default = "default value"',
|
||||
)
|
||||
|
||||
expect(value.suggestConstantName()).toBe("DEFAULT_VALUE")
|
||||
})
|
||||
|
||||
it("should suggest MAGIC_STRING for unknown context", () => {
|
||||
const value = HardcodedValue.create(
|
||||
"some random string",
|
||||
HARDCODE_TYPES.MAGIC_STRING,
|
||||
1,
|
||||
1,
|
||||
'const x = "some random string"',
|
||||
)
|
||||
|
||||
expect(value.suggestConstantName()).toBe("MAGIC_STRING")
|
||||
})
|
||||
})
|
||||
|
||||
describe("suggestLocation", () => {
|
||||
it("should suggest shared/constants when no layer specified", () => {
|
||||
const value = HardcodedValue.create(
|
||||
5000,
|
||||
HARDCODE_TYPES.MAGIC_NUMBER,
|
||||
1,
|
||||
1,
|
||||
"timeout = 5000",
|
||||
)
|
||||
|
||||
expect(value.suggestLocation()).toBe("shared/constants")
|
||||
})
|
||||
|
||||
it("should suggest shared/constants for general values", () => {
|
||||
const value = HardcodedValue.create(
|
||||
8080,
|
||||
HARDCODE_TYPES.MAGIC_NUMBER,
|
||||
1,
|
||||
1,
|
||||
"port = 8080",
|
||||
)
|
||||
|
||||
expect(value.suggestLocation("infrastructure")).toBe("shared/constants")
|
||||
})
|
||||
|
||||
it("should suggest layer/constants for domain context", () => {
|
||||
const value = HardcodedValue.create(
|
||||
100,
|
||||
HARDCODE_TYPES.MAGIC_NUMBER,
|
||||
1,
|
||||
1,
|
||||
"entity limit = 100",
|
||||
)
|
||||
|
||||
expect(value.suggestLocation("domain")).toBe("domain/constants")
|
||||
})
|
||||
|
||||
it("should suggest layer/constants for aggregate context", () => {
|
||||
const value = HardcodedValue.create(
|
||||
50,
|
||||
HARDCODE_TYPES.MAGIC_NUMBER,
|
||||
1,
|
||||
1,
|
||||
"aggregate max = 50",
|
||||
)
|
||||
|
||||
expect(value.suggestLocation("domain")).toBe("domain/constants")
|
||||
})
|
||||
|
||||
it("should suggest infrastructure/config for config context", () => {
|
||||
const value = HardcodedValue.create(
|
||||
3000,
|
||||
HARDCODE_TYPES.MAGIC_NUMBER,
|
||||
1,
|
||||
1,
|
||||
"config timeout = 3000",
|
||||
)
|
||||
|
||||
expect(value.suggestLocation("infrastructure")).toBe("infrastructure/config")
|
||||
})
|
||||
|
||||
it("should suggest infrastructure/config for env context", () => {
|
||||
const value = HardcodedValue.create(
|
||||
"production",
|
||||
HARDCODE_TYPES.MAGIC_STRING,
|
||||
1,
|
||||
1,
|
||||
'env mode = "production"',
|
||||
)
|
||||
|
||||
expect(value.suggestLocation("infrastructure")).toBe("infrastructure/config")
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user