diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..195d956 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "enre-java-test"] + path = enre-java-test + url = git@github.com:ba1man/enre-java-test.git diff --git a/README.md b/README.md index 454ccf1..b1ed196 100644 --- a/README.md +++ b/README.md @@ -102,3 +102,38 @@ $java -jar enre_java.jar java ...\frameworks\base base -a # in windows platform $java -jar enre_java.jar java ...\frameworks\base base -d ...\base ``` + +## Testing + +### Prerequests + +* Node.js 16~18 + +### Steps + +ENRE-java is integrated with [ENRE-test](https://github.com/xjtu-enre/enre-test). All you need to do for performing unit test is running the following script: + +```sh +./scripts/gen_tests.sh +``` + +or (In case you're using Windows platform): + +```cmd +scripts\gen_tests.bat +``` + +Test cases and `JUnit` java files will be generated under directory `src/test/resources` and `src/test/java/client`. + +you can execute all `JUnit` test cases by executing the following command in the project directory: + +```sh +mvn clean test +``` + +or execute specific test case by passing class name: + +```sh +mvn clean test -DTest=AClassDefinesAFieldTest +``` + diff --git a/docs/entity/Class.md b/docs/entity/Class.md index 46e28b2..b1207e8 100644 --- a/docs/entity/Class.md +++ b/docs/entity/Class.md @@ -101,11 +101,11 @@ name: Anonymous Class Declaration entity: type: Class items: - - name: - qualified: Foo.doThings. + - name: + qualified: Foo.doThings. loc: 13:13 - - name: - qualified: Foo.doThings. + - name: + qualified: Foo.doThings. loc: 19:13 -``` \ No newline at end of file +``` diff --git a/docs/entity/Method.md b/docs/entity/Method.md index 13f2021..f104ffe 100644 --- a/docs/entity/Method.md +++ b/docs/entity/Method.md @@ -126,7 +126,7 @@ name: LambdaMethod Declaration entity: type: Method items: - - name: + - name: loc: 3:33:0 Lambda: true ``` diff --git a/enre-java-test b/enre-java-test new file mode 160000 index 0000000..9495d9e --- /dev/null +++ b/enre-java-test @@ -0,0 +1 @@ +Subproject commit 9495d9e5783d51e92cb552b3b1102e634b233013 diff --git a/scripts/gen_tests.bat b/scripts/gen_tests.bat new file mode 100644 index 0000000..8394d21 --- /dev/null +++ b/scripts/gen_tests.bat @@ -0,0 +1,15 @@ +@echo off + +SET ENRE_REPO=../ +SET TEST_REPO=%CD%\..\enre-java-test +git "submodule" "init" +git "submodule" "update" +pushd "%TEST_REPO%" && git "checkout" "main" && popd +IF "-d" "./%TEST_REPO%" ( + [ "-d" "./%TEST_REPO%/docs" "]" && DEL /S "./%TEST_REPO%/docs" + [ "-d" "./%TEST_REPO%/tests" "]" && DEL /S "./%TEST_REPO%/tests" + COPY "%ENRE_REPO%\docs" "%TEST_REPO%\docs" + [ "!" "-d" "%ENRE_REPO%/src/test/java/client" "]" && mkdir "-vp" "%ENRE_REPO%/src/test/java/client" + [ "!" "-d" "%ENRE_REPO%/src/test/resources" "]" && mkdir "-vp" "%ENRE_REPO%/src/test/resources" + pushd "%TEST_REPO%" && npm "install" && node "--experimental-specifier-resolution=node" "%TEST_REPO%/src/index.js" && popd && COPY "%TEST_REPO%/tests/suites/*.java" "%ENRE_REPO%/src/test/java/client/" && COPY "%TEST_REPO%/tests/cases" "%ENRE_REPO%/src/test/resources/" +) diff --git a/scripts/gen_tests.sh b/scripts/gen_tests.sh new file mode 100755 index 0000000..9f1423e --- /dev/null +++ b/scripts/gen_tests.sh @@ -0,0 +1,27 @@ +#! /usr/bin/env bash + +ENRE_REPO="./" +TEST_REPO="./enre-java-test" + +git submodule init +git submodule update + +pushd $TEST_REPO && \ + git pull origin main && \ + git checkout main && \ + popd + +if [ -d "./$TEST_REPO" ]; then + [ -d "./$TEST_REPO/docs" ] && rm -rfv "./$TEST_REPO/docs" + [ -d "./$TEST_REPO/tests" ] && rm -rfv "./$TEST_REPO/tests" + cp -rv $ENRE_REPO/docs $TEST_REPO/docs + [ ! -d "$ENRE_REPO/src/test/java/client" ] && mkdir -vp "$ENRE_REPO/src/test/java/client" + [ ! -d "$ENRE_REPO/src/test/resources" ] && mkdir -vp "$ENRE_REPO/src/test/resources" + pushd "$TEST_REPO" && \ + npm install && \ + node --experimental-specifier-resolution=node "./src/index.js" && \ + popd && \ + cp -rv $TEST_REPO/tests/suites/*.java "$ENRE_REPO/src/test/java/client/" && \ + cp -rv "$TEST_REPO/tests/cases" "$ENRE_REPO/src/test/resources/" +fi + diff --git a/test/README.md b/test/README.md deleted file mode 100644 index 0dffcd8..0000000 --- a/test/README.md +++ /dev/null @@ -1,118 +0,0 @@ -# ENRE-JAVA testing framework - -## About - -* Using [ENRE testing framework within ENRE-ts](https://github.com/xjtu-enre/enre-ts), we are able to build our own ENRE testing framework based on different programming languages and generate test code based on certain test framework. -* For instance, we will generate test code based on `JUnit` for ENRE-JAVA. - -## Installation && Build - -The whole testing framework is built based on ENRE-ts, so we need to clone the ENRE-ts repo and modify some of its files. - -Since ENRE-ts's testing framework does not provide multi-language support on its own, we have to modify its files manually. So if ENRE-ts's code updated, we need to sync its updates by ourselves. - -Here are the steps required to generate test source code files: - -1. Clone ENRE-ts repo to `${ENRE_TS_REPO}` directory: - -```sh -git clone https://github.com/xjtu-enre/enre-ts.git ${ENRE_TS_REPO} -``` - -2. Clean up existing files: - -```sh -rm -rf "${ENRE_TS_REPO}/docs" -rm -rf "${ENRE_TS_REPO}/tests" -rm -rf ${ENRE_JAVA_REPO}/src/test/java/client/*.java -rm -rf "${ENRE_JAVA_REPO}/src/test/resources/cases" -``` - -3. Copy some source code files and ENRE-java's docs directory to your ENRE-ts repo directory: - -```sh -rsync "${ENRE_JAVA_REPO}/test/basic.ts" "${ENRE_TS_REPO}/packages/enre-doc-meta-parser/src/case-meta/basic.ts" -rsync "${ENRE_JAVA_REPO}/test/raw.ts" "${ENRE_TS_REPO}/packages/enre-doc-meta-parser/src/case-meta/raw.ts" -rsync "${ENRE_JAVA_REPO}/test/index.ts" "${ENRE_TS_REPO}/packages/enre-doc-meta-parser/src/case-meta/index.ts" -rsync "${ENRE_JAVA_REPO}/test/cli.ts" "${ENRE_TS_REPO}/packages/enre-test-generator/src/cli.ts" -rsync "${ENRE_JAVA_REPO}/test/tag-anonymous.ts" "${ENRE_TS_REPO}/packages/enre-naming/src/xml/tag-anonymous.ts" -rsync -a "${ENRE_JAVA_REPO}/test/java/" "${ENRE_TS_REPO}/packages/enre-test-generator/src/java/" -rsync -a "${ENRE_JAVA_REPO}/docs" "${ENRE_TS_REPO}/" -``` - -4. cd into your ENRE-ts directory and build ENRE-ts: - -```sh -cd ${ENRE_TS_REPO} -npm install -npm run build -``` - -5. Generate tests directory (check packages/enre-test-generator/lib/cli.js for further cli parameters): - -```sh -node --experimental-specifier-resolution=node packages/enre-test-generator/lib/cli.js -``` - -6. rsync generated files to ENRE-JAVA repo: - -```sh -mkdir -p "${ENRE_JAVA_REPO}/src/test/java/client/" -rsync ${ENRE_TS_REPO}/tests/suites/*.java "${ENRE_JAVA_REPO}/src/test/java/client/" -rsync -a ${ENRE_TS_REPO}/tests/cases "${ENRE_JAVA_REPO}/src/test/resources/" -``` - -7. Then you can execute tests in command line under ENRE-JAVA repo directory: - -```sh -mvn clean test -``` - -or execute tests in IDE. - -If you want to execute single test case in command line: - -```sh -mvn clean test -Dtest="${TEST_CLASS_QUALIFIED_NAME}" -``` - -If you want to build jar package without executing tests: - -```sh -mvn clean package assembly:single -DskipTests -``` - -[jsonexport](./jsonexport.ts) is used to extract groundtruth from YAML code block to json files. - -## Issues - -### blockrange/identifier range - -* ENRE-workflow standards the line number of ENRE platform to be identifier range, so does ENRE-JAVA's docs. However ENRE-JAVA's actual line number extracted is using blockrange, so the line number of result and docs do not match. -* Now ENRE-JAVA's test framework only compares the `startLine` between result and ground truth. - -### Unimplemented entities/relations - -* There are some entities in ENRE-JAVA remain unimplemented yet. -* `Lambda` in `Method` Entity -* `Record` entity -* `Module` entity - -### `startLine` of `Package` entity - -* Every `startLine` of `package` entity in result is `0`, however in docs/realiy, `startLine` of `startLine` should be `1`. - -### Lacking `UseVar` relations - -* `MethodUseParameterTest` - -### Lacking `Modify` relations - -* `ModifyLocalVarTest` - -### `Variable` entity's rawType should be qualifiedName or name? - -* `VariableDeclarationStatementTest`: `String` or `java.lang.String`? -* `ForLoopVariableTest`: `Integer` or `java.lang.Integer`? - - diff --git a/test/basic.ts b/test/basic.ts deleted file mode 100644 index 9f5c405..0000000 --- a/test/basic.ts +++ /dev/null @@ -1,107 +0,0 @@ -/** - * Defines schema for meta describing single testcase. - * - * This a basic schema designed exclusively for languages other than JS/TS. - * JS/TS should use `raw.ts` rather than this file. - */ -export const schemaObjBasic = { - type: 'object', - properties: { - /** - * Case's name. - * - * Any non-alphabetical character will be converted to `-`. - */ - name: {type: 'string'}, - /** - * Defines entity's fetching properties. - */ - entity: { - type: 'object', - properties: { - /** - * Set `type` property for all entity items conveniently. - * - * If another `type` is presented in an item, - * that value will override this. - */ - type: {type: 'string'}, - /** - * Whether to allow unlisted entities to exist. - * - * Only items without `negative` will be counted. - * - * Rules: - * 1. If `entity.type` is set: no more entities with the explicit `entity.type`, other types are still allowed; - * 2. If `entity.type` is not set: no more entities other than those in items; - * 3. Items that `item.negative: true` will always be ignored in any circumstance. - * - * @default true - */ - extra: {type: 'boolean', default: true}, - /** - * Entities to be validated. - */ - items: { - type: 'array', - uniqueItems: true, - items: { - type: 'object', - properties: { - /** - * Entity's name. - */ - name: {type: 'string'}, - /** - * Entity's qualified name. - */ - qualified: {type: 'string'}, - /** - * Entity's location (String format explained in packages/enre-location). - */ - loc: {type: 'string'}, - /** - * Whether it is a negative test item. - * - * A negative test item is entity that should NOT be extracted. - */ - negative: {type: 'boolean', default: false}, - }, - /** - * Some entities do not possess of location info. - */ - required: ['name', 'type'], - }, - }, - }, - }, - relation: { - type: 'object', - properties: { - type: {type: 'string'}, - extra: {type: 'boolean', default: true}, - items: { - type: 'array', - uniqueItems: true, - items: { - type: 'object', - properties: { - from: {type: 'string'}, - to: {type: 'string'}, - loc: {type: 'string'}, - /** - * Negative relation expects both entities, and the relation does not exist. - */ - negative: {type: 'boolean', default: false}, - }, - required: ['from', 'to', 'loc'], - } - } - }, - } - }, - required: ['name'], -}; - -// TODO: Typing it -export type CaseSchemaBasic = any; diff --git a/test/cli.ts b/test/cli.ts deleted file mode 100644 index 34f83c0..0000000 --- a/test/cli.ts +++ /dev/null @@ -1,14 +0,0 @@ -import {Command} from 'commander'; -import handler from './java'; - -const cli = new Command(); - -cli - .description('generate test cases and suites from docs/entity/* or docs/relation/*\nleaving option empty will process all') - .option('-e --entity [name...]', - 'specify scope names in docs/entity\nleaving name empty will process all files under docs/entity') - .option('-r --relation [name...]', - 'specify scope names in docs/relation\nleaving name empty will process all files under docs/relation') - .action(handler); - -cli.parse(process.argv); diff --git a/test/deploy.sh b/test/deploy.sh deleted file mode 100755 index da77ed3..0000000 --- a/test/deploy.sh +++ /dev/null @@ -1,40 +0,0 @@ -#! /usr/bin/env bash - -export NODE_ENV="test" -ENRE_TS_REPO="$HOME/build/enre-ts" -ENRE_JAVA_REPO="$HOME/fun/enre-java" - -exec_copy() { - # copy modified files to ENRE-ts repo - rsync "${ENRE_JAVA_REPO}/test/basic.ts" "${ENRE_TS_REPO}/packages/enre-doc-meta-parser/src/case-meta/basic.ts" - rsync "${ENRE_JAVA_REPO}/test/raw.ts" "${ENRE_TS_REPO}/packages/enre-doc-meta-parser/src/case-meta/raw.ts" - rsync "${ENRE_JAVA_REPO}/test/index.ts" "${ENRE_TS_REPO}/packages/enre-doc-meta-parser/src/case-meta/index.ts" - rsync "${ENRE_JAVA_REPO}/test/cli.ts" "${ENRE_TS_REPO}/packages/enre-test-generator/src/cli.ts" - rsync "${ENRE_JAVA_REPO}/test/tag-anonymous.ts" "${ENRE_TS_REPO}/packages/enre-naming/src/xml/tag-anonymous.ts" - rsync -a "${ENRE_JAVA_REPO}/test/java/" "${ENRE_TS_REPO}/packages/enre-test-generator/src/java/" -} - -exec_prebuild() { - # clean up old generated files and docs directory - rm -rf "$ENRE_TS_REPO/docs" - rm -rf "$ENRE_TS_REPO/tests" - rm -rf $ENRE_JAVA_REPO/src/test/java/client/*.java - rm -rf "$ENRE_JAVA_REPO/src/test/resources/cases" - - # rsync `docs` directory to ENRE-ts repo - rsync -a "$ENRE_JAVA_REPO/docs" "${ENRE_TS_REPO}" -} - -exec_build() { - # npm build - cd $ENRE_TS_REPO && \ - npm install && \ - npm run build && \ - node --experimental-specifier-resolution=node packages/enre-test-generator/lib/cli.js - cd - - # rsync generated files to ENRE-JAVA - rsync $ENRE_TS_REPO/tests/suites/*.java "$ENRE_JAVA_REPO/src/test/java/client/" - rsync -a $ENRE_TS_REPO/tests/cases "$ENRE_JAVA_REPO/src/test/resources/" -} - -exec_copy && exec_prebuild && exec_build diff --git a/test/index.ts b/test/index.ts deleted file mode 100644 index b5765e7..0000000 --- a/test/index.ts +++ /dev/null @@ -1,71 +0,0 @@ -import {buildENREName} from '@enre/naming'; -import {ajv, toUrlFriendlyName} from '../common'; -import entityRefMetaParser from '../entity-ref-meta'; -import locMetaParser from '../loc-meta'; -import {schemaObj} from './raw'; -import {schemaObjBasic} from './basic'; - -export default (meta: any, useBasic = false) => { - let validator; - if (useBasic) { - validator = ajv.compile(schemaObjBasic); - } else { - validator = ajv.compile(schemaObj); - } - - let typeInitializer = meta.entity?.type; - - if (meta.entity && meta.entity.type) { - meta.entity["type"] = meta.entity.type.toLowerCase(); - } - - // Pre-fulfill fields that are not part of the schema - // Fulfill `type` for entity.items - for (const ent of meta.entity?.items || []) { - if (typeInitializer && !ent.type) { - ent.type = typeInitializer; - } - ent.type = ent.type.toLowerCase(); - } - - if (meta.relation && meta.relation.type) { - meta.relation["type"] = meta.relation.type.toLowerCase(); - } - // Fulfill `type` for relation.items - typeInitializer = meta.relation?.type; - for (const rel of meta.relation?.items || []) { - if (typeInitializer && !rel.type) { - rel.type = typeInitializer; - } - rel.type = rel.type.toLowerCase(); - } - - // After preprocessing, validate cases by ajv - const valid = validator(meta); - - if (!valid) { - throw validator.errors; - } - - // After validating, convert string representations to objects - for (const ent of (meta as any).entity?.items || []) { - ent.name = buildENREName(ent.name); - ent.loc = locMetaParser(ent.loc, ent.name); - ent.declarations ? ent.declarations = ent.declarations.forEach((d: string) => locMetaParser(d)) : undefined; - } - - for (const rel of (meta as any).relation?.items || []) { - rel.from = entityRefMetaParser(rel.from); - rel.to = entityRefMetaParser(rel.to); - rel.loc = locMetaParser(rel.loc); - - if (rel.src || rel.dest) { - throw 'You are using legacy syntax \'src\' and \'dest\', please use \'from\' and \'to\' instead'; - } - } - - // After validating, convert name to url-friendly-name - meta.name = toUrlFriendlyName(meta.name as string); - - return meta; -}; diff --git a/test/java/ASTTypes.ts b/test/java/ASTTypes.ts deleted file mode 100644 index bfd73d9..0000000 --- a/test/java/ASTTypes.ts +++ /dev/null @@ -1,262 +0,0 @@ -export const INDENT_SYMBOL = "\t"; - -export function getIndent(count: number) { - return INDENT_SYMBOL.repeat(count); -} - -export class FileDeclaration { - packageDeclaration: PackageDeclaration; - importStatements: Array; - classDeclarations: Array; - indentLevel: number; - - constructor( - packageDeclarations: PackageDeclaration, - importStatements: Array, - classDeclarations: Array, - indentLevel: number = 0, - ) { - this.packageDeclaration = packageDeclarations; - this.importStatements = importStatements; - this.classDeclarations = classDeclarations; - this.indentLevel = indentLevel; - } - - toString() { - let packageString = this.packageDeclaration.toString(); - let importString = this.importStatements.map((x) => x.toString()).join(""); - let classString = this.classDeclarations.map((x) => x.toString()).join(""); - return `${packageString}\n${importString}\n${classString}`; - } -} - -export class ImportStatement implements Statement { - name: string; - indentLevel: number; - - constructor(name: string, indentLevel: number = 1) { - this.name = name; - this.indentLevel = indentLevel; - } - - toString() { - let indentPrefix = getIndent(this.indentLevel); - return `${indentPrefix}import ${this.name};\n`; - } -} - -export class PackageDeclaration { - name: string; - indentLevel: number; - - constructor(name: string, indentLevel: number = 0) { - this.name = name; - this.indentLevel = indentLevel; - } - - toString() { - let indentPrefix = getIndent(this.indentLevel); - return `${indentPrefix}package ${this.name};\n`; - } -} - -export class ClassDeclaration { - modifiers: string | undefined; - name: string; - memberDeclarations: Array; - methods: Array; - indentLevel: number; - - constructor(modifiers: string | undefined, - name: string, - memberDeclaration: Array, - methods: Array, - indentLevel: number = 1) { - this.modifiers = modifiers; - this.name = name; - this.memberDeclarations = memberDeclaration; - this.methods = methods; - this.indentLevel = indentLevel; - } - - toString() { - let indentPrefix = getIndent(this.indentLevel); - let modifierString = this.modifiers ? this.modifiers : ""; - let signaturePrefix = `${indentPrefix}${modifierString} class ${this.name} {\n`; - let memberString = this.memberDeclarations.map((x) => x.toString()).join(""); - let methodString = this.methods.map((x) => x.toString()).join(""); - let signatureSuffix = `}\n`; - return `${signaturePrefix}${memberString}\n${methodString}\n${signatureSuffix}`; - } -} - -export class MethodDeclaration { - comment: CommentBlock | undefined; - modifiers: string | undefined; - name: string; - parameters: Array; - body: CodeBlock | undefined; - annotation: string | undefined; - indentLevel: number; - - constructor( - comment: CommentBlock | undefined, - modifiers: string | undefined, - name: string, - parameters: Array, - body: CodeBlock | undefined, - annotation: string | undefined, - indentLevel: number = 1 - ) { - this.comment = comment; - this.modifiers = modifiers; - this.name = name; - this.parameters = parameters; - this.body = body; - this.annotation = annotation; - this.indentLevel = indentLevel; - } - - toString() { - let indentPrefix = getIndent(this.indentLevel); - let parameterString = this.parameters ? this.parameters.join(", ") : ""; - let commentString = this.comment ? `${this.comment.toString()}\n` : "\n"; - let annotationString = this.annotation ? `${indentPrefix}@${this.annotation}\n` : "\n"; - let methodSignaturePrefix = `${indentPrefix}${this.modifiers} ${this.name}(${parameterString}) {\n`; - let methodBodyString = this.body ? this.body.toString() : "\n"; - let methodSignatureSuffix = `${indentPrefix}}\n\n`; - return `${commentString}${annotationString}${methodSignaturePrefix}${methodBodyString}${methodSignatureSuffix}`; - } -} - -export class Statement { - indentLevel: number; - - constructor(indentLevel: number) { - this.indentLevel = indentLevel; - } - - toString(): string { - return ""; - } -} - -export class CommentBlock extends Statement { - lines: Array; - - constructor(lines: Array, indentLevel: number = 1) { - super(indentLevel); - this.lines = lines; - } - - toString() { - let indentPrefix = getIndent(this.indentLevel); - let res = `${indentPrefix}/**\n`; - for (const line of this.lines) { - res += `${indentPrefix} * ${line}\n`; - } - res += `${indentPrefix} */`; - return res; - } -} - -export class VariableDeclaration extends Statement { - modifiers: string | undefined; - variableType: string | undefined; - name: string; - initializer: string | undefined; - - constructor( - modifiers: string | undefined, - variableType: string | undefined, - name: string, - indentLevel: number, - initializer?: string, - ) { - super(indentLevel); - this.modifiers = modifiers; - this.name = name; - this.variableType = variableType; - this.initializer = initializer; - } - - toString() { - let indentPrefix = getIndent(this.indentLevel); - let modifierString = this.modifiers ? `${this.modifiers} ` : ""; - let typeString = this.variableType ? `${this.variableType} ` : ""; - let initializerString = this.initializer ? ` = ${this.initializer}` : ""; - return `${indentPrefix}${modifierString}${typeString}${this.name}${initializerString};\n`; - } -} - -export class ThrowStatement extends Statement { - exceptionClassName: string; - message: string; - - constructor(exceptionClassName: string, message: string, indentLevel: number = 1) { - super(indentLevel); - this.exceptionClassName = exceptionClassName; - this.message = message; - } - - toString() { - let indentPrefix = getIndent(this.indentLevel); - return `${indentPrefix}throw new ${this.exceptionClassName}("${this.message}");\n`; - } -} - -export class CodeBlock { - statements: Array; - indentLevel: number; - - constructor(statements: Array, indentLevel: number = 1) { - this.statements = statements; - this.indentLevel = indentLevel; - } - - toString() { - return this.statements.map((x) => x.toString()).join(""); - } -} - -export class ConditionalStatement extends Statement { - condition: string; - trueBranch: CodeBlock; - falseBranch: CodeBlock; - - constructor(condition: string, trueBranch: CodeBlock, falseBranch: CodeBlock, indentLevel: number = 1) { - super(indentLevel); - this.condition = condition; - this.trueBranch = trueBranch; - this.falseBranch = falseBranch; - } - - toString() { - let indentPrefix = getIndent(this.indentLevel); - let res = `${indentPrefix}if (${this.condition}) {\n`; - res += this.trueBranch.toString(); - if (this.falseBranch.statements.length > 0) { - res += `${indentPrefix}} else {\n`; - res += this.falseBranch.toString(); - } - res += `${indentPrefix}}\n`; - return res; - } -} - -export class MethodInvocationStatement extends Statement { - invokeName: string; - invokeArguments: Array; - - constructor(invokeName: string, invokeArguments: Array, indentLevel: number) { - super(indentLevel); - this.invokeName = invokeName; - this.invokeArguments = invokeArguments; - } - - toString() { - let indentPrefix = getIndent(this.indentLevel); - let argumentsString = this.invokeArguments.join(", "); - return `${indentPrefix}${this.invokeName}(${argumentsString});\n`; - } -} diff --git a/test/java/JUnitBuilder.ts b/test/java/JUnitBuilder.ts deleted file mode 100644 index 2f910cb..0000000 --- a/test/java/JUnitBuilder.ts +++ /dev/null @@ -1,480 +0,0 @@ -import { - CodeBlock, - CommentBlock, ConditionalStatement, ImportStatement, - MethodDeclaration, - MethodInvocationStatement, PackageDeclaration, - Statement, ThrowStatement, - VariableDeclaration -} from "./ASTTypes"; - -export const JUNIT_COMPARE_COLUMN = false; -export const JUNIT_MODIFIERS_TEST_METHOD = "public void"; -export const JUNIT_MODIFIERS_TEST_CLASS = "public"; -export const JUNIT_ANNOTATION_BEFORE = "Before"; -export const JUNIT_ANNOTATION_AFTER = "After"; -export const JUNIT_ANNOTATION_TEST = "Test"; -export const JUNIT_INDENT_LEVEL_METHOD = 1; -export const JUNIT_INDENT_LEVEL_CLASS = 0; -export const JUNIT_INDENT_LEVEL_IMPORT = 0; -export const JUNIT_INDENT_LEVEL_PACKAGE = 0; -export const JUNIT_INDENT_LEVEL_MEMBER = 1; -export const JUNIT_INDENT_LEVEL_BLOCK = 2; -export const JUNIT_INDENT_LEVEL_BLOCK1 = 3; -export const JUNIT_INDENT_LEVEL_BLOCK2 = 4; - -const anonymousNameMap = new Map([ - ["", "Anonymous_Class"], - ["", "Anonymous_Method"], -]); - -const entityNameMap = new Map([ - ["package", "Package"], - ["file", "File"], - ["class", "Class"], - ["enum", "Enum"], - ["enum constant", "EnumConstant"], - ["annotation", "Annotation"], - ["annotation member", "AnnotationMember"], - ["interface", "Interface"], - ["method", "Method"], - ["module", "Module"], - ["record", "Record"], - ["type parameter", "TypeParameter"], - ["variable", "Variable"], -]); - -const relationNameMap = new Map([ - ["import", "Import"], - ["call", "Call"], - ["parameter", "Parameter"], - ["return", "Return"], - ["set", "Set"], - ["usevar", "UseVar"], - ["modify", "Modify"], - ["inherit", "Inherit"], - ["implement", "Implement"], - ["contain", "Contain"], - ["define", "Define"], - ["cast", "Cast"], - ["annotate", "Annotate"], - ["override", "Override"], - ["reflect", "Reflect"], - ["typed", "Typed"], -]); - -const relationCategoryMap = new Map([ - ["import", "RELATION_IMPORT"], - ["call", "RELATION_CALL"], - ["parameter", "RELATION_PARAMETER"], - ["return", "RELATION_RETURN"], - ["set", "RELATION_SET"], - ["usevar", "RELATION_USE"], - ["modify", "RELATION_MODIFY"], - ["inherit", "RELATION_INHERIT"], - ["implement", "RELATION_IMPLEMENT"], - ["contain", "RELATION_CONTAIN"], - ["define", "RELATION_DEFINE"], - ["cast", "RELATION_CAST"], - ["annotate", "RELATION_ANNOTATE"], - ["override", "RELATION_OVERRIDE"], - ["reflect", "RELATION_REFLECT"], - ["typed", "RELATION_TYPED"], -]); - -const entityCategoryMap = new Map([ - ["package", "isPackage"], - ["file", "isFile"], - ["class", "isClass"], - ["interface", "isInterface"], - ["method", "isMethod"], - ["variable", "isVariable"], - ["enum", "isEnum"], - ["enum constant", "isEnumCont"], - ["module", "isModule"], - ["annotation", "isAnnotation"], - ["annotation member", "isAnnotationMem"], - ["type parameter", "isTypeParameter"], - ["record", "isRecord"], -]); - -export function capFirst(str: string) { - return str.charAt(0).toUpperCase() + str.slice(1); -} - -export class JUnitBuilder { - - static buildOnlyContainsComment( - entityOrRelation: "entity" | "relation", - count: number, - category: string - ) { - return new CommentBlock([ - `only contains ${count} ${category} ${entityOrRelation}(s)` - ]); - } - - static buildContainsComment( - entityOrRelation: "entity" | "relation", - name: string, - category: string, - negative: boolean = false, - ) { - let categoryString: string | undefined = undefined; - if (entityOrRelation === "entity") { - categoryString = entityNameMap.get(category); - } else if (entityOrRelation === "relation") { - categoryString = relationNameMap.get(category); - } - return new CommentBlock([ - `contains ${negative ? "no" : ""}${categoryString} ${entityOrRelation} ${name}` - ]); - } - - static buildContainsRelationIndexComment( - category: string, - index: number, - negative: boolean = false - ) { - return new CommentBlock([ - `contains ${negative ? "no" : ""}${relationNameMap.get(category)} relation described in index ${index}` - ]); - } - - static buildEntityFilterStmt( - variableName: string, - category: string, - isFullName: boolean = false, - name?: string | undefined, - startLine?: number | undefined, - startColumn?: number | undefined, - ): VariableDeclaration { - let entityName = name; - if (name?.includes('"')) { - entityName = name?.replaceAll('"', '\\"'); - } - let initializer = `TestUtil.filter(entities, (x) -> singleCollect.${entityCategoryMap.get(category)}(x.getId())`; - if (name) { - initializer += ` && x.get${isFullName ? "Qualified" : ""}Name().equals("${entityName}")`; - } - if (startLine) { - initializer += ` && x.getLocation().getStartLine() == ${startLine}`; - } - if (JUNIT_COMPARE_COLUMN && startColumn) { - initializer += ` && x.getLocation().getStartColumn() == ${startColumn}`; - } - initializer += ")"; - return new VariableDeclaration("", "List", variableName, JUNIT_INDENT_LEVEL_BLOCK, initializer); - } - - static buildRelationFilterStmt( - variableName: string, - category: string, - fromIdString?: string, - toIdString?: string, - startLine?: number, - startColumn?: number, - ) { - let initializer = `TestUtil.filter(relations, (x) -> x.getRelation().getKind().equals(Configure.${relationCategoryMap.get(category.toLowerCase())})`; - if (fromIdString) { - initializer += ` && x.getFromEntityId() == ${fromIdString}`; - } - if (toIdString) { - initializer += ` && x.getToEntityId() == ${toIdString}`; - } - if (startLine) { - initializer += ` && x.getRelation().getLocation().getStartLine() == ${startLine}`; - } - if (JUNIT_COMPARE_COLUMN && startColumn) { - initializer += ` && x.getRelation().getLocation().getStartColumn() == ${startColumn}`; - } - initializer += ")"; - return new VariableDeclaration("", "List", variableName, JUNIT_INDENT_LEVEL_BLOCK, initializer); - } - - static buildAssertionStmt( - assertionName: "assertEquals" | "assertArrayEquals", - obj1: string, - obj2: string, - ): MethodInvocationStatement { - let invokeArguments : Array = []; - invokeArguments.push(obj2, obj1); - return new MethodInvocationStatement( - `Assert.${assertionName}`, - invokeArguments, - JUNIT_INDENT_LEVEL_BLOCK, - ); - } - - static buildOnlyContainsEntityMethodDeclaration( - count: number, - category: string, - ): MethodDeclaration { - let comment = this.buildOnlyContainsComment("entity", count, category); - let methodName = `onlyContains${count}${category}Entity`; - let methodParameters: Array = []; - let statements: Array = []; - let methodBody: CodeBlock = new CodeBlock(statements, JUNIT_INDENT_LEVEL_BLOCK); - let variableName = "filteredEntities"; - statements.push(this.buildEntityFilterStmt(variableName, category)); - statements.push(this.buildAssertionStmt("assertEquals", `${variableName}.size()`, `${count}`)); - return new MethodDeclaration( - comment, - JUNIT_MODIFIERS_TEST_METHOD, - methodName, - methodParameters, - methodBody, - JUNIT_ANNOTATION_TEST, - JUNIT_INDENT_LEVEL_METHOD, - ); - } - - static buildOnlyContainsRelationMethodDeclaration( - count: number, - category: string, - ): MethodDeclaration { - let comment = this.buildOnlyContainsComment("relation", count, category); - let methodName = `onlyContains${count}${category}Relation`; - let statements: Array = []; - let methodBody: CodeBlock = new CodeBlock(statements, 1); - let variableName = "filteredRelations"; - statements.push(this.buildRelationFilterStmt(variableName, category)); - statements.push(this.buildAssertionStmt("assertEquals", `${variableName}.size()`, `${count}`)); - return new MethodDeclaration( - comment, - JUNIT_MODIFIERS_TEST_METHOD, - methodName, - [], - methodBody, - JUNIT_ANNOTATION_TEST, - JUNIT_INDENT_LEVEL_METHOD, - ); - } - - static buildRelationException(condition: string, key: "from" | 'to'): ConditionalStatement { - return new ConditionalStatement( - condition, - new CodeBlock([new ThrowStatement( - "RuntimeException", - `Insufficient or wrong predicates to determine only one [${key}] entity`, - JUNIT_INDENT_LEVEL_BLOCK1, - )], - JUNIT_INDENT_LEVEL_BLOCK1, - ), - new CodeBlock([], 1), - JUNIT_INDENT_LEVEL_BLOCK, - ); - } - - static buildContainsRelationIndexMethodDeclaration( - relationCategory: string, - index: number, - negative: boolean = false, - isFromFullName: boolean = false, - isToFullName: boolean = false, - fromCategory: string, - toCategory: string, - fromName: string, - toName: string, - additionalAssertions: Array, - fromStartLine?: number, - toStartLine?: number, - relStartLine?: number, - relStartColumn?: number, - ): MethodDeclaration { - let comment = this.buildContainsRelationIndexComment(relationCategory, index, negative); - let fromVariableName = "fromEntities"; - let toVariableName = "toEntities"; - let filteredRelationsName = "filteredRelations"; - let methodName = `contains${relationNameMap.get(relationCategory)}RelationDescribedInIndex${index}`; - let statements: Array = [ - this.buildEntityFilterStmt(fromVariableName, fromCategory, isFromFullName, fromName, fromStartLine), - this.buildRelationException(`${fromVariableName}.size() != 1`, "from"), - this.buildEntityFilterStmt(toVariableName, toCategory, isToFullName, toName, toStartLine), - this.buildRelationException(`${toVariableName}.size() != 1`, "to"), - this.buildRelationFilterStmt( - filteredRelationsName, - relationCategory.toLowerCase(), - `${fromVariableName}.get(0).getId()`, - `${toVariableName}.get(0).getId()`, - relStartLine, - relStartColumn, - ), - this.buildAssertionStmt("assertEquals", `${filteredRelationsName}.size()`, `${negative? '0' : '1'}`), - ]; - if (additionalAssertions) { - statements.push(...additionalAssertions) - } - let methodBody: CodeBlock = new CodeBlock(statements, JUNIT_INDENT_LEVEL_BLOCK); - return new MethodDeclaration( - comment, - JUNIT_MODIFIERS_TEST_METHOD, - methodName, - [], - methodBody, - JUNIT_ANNOTATION_TEST, - JUNIT_INDENT_LEVEL_METHOD, - ); - } - - static buildContainsEntityMethodDeclaration( - category: string, - name: string, - negative: boolean = false, - qualified?: string, - additionalAssertions?: Array, - startLine?: number, - startColumn?: number, - endLine?: number, - endColumn?: number, - ): MethodDeclaration { - let comment = this.buildContainsComment("entity", name, category, negative); - let variableName = "filteredEntities"; - let entityName = name; - let titleName = name; - if (anonymousNameMap.has(name)) { - entityName = `${anonymousNameMap.get(name)}`; - titleName = entityName; - } - if (name.includes(".")) { - titleName = titleName.replaceAll(".", "_"); - } - let methodName = `contains${entityNameMap.get(category)}Entity${titleName}${startLine?startLine:""}`; - let statements: Array = [ - this.buildEntityFilterStmt(variableName, category, false, entityName, startLine, startColumn), - this.buildAssertionStmt("assertEquals", `${variableName}.size()`, "1"), - new VariableDeclaration("", "BaseEntity", "ent", JUNIT_INDENT_LEVEL_BLOCK, `${variableName}.get(0)`), - ]; - if (qualified) { - let qualifiedName = qualified; - if (qualified.includes('"')) { - qualifiedName = qualified.replaceAll('"', '\\"'); - } - if (anonymousNameMap.has(name)) { - qualifiedName = qualified.replace(name, `${anonymousNameMap.get(name)}`); - } - statements.push(this.buildAssertionStmt("assertEquals", "ent.getQualifiedName()", `"${qualifiedName}"`)); - } - if (additionalAssertions) { - statements.push(...additionalAssertions); - } - let loc: Array = [ - startLine? startLine : -1, - startColumn? startColumn: -1, - endLine? endLine: -1, - endColumn? endColumn: -1, - ]; - statements.push(new VariableDeclaration("", "int[]", "gt", JUNIT_INDENT_LEVEL_BLOCK, `{${loc[0]}, ${loc[1]}, ${loc[2]}, ${loc[3]}}`)); - statements.push(this.buildAssertionStmt("assertArrayEquals", "TestUtil.expandLocationArray(ent.getLocation(), gt)", "gt")); - let methodBody = new CodeBlock(statements, JUNIT_INDENT_LEVEL_METHOD); - return new MethodDeclaration( - comment, - JUNIT_MODIFIERS_TEST_METHOD, - methodName, - [], - methodBody, - JUNIT_ANNOTATION_TEST, - JUNIT_INDENT_LEVEL_METHOD, - ); - } - - static buildClassMembers() { - let res: Array = [ - new VariableDeclaration( - "private final", - "SingleCollect", - "singleCollect", - JUNIT_INDENT_LEVEL_MEMBER, - "SingleCollect.getSingleCollectInstance()", - ), - new VariableDeclaration( - "private", - "Map>>", - "relationMap", - JUNIT_INDENT_LEVEL_MEMBER, - undefined, - ), - new VariableDeclaration( - "private", - "ArrayList", - "entities", - JUNIT_INDENT_LEVEL_MEMBER, - undefined, - ), - new VariableDeclaration( - "private", - "List", - "relations", - JUNIT_INDENT_LEVEL_MEMBER, - undefined, - ), - ]; - return res; - } - - static buildImportStatements() { - let res: Array = [ - new ImportStatement("entity.BaseEntity", JUNIT_INDENT_LEVEL_IMPORT), - new ImportStatement("entity.MethodEntity", JUNIT_INDENT_LEVEL_IMPORT), - new ImportStatement("entity.VariableEntity", JUNIT_INDENT_LEVEL_IMPORT), - new ImportStatement("entity.RecordEntity", JUNIT_INDENT_LEVEL_IMPORT), - new ImportStatement("entity.properties.Relation", JUNIT_INDENT_LEVEL_IMPORT), - new ImportStatement("org.junit.Assert", JUNIT_INDENT_LEVEL_IMPORT), - new ImportStatement("org.junit.Before", JUNIT_INDENT_LEVEL_IMPORT), - new ImportStatement("org.junit.After", JUNIT_INDENT_LEVEL_IMPORT), - new ImportStatement("org.junit.Test", JUNIT_INDENT_LEVEL_IMPORT), - new ImportStatement("picocli.CommandLine", JUNIT_INDENT_LEVEL_IMPORT), - new ImportStatement("util.*", JUNIT_INDENT_LEVEL_IMPORT), - new ImportStatement("java.util.ArrayList", JUNIT_INDENT_LEVEL_IMPORT), - new ImportStatement("java.util.List", JUNIT_INDENT_LEVEL_IMPORT), - new ImportStatement("java.util.Map", JUNIT_INDENT_LEVEL_IMPORT), - ]; - return res; - } - - static buildPackageStatement() { - return new PackageDeclaration("client"); - } - - static buildBeforeMethodDeclaration(groupName: string, caseName: string) { - let methodName = "execute"; - let statements: Array = [ - new VariableDeclaration(undefined, "String", "groupName", JUNIT_INDENT_LEVEL_BLOCK, `"${groupName}"`), - new VariableDeclaration(undefined, "String", "caseName", JUNIT_INDENT_LEVEL_BLOCK, `"${caseName}"`), - new VariableDeclaration(undefined, "String[]", "args", JUNIT_INDENT_LEVEL_BLOCK, `{ "java", String.format("src/test/resources/cases/_%s/_%s/", groupName, caseName), String.format("_%s", caseName) }`), - new VariableDeclaration(undefined, "TemplateWork", "work", JUNIT_INDENT_LEVEL_BLOCK, "new TemplateWork()"), - new VariableDeclaration(undefined, undefined, "relationMap", JUNIT_INDENT_LEVEL_BLOCK, "work.execute(CommandLine.populateCommand(new EnreCommand(), args))"), - new VariableDeclaration(undefined, undefined, "relations", JUNIT_INDENT_LEVEL_BLOCK, "TestUtil.getRelations(relationMap)"), - new VariableDeclaration(undefined, undefined, "entities", JUNIT_INDENT_LEVEL_BLOCK, "singleCollect.getEntities()"), - ]; - let methodBody = new CodeBlock(statements, JUNIT_INDENT_LEVEL_BLOCK); - return new MethodDeclaration( - new CommentBlock([ - "execute ENRE-JAVA and get generated entities and relations before every test cases" - ]), - JUNIT_MODIFIERS_TEST_METHOD, - methodName, - [], - methodBody, - JUNIT_ANNOTATION_BEFORE, - JUNIT_INDENT_LEVEL_METHOD, - ); - } - - static buildAfterMethodDeclaration() { - let methodName = "clear"; - let statements: Array = [ - new MethodInvocationStatement("singleCollect.clear", [], JUNIT_INDENT_LEVEL_BLOCK), - ]; - let methodBody = new CodeBlock(statements, JUNIT_INDENT_LEVEL_BLOCK); - return new MethodDeclaration( - new CommentBlock([ - "clear ENRE-JAVA result in memory" - ]), - JUNIT_MODIFIERS_TEST_METHOD, - methodName, - [], - methodBody, - JUNIT_ANNOTATION_AFTER, - ) - } -} diff --git a/test/java/index.ts b/test/java/index.ts deleted file mode 100644 index 3d6be3d..0000000 --- a/test/java/index.ts +++ /dev/null @@ -1,245 +0,0 @@ -import parser from '@enre/doc-parser'; -import finder from '@enre/doc-path-finder'; -import {error} from '@enre/logging'; -import {promises as fs} from 'fs'; -import clean from '../cleaner'; -import { - capFirst, - JUNIT_INDENT_LEVEL_CLASS, - JUNIT_INDENT_LEVEL_PACKAGE, - JUNIT_MODIFIERS_TEST_CLASS, - JUnitBuilder -} from "./JUnitBuilder"; -import * as path from "path"; -import {Statement, ClassDeclaration, FileDeclaration, MethodDeclaration} from "./ASTTypes"; - -// TODO: Cache md5 and only regenerate files that were modified - -function getClassNameFromCaseName(caseName: string | undefined) { - if (caseName) { - return caseName.split("-").map((x) => capFirst(x)).join(""); - } - return undefined; -} - - -export default async function (opt: any) { - let prevGroupName: string | undefined = undefined; - let prevCaseName: string | undefined = undefined; - let tests: Array = []; - - await parser( - await finder(opt), - async (entry, groupMeta) => { - }, - undefined, - // build cases into filesystem - async (entry, caseObj, groupMeta) => { - const casePath = `tests/cases/_${groupMeta.name}/_${caseObj.assertion.name}`; - try { - await fs.mkdir(casePath); - } catch (e) { - } - const filePathList = []; - for (const file of caseObj.code) { - filePathList.push(file.path); - const fullPath = `${casePath}/${file.path}`; - const parent = path.dirname(fullPath); - try { - await fs.mkdir(parent, {recursive: true}); - } catch (e) { - console.log(e); - } - try { - await fs.writeFile(`${casePath}/${file.path}`, file.content); - } catch (e) { - console.log(e); - } - } - - if (prevGroupName === undefined || prevCaseName === undefined) { - prevGroupName = groupMeta.name; - prevCaseName = caseObj.assertion.name; - } - // write previous cases into file - if (tests.length !== 0) { - let className = `${getClassNameFromCaseName(prevCaseName)}Test`; - let classCase = new ClassDeclaration( - JUNIT_MODIFIERS_TEST_CLASS, - className, - JUnitBuilder.buildClassMembers(), - tests, - JUNIT_INDENT_LEVEL_CLASS, - ); - let fileCase = new FileDeclaration( - JUnitBuilder.buildPackageStatement(), - JUnitBuilder.buildImportStatements(), - [classCase], - JUNIT_INDENT_LEVEL_PACKAGE, - ); - const ast = fileCase.toString(); - try { - await fs.writeFile(`tests/suites/${className}.java`, ast); - } catch (e) { - console.error(e); - } - } - - - prevGroupName = groupMeta.name; - prevCaseName = caseObj.assertion.name; - tests = []; - if (groupMeta.name !== "END_OF_PROCESS") { - await clean(groupMeta.name); - } - // ignored package.json - - // build specific test methods and push each method into accumulatedCaseMethods - // `tests` stores all methods; each element of `tests` represents all statements in a single method - tests = []; - tests.push(JUnitBuilder.buildBeforeMethodDeclaration(groupMeta.name, caseObj.assertion.name)); - tests.push(JUnitBuilder.buildAfterMethodDeclaration()); - if (caseObj.assertion.entity) { - const entity = caseObj.assertion.entity; - if (!entity.extra) { - if (entity.type) { - // @ts-ignore - const typedCount = entity.items.filter(i => !i.negative && (i.type === entity.type)).length; - tests.push(JUnitBuilder.buildOnlyContainsEntityMethodDeclaration(typedCount, entity.type())); - } - } - - for (const ent of entity.items) { - // `test` stores single/multiple assertions within a method - let additionalAssertions: Array = []; - switch (ent.type) { - case "package": - break; - case "file": - break; - case "class": - break; - case "enum": - break; - case "enum constant": - break; - case "annotation": - break; - case "annotation member": - break; - case "interface": - break; - case "method": - if (ent.Lambda) { - additionalAssertions.push(JUnitBuilder.buildAssertionStmt("assertEquals", "((MethodEntity)ent).isLambda()", ent.Lambda ?? false)); - } - break; - case "module": - break; - case "record": - if (ent.Modifier) { - additionalAssertions.push(JUnitBuilder.buildAssertionStmt("assertEquals", "((RecordEntity)ent).getModifier()", `"${ent.Modifier}"`)); - } - break; - case "type parameter": - break; - case "variable": - if (ent.global) { - additionalAssertions.push(JUnitBuilder.buildAssertionStmt("assertEquals", "((VariableEntity)ent).getGlobal()", ent.global ?? false)); - } - if (ent.rawType) { - additionalAssertions.push(JUnitBuilder.buildAssertionStmt("assertEquals", "((VariableEntity)ent).getRawType()", `"${ent.rawType}"`)); - } - break; - default: - error(`Entity type '${ent.type}' unimplemented for testing`); - continue; - } - tests.push(JUnitBuilder.buildContainsEntityMethodDeclaration( - ent.type, - ent.name.printableName, - ent.negative, - ent.qualified, - additionalAssertions, - ent.loc.start?.line, - -1, - -1, - -1, - )); - } - - if (caseObj.assertion.relation) { - const relation = caseObj.assertion.relation; - if (!relation.extra) { - if (relation.type) { - // @ts-ignore - const typedCount = relation.items.filter(i => !i.negative && (i.type === relation.type)).length; - tests.push(JUnitBuilder.buildOnlyContainsRelationMethodDeclaration(typedCount, relation.type)); - } - } - - for (const [index, rel] of relation.items.entries()) { - let additionalAssertions: Array = []; - switch (rel.type) { - case "import": - break; - case "inherit": - break; - case "implement": - break; - case "contain": - break; - case "call": - break; - case "parameter": - break; - case "typed": - break; - case "usevar": - break; - case "set": - break; - case "modify": - break; - case "annotate": - break; - case "cast": - break; - case "override": - break; - case "reflect": - break; - case "define": - break; - default: - error(`Relation type '${rel.type}' unimplemented for testing`); - continue; - } - // @ts-ignore - tests.push( - JUnitBuilder.buildContainsRelationIndexMethodDeclaration( - rel.type, - index, - rel.negative, - rel.from.isFullName, - rel.to.isFullName, - rel.from.type, - rel.to.type, - rel.from.name, - rel.to.name, - additionalAssertions, - rel.from.predicates?.loc?.start?.line, - rel.to.predicates?.loc?.start?.line, - rel.loc.start?.line, - -1, - ) - ); - } - } - } - }, - /java/, - 'java', - false, - ); -} diff --git a/test/jsonexport.ts b/test/jsonexport.ts deleted file mode 100644 index d3ae1d6..0000000 --- a/test/jsonexport.ts +++ /dev/null @@ -1,112 +0,0 @@ -import parser from "@enre/doc-parser"; -import finder from "@enre/doc-path-finder"; -import {promises as fs} from 'fs'; -import {entityNameMap, relationNameMap} from './java/JUnitBuilder'; -import path from 'node:path'; - -interface LocationDTO { - startLine?: number; - startColumn?: number; - endLine?: number; - endColumn?: number; -} - -interface EntityDTO { - name: string; - type: string | undefined; - qualifiedName?: string; - File: string; - location: LocationDTO; - isLambda?: boolean; - Modifier?: string; - global?: boolean; - rawType?: string; - negative?: boolean; - extra?: boolean; -} - -function convertEntity(schemaObj: any) { - let res: EntityDTO = {}; - res["name"] = schemaObj["name"]["printableName"]; - res["type"] = entityNameMap.get(schemaObj["type"]); - if (res["type"] == "Method") { - res["isLambda"] = schemaObj["Lambda"]; - } else if (res["type"] == "Record") { - res["Modifier"] = schemaObj["Modifier"]; - } else if (res["type"] == "Variable") { - res["global"] = schemaObj["global"]; - res["rawType"] = schemaObj["rawType"]; - } - if ("qualified" in schemaObj) { - res["qualifiedName"] = schemaObj["qualified"]; - } - if ("negative" in schemaObj) { - res["negative"] = schemaObj["negative"]; - } - if ("extra" in schemaObj) { - res["extra"] = schemaObj["extra"]; - } - if ("loc" in schemaObj) { - const sloc = schemaObj["loc"]; - let loc: LocationDTO = {}; - if ("file" in sloc) { - res["File"] = sloc["file"]; - } - if ("start" in sloc) { - loc["startLine"] = sloc["start"]["line"]; - loc["startColumn"] = sloc["start"]["column"]; - } - if ("end" in sloc) { - loc["endLine"] = sloc["end"]["line"]; - loc["endColumn"] = sloc["end"]["column"]; - } - res["location"] = loc; - } - return res; -} - -function convertRelation(schemaObj: any) { - schemaObj["type"] = relationNameMap.get(schemaObj["type"]); - return schemaObj; -} - -export default async function(opt: any) { - await parser( - await finder(opt), - async (entry, groupMeta) => { - }, - undefined, - async (entry, caseObj, groupMeta) => { - let entities: Array = []; - let cells: Array = []; - let res = { - "variables": entities, - "cells": cells, - }; - caseObj.assertion.entity.items.forEach((x: any) => { - entities.push(convertEntity(x)); - }); - caseObj.assertion.relation?.items?.forEach((x: any) => { - cells.push(convertRelation(x)); - }); - let filename = `${caseObj.assertion.name}.json`; - let filepath = path.join("groundtruth", groupMeta.name); - try { - await fs.mkdir(filepath, { - recursive: true, - }); - } catch (error) { - console.error(error); - } - filepath = path.join(filepath, filename); - try { - await fs.writeFile(filepath, JSON.stringify(res, null, 2)); - } catch (error) { - console.error(error); - } - }, - /java/, - 'java', - false, - ); -} diff --git a/test/raw.ts b/test/raw.ts deleted file mode 100644 index 855ccae..0000000 --- a/test/raw.ts +++ /dev/null @@ -1,426 +0,0 @@ -/** - * Defines schema for meta describing single testcase. - */ -export const schemaObj = { - type: 'object', - properties: { - /** - * Case's name. - * - * Any non-alphabetical character will be converted to `-`. - */ - name: {type: 'string'}, - /** - * Config fields in package.json - */ - pkg: { - type: 'object', - properties: { - /** - * Determine what module system does the file use. - */ - type: {enum: ['commonjs', 'module']} - }, - additionalProperties: false, - }, - /** - * Assert what errors/warnings should be thrown. - * - * // TODO: Decide whether to use error id number, name or full string - */ - throw: { - type: 'array', - uniqueItems: true, - items: { - type: 'string', - } - }, - /** - * Defines entity's fetching properties. - */ - entity: { - type: 'object', - properties: { - /** - * Set `type` property for all entity items conveniently. - * - * If another `type` is presented in an item, - * that value will override this. - */ - type: { - enum: [ - 'package', - 'file', - 'class', - 'enum', - 'enum constant', - 'annotation', - 'annotation member', - 'interface', - 'method', - 'module', - 'record', - 'type parameter', - 'variable', - ], - }, - /** - * Whether to allow unlisted entities to exist. - * - * Only items without `negative` will be counted. - * - * Rules: - * 1. If `entity.type` is set: no more entities with the explicit `entity.type`, other types are still allowed; - * 2. If `entity.type` is not set: no more entities other than those in items; - * 3. Items that `item.negative: true` will always be ignored in any circumstance. - * - * @default true - */ - extra: {type: 'boolean', default: true}, - /** - * Entities to be validated. - */ - items: { - type: 'array', - uniqueItems: true, - items: { - type: 'object', - properties: { - /** - * Entity's name. - */ - name: {type: 'string'}, - /** - * Entity's qualified name. - */ - qualified: {type: 'string'}, - /** - * Entity's location (String format explained in packages/enre-location). - */ - loc: {type: 'string'}, - /** - * Whether it is a negative test item. - * - * A negative test item is entity that should NOT be extracted. - */ - negative: {type: 'boolean', default: false}, - additionalProperties: false, - }, - required: ['name', 'loc', 'type'], - oneOf: [ - /** - * package - */ - { - type: 'object', - properties: { - type: {const: 'package'}, - }, - }, - /** - * File - */ - { - type: 'object', - properties: { - type: {const: 'file'}, - }, - }, - /** - * Class - */ - { - type: 'object', - properties: { - type: {const: 'class'}, - }, - }, - /** - * Enum - */ - { - type: 'object', - properties: { - type: {const: 'enum'}, - }, - }, - /** - * Enum Constant - */ - { - type: 'object', - properties: { - type: {const: 'enum constant'}, - }, - }, - /** - * Annotation - */ - { - type: 'object', - properties: { - type: {const: 'annotation'}, - }, - }, - /** - * Annotation Member - */ - { - type: 'object', - properties: { - type: {const: 'annotation member'}, - }, - }, - /** - * Interface - */ - { - type: 'object', - properties: { - type: {const: 'interface'}, - }, - }, - /** - * Method - */ - { - type: 'object', - properties: { - type: {const: 'method'}, - Lambda: {type: 'boolean'}, - }, - }, - /** - * Module - */ - { - type: 'object', - properties: { - type: {const: 'module'}, - }, - }, - /** - * Record - */ - { - type: 'object', - properties: { - type: {const: 'record'}, - Modifier: {enum: ['public', 'protected', 'private']}, - }, - }, - /** - * Type Parameter - */ - { - type: 'object', - properties: { - type: {const: 'type parameter'}, - }, - }, - /** - * Variable - */ - { - type: 'object', - properties: { - type: {const: 'variable'}, - global: {type: 'boolean'}, - rawType: {type: 'string'}, - }, - }, - ], - }, - }, - }, - additionalProperties: false, - }, - relation: { - type: 'object', - properties: { - type: { - enum: [ - 'import', - 'inherit', - 'implement', - 'contain', - 'call', - 'parameter', - 'typed', - 'usevar', - 'set', - 'modify', - 'annotate', - 'cast', - 'override', - 'reflect', - 'define', - ] - }, - extra: {type: 'boolean', default: true}, - items: { - type: 'array', - uniqueItems: true, - items: { - type: 'object', - properties: { - from: {type: 'string'}, - to: {type: 'string'}, - loc: {type: 'string'}, - /** - * Negative relation expects both entities, and the relation does not exist. - */ - negative: {type: 'boolean', default: false}, - additionalProperties: false, - }, - required: ['from', 'to', 'loc'], - oneOf: [ - /** - * Import - */ - { - type: 'object', - properties: { - type: {const: 'import'}, - }, - }, - /** - * Inherit - */ - { - type: 'object', - properties: { - type: {const: 'inherit'}, - }, - }, - /** - * Implement - */ - { - type: 'object', - properties: { - type: {const: 'implement'}, - }, - }, - /** - * Contain - */ - { - type: 'object', - properties: { - type: {const: 'contain'}, - }, - }, - /** - * Call - */ - { - type: 'object', - properties: { - type: {const: 'call'}, - }, - }, - /** - * Parameter - */ - { - type: 'object', - properties: { - type: {const: 'parameter'}, - }, - }, - /** - * Typed - */ - { - type: 'object', - properties: { - type: {const: 'typed'}, - }, - }, - /** - * UseVar - */ - { - type: 'object', - properties: { - type: {const: 'usevar'}, - }, - }, - /** - * Set - */ - { - type: 'object', - properties: { - type: {const: 'set'}, - }, - }, - /** - * Modify - */ - { - type: 'object', - properties: { - type: {const: 'modify'}, - }, - }, - /** - * Annotate - */ - { - type: 'object', - properties: { - type: {const: 'annotate'}, - }, - }, - /** - * Cast - */ - { - type: 'object', - properties: { - type: {const: 'cast'}, - }, - }, - /** - * Override - */ - { - type: 'object', - properties: { - type: {const: 'override'}, - negative: {type: 'boolean'}, - }, - }, - /** - * Reflect - */ - { - type: 'object', - properties: { - type: {const: 'reflect'}, - }, - }, - /** - * Define - */ - { - type: 'object', - properties: { - type: {const: 'define'}, - }, - }, - ], - } - } - }, - additionalProperties: false, - } - }, - required: ['name'], - additionalProperties: false, -}; - -// TODO: Typing it -export type CaseSchema = any; diff --git a/test/tag-anonymous.ts b/test/tag-anonymous.ts deleted file mode 100644 index 40c285c..0000000 --- a/test/tag-anonymous.ts +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Allowed types for `Anonymous` entity name. - */ -export const ENRENameAnonymousTypes = [ - 'Function', - 'ArrowFunction', - 'Class', - 'CallableSignature', - 'NumberIndexSignature', - 'StringIndexSignature', - - // To support cross-tester - 'Namespace', - 'Package', - 'Struct', - 'Union', - 'Enum', - 'Variable', - 'Method' -] as const; - -export type ENRENameAnonymousType = typeof ENRENameAnonymousTypes[number]; - -/** - * An object representing properties needed by an anonymous entity. - */ -export type ENRENameAnonymous = { - /** - * Indicates in which type of anonymous entity this is. - */ - readonly as: ENRENameAnonymousType; -}