archunit
Version:
ArchUnit TypeScript is an architecture testing library, to specify and assert architecture rules in your TypeScript app
117 lines • 6.54 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
const metrics_1 = require("../../src/metrics");
describe('Custom Metrics Logic', () => {
describe('Custom Metric Builder', () => {
it('should create custom metric builder with calculation function', () => {
const customMetric = (0, metrics_1.metrics)().customMetric('methodFieldRatio', 'Ratio of methods to fields', (classInfo) => {
return classInfo.fields.length === 0
? 0
: classInfo.methods.length / classInfo.fields.length;
});
expect(customMetric).toBeDefined();
expect(customMetric.metricName).toBe('methodFieldRatio');
expect(customMetric.metricDescription).toBe('Ratio of methods to fields');
});
it('should create threshold-based conditions', () => {
const customMetric = (0, metrics_1.metrics)().customMetric('complexityScore', 'Custom complexity score', (classInfo) => classInfo.methods.length + classInfo.fields.length);
// Test all threshold methods
expect(customMetric.shouldBeBelow(10)).toBeDefined();
expect(customMetric.shouldBeBelowOrEqual(10)).toBeDefined();
expect(customMetric.shouldBeAbove(5)).toBeDefined();
expect(customMetric.shouldBeAboveOrEqual(5)).toBeDefined();
expect(customMetric.shouldBe(7)).toBeDefined();
});
it('should create custom assertion conditions', () => {
const customMetric = (0, metrics_1.metrics)().customMetric('hasMinMethods', 'Classes should have minimum methods', (classInfo) => classInfo.methods.length);
const condition = customMetric.shouldSatisfy((value, classInfo) => {
return value >= 2 || classInfo.name.includes('Util');
});
expect(condition).toBeDefined();
expect(condition.check).toBeDefined();
});
});
describe('Custom Metric Conditions', () => {
it('should check threshold-based conditions', async () => {
const condition = (0, metrics_1.metrics)()
.customMetric('methodCount', 'Number of methods', (classInfo) => classInfo.methods.length)
.shouldBeBelowOrEqual(50);
const violations = await condition.check();
expect(Array.isArray(violations)).toBe(true);
// Since this uses real project files, we can only test that the check method works
});
it('should check custom assertion conditions', async () => {
const condition = (0, metrics_1.metrics)()
.customMetric('fieldMethodBalance', 'Balance between fields and methods', (classInfo) => Math.abs(classInfo.fields.length - classInfo.methods.length))
.shouldSatisfy((value, classInfo) => {
// Allow imbalance for classes with very few members
if (classInfo.fields.length + classInfo.methods.length < 3) {
return true;
}
// Otherwise, difference should not be too large
return value <= 5;
});
const violations = await condition.check();
expect(Array.isArray(violations)).toBe(true);
});
it('should work with filters', async () => {
const condition = (0, metrics_1.metrics)()
.inFolder('src/metrics')
.customMetric('simpleFieldCount', 'Count of fields', (classInfo) => classInfo.fields.length)
.shouldBeAbove(-1); // Should always pass
const violations = await condition.check();
expect(Array.isArray(violations)).toBe(true);
});
});
describe('Custom Metric Examples', () => {
it('should calculate method-to-field ratio', async () => {
const condition = (0, metrics_1.metrics)()
.customMetric('methodFieldRatio', 'Ratio of methods to fields', (classInfo) => {
if (classInfo.fields.length === 0) {
return classInfo.methods.length > 0
? Number.MAX_SAFE_INTEGER
: 0;
}
return classInfo.methods.length / classInfo.fields.length;
})
.shouldBeBelowOrEqual(10); // Maximum ratio of 10:1
const violations = await condition.check();
expect(Array.isArray(violations)).toBe(true);
});
it('should detect data classes (many fields, few methods)', async () => {
const condition = (0, metrics_1.metrics)()
.customMetric('dataClassDetector', 'Detect potential data classes', (classInfo) => {
const fieldCount = classInfo.fields.length;
const methodCount = classInfo.methods.length;
// Score increases with more fields and fewer methods
return fieldCount > 0 ? fieldCount / Math.max(methodCount, 1) : 0;
})
.shouldSatisfy((score, classInfo) => {
// Allow data classes if they have few fields or are specifically named
return (score <= 3 ||
classInfo.fields.length <= 2 ||
classInfo.name.includes('Data'));
});
const violations = await condition.check();
expect(Array.isArray(violations)).toBe(true);
});
it('should check method naming consistency', async () => {
const condition = (0, metrics_1.metrics)()
.customMetric('namingConsistency', 'Method naming consistency', (classInfo) => {
const getterMethods = classInfo.methods.filter((m) => m.name.startsWith('get')).length;
const setterMethods = classInfo.methods.filter((m) => m.name.startsWith('set')).length;
// Return the difference - should be small for consistent naming
return Math.abs(getterMethods - setterMethods);
})
.shouldSatisfy((difference, classInfo) => {
// Allow difference for small classes or utility classes
return (difference <= 2 ||
classInfo.methods.length <= 3 ||
classInfo.name.includes('Util'));
});
const violations = await condition.check();
expect(Array.isArray(violations)).toBe(true);
});
});
});
//# sourceMappingURL=custom-metrics.spec.js.map
;