2021-02-05 14:24:41 +01:00
|
|
|
import fs from 'fs';
|
2021-05-20 11:24:59 +02:00
|
|
|
import path from 'path';
|
2021-02-05 14:24:41 +01:00
|
|
|
|
2022-01-17 20:13:15 +01:00
|
|
|
import { generateOneRuleMetadata, generateRulesMetadata } from '../metadata';
|
2021-02-05 14:24:41 +01:00
|
|
|
import { withTestDir, createFiles } from '../testutils';
|
|
|
|
|
|
|
|
describe('metadata generation', () => {
|
|
|
|
|
|
|
|
test('language specific metadata overrides generic metadata', () => {
|
|
|
|
return withTestDir((srcPath) => {
|
|
|
|
createFiles(srcPath, {
|
|
|
|
'S100/metadata.json': JSON.stringify({
|
|
|
|
title: 'Rule S100',
|
|
|
|
tags: ['confusing']
|
|
|
|
}),
|
|
|
|
'S100/java/metadata.json': JSON.stringify({
|
|
|
|
title: 'Java Rule S100'
|
|
|
|
}),
|
|
|
|
'S100/python/metadata.json': JSON.stringify({
|
|
|
|
tags: ['pep8']
|
|
|
|
}),
|
|
|
|
});
|
|
|
|
return withTestDir(async (dstPath) => {
|
2022-01-17 20:13:15 +01:00
|
|
|
generateRulesMetadata(srcPath, dstPath);
|
2021-02-05 14:24:41 +01:00
|
|
|
const javaStrMetadata = fs.readFileSync(`${dstPath}/S100/java-metadata.json`);
|
|
|
|
const javaMetadata = JSON.parse(javaStrMetadata.toString());
|
|
|
|
expect(javaMetadata).toMatchObject({
|
|
|
|
title: 'Java Rule S100',
|
|
|
|
tags: ['confusing']
|
|
|
|
});
|
|
|
|
|
|
|
|
const pythonStrMetadata = fs.readFileSync(`${dstPath}/S100/python-metadata.json`);
|
|
|
|
const pythonMetadata = JSON.parse(pythonStrMetadata.toString());
|
|
|
|
expect(pythonMetadata).toMatchObject({
|
|
|
|
title: 'Rule S100',
|
|
|
|
tags: ['pep8']
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2022-01-17 20:13:15 +01:00
|
|
|
test('check status computation', () => {
|
|
|
|
return withTestDir((srcPath) => {
|
|
|
|
createFiles(srcPath, {
|
|
|
|
'S100/metadata.json': JSON.stringify({
|
|
|
|
title: 'Rule S100',
|
|
|
|
status: 'ready'
|
|
|
|
}),
|
|
|
|
'S100/java/metadata.json': JSON.stringify({
|
|
|
|
title: 'Java Rule S100'
|
|
|
|
}),
|
|
|
|
'S100/python/metadata.json': JSON.stringify({
|
|
|
|
status: 'closed'
|
|
|
|
}),
|
|
|
|
});
|
|
|
|
return withTestDir(async (dstPath) => {
|
|
|
|
generateRulesMetadata(srcPath, dstPath);
|
|
|
|
const javaStrMetadata = fs.readFileSync(`${dstPath}/S100/java-metadata.json`);
|
|
|
|
const pythonStrMetadata = fs.readFileSync(`${dstPath}/S100/python-metadata.json`);
|
|
|
|
const javaMetadata = JSON.parse(javaStrMetadata.toString());
|
|
|
|
const pythonMetadata = JSON.parse(pythonStrMetadata.toString());
|
|
|
|
expect(pythonMetadata).toMatchObject({
|
|
|
|
title: 'Rule S100',
|
|
|
|
languagesSupport: [
|
|
|
|
{name: 'java', status: 'ready'},
|
|
|
|
{name: 'python', status: 'closed'}
|
|
|
|
]
|
|
|
|
});
|
|
|
|
|
|
|
|
expect(javaMetadata.languagesSupport).toStrictEqual(pythonMetadata.languagesSupport);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2022-01-28 09:51:13 +01:00
|
|
|
test('computes rule types correctly', () => {
|
|
|
|
return withTestDir((srcPath) => {
|
|
|
|
createFiles(srcPath, {
|
|
|
|
'S100/metadata.json': JSON.stringify({
|
|
|
|
title: 'Rule S100',
|
|
|
|
type: 'CODE_SMELL',
|
|
|
|
}),
|
|
|
|
'S100/java/metadata.json': JSON.stringify({
|
|
|
|
title: 'Java Rule S100',
|
|
|
|
}),
|
|
|
|
'S100/python/metadata.json': JSON.stringify({
|
|
|
|
type: 'CODE_SMELL',
|
|
|
|
}),
|
|
|
|
'S100/cfamily/metadata.json': JSON.stringify({
|
|
|
|
type: 'BUG',
|
|
|
|
}),
|
|
|
|
});
|
|
|
|
|
|
|
|
return withTestDir(async (dstPath) => {
|
|
|
|
generateRulesMetadata(srcPath, dstPath);
|
|
|
|
|
|
|
|
const javaStrMetadata = fs.readFileSync(`${dstPath}/S100/java-metadata.json`);
|
|
|
|
const pythonStrMetadata = fs.readFileSync(`${dstPath}/S100/python-metadata.json`);
|
|
|
|
const cfamilyStrMetadata = fs.readFileSync(`${dstPath}/S100/cfamily-metadata.json`);
|
|
|
|
const javaMetadata = JSON.parse(javaStrMetadata.toString());
|
|
|
|
const pythonMetadata = JSON.parse(pythonStrMetadata.toString());
|
|
|
|
const cfamilyMetadata = JSON.parse(cfamilyStrMetadata.toString());
|
|
|
|
|
|
|
|
expect(javaMetadata).toMatchObject({
|
|
|
|
title: 'Java Rule S100',
|
|
|
|
type: 'CODE_SMELL',
|
|
|
|
});
|
|
|
|
|
|
|
|
expect(pythonMetadata).toMatchObject({
|
|
|
|
title: 'Rule S100',
|
|
|
|
type: 'CODE_SMELL',
|
|
|
|
});
|
|
|
|
|
|
|
|
expect(cfamilyMetadata).toMatchObject({
|
|
|
|
title: 'Rule S100',
|
|
|
|
type: 'BUG',
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2021-02-05 14:24:41 +01:00
|
|
|
test('generates only requested rules if a list of rule is provided', () => {
|
|
|
|
return withTestDir((srcPath) => {
|
|
|
|
createFiles(srcPath, {
|
|
|
|
'S100/java/metadata.json': JSON.stringify({
|
|
|
|
title: 'Rule S100'
|
|
|
|
}),
|
|
|
|
'S200/java/metadata.json': JSON.stringify({
|
|
|
|
title: 'Rule S200'
|
|
|
|
}),
|
|
|
|
});
|
|
|
|
return withTestDir(async (dstPath) => {
|
2022-01-17 20:13:15 +01:00
|
|
|
generateRulesMetadata(srcPath, dstPath, ['S100']);
|
2021-02-05 14:24:41 +01:00
|
|
|
|
|
|
|
const s100Exists = fs.existsSync(`${dstPath}/S100/java-metadata.json`);
|
|
|
|
expect(s100Exists).toBeTruthy();
|
|
|
|
|
|
|
|
const s200Exists = fs.existsSync(`${dstPath}/S200/java-metadata.json`);
|
|
|
|
expect(s200Exists).toBeFalsy();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2021-05-20 11:24:59 +02:00
|
|
|
|
|
|
|
test('forwards the pr url when provided', () => {
|
|
|
|
return withTestDir((srcPath) => {
|
|
|
|
createFiles(srcPath, {
|
|
|
|
'S100/java/metadata.json': JSON.stringify({
|
|
|
|
title: 'Rule S100'
|
|
|
|
}),
|
|
|
|
'S200/java/metadata.json': JSON.stringify({
|
|
|
|
title: 'Rule S200'
|
|
|
|
}),
|
|
|
|
});
|
|
|
|
return withTestDir(async (dstPath) => {
|
2022-01-17 20:13:15 +01:00
|
|
|
generateOneRuleMetadata(path.join(srcPath, 'S100'), path.join(dstPath, 'S100'), 'master');
|
2021-05-20 11:24:59 +02:00
|
|
|
|
|
|
|
const s100StrMetadata = fs.readFileSync(`${dstPath}/S100/java-metadata.json`);
|
|
|
|
const s100Metadata = JSON.parse(s100StrMetadata.toString());
|
2021-06-08 13:55:27 +02:00
|
|
|
expect(Object.keys(s100Metadata)).toContain('branch');
|
|
|
|
expect(s100Metadata.branch).toEqual('master');
|
2021-05-20 11:24:59 +02:00
|
|
|
expect(Object.keys(s100Metadata)).not.toContain('prUrl');
|
|
|
|
|
2022-01-17 20:13:15 +01:00
|
|
|
generateOneRuleMetadata(path.join(srcPath, 'S200'), path.join(dstPath, 'S200'), 'add-my-rule', 'https://some.pr/url');
|
2021-06-08 13:55:27 +02:00
|
|
|
|
2021-05-20 11:24:59 +02:00
|
|
|
|
|
|
|
const s200StrMetadata = fs.readFileSync(`${dstPath}/S200/java-metadata.json`);
|
|
|
|
const s200Metadata = JSON.parse(s200StrMetadata.toString());
|
|
|
|
expect(Object.keys(s200Metadata)).toContain('prUrl');
|
2021-06-08 13:55:27 +02:00
|
|
|
expect(s200Metadata.branch).toEqual('add-my-rule');
|
2021-05-20 11:24:59 +02:00
|
|
|
expect(s200Metadata.prUrl).toEqual('https://some.pr/url');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2022-01-17 20:13:15 +01:00
|
|
|
|
2022-01-28 09:51:13 +01:00
|
|
|
test('generates metadata for active rules', () => {
|
2022-01-17 20:13:15 +01:00
|
|
|
return withTestDir(async (dstPath) => {
|
|
|
|
generateRulesMetadata(path.join(__dirname, 'resources', 'rules'), dstPath);
|
|
|
|
const rules = fs.readdirSync(dstPath);
|
2023-03-03 13:49:24 +01:00
|
|
|
expect(rules.length).toEqual(5);
|
2022-01-17 20:13:15 +01:00
|
|
|
let treated = 0;
|
|
|
|
rules.forEach(ruleDir => {
|
|
|
|
const languages = fs.readdirSync(`${dstPath}/${ruleDir}`);
|
|
|
|
expect(languages.length).toBeGreaterThanOrEqual(1);
|
|
|
|
languages.forEach(file => {
|
|
|
|
const actual = JSON.parse(fs.readFileSync(`${dstPath}/${ruleDir}/${file}`).toString());
|
|
|
|
const expectedPath = path.join(__dirname, 'resources', 'metadata', ruleDir, file);
|
|
|
|
const expected = JSON.parse(fs.readFileSync(expectedPath).toString());
|
|
|
|
expect(actual).toStrictEqual(expected);
|
|
|
|
treated++;
|
|
|
|
})
|
|
|
|
});
|
2023-03-03 13:49:24 +01:00
|
|
|
expect(treated).toBe(13);
|
2022-01-17 20:13:15 +01:00
|
|
|
});
|
|
|
|
});
|
2022-01-28 09:51:13 +01:00
|
|
|
|
|
|
|
test('generates metadata for closed rules', () => {
|
|
|
|
return withTestDir(srcPath => {
|
|
|
|
createFiles(srcPath, {
|
|
|
|
'S01/metadata.json': JSON.stringify({
|
|
|
|
title: 'Rule is closed and has no language-specific specification',
|
|
|
|
type: 'CODE_SMELL',
|
|
|
|
status: 'closed',
|
|
|
|
sqKey: 'S01',
|
|
|
|
extra: {
|
|
|
|
legacyKeys: ['OldS01'],
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
|
|
|
|
'S02/metadata.json': JSON.stringify({
|
|
|
|
title: 'Rule is closed and has one closed language-specific specification',
|
|
|
|
type: 'CODE_SMELL',
|
|
|
|
status: 'closed',
|
|
|
|
sqKey: 'S02',
|
|
|
|
}),
|
|
|
|
'S02/cfamily/metadata.json': JSON.stringify({
|
|
|
|
title: 'Language specification is closed',
|
|
|
|
status: 'closed',
|
|
|
|
extra: {
|
|
|
|
legacyKeys: ['OldS02'],
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
});
|
|
|
|
|
|
|
|
return withTestDir(async dstPath => {
|
|
|
|
generateRulesMetadata(srcPath, dstPath);
|
|
|
|
|
|
|
|
const rules = fs.readdirSync(dstPath).sort();
|
|
|
|
expect(rules).toEqual(['S01', 'S02'].sort());
|
|
|
|
|
|
|
|
{
|
|
|
|
const rule = 'S01';
|
|
|
|
const rulePath = path.join(dstPath, rule);
|
|
|
|
// Verify that the expected files are generated and no others
|
|
|
|
const entries = fs.readdirSync(rulePath).sort();
|
|
|
|
expect(entries).toEqual(['default-metadata.json'].sort());
|
|
|
|
|
|
|
|
// Check the top-level metadata
|
|
|
|
const defaultFile = path.join(rulePath, 'default-metadata.json');
|
|
|
|
const defaultData = JSON.parse(fs.readFileSync(defaultFile, 'utf8'));
|
|
|
|
expect(defaultData).toMatchObject({
|
|
|
|
title: 'Rule is closed and has no language-specific specification',
|
|
|
|
type: 'CODE_SMELL',
|
|
|
|
status: 'closed',
|
|
|
|
languagesSupport: [],
|
|
|
|
allKeys: ['S01', 'OldS01'],
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
const rule = 'S02';
|
|
|
|
const rulePath = path.join(dstPath, rule);
|
|
|
|
// Verify that the expected files are generated and no others
|
|
|
|
const entries = fs.readdirSync(rulePath).sort();
|
|
|
|
expect(entries).toEqual(['default-metadata.json', 'cfamily-metadata.json'].sort());
|
|
|
|
|
|
|
|
// Check the top-level metadata
|
|
|
|
const defaultFile = path.join(rulePath, 'default-metadata.json');
|
|
|
|
const defaultData = JSON.parse(fs.readFileSync(defaultFile, 'utf8'));
|
|
|
|
// Generic data is overriden by the first language-specific specification.
|
|
|
|
expect(defaultData).toMatchObject({
|
|
|
|
title: 'Language specification is closed',
|
|
|
|
type: 'CODE_SMELL',
|
|
|
|
status: 'closed',
|
|
|
|
languagesSupport: [{ name: 'cfamily', status: 'closed', }],
|
|
|
|
allKeys: ['S02', 'OldS02'],
|
|
|
|
});
|
|
|
|
|
|
|
|
// Check the language-specific metadata
|
|
|
|
const cfamilyFile = path.join(rulePath, 'cfamily-metadata.json');
|
|
|
|
const cfamilyData = JSON.parse(fs.readFileSync(cfamilyFile, 'utf8'));
|
|
|
|
expect(cfamilyData).toMatchObject({
|
|
|
|
title: 'Language specification is closed',
|
|
|
|
type: 'CODE_SMELL',
|
|
|
|
status: 'closed',
|
|
|
|
languagesSupport: [{ name: 'cfamily', status: 'closed', }],
|
|
|
|
allKeys: ['S02', 'OldS02'],
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2021-05-20 11:24:59 +02:00
|
|
|
});
|