downport and unit tests (#12)

* refactor tests

* additional unit tests, closes #10

* refactor

* better error messages

* add downport step, closes #9

* test
This commit is contained in:
Lars Hvam
2021-11-25 18:23:15 +01:00
committed by GitHub
parent 94a1e2392c
commit e088e2de27
15 changed files with 224 additions and 68 deletions

View File

@@ -4,6 +4,7 @@ WORKDIR /opt/test-runner
COPY . . COPY . .
RUN npm ci RUN npm ci
RUN npm run build RUN npm run build
RUN npm install @abaplint/cli -g
RUN npm install @abaplint/transpiler-cli -g RUN npm install @abaplint/transpiler-cli -g
RUN npm install @abaplint/runtime -g RUN npm install @abaplint/runtime -g
ENTRYPOINT ["/opt/test-runner/bin/run.sh"] ENTRYPOINT ["/opt/test-runner/bin/run.sh"]

17
package-lock.json generated
View File

@@ -9,6 +9,7 @@
"version": "0.1.0", "version": "0.1.0",
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"dependencies": { "dependencies": {
"@abaplint/cli": "^2.82.1",
"@abaplint/runtime": "^1.6.66", "@abaplint/runtime": "^1.6.66",
"@abaplint/transpiler": "^1.6.66", "@abaplint/transpiler": "^1.6.66",
"@abaplint/transpiler-cli": "^1.6.66" "@abaplint/transpiler-cli": "^1.6.66"
@@ -26,6 +27,17 @@
"typescript": "^4.5.2" "typescript": "^4.5.2"
} }
}, },
"node_modules/@abaplint/cli": {
"version": "2.82.1",
"resolved": "https://registry.npmjs.org/@abaplint/cli/-/cli-2.82.1.tgz",
"integrity": "sha512-ZG5ykfBbUYw2dfe69k1ON4yQKNpzr+ddV4OwtYYU8/TPyPMkXnzn9hTPigiNK3SxyoKTW2X1KLtfllLAx5V+KA==",
"bin": {
"abaplint": "abaplint"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/@abaplint/core": { "node_modules/@abaplint/core": {
"version": "2.80.10", "version": "2.80.10",
"resolved": "https://registry.npmjs.org/@abaplint/core/-/core-2.80.10.tgz", "resolved": "https://registry.npmjs.org/@abaplint/core/-/core-2.80.10.tgz",
@@ -1211,6 +1223,11 @@
} }
}, },
"dependencies": { "dependencies": {
"@abaplint/cli": {
"version": "2.82.1",
"resolved": "https://registry.npmjs.org/@abaplint/cli/-/cli-2.82.1.tgz",
"integrity": "sha512-ZG5ykfBbUYw2dfe69k1ON4yQKNpzr+ddV4OwtYYU8/TPyPMkXnzn9hTPigiNK3SxyoKTW2X1KLtfllLAx5V+KA=="
},
"@abaplint/core": { "@abaplint/core": {
"version": "2.80.10", "version": "2.80.10",
"resolved": "https://registry.npmjs.org/@abaplint/core/-/core-2.80.10.tgz", "resolved": "https://registry.npmjs.org/@abaplint/core/-/core-2.80.10.tgz",

View File

@@ -28,6 +28,7 @@
"dependencies": { "dependencies": {
"@abaplint/transpiler-cli": "^1.6.66", "@abaplint/transpiler-cli": "^1.6.66",
"@abaplint/transpiler": "^1.6.66", "@abaplint/transpiler": "^1.6.66",
"@abaplint/cli": "^2.82.1",
"@abaplint/runtime": "^1.6.66" "@abaplint/runtime": "^1.6.66"
}, },
"devDependencies": { "devDependencies": {

View File

@@ -26,69 +26,104 @@ export interface ITranspilerConfig {
options: Transpiler.ITranspilerOptions; options: Transpiler.ITranspilerOptions;
} }
const COMPILE_RESULT = "_compile_result.txt"; const output: IOutput = {
const RUN_RESULT = "_run_result.txt"; version: 1,
status: "pass",
}
function run() { class Runner {
private readonly tmpDir: string;
let config: ITranspilerConfig = { public constructor() {
input_folder: ".", this.tmpDir = fs.mkdtempSync(path.join(tmpdir(), 'exercism-abap-runner-'));
input_filter: [], }
output_folder: "compiled",
lib: "", public run() {
write_source_map: true, this.initialize();
write_unit_tests: true, this.syntaxAndDownport();
options: { if (output.status === "pass") {
ignoreSyntaxCheck: false, this.transpile();
addFilenames: true, }
addCommonJS: true, if (output.status === "pass") {
unknownTypes: "runtimeError", this.executeTests();
}
fs.writeFileSync(outputFile, JSON.stringify(output));
}
private syntaxAndDownport() {
const LINT_RESULT = "_abaplint.txt";
const abaplintConfig = Transpiler.config;
abaplintConfig.rules["downport"] = true;
fs.writeFileSync(path.join(this.tmpDir, "abaplint.json"), JSON.stringify(abaplintConfig, null, 2));
try {
execSync(`abaplint --fix > ` + LINT_RESULT, {
stdio: 'pipe',
cwd: this.tmpDir});
} catch (error) {
output.status = "error";
output.message = fs.readFileSync(path.join(this.tmpDir, LINT_RESULT), "utf-8");
} }
} }
const tmpDir = fs.mkdtempSync(path.join(tmpdir(), 'exercism-abap-runner-')); private initialize() {
fs.writeFileSync(path.join(tmpDir, "abap_transpile.json"), JSON.stringify(config, null, 2)); const config: ITranspilerConfig = {
execSync(`cp ${inputDir}/*.abap ${tmpDir}`, {stdio: 'pipe'}); input_folder: ".",
fs.mkdirSync(`${tmpDir}/deps`); input_filter: [],
execSync(`cp open-abap/src/unit/*.clas.abap ${tmpDir}/deps/`, {stdio: 'pipe'}); output_folder: "compiled",
execSync(`cp open-abap/src/classrun/*.intf.abap ${tmpDir}/deps/`, {stdio: 'pipe'}); lib: "",
write_source_map: true,
write_unit_tests: true,
options: {
ignoreSyntaxCheck: false,
addFilenames: true,
addCommonJS: true,
unknownTypes: "runtimeError",
}
}
const output: IOutput = { fs.writeFileSync(path.join(this.tmpDir, "abap_transpile.json"), JSON.stringify(config, null, 2));
version: 1, execSync(`cp ${inputDir}/*.abap ${this.tmpDir}`, {stdio: 'pipe'});
status: "pass", fs.mkdirSync(`${this.tmpDir}/deps`);
execSync(`cp open-abap/src/unit/*.clas.abap ${this.tmpDir}/deps/`, {stdio: 'pipe'});
execSync(`cp open-abap/src/exceptions/* ${this.tmpDir}/deps/`, {stdio: 'pipe'});
execSync(`cp open-abap/src/ddic/*.xml ${this.tmpDir}/deps/`, {stdio: 'pipe'});
execSync(`cp open-abap/src/classrun/*.intf.abap ${this.tmpDir}/deps/`, {stdio: 'pipe'});
execSync(`rm ${this.tmpDir}/deps/*.testclasses.*`, {stdio: 'pipe'});
} }
try { private transpile() {
execSync(`abap_transpile > ` + COMPILE_RESULT, { const COMPILE_RESULT = "_compile_result.txt";
stdio: 'pipe', try {
cwd: tmpDir}); execSync(`abap_transpile > ` + COMPILE_RESULT, {
} catch (error) { stdio: 'pipe',
output.status = "error"; cwd: this.tmpDir});
output.message = fs.readFileSync(path.join(tmpDir, COMPILE_RESULT), "utf-8"); } catch (error) {
output.message = output.message.split("at Transpiler.validate")[0]; output.status = "error";
output.message = output.message.trim(); output.message = fs.readFileSync(path.join(this.tmpDir, COMPILE_RESULT), "utf-8");
output.message = output.message.split("at Transpiler.validate")[0];
output.message = output.message.trim();
}
} }
if (output.status === "pass") { private executeTests() {
const RUN_RESULT = "_run_result.txt";
execSync(`npm link @abaplint/runtime`, { execSync(`npm link @abaplint/runtime`, {
stdio: 'pipe', stdio: 'pipe',
cwd: tmpDir }); cwd: this.tmpDir });
try { try {
execSync(`node compiled/index.mjs > ` + RUN_RESULT, { execSync(`node compiled/index.mjs > ` + RUN_RESULT, {
stdio: 'pipe', stdio: 'pipe',
cwd: tmpDir}); cwd: this.tmpDir});
} catch (error) { } catch (error) {
output.status = "fail"; output.status = "fail";
output.message = fs.readFileSync(path.join(tmpDir, RUN_RESULT), "utf-8"); output.message = fs.readFileSync(path.join(this.tmpDir, RUN_RESULT), "utf-8");
if (output.message.includes("Error: ASSERT failed")) { if (output.message.includes("Error: ASSERT failed")) {
output.message = output.message.split("Error: ASSERT failed")[0] + "Error: ASSERT failed"; output.message = output.message.split("Error: ASSERT failed")[0] + "Error: ASSERT failed";
} }
output.message = output.message.trim(); output.message = output.message.trim();
} }
} }
fs.writeFileSync(outputFile, JSON.stringify(output));
} }
run(); new Runner().run();

View File

@@ -20,40 +20,40 @@ function checkExpected(expectedFile: string): void {
expect(act).to.equal(exp); expect(act).to.equal(exp);
} }
function test(slug: string, expectedStatus: string) {
const path = join(fixtures, slug);
const res = spawnSync('bash', [run, slug, path, output], {cwd: root});
expect(res.status).to.equal(0);
checkExpected(join(path, "expected_results.json"));
expect(readResult().status).to.equal(expectedStatus);
}
describe('abap-test-runner', async () => { describe('abap-test-runner', async () => {
it('simple, pass', async () => { it('simple, pass', async () => {
const slug = "simple-pass"; test("simple-pass", "pass");
const path = join(fixtures, slug);
const res = spawnSync('bash', [run, slug, path, output], {cwd: root});
expect(res.status).to.equal(0);
expect(readResult().status).to.equal("pass");
checkExpected(join(path, "expected_results.json"));
}); });
it('simple, fail', async () => { it('simple-fail', async () => {
const slug = "simple-fail"; test("simple-fail", "fail");
const path = join(fixtures, slug);
const res = spawnSync('bash', [run, slug, path, output], {cwd: root});
expect(res.status).to.equal(0);
expect(readResult().status).to.equal("fail");
checkExpected(join(path, "expected_results.json"));
}); });
it('simple, syntax error', async () => { it('simple-error', async () => {
const slug = "simple-error"; test("simple-error", "error");
const path = join(fixtures, slug);
const res = spawnSync('bash', [run, slug, path, output], {cwd: root});
expect(res.status).to.equal(0);
expect(readResult().status).to.equal("error");
checkExpected(join(path, "expected_results.json"));
}); });
it('hello-world, pass', async () => { it('hello-world-pass', async () => {
const slug = "hello-world-pass"; test("hello-world-pass", "pass");
const path = join(fixtures, slug); });
const res = spawnSync('bash', [run, slug, path, output], {cwd: root});
expect(res.status).to.equal(0); it('simple-all-fail', async () => {
expect(readResult().status).to.equal("pass"); test("simple-all-fail", "fail");
checkExpected(join(path, "expected_results.json")); });
it('simple-some-fail', async () => {
test("simple-some-fail", "fail");
});
it('simple-downport-pass', async () => {
test("simple-downport-pass", "pass");
}); });
}); });

View File

@@ -0,0 +1 @@
{"version":1,"status":"fail","message":"ZCL_SIMPLE: running ltcl_simple->test1\n\nError: ASSERT failed"}

View File

@@ -0,0 +1,12 @@
CLASS zcl_simple DEFINITION PUBLIC.
PUBLIC SECTION.
METHODS run RETURNING VALUE(res) TYPE i.
ENDCLASS.
CLASS zcl_simple IMPLEMENTATION.
METHOD run.
res = 3.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,23 @@
CLASS ltcl_simple DEFINITION FOR TESTING RISK LEVEL HARMLESS DURATION SHORT FINAL.
PRIVATE SECTION.
METHODS test1 FOR TESTING RAISING cx_static_check.
METHODS test2 FOR TESTING RAISING cx_static_check.
ENDCLASS.
CLASS ltcl_simple IMPLEMENTATION.
METHOD test1.
cl_abap_unit_assert=>assert_equals(
act = 2
exp = 123 ).
ENDMETHOD.
METHOD test2.
cl_abap_unit_assert=>assert_equals(
act = 2
exp = 36 ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1 @@
{"version":1,"status":"pass"}

View File

@@ -0,0 +1,12 @@
CLASS zcl_simple DEFINITION PUBLIC.
PUBLIC SECTION.
METHODS run RETURNING VALUE(res) TYPE i.
ENDCLASS.
CLASS zcl_simple IMPLEMENTATION.
METHOD run.
res = 3.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,17 @@
CLASS ltcl_simple DEFINITION FOR TESTING RISK LEVEL HARMLESS DURATION SHORT FINAL.
PRIVATE SECTION.
METHODS test FOR TESTING RAISING cx_static_check.
ENDCLASS.
CLASS ltcl_simple IMPLEMENTATION.
METHOD test.
DATA(simple) = NEW zcl_simple( ).
cl_abap_unit_assert=>assert_equals(
act = simple->run( )
exp = 3 ).
ENDMETHOD.
ENDCLASS.

View File

@@ -1 +1 @@
{"version":1,"status":"error","message":"Transpiler CLI\nUsing config: abap_transpile.json\n7 files added\n0 files skipped\n\nBuilding\nError: parser_error, Statement does not exist in ABAPopen-abap(or a parser error), \"blah\", zcl_simple.clas.abap:9"} {"version":1,"status":"error","message":"./zcl_simple.clas.abap[9, 5] - Statement does not exist in ABAPopen-abap(or a parser error), \"blah\" (parser_error) [E]\nabaplint: 1 issue(s) found, 59 file(s) analyzed\nFixes applied"}

View File

@@ -0,0 +1 @@
{"version":1,"status":"fail","message":"ZCL_SIMPLE: running ltcl_simple->test1\nZCL_SIMPLE: running ltcl_simple->test2\n\nError: ASSERT failed"}

View File

@@ -0,0 +1,12 @@
CLASS zcl_simple DEFINITION PUBLIC.
PUBLIC SECTION.
METHODS run RETURNING VALUE(res) TYPE i.
ENDCLASS.
CLASS zcl_simple IMPLEMENTATION.
METHOD run.
res = 3.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,23 @@
CLASS ltcl_simple DEFINITION FOR TESTING RISK LEVEL HARMLESS DURATION SHORT FINAL.
PRIVATE SECTION.
METHODS test1 FOR TESTING RAISING cx_static_check.
METHODS test2 FOR TESTING RAISING cx_static_check.
ENDCLASS.
CLASS ltcl_simple IMPLEMENTATION.
METHOD test1.
cl_abap_unit_assert=>assert_equals(
act = 2
exp = 2 ).
ENDMETHOD.
METHOD test2.
cl_abap_unit_assert=>assert_equals(
act = 2
exp = 36 ).
ENDMETHOD.
ENDCLASS.