114
114
true = classmethod(lambda *x: True)
115
115
false = classmethod(lambda *x: False)
117
def __init__(self, succeed, fail, default='match'):
118
"""Initialise with descriptions (succeed,fail) and a default behavior for output
117
def __init__(self, pass_msg, fail_msg, default='match'):
118
"""Initialise with descriptions (pass,fail) and a default behavior for output
119
119
If default is match, unspecified files are matched exactly
120
120
If default is ignore, unspecified files are ignored
121
121
The default default is match.
123
self._succeed = succeed
123
self._pass_msg = pass_msg
124
self._fail_msg = fail_msg
125
125
self._default = default
126
126
if default == 'ignore':
127
127
self._default_func = self.true
133
133
self._stderr_test = ('check', self._default_func)
134
134
self._exception_test = ('check', self._default_func)
135
135
self._result_test = ('check', self._default_func)
136
self._code_test = ('check', self._default_func)
137
138
def _set_default_function(self, function, test_type):
138
139
""""Ensure test type is valid and set function to a default
150
151
def _validate_function(self, function, included_code):
151
152
"""Create a function object from the given string.
152
If a valid function object cannot be created, raise and error.
153
If a valid function object cannot be created, raise an error.
154
155
if not callable(function):
184
185
"Test part that compares function return values"
185
186
function = self._set_default_function(function, test_type)
186
187
self._result_test = (test_type, function)
189
189
def add_stdout_test(self, function, test_type='norm'):
190
190
"Test part that compares stdout"
191
191
function = self._set_default_function(function, test_type)
192
192
self._stdout_test = (test_type, function)
195
194
def add_stderr_test(self, function, test_type='norm'):
196
195
"Test part that compares stderr"
207
206
function = self._set_default_function(function, test_type)
208
207
self._file_tests[filename] = (test_type, function)
209
def add_code_test(self, function, test_type='norm'):
210
"Test part that examines the supplied code"
211
function = self._set_default_function(function, test_type)
212
self._code_test = (test_type, function)
210
214
def _check_output(self, solution_output, attempt_output, test_type, f):
211
215
"""Compare solution output and attempt output using the
212
specified comparision function.
216
specified comparison function.
214
218
# converts unicode to string
215
219
if type(solution_output) == unicode:
224
228
return f(solution_output, attempt_output)
230
def _check_code(self, solution, attempt, test_type, f):
231
"""Compare solution code and attempt code using the
232
specified comparison function.
235
raise TestCreationError("Invalid function %s" %f)
236
if test_type == 'norm':
237
return f(solution) == f(attempt)
239
return f(solution, attempt)
226
241
def run(self, solution_data, attempt_data):
227
242
"""Run the tests to compare the solution and attempt data
228
243
Returns the empty string if the test passes, or else an error message.
246
# check source code itself
247
(test_type, f) = self._code_test
248
if not self._check_code(solution_data['code'], attempt_data['code'], test_type, f):
249
return 'Unexpected code'
231
251
# check function return value (None for scripts)
232
252
(test_type, f) = self._result_test
233
253
if not self._check_output(solution_data['result'], attempt_data['result'], test_type, f):
234
return 'function return value does not match'
254
return 'Unexpected function return value'
237
257
(test_type, f) = self._stdout_test
238
258
if not self._check_output(solution_data['stdout'], attempt_data['stdout'], test_type, f):
239
return 'stdout does not match'
259
return 'Unexpected output'
242
262
(test_type, f) = self._stderr_test
243
263
if not self._check_output(solution_data['stderr'], attempt_data['stderr'], test_type, f):
244
return 'stderr does not match'
264
return 'Unexpected error output'
247
267
(test_type, f) = self._exception_test
248
268
if not self._check_output(solution_data['exception'], attempt_data['exception'], test_type, f):
249
return 'exception does not match'
269
return 'Unexpected exception'
252
271
solution_files = solution_data['modified_files']
253
272
attempt_files = attempt_data['modified_files']
404
423
raise TestError(sys.exc_info())
407
result_dict['description'] = test_part._succeed
426
result_dict['description'] = test_part._pass_msg
408
427
result_dict['passed'] = (result == '')
409
428
if result_dict['passed'] == False:
410
429
result_dict['error_message'] = result
411
result_dict['description'] = test_part._fail
430
result_dict['description'] = test_part._fail_msg
414
433
results.append(result_dict)
422
441
""" Execute the file given by 'filename' in global_space, and return the outputs. """
423
442
self._initialise_global_space(global_space)
424
443
data = self._run_function(lambda: execfile(filename, global_space))
444
data['code'] = open(filename).read()
427
447
def _execstring(self, string, global_space):
522
543
self._tests.append(test_case)
523
544
test_case.validate_functions(self._include_space)
525
def run_tests(self, attempt_code, stop_on_fail=True):
546
def run_tests(self, attempt_code, stop_on_fail=False):
526
547
" Run all test cases and collate the results "
528
549
problem_dict = {}