lion/packages-node/providence-analytics/test-node/program/core/Analyzer.test.js
2023-11-08 19:01:20 +01:00

230 lines
7.3 KiB
JavaScript

const { expect } = require('chai');
const {
mockProject,
restoreMockedProjects,
} = require('../../../test-helpers/mock-project-helpers.js');
const { setupAnalyzerTest } = require('../../../test-helpers/setup-analyzer-test.js');
const { QueryService } = require('../../../src/program/core/QueryService.js');
const { providence } = require('../../../src/program/providence.js');
const { DummyAnalyzer } = require('../../../test-helpers/templates/DummyAnalyzer.js');
/**
* @typedef {import('../../../src/program/types/core').ProvidenceConfig} ProvidenceConfig
*/
describe('Analyzer', () => {
const dummyAnalyzer = new DummyAnalyzer();
const queryResults = setupAnalyzerTest();
describe('Public api', () => {
it('has a "name" string', async () => {
expect(typeof dummyAnalyzer.name).to.equal('string');
});
it('has an "execute" function', async () => {
expect(typeof dummyAnalyzer.execute).to.equal('function');
});
it('has a "requiredAst" string', async () => {
expect(typeof dummyAnalyzer.requiredAst).to.equal('string');
const allowedAsts = ['babel'];
expect(allowedAsts).to.include(dummyAnalyzer.requiredAst);
});
it('has a "requiresReference" boolean', async () => {
expect(typeof DummyAnalyzer.requiresReference).to.equal('boolean');
});
});
describe.skip('Find Analyzers', async () => {
afterEach(() => {
restoreMockedProjects();
});
const myQueryConfigObject = QueryService.getQueryConfigFromAnalyzer(DummyAnalyzer);
/** @type {Partial<ProvidenceConfig>} */
const _providenceCfg = {
targetProjectPaths: ['/fictional/project'],
};
describe('Prepare phase', () => {
it('looks for a cached result', async () => {
// Our configuration object
mockProject([`const validJs = true;`, `let invalidJs = false;`]);
await providence(myQueryConfigObject, _providenceCfg);
});
it('exposes a ".targetMeta" object', async () => {});
it('exposes a ".targetData" object', async () => {});
it('exposes a ".identifier" string', async () => {});
});
describe('Traverse phase', () => {
it('schedules a Babel visitor', async () => {});
it('merges multiple Babel visitors for performance', async () => {});
it('traverses Babel visitor and stores traversal result', async () => {});
});
describe('Postprocess phase', () => {
it('optionally post processes traversal result', async () => {});
});
describe('Performance', () => {
it('memoizes execute functions', async () => {});
});
describe('Finalize phase', () => {
it('returns an AnalyzerQueryResult', async () => {
await providence(myQueryConfigObject, _providenceCfg);
const queryResult = queryResults[0];
const { queryOutput, meta } = queryResult;
expect(queryOutput[0]).to.eql({
file: './test-file-0.js',
meta: {},
result: [{ matched: 'entry' }],
});
expect(queryOutput[1]).to.eql({
file: './test-file2.js',
meta: {},
result: [{ matched: 'entry' }],
});
// Local machine info needs to be deleted, so that results are always 'machine agnostic'
// (which is needed to share cached json results via git)
expect(meta).to.eql({
searchType: 'ast-analyzer',
analyzerMeta: {
name: 'my-analyzer',
requiredAst: 'babel',
identifier: 'my-project_0.1.0-mock__542516121',
targetProject: {
name: 'my-project',
commitHash: '[not-a-git-repo]',
version: '0.1.0-mock',
},
configuration: {
targetProjectPaths: null,
optionA: false,
optionB: '',
debugEnabled: false,
gatherFilesConfig: {},
},
},
});
});
});
// TODO: think of exposing the ast traversal part in a distinct method "traverse", so we can
// create integrations with (a local version of) https://astexplorer.net
});
// describe.skip('Match Analyzers', () => {
// const referenceProject = {
// path: '/exporting/ref/project',
// name: 'exporting-ref-project',
// files: [
// {
// file: './package.json',
// code: `{
// "name": "importing-target-project",
// "version": "2.20.3",
// "dependencies": {
// "exporting-ref-project": "^2.3.0"
// }
// }`,
// },
// ],
// };
// const matchingTargetProject = {
// path: '/importing/target/project/v10',
// files: [
// {
// file: './package.json',
// code: `{
// "name": "importing-target-project",
// "version": "10.1.2",
// "dependencies": {
// "exporting-ref-project": "^2.3.0"
// }
// }`,
// },
// ],
// };
// const matchingDevDepTargetProject = {
// path: '/importing/target/project/v10',
// files: [
// {
// file: './package.json',
// code: `{
// "name": "importing-target-project",
// "version": "10.1.2",
// "devDependencies": {
// "exporting-ref-project": "^2.3.0"
// }
// }`,
// },
// ],
// };
// // A previous version that does not match our reference version
// const nonMatchingVersionTargetProject = {
// path: '/importing/target/project/v8',
// files: [
// {
// file: './package.json',
// code: `{
// "name": "importing-target-project",
// "version": "8.1.2",
// "dependencies": {
// "exporting-ref-project": "^1.9.0"
// }
// }`,
// },
// ],
// };
// const nonMatchingDepTargetProject = {
// path: '/importing/target/project/v8',
// files: [
// {
// file: './package.json',
// code: `{
// "name": "importing-target-project",
// "version": "8.1.2",
// "dependencies": {
// "some-other-project": "^0.1.0"
// }
// }`,
// },
// ],
// };
// it('has a "requiresReference" boolean', async () => {
// expect(dummyAnalyzer.requiresReference).to.equal(true);
// });
// describe('Prepare phase', () => {
// it('halts non-compatible reference + target combinations', async () => {
// mockTargetAndReferenceProject(referenceProject, nonMatchingVersionTargetProject);
// // Check stubbed LogService.info with reason 'no-matched-version'
// mockTargetAndReferenceProject(referenceProject, nonMatchingDepTargetProject);
// // Check stubbed LogService.info with reason 'no-dependency'
// });
// it('starts analysis for compatible reference + target combinations', async () => {
// mockTargetAndReferenceProject(referenceProject, matchingTargetProject);
// mockTargetAndReferenceProject(referenceProject, matchingDevDepTargetProject);
// // _prepare: startAnalysis: true
// });
// });
// });
});
describe('FindAnalyzer', () => {});
describe('MatchAnalyzer', () => {});