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:
@@ -4,6 +4,7 @@ WORKDIR /opt/test-runner
|
||||
COPY . .
|
||||
RUN npm ci
|
||||
RUN npm run build
|
||||
RUN npm install @abaplint/cli -g
|
||||
RUN npm install @abaplint/transpiler-cli -g
|
||||
RUN npm install @abaplint/runtime -g
|
||||
ENTRYPOINT ["/opt/test-runner/bin/run.sh"]
|
||||
17
package-lock.json
generated
17
package-lock.json
generated
@@ -9,6 +9,7 @@
|
||||
"version": "0.1.0",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"@abaplint/cli": "^2.82.1",
|
||||
"@abaplint/runtime": "^1.6.66",
|
||||
"@abaplint/transpiler": "^1.6.66",
|
||||
"@abaplint/transpiler-cli": "^1.6.66"
|
||||
@@ -26,6 +27,17 @@
|
||||
"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": {
|
||||
"version": "2.80.10",
|
||||
"resolved": "https://registry.npmjs.org/@abaplint/core/-/core-2.80.10.tgz",
|
||||
@@ -1211,6 +1223,11 @@
|
||||
}
|
||||
},
|
||||
"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": {
|
||||
"version": "2.80.10",
|
||||
"resolved": "https://registry.npmjs.org/@abaplint/core/-/core-2.80.10.tgz",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"dependencies": {
|
||||
"@abaplint/transpiler-cli": "^1.6.66",
|
||||
"@abaplint/transpiler": "^1.6.66",
|
||||
"@abaplint/cli": "^2.82.1",
|
||||
"@abaplint/runtime": "^1.6.66"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
81
src/index.ts
81
src/index.ts
@@ -26,12 +26,47 @@ export interface ITranspilerConfig {
|
||||
options: Transpiler.ITranspilerOptions;
|
||||
}
|
||||
|
||||
const COMPILE_RESULT = "_compile_result.txt";
|
||||
const RUN_RESULT = "_run_result.txt";
|
||||
const output: IOutput = {
|
||||
version: 1,
|
||||
status: "pass",
|
||||
}
|
||||
|
||||
function run() {
|
||||
class Runner {
|
||||
private readonly tmpDir: string;
|
||||
|
||||
let config: ITranspilerConfig = {
|
||||
public constructor() {
|
||||
this.tmpDir = fs.mkdtempSync(path.join(tmpdir(), 'exercism-abap-runner-'));
|
||||
}
|
||||
|
||||
public run() {
|
||||
this.initialize();
|
||||
this.syntaxAndDownport();
|
||||
if (output.status === "pass") {
|
||||
this.transpile();
|
||||
}
|
||||
if (output.status === "pass") {
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
private initialize() {
|
||||
const config: ITranspilerConfig = {
|
||||
input_folder: ".",
|
||||
input_filter: [],
|
||||
output_folder: "compiled",
|
||||
@@ -46,49 +81,49 @@ function run() {
|
||||
}
|
||||
}
|
||||
|
||||
const tmpDir = fs.mkdtempSync(path.join(tmpdir(), 'exercism-abap-runner-'));
|
||||
fs.writeFileSync(path.join(tmpDir, "abap_transpile.json"), JSON.stringify(config, null, 2));
|
||||
execSync(`cp ${inputDir}/*.abap ${tmpDir}`, {stdio: 'pipe'});
|
||||
fs.mkdirSync(`${tmpDir}/deps`);
|
||||
execSync(`cp open-abap/src/unit/*.clas.abap ${tmpDir}/deps/`, {stdio: 'pipe'});
|
||||
execSync(`cp open-abap/src/classrun/*.intf.abap ${tmpDir}/deps/`, {stdio: 'pipe'});
|
||||
|
||||
const output: IOutput = {
|
||||
version: 1,
|
||||
status: "pass",
|
||||
fs.writeFileSync(path.join(this.tmpDir, "abap_transpile.json"), JSON.stringify(config, null, 2));
|
||||
execSync(`cp ${inputDir}/*.abap ${this.tmpDir}`, {stdio: 'pipe'});
|
||||
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'});
|
||||
}
|
||||
|
||||
private transpile() {
|
||||
const COMPILE_RESULT = "_compile_result.txt";
|
||||
try {
|
||||
execSync(`abap_transpile > ` + COMPILE_RESULT, {
|
||||
stdio: 'pipe',
|
||||
cwd: tmpDir});
|
||||
cwd: this.tmpDir});
|
||||
} catch (error) {
|
||||
output.status = "error";
|
||||
output.message = fs.readFileSync(path.join(tmpDir, COMPILE_RESULT), "utf-8");
|
||||
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`, {
|
||||
stdio: 'pipe',
|
||||
cwd: tmpDir });
|
||||
cwd: this.tmpDir });
|
||||
|
||||
try {
|
||||
execSync(`node compiled/index.mjs > ` + RUN_RESULT, {
|
||||
stdio: 'pipe',
|
||||
cwd: tmpDir});
|
||||
cwd: this.tmpDir});
|
||||
} catch (error) {
|
||||
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")) {
|
||||
output.message = output.message.split("Error: ASSERT failed")[0] + "Error: ASSERT failed";
|
||||
}
|
||||
output.message = output.message.trim();
|
||||
}
|
||||
}
|
||||
|
||||
fs.writeFileSync(outputFile, JSON.stringify(output));
|
||||
}
|
||||
|
||||
run();
|
||||
new Runner().run();
|
||||
54
test/test.ts
54
test/test.ts
@@ -20,40 +20,40 @@ function checkExpected(expectedFile: string): void {
|
||||
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 () => {
|
||||
it('simple, pass', async () => {
|
||||
const slug = "simple-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"));
|
||||
test("simple-pass", "pass");
|
||||
});
|
||||
|
||||
it('simple, fail', async () => {
|
||||
const slug = "simple-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-fail', async () => {
|
||||
test("simple-fail", "fail");
|
||||
});
|
||||
|
||||
it('simple, syntax error', async () => {
|
||||
const slug = "simple-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('simple-error', async () => {
|
||||
test("simple-error", "error");
|
||||
});
|
||||
|
||||
it('hello-world, pass', async () => {
|
||||
const slug = "hello-world-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('hello-world-pass', async () => {
|
||||
test("hello-world-pass", "pass");
|
||||
});
|
||||
|
||||
it('simple-all-fail', async () => {
|
||||
test("simple-all-fail", "fail");
|
||||
});
|
||||
|
||||
it('simple-some-fail', async () => {
|
||||
test("simple-some-fail", "fail");
|
||||
});
|
||||
|
||||
it('simple-downport-pass', async () => {
|
||||
test("simple-downport-pass", "pass");
|
||||
});
|
||||
});
|
||||
1
tests/simple-all-fail/expected_results.json
Normal file
1
tests/simple-all-fail/expected_results.json
Normal file
@@ -0,0 +1 @@
|
||||
{"version":1,"status":"fail","message":"ZCL_SIMPLE: running ltcl_simple->test1\n\nError: ASSERT failed"}
|
||||
12
tests/simple-all-fail/zcl_simple.clas.abap
Normal file
12
tests/simple-all-fail/zcl_simple.clas.abap
Normal 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.
|
||||
23
tests/simple-all-fail/zcl_simple.clas.testclasses.abap
Normal file
23
tests/simple-all-fail/zcl_simple.clas.testclasses.abap
Normal 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.
|
||||
1
tests/simple-downport-pass/expected_results.json
Normal file
1
tests/simple-downport-pass/expected_results.json
Normal file
@@ -0,0 +1 @@
|
||||
{"version":1,"status":"pass"}
|
||||
12
tests/simple-downport-pass/zcl_simple.clas.abap
Normal file
12
tests/simple-downport-pass/zcl_simple.clas.abap
Normal 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.
|
||||
17
tests/simple-downport-pass/zcl_simple.clas.testclasses.abap
Normal file
17
tests/simple-downport-pass/zcl_simple.clas.testclasses.abap
Normal 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.
|
||||
@@ -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"}
|
||||
1
tests/simple-some-fail/expected_results.json
Normal file
1
tests/simple-some-fail/expected_results.json
Normal 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"}
|
||||
12
tests/simple-some-fail/zcl_simple.clas.abap
Normal file
12
tests/simple-some-fail/zcl_simple.clas.abap
Normal 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.
|
||||
23
tests/simple-some-fail/zcl_simple.clas.testclasses.abap
Normal file
23
tests/simple-some-fail/zcl_simple.clas.testclasses.abap
Normal 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.
|
||||
Reference in New Issue
Block a user