-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtest-parser.js
155 lines (118 loc) · 4.63 KB
/
test-parser.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// file system access
const fs = require("fs");
// sandboxing
const vm = require("vm");
// Dodona types
const {Message, Submission, Tab, Context, TestCase, Test} = require("./dodona.js");
//
// TestParser: parser for test cases
//
class TestParser {
constructor() {
// support for tab switches
this.tabSwitched = false; // context switch since last testcase
// support for context switches
this.autoSwitchContext = true; // automatic context switching between testcases
this.contextSwitched = false; // context switch since last testcase
// create new submission
this.feedback = new Submission();
}
parse(testFile, options) {
// options parameter is optional
options = options || {};
// setup separate scope in which tests will be parsed
const scope = { judge: this };
// setup sandbox for parsing of tests
const sandbox = new vm.createContext(scope);
// define options for evaluating submitted source code and tests
const sandboxOptions = {
filename: "<tests>",
lineOffset: 0,
columnOffset: 0,
displayErrors: true,
timeout: options.time_limit ? Math.max(1, options.time_limit): 1000
};
// parse tests
vm.runInContext(
fs.readFileSync(testFile, "utf8"),
sandbox,
sandboxOptions
);
// return feedback
return this.feedback;
}
test(expression, expected, comparison) {
// switch to new context if automatic context switching is on and no
// context switch has happend since last testcase
if (this.autoSwitchContext && !this.contextSwitched) {
this.feedback.addContext(new Context());
}
// get ready for next tab and context switch
this.tabSwitched = false;
this.contextSwitched = false;
// add expression as testcase
this.feedback.addTestCase(new TestCase({description: expression}));
// determine channel of expected result
let channel = "return";
if (
typeof expected === "string" &&
expected.slice(0, 10) === "exception:"
) {
channel = "exception";
// remove "expection:" prefix in case of expected exception
expected = expected.slice(10);
}
// add expected result
this.feedback.addTest(
new Test({
expected: expected,
data: {
channel: channel,
evaluation: {
comparison: comparison,
// capture additional arguments passed on to the test
// method (following the expression to evaluate, the
// expected result and the comparison function to be
// used; these additional argument will be provided to
// the comparison function, following the expected and
// generated result
arguments: [].slice.call(arguments, 3)
}
}
})
);
}
config(name, value) {
if (name === "switch-context") {
// switch context if not already switched
if (!this.contextSwitched) {
this.feedback.addContext(new Context());
this.contextSwitched = true;
}
} else if (name === "auto-switch-context") {
// check if value is a Boolean
if (typeof value !== "boolean") {
throw new Error(
"parameter \"auto-switch-context\" must be a boolean"
);
}
// switch context if not already switched
this.autoSwitchContext = value;
} else if (name === "switch-tab") {
// check if value is a string
if (typeof value !== "string") {
throw new Error(
"parameter \"switch-tab\" must be a string"
);
}
// switch context if not already switched
if (!this.tabSwitched) {
this.feedback.addTab(new Tab({
description: value
}));
this.tabSwitched = true;
}
}
}
}
module.exports = TestParser;