diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..853f837 --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,27 @@ +name: Unit test + +on: + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + permissions: + contents: read + packages: read + steps: + - uses: actions/checkout@v3 + # Setup .npmrc file to publish to GitHub Packages + - uses: actions/setup-node@v3 + with: + node-version: "16.x" + registry-url: "https://npm.pkg.github.com" + # Defaults to the user or organization that owns the workflow file + scope: "@agoraio-extensions" + + - name: Run unit test + env: + NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + npm install + npm run test diff --git a/jest.config.js b/jest.config.js index dc0e22f..97d89c4 100644 --- a/jest.config.js +++ b/jest.config.js @@ -2,5 +2,5 @@ module.exports = { coverageDirectory: 'coverage', preset: 'ts-jest', testEnvironment: 'node', - testRegex: '/__tests__/.*\\.(test|spec)\\.[jt]sx?$', + testRegex: 'src/__tests__/.*\\.(test|spec)\\.[jt]sx?$', }; diff --git a/package-lock.json b/package-lock.json index 4698dfc..f5d5778 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,8 +9,8 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@agoraio-extensions/cxx-parser": ">=0.1.3", - "@agoraio-extensions/terra-core": ">=0.1.2", + "@agoraio-extensions/cxx-parser": "latest", + "@agoraio-extensions/terra-core": "latest", "mustache": "^4.2.0" }, "devDependencies": { @@ -41,33 +41,21 @@ } }, "node_modules/@agoraio-extensions/cxx-parser": { - "version": "0.1.3", - "resolved": "https://npm.pkg.github.com/download/@agoraio-extensions/cxx-parser/0.1.3/9785f725760018571202b9e3c858aa7c6d61ef33", - "integrity": "sha512-yOTxTFipXS5MdbQvhTDieMymEicl81SoFvJH5RupgX1VOesAgfTihio7yR5h9MnGckz6puhpvlxVernomJ0Aog==", + "version": "0.1.7", + "resolved": "https://npm.pkg.github.com/download/@agoraio-extensions/cxx-parser/0.1.7/ecd565913ae7c8c524a65195cc91b51487ce7c3e", + "integrity": "sha512-Mz53ngTpZ3RKmz7atBvo5M6wWU32YRgpcNF2db6+UAY343mlWFSzsLRa9ozYUNJw1ve4TIs6wXsSGG5eh9MRYQ==", "license": "ISC", "dependencies": { "@types/node": "^20.5.9", "glob": "^10.3.4", "ts-node": "^10.9.1", - "typescript": "^5.2.2", + "typescript": "^4.8.4", "yaml": "^2.1.3" }, "peerDependencies": { "@agoraio-extensions/terra-core": ">=0.1.0" } }, - "node_modules/@agoraio-extensions/cxx-parser/node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, "node_modules/@agoraio-extensions/terra-core": { "version": "0.1.2", "resolved": "https://npm.pkg.github.com/download/@agoraio-extensions/terra-core/0.1.2/a14f3b4e815b6dfbd124a9197e2190bfda6ff19d", diff --git a/package.json b/package.json index be9ae79..d28fd5c 100644 --- a/package.json +++ b/package.json @@ -20,8 +20,8 @@ "author": "", "license": "ISC", "dependencies": { - "@agoraio-extensions/cxx-parser": ">=0.1.3", - "@agoraio-extensions/terra-core": ">=0.1.2", + "@agoraio-extensions/cxx-parser": "latest", + "@agoraio-extensions/terra-core": "latest", "mustache": "^4.2.0" }, "devDependencies": { diff --git a/src/__tests__/parsers/add_node_parser.mock.ts b/src/__tests__/parsers/add_node_parser.mock.ts new file mode 100644 index 0000000..cd3ff2d --- /dev/null +++ b/src/__tests__/parsers/add_node_parser.mock.ts @@ -0,0 +1,18 @@ +export const parseMock = jest.fn(); +// export const generateCustomNodesMock = jest.fn(); +jest.mock('@agoraio-extensions/cxx-parser', () => { + const originalModule = jest.requireActual('@agoraio-extensions/cxx-parser'); + return { + __esModule: true, + ...originalModule, + CXXParser: parseMock, + }; +}); + +import * as Tester from '../../parsers/add_node_parser'; + +export const generateCustomNodesMock = jest.spyOn( + Tester, + 'generateCustomNodes' +); +export const AddNodeParser = Tester.AddNodeParser; diff --git a/src/__tests__/parsers/add_node_parser.test.ts b/src/__tests__/parsers/add_node_parser.test.ts new file mode 100644 index 0000000..c11f7f9 --- /dev/null +++ b/src/__tests__/parsers/add_node_parser.test.ts @@ -0,0 +1,338 @@ +// eslint-disable-next-line import/order +import { + AddNodeParser, + generateCustomNodesMock, + parseMock, +} from './add_node_parser.mock'; + +import { + CXXFile, + CXXParserConfigs, + CXXTYPE, + Clazz, +} from '@agoraio-extensions/cxx-parser'; + +import { TerraContext } from '@agoraio-extensions/terra-core'; + +const customPrefix = 'test'; +const parseConfig: CXXParserConfigs = { + customHeaders: ['/my/path/test.h'], + includeHeaderDirs: [], + definesMacros: [], + parseFiles: { + include: [], + exclude: [], + }, +}; +const genParseResultFromNode = (nodes: any[] = [], custom: boolean = false) => { + const filePath = `/my/path/${custom ? customPrefix : ''}IAgoraRtcEngine.h`; + const json = [ + { + __TYPE: 'CXXFile', + file_path: filePath, + nodes, + }, + ]; + const { genParseResultFromJson } = jest.requireActual( + '@agoraio-extensions/cxx-parser' + ); + return genParseResultFromJson(JSON.stringify(json)); +}; + +describe('AddNodeParser', () => { + it('parse with TerraConfig', () => { + AddNodeParser(new TerraContext(), { + ...parseConfig, + customHeaderFileNamePrefix: customPrefix, + }); + expect(parseMock.mock.lastCall[1].customHeaders).toStrictEqual( + parseConfig.customHeaders + ); + }); + + it('parse with AddNodeParserArgs', () => { + const customHeaders = ['/my/path/test2.h']; + AddNodeParser(new TerraContext(), { + ...parseConfig, + customHeaders, + customHeaderFileNamePrefix: customPrefix, + }); + expect(parseMock.mock.lastCall[1].customHeaders).toStrictEqual( + customHeaders + ); + }); + + it('generateCustomNodes', () => { + const preParseResult = genParseResultFromNode(); + const config = { + ...parseConfig, + customHeaderFileNamePrefix: customPrefix, + }; + const result = AddNodeParser(new TerraContext(), config, preParseResult); + expect(generateCustomNodesMock.mock.lastCall![1]).toStrictEqual(config); + expect(result).toEqual(preParseResult); + }); + + it('add custom struct', () => { + const preParseResult = genParseResultFromNode(); + generateCustomNodesMock.mockImplementation(() => { + return genParseResultFromNode( + [ + { + __TYPE: 'Struct', + name: 'LocalVideoStats', + }, + ], + true + ); + }); + const result = AddNodeParser( + new TerraContext(), + { + ...parseConfig, + customHeaderFileNamePrefix: customPrefix, + }, + preParseResult + ); + expect( + (result?.nodes[0] as CXXFile).nodes[0].__TYPE === CXXTYPE.Struct + ).toBe(true); + expect((result?.nodes[0] as CXXFile).nodes[0].name).toEqual( + 'LocalVideoStats' + ); + }); + + it('add custom enum', () => { + const preParseResult = genParseResultFromNode(); + generateCustomNodesMock.mockImplementation(() => { + return genParseResultFromNode( + [ + { + __TYPE: 'Enumz', + name: 'MEDIA_DEVICE_TYPE', + }, + ], + true + ); + }); + const result = AddNodeParser( + new TerraContext(), + { + ...parseConfig, + customHeaderFileNamePrefix: customPrefix, + }, + preParseResult + ); + expect( + (result?.nodes[0] as CXXFile).nodes[0].__TYPE === CXXTYPE.Enumz + ).toBe(true); + expect((result?.nodes[0] as CXXFile).nodes[0].name).toEqual( + 'MEDIA_DEVICE_TYPE' + ); + }); + + it('add custom class', () => { + const preParseResult = genParseResultFromNode(); + generateCustomNodesMock.mockImplementation(() => { + return genParseResultFromNode( + [ + { + __TYPE: 'Clazz', + name: 'IScreenCaptureSourceList', + }, + ], + true + ); + }); + const result = AddNodeParser( + new TerraContext(), + { + ...parseConfig, + customHeaderFileNamePrefix: customPrefix, + }, + preParseResult + ); + expect( + (result?.nodes[0] as CXXFile).nodes[0].__TYPE === CXXTYPE.Clazz + ).toBe(true); + expect((result?.nodes[0] as CXXFile).nodes[0].name).toEqual( + 'IScreenCaptureSourceList' + ); + }); + + it('add custom class and struct', () => { + const preParseResult = genParseResultFromNode(); + generateCustomNodesMock.mockImplementation(() => { + return genParseResultFromNode( + [ + { + __TYPE: 'Struct', + name: 'LocalVideoStats', + }, + { + __TYPE: 'Clazz', + name: 'IScreenCaptureSourceList', + }, + ], + true + ); + }); + const result = AddNodeParser( + new TerraContext(), + { + ...parseConfig, + customHeaderFileNamePrefix: customPrefix, + }, + preParseResult + ); + expect( + (result?.nodes[0] as CXXFile).nodes[0].__TYPE === CXXTYPE.Struct + ).toBe(true); + expect((result?.nodes[0] as CXXFile).nodes[0].name).toEqual( + 'LocalVideoStats' + ); + expect( + (result?.nodes[0] as CXXFile).nodes[1].__TYPE === CXXTYPE.Clazz + ).toBe(true); + expect((result?.nodes[0] as CXXFile).nodes[1].name).toEqual( + 'IScreenCaptureSourceList' + ); + }); + + it('only process enum struct class', () => { + const preParseResult = genParseResultFromNode(); + generateCustomNodesMock.mockImplementation(() => { + return genParseResultFromNode( + [ + { + __TYPE: 'IncludeDirective', + include_file_path: '/my/path/AgoraBase.h', + }, + ], + true + ); + }); + const result = AddNodeParser( + new TerraContext(), + { + ...parseConfig, + customHeaderFileNamePrefix: customPrefix, + }, + preParseResult + ); + expect((result?.nodes[0] as CXXFile).nodes.length).toBe(0); + }); + + it('add member function', () => { + const preParseResult = genParseResultFromNode( + [ + { + __TYPE: 'Clazz', + name: 'IScreenCaptureSourceList', + methods: [], + }, + ], + false + ); + generateCustomNodesMock.mockImplementation(() => { + return genParseResultFromNode( + [ + { + __TYPE: 'Clazz', + name: 'IScreenCaptureSourceList', + methods: [ + { + __TYPE: 'MemberFunction', + name: 'getCount', + }, + ], + }, + ], + true + ); + }); + const result = AddNodeParser( + new TerraContext(), + { + ...parseConfig, + customHeaderFileNamePrefix: customPrefix, + }, + preParseResult + ); + const clazz = (result?.nodes[0] as CXXFile).nodes[0] as Clazz; + expect( + (result?.nodes[0] as CXXFile).nodes[0].__TYPE === CXXTYPE.Clazz + ).toBe(true); + expect(clazz.methods[0].__TYPE === CXXTYPE.MemberFunction).toBe(true); + expect(clazz.methods[0].name).toBe('getCount'); + }); + + it('overload function', () => { + const preParseResult = genParseResultFromNode( + [ + { + __TYPE: 'Clazz', + name: 'IScreenCaptureSourceList', + methods: [ + { + __TYPE: 'MemberFunction', + name: 'getCount', + parameters: [ + { + __TYPE: 'Variable', + name: 'a', + }, + ], + }, + { + __TYPE: 'MemberFunction', + name: 'getCount', + parameters: [ + { + __TYPE: 'Variable', + name: 'b', + }, + ], + }, + ], + }, + ], + false + ); + generateCustomNodesMock.mockImplementation(() => { + return genParseResultFromNode( + [ + { + __TYPE: 'Clazz', + name: 'IScreenCaptureSourceList', + methods: [ + { + __TYPE: 'MemberFunction', + name: 'getCount', + parameters: [ + { + __TYPE: 'Variable', + name: 'c', + }, + ], + }, + ], + }, + ], + true + ); + }); + const result = AddNodeParser( + new TerraContext(), + { + ...parseConfig, + customHeaderFileNamePrefix: customPrefix, + }, + preParseResult + ); + const clazz = (result?.nodes[0] as CXXFile).nodes[0] as Clazz; + expect(clazz.methods.length).toBe(1); + expect(clazz.methods[0].name).toBe('getCount'); + expect(clazz.methods[0].parameters[0].name).toBe('c'); + }); +}); diff --git a/src/__tests__/parsers/fix_enum_constant_parser.test.ts b/src/__tests__/parsers/fix_enum_constant_parser.test.ts new file mode 100644 index 0000000..ab0fdde --- /dev/null +++ b/src/__tests__/parsers/fix_enum_constant_parser.test.ts @@ -0,0 +1,176 @@ +import { + CXXFile, + genParseResultFromJson, +} from '@agoraio-extensions/cxx-parser'; + +import { TerraContext } from '@agoraio-extensions/terra-core'; + +import { FixEnumConstantParser } from '../../'; + +describe('FixEnumConstantParser', () => { + it('fill empty value', () => { + let json = ` +[ + { + "file_path": "/my/path/IAgoraRtcEngine.h", + "nodes": [ + { + "__TYPE": "Enumz", + "enum_constants": [ + { + "__TYPE": "EnumConstant", + "name": "AUDIO_DEVICE1", + "source": "", + "value": "" + }, + { + "__TYPE": "EnumConstant", + "name": "AUDIO_DEVICE2", + "source": "12", + "value": "12" + }, + { + "__TYPE": "EnumConstant", + "name": "AUDIO_DEVICE3", + "source": "", + "value": "" + } + ], + "file_path": "/my/path/IAgoraRtcEngine.h", + "name": "MEDIA_DEVICE_TYPE", + "namespaces": [ + "agora", + "rtc" + ], + "parent_name": "rtc" + } + ] + } +] +`; + let preParseResult = genParseResultFromJson(json); + + const result = ( + FixEnumConstantParser(new TerraContext(), {}, preParseResult) + ?.nodes[0] as CXXFile + ).nodes[0].asEnumz(); + expect(result?.enum_constants[0].source).toEqual('0'); + expect(result?.enum_constants[0].value).toEqual('0'); + expect(result?.enum_constants[1].source).toEqual('12'); + expect(result?.enum_constants[1].value).toEqual('12'); + expect(result?.enum_constants[2].source).toEqual('13'); + expect(result?.enum_constants[2].value).toEqual('13'); + }); + + it('use other EnumConstant value', () => { + let json = ` +[ + { + "file_path": "/my/path/IAgoraRtcEngine.h", + "nodes": [ + { + "__TYPE": "Enumz", + "enum_constants": [ + { + "__TYPE": "EnumConstant", + "name": "AUDIO_DEVICE1", + "source": "0", + "value": "0" + }, + { + "__TYPE": "EnumConstant", + "name": "AUDIO_DEVICE2", + "source": "AUDIO_DEVICE1", + "value": "AUDIO_DEVICE1" + } + ], + "file_path": "/my/path/IAgoraRtcEngine.h", + "name": "MEDIA_DEVICE_TYPE", + "namespaces": [ + "agora", + "rtc" + ], + "parent_name": "rtc" + } + ] + } +] +`; + let preParseResult = genParseResultFromJson(json); + + const result = ( + FixEnumConstantParser(new TerraContext(), {}, preParseResult) + ?.nodes[0] as CXXFile + ).nodes[0].asEnumz(); + expect(result?.enum_constants[1].source).toEqual('AUDIO_DEVICE1'); + expect(result?.enum_constants[1].value).toEqual('0'); + }); + + it('calculate value', () => { + let json = ` +[ + { + "file_path": "/my/path/IAgoraRtcEngine.h", + "nodes": [ + { + "__TYPE": "Enumz", + "enum_constants": [ + { + "__TYPE": "EnumConstant", + "name": "AUDIO_DEVICE1", + "source": "(0xFFFFFFFF)", + "value": "(0xFFFFFFFF)" + }, + { + "__TYPE": "EnumConstant", + "name": "AUDIO_DEVICE2", + "source": "1<<0", + "value": "1<<0" + }, + { + "__TYPE": "EnumConstant", + "name": "AUDIO_DEVICE3", + "source": "AUDIO_DEVICE1|AUDIO_DEVICE2", + "value": "AUDIO_DEVICE1|AUDIO_DEVICE2" + }, + { + "__TYPE": "EnumConstant", + "name": "AUDIO_DEVICE4", + "source": "AUDIO_DEVICE3*sizeof(int16_t)", + "value": "AUDIO_DEVICE3*sizeof(int16_t)" + } + ], + "file_path": "/my/path/IAgoraRtcEngine.h", + "name": "MEDIA_DEVICE_TYPE", + "namespaces": [ + "agora", + "rtc" + ], + "parent_name": "rtc" + } + ] + } +] +`; + let preParseResult = genParseResultFromJson(json); + + const result = ( + FixEnumConstantParser(new TerraContext(), {}, preParseResult) + ?.nodes[0] as CXXFile + ).nodes[0].asEnumz(); + expect(result?.enum_constants[0].source).toEqual('(0xFFFFFFFF)'); + expect(result?.enum_constants[0].value).toEqual(`${0xffffffff}`); + expect(result?.enum_constants[1].source).toEqual('1<<0'); + expect(result?.enum_constants[1].value).toEqual(`${1 << 0}`); + expect(result?.enum_constants[2].source).toEqual( + 'AUDIO_DEVICE1|AUDIO_DEVICE2' + ); + expect(result?.enum_constants[2].value).toEqual(`${0xffffffff | (1 << 0)}`); + expect(result?.enum_constants[3].source).toEqual( + 'AUDIO_DEVICE3*sizeof(int16_t)' + ); + expect(result?.enum_constants[3].value).toEqual( + `${(0xffffffff | (1 << 0)) * 2}` + ); + }); +}); diff --git a/src/__tests__/parsers/order_node_parser.test.ts b/src/__tests__/parsers/order_node_parser.test.ts new file mode 100644 index 0000000..96ec937 --- /dev/null +++ b/src/__tests__/parsers/order_node_parser.test.ts @@ -0,0 +1,67 @@ +import { + CXXFile, + genParseResultFromJson, +} from '@agoraio-extensions/cxx-parser'; +import { TerraContext } from '@agoraio-extensions/terra-core'; + +import { OrderNodeParser } from '../..'; + +describe('OrderNodeParser', () => { + it('swap order', () => { + let json = ` +[ + { + "file_path": "/my/path/IAgoraRtcEngine.h", + "nodes": [ + { + "__TYPE": "Clazz", + "file_path": "/my/path/IAgoraRtcEngine.h", + "name": "Test", + "namespaces": [ + "agora", + "rtc" + ], + "parent_name": "rtc" + }, + { + "__TYPE": "Enumz", + "enum_constants": [ + { + "__TYPE": "EnumConstant", + "name": "AUDIO_DEVICE1", + "source": "", + "value": "" + }, + { + "__TYPE": "EnumConstant", + "name": "AUDIO_DEVICE2", + "source": "12", + "value": "12" + }, + { + "__TYPE": "EnumConstant", + "name": "AUDIO_DEVICE3", + "source": "", + "value": "" + } + ], + "file_path": "/my/path/IAgoraRtcEngine.h", + "name": "MEDIA_DEVICE_TYPE", + "namespaces": [ + "agora", + "rtc" + ], + "parent_name": "Test" + } + ] + } +] +`; + let preParseResult = genParseResultFromJson(json); + + const result = OrderNodeParser(new TerraContext(), {}, preParseResult) + ?.nodes[0] as CXXFile; + expect(result?.nodes[0].name).toEqual('MEDIA_DEVICE_TYPE'); + expect(result?.nodes[1].name).toEqual('Test'); + }); +}); diff --git a/src/__tests__/parsers/pointer_to_array_parser.test.ts b/src/__tests__/parsers/pointer_to_array_parser.test.ts new file mode 100644 index 0000000..f2492a2 --- /dev/null +++ b/src/__tests__/parsers/pointer_to_array_parser.test.ts @@ -0,0 +1,160 @@ +import { + CXXFile, + genParseResultFromJson, +} from '@agoraio-extensions/cxx-parser'; + +import { TerraContext } from '@agoraio-extensions/terra-core'; + +import { PointerToArrayParser } from '../..'; + +describe('PointerToArrayParser', () => { + it('can process MemberFunction Variable', () => { + const json = JSON.stringify([ + { + file_path: '/my/path/IAgoraRtcEngine.h', + nodes: [ + { + __TYPE: 'Clazz', + name: 'TestClazz', + methods: [ + { + __TYPE: 'MemberFunction', + name: 'test', + parameters: [ + { + __TYPE: 'Variable', + name: 'test', + type: { + __TYPE: 'SimpleType', + is_builtin_type: false, + is_const: false, + kind: 101, + name: 'Test', + source: 'Test *', + }, + }, + ], + parent_name: 'TestClazz', + namespaces: ['test'], + }, + ], + namespaces: ['test'], + }, + ], + }, + ]); + let preParseResult = genParseResultFromJson(json); + + const result = ( + PointerToArrayParser( + new TerraContext(), + { + configJson: JSON.stringify(['test::TestClazz.test.test']), + }, + preParseResult + )?.nodes[0] as CXXFile + ).nodes[0].asClazz(); + expect(result?.methods[0].parameters[0].type.kind).toEqual(103); + }); + + it('can process MemberVariable', () => { + const json = JSON.stringify([ + { + file_path: '/my/path/IAgoraRtcEngine.h', + nodes: [ + { + __TYPE: 'Struct', + name: 'TestStruct', + member_variables: [ + { + __TYPE: 'MemberVariable', + access_specifier: '', + is_mutable: false, + name: 'test', + type: { + __TYPE: 'SimpleType', + is_builtin_type: false, + is_const: false, + kind: 101, + name: 'Test', + source: 'Test *', + }, + }, + ], + namespaces: ['test'], + }, + ], + }, + ]); + let preParseResult = genParseResultFromJson(json); + + const result = ( + PointerToArrayParser( + new TerraContext(), + { + configJson: JSON.stringify(['test::TestStruct.test']), + }, + preParseResult + )?.nodes[0] as CXXFile + ).nodes[0].asStruct(); + expect(result?.member_variables[0].type.kind).toEqual(103); + }); + + it('can process with regex', () => { + const json = JSON.stringify([ + { + file_path: '/my/path/IAgoraRtcEngine.h', + nodes: [ + { + __TYPE: 'Struct', + name: 'TestStruct', + member_variables: [ + { + __TYPE: 'MemberVariable', + access_specifier: '', + is_mutable: false, + name: 'test123', + type: { + __TYPE: 'SimpleType', + is_builtin_type: false, + is_const: false, + kind: 101, + name: 'Test', + source: 'Test *', + }, + }, + { + __TYPE: 'MemberVariable', + access_specifier: '', + is_mutable: false, + name: 'test456', + type: { + __TYPE: 'SimpleType', + is_builtin_type: false, + is_const: false, + kind: 101, + name: 'Test', + source: 'Test *', + }, + }, + ], + namespaces: ['test'], + }, + ], + }, + ]); + let preParseResult = genParseResultFromJson(json); + + const result = ( + PointerToArrayParser( + new TerraContext(), + { + configJson: JSON.stringify(['^test\\d*']), + }, + preParseResult + )?.nodes[0] as CXXFile + ).nodes[0].asStruct(); + expect(result?.member_variables[0].type.kind).toEqual(103); + expect(result?.member_variables[1].type.kind).toEqual(103); + }); +}); diff --git a/src/__tests__/parsers/remove_node_parser.test.ts b/src/__tests__/parsers/remove_node_parser.test.ts new file mode 100644 index 0000000..85b4abc --- /dev/null +++ b/src/__tests__/parsers/remove_node_parser.test.ts @@ -0,0 +1,116 @@ +import { + CXXFile, + genParseResultFromJson, +} from '@agoraio-extensions/cxx-parser'; + +import { TerraContext } from '@agoraio-extensions/terra-core'; + +import { RemoveNodeParser } from '../..'; + +describe('RemoveNodeParser', () => { + it('can process MemberFunction Variable', () => { + const json = JSON.stringify([ + { + file_path: '/my/path/IAgoraRtcEngine.h', + nodes: [ + { + __TYPE: 'Clazz', + name: 'TestClazz', + methods: [ + { + __TYPE: 'MemberFunction', + name: 'test', + parameters: [ + { + __TYPE: 'Variable', + name: 'test', + type: { + __TYPE: 'SimpleType', + is_builtin_type: false, + is_const: false, + kind: 101, + name: 'Test', + source: 'Test *', + }, + }, + ], + parent_name: 'TestClazz', + namespaces: ['test'], + }, + ], + namespaces: ['test'], + }, + ], + }, + ]); + let preParseResult = genParseResultFromJson(json); + + const result = ( + RemoveNodeParser( + new TerraContext(), + { + configJson: JSON.stringify(['test::TestClazz.test.test']), + }, + preParseResult + )?.nodes[0] as CXXFile + ).nodes[0].asClazz(); + expect(result?.methods[0].parameters.length).toEqual(0); + }); + + it('can process with regex', () => { + const json = JSON.stringify([ + { + file_path: '/my/path/IAgoraRtcEngine.h', + nodes: [ + { + __TYPE: 'Struct', + name: 'TestStruct', + member_variables: [ + { + __TYPE: 'MemberVariable', + access_specifier: '', + is_mutable: false, + name: 'test123', + type: { + __TYPE: 'SimpleType', + is_builtin_type: false, + is_const: false, + kind: 101, + name: 'Test', + source: 'Test *', + }, + }, + { + __TYPE: 'MemberVariable', + access_specifier: '', + is_mutable: false, + name: 'test456', + type: { + __TYPE: 'SimpleType', + is_builtin_type: false, + is_const: false, + kind: 101, + name: 'Test', + source: 'Test *', + }, + }, + ], + namespaces: ['test'], + }, + ], + }, + ]); + let preParseResult = genParseResultFromJson(json); + + const result = ( + RemoveNodeParser( + new TerraContext(), + { + configJson: JSON.stringify(['^test\\d*']), + }, + preParseResult + )?.nodes[0] as CXXFile + ).nodes[0].asStruct(); + expect(result?.member_variables.length).toEqual(0); + }); +}); diff --git a/src/__tests__/parsers/update_simple_type_parser.test.ts b/src/__tests__/parsers/update_simple_type_parser.test.ts new file mode 100644 index 0000000..5ec09fc --- /dev/null +++ b/src/__tests__/parsers/update_simple_type_parser.test.ts @@ -0,0 +1,198 @@ +import { + CXXFile, + genParseResultFromJson, +} from '@agoraio-extensions/cxx-parser'; + +import { TerraContext } from '@agoraio-extensions/terra-core'; + +import { UpdateSimpleTypeParser } from '../..'; + +describe('UpdateSimpleTypeParser', () => { + it('can update with full name', () => { + const json = JSON.stringify([ + { + file_path: '/my/path/IAgoraRtcEngine.h', + nodes: [ + { + __TYPE: 'Clazz', + name: 'TestClazz', + methods: [ + { + __TYPE: 'MemberFunction', + name: 'test', + parameters: [ + { + __TYPE: 'Variable', + name: 'test', + type: { + __TYPE: 'SimpleType', + is_builtin_type: false, + is_const: false, + kind: 101, + name: 'Test', + source: 'Test *', + }, + }, + ], + parent_name: 'TestClazz', + namespaces: ['test'], + return_type: { + __TYPE: 'SimpleType', + is_builtin_type: false, + is_const: false, + kind: 101, + name: 'Test', + source: 'Test *', + }, + }, + ], + namespaces: ['test'], + }, + ], + }, + ]); + let preParseResult = genParseResultFromJson(json); + + const result = ( + UpdateSimpleTypeParser( + new TerraContext(), + { + configJson: JSON.stringify({ + 'test::TestClazz.test.test': 'test', + 'test::TestClazz.test@return_type': 'ABC', + 'test::TestClazz.test.test@type': 'ABC', + }), + }, + preParseResult + )?.nodes[0] as CXXFile + ).nodes[0].asClazz(); + expect(result?.methods[0].parameters[0].source).toEqual('test'); + expect(result?.methods[0].parameters[0].type.source).toEqual('ABC'); + expect(result?.methods[0].return_type.source).toEqual('ABC'); + }); + + it('can update with type name', () => { + const json = JSON.stringify([ + { + file_path: '/my/path/IAgoraRtcEngine.h', + nodes: [ + { + __TYPE: 'Clazz', + name: 'TestClazz', + methods: [ + { + __TYPE: 'MemberFunction', + name: 'test', + parameters: [ + { + __TYPE: 'Variable', + name: 'test', + type: { + __TYPE: 'SimpleType', + is_builtin_type: false, + is_const: false, + kind: 101, + name: 'Test', + source: 'Test *', + }, + }, + ], + parent_name: 'TestClazz', + namespaces: ['test'], + return_type: { + __TYPE: 'SimpleType', + is_builtin_type: false, + is_const: false, + kind: 101, + name: 'Test', + source: 'Test *', + }, + }, + ], + namespaces: ['test'], + }, + ], + }, + ]); + let preParseResult = genParseResultFromJson(json); + + const result = ( + UpdateSimpleTypeParser( + new TerraContext(), + { + configJson: JSON.stringify({ + Test: 'ABC', + }), + }, + preParseResult + )?.nodes[0] as CXXFile + ).nodes[0].asClazz(); + expect(result?.methods[0].parameters[0].type.name).toEqual('ABC'); + expect(result?.methods[0].parameters[0].type.source).toEqual('ABC *'); + expect(result?.methods[0].return_type.name).toEqual('ABC'); + expect(result?.methods[0].return_type.source).toEqual('ABC *'); + }); + + it('can update with regex', () => { + const json = JSON.stringify([ + { + file_path: '/my/path/IAgoraRtcEngine.h', + nodes: [ + { + __TYPE: 'Clazz', + name: 'TestClazz', + methods: [ + { + __TYPE: 'MemberFunction', + name: 'test', + parameters: [ + { + __TYPE: 'Variable', + name: 'test', + type: { + __TYPE: 'SimpleType', + is_builtin_type: false, + is_const: false, + kind: 104, + name: 'Optional', + source: 'Optional', + }, + }, + ], + parent_name: 'TestClazz', + namespaces: ['test'], + return_type: { + __TYPE: 'SimpleType', + is_builtin_type: false, + is_const: false, + kind: 104, + name: 'Optional', + source: 'Optional', + }, + }, + ], + namespaces: ['test'], + }, + ], + }, + ]); + let preParseResult = genParseResultFromJson(json); + + const result = ( + UpdateSimpleTypeParser( + new TerraContext(), + { + configJson: JSON.stringify({ + 'Test': 'ABC', + '^Optional<(.*)>': '$1', + }), + }, + preParseResult + )?.nodes[0] as CXXFile + ).nodes[0].asClazz(); + expect(result?.methods[0].parameters[0].type.name).toEqual('ABC'); + expect(result?.methods[0].parameters[0].type.source).toEqual('ABC'); + expect(result?.methods[0].return_type.name).toEqual('ABC'); + expect(result?.methods[0].return_type.source).toEqual('ABC'); + }); +}); diff --git a/src/parsers/add_node_parser.ts b/src/parsers/add_node_parser.ts index 16ef674..94663ad 100644 --- a/src/parsers/add_node_parser.ts +++ b/src/parsers/add_node_parser.ts @@ -9,19 +9,23 @@ import { } from '@agoraio-extensions/cxx-parser'; import { ParseResult, TerraContext } from '@agoraio-extensions/terra-core'; -function generateCustomNodes( +export type AddNodeParserArgs = CXXParserConfigs & { + customHeaderFileNamePrefix?: string; +}; + +export const generateCustomNodes = ( parseConfig: TerraContext, cxxParserConfigs: CXXParserConfigs -): ParseResult | undefined { +): ParseResult | undefined => { const customParser = CXXParser; return customParser(parseConfig, cxxParserConfigs, undefined); -} +}; -export function AddNodeParser( +export const AddNodeParser = ( terraContext: TerraContext, - args: any, + args: AddNodeParserArgs, preParseResult?: ParseResult -): ParseResult | undefined { +): ParseResult | undefined => { const customNodes = generateCustomNodes(terraContext, args); customNodes?.nodes.forEach((f) => { let file = f as CXXFile; @@ -29,7 +33,9 @@ export function AddNodeParser( const foundFile = preParseResult?.nodes.find((it) => { return ( path.basename(file.file_path) === - `${path.basename((it as CXXFile).file_path)}` + `${args.customHeaderFileNamePrefix}${path.basename( + (it as CXXFile).file_path + )}` ); }); if (!foundFile) { @@ -81,4 +87,4 @@ export function AddNodeParser( }); }); return preParseResult; -} +}; diff --git a/src/parsers/pointer_to_array_parser.ts b/src/parsers/pointer_to_array_parser.ts index a361924..f00bdf8 100644 --- a/src/parsers/pointer_to_array_parser.ts +++ b/src/parsers/pointer_to_array_parser.ts @@ -51,11 +51,9 @@ function markArray( export function PointerToArrayParser( terraContext: TerraContext, - _args: any, + args: PointerToArrayParserArgs, preParseResult?: ParseResult ): ParseResult | undefined { - let args = _args as PointerToArrayParserArgs; - if (args.configJson === undefined) { args.configJson = readFileSync( resolvePath(args.configJsonFilePath!, terraContext.configDir) diff --git a/src/parsers/remove_node_parser.ts b/src/parsers/remove_node_parser.ts index 4cddb86..19a6d19 100644 --- a/src/parsers/remove_node_parser.ts +++ b/src/parsers/remove_node_parser.ts @@ -36,10 +36,9 @@ function filterNode( export function RemoveNodeParser( terraContext: TerraContext, - _args: any, + args: RemoveNodeParserArgs, preParseResult?: ParseResult ): ParseResult | undefined { - let args = _args as RemoveNodeParserArgs; if (args.configJson === undefined) { args.configJson = readFileSync( resolvePath(args.configJsonFilePath!, terraContext.configDir) diff --git a/src/parsers/update_simple_type_parser.ts b/src/parsers/update_simple_type_parser.ts index e424d90..9ca1728 100644 --- a/src/parsers/update_simple_type_parser.ts +++ b/src/parsers/update_simple_type_parser.ts @@ -49,10 +49,9 @@ function updateNode( export function UpdateSimpleTypeParser( terraContext: TerraContext, - _args: any, + args: UpdateSimpleTypeParserArgs, preParseResult?: ParseResult ): ParseResult | undefined { - let args = _args as UpdateSimpleTypeParserArgs; if (args.configJson === undefined) { args.configJson = readFileSync( resolvePath(args.configJsonFilePath!, terraContext.configDir)