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
|
#!/usr/bin/env python
import traceback
import pwd
import os
from os.path import join, isfile
import subprocess
import importlib
# local imports
from code_evaluator import CodeEvaluator
class CppCodeEvaluator(CodeEvaluator):
"""Tests the C code obtained from Code Server"""
def __init__(self, test_case_data, test, language, user_answer,
ref_code_path=None, in_dir=None):
super(CppCodeEvaluator, self).__init__(test_case_data, test, language,
user_answer, ref_code_path,
in_dir)
self.submit_path = self.create_submit_code_file('submit.c')
self.test_case_args = self._setup()
# Private Protocol ##########
def _setup(self):
super(CppCodeEvaluator, self)._setup()
get_ref_path = self.ref_code_path
ref_path, test_case_path = self._set_test_code_file_path(get_ref_path)
# Set file paths
c_user_output_path = os.getcwd() + '/output'
c_ref_output_path = os.getcwd() + '/executable'
# Set command variables
compile_command = 'g++ {0} -c -o {1}'.format(self.submit_path,
c_user_output_path)
compile_main = 'g++ {0} {1} -o {2}'.format(ref_path,
c_user_output_path,
c_ref_output_path)
run_command_args = [c_ref_output_path]
remove_user_output = c_user_output_path
remove_ref_output = c_ref_output_path
return (ref_path, self.submit_path, compile_command, compile_main,
run_command_args, remove_user_output, remove_ref_output)
def _teardown(self):
# Delete the created file.
super(CppCodeEvaluator, self)._teardown()
os.remove(self.submit_path)
def _check_code(self, ref_code_path, submit_code_path, compile_command,
compile_main, run_command_args, remove_user_output,
remove_ref_output):
""" Function validates student code using instructor code as
reference.The first argument ref_code_path, is the path to
instructor code, it is assumed to have executable permission.
The second argument submit_code_path, is the path to the student
code, it is assumed to have executable permission.
Returns
--------
returns (True, "Correct answer") : If the student function returns
expected output when called by reference code.
returns (False, error_msg): If the student function fails to return
expected output when called by reference code.
Returns (False, error_msg): If mandatory arguments are not files or
if the required permissions are not given to the file(s).
"""
if not isfile(ref_code_path):
return False, "No file at %s or Incorrect path" % ref_code_path
if not isfile(submit_code_path):
return False, 'No file at %s or Incorrect path' % submit_code_path
success = False
ret = self._compile_command(compile_command)
proc, stdnt_stderr = ret
stdnt_stderr = self._remove_null_substitute_char(stdnt_stderr)
# Only if compilation is successful, the program is executed
# And tested with testcases
if stdnt_stderr == '':
ret = self._compile_command(compile_main)
proc, main_err = ret
main_err = self._remove_null_substitute_char(main_err)
if main_err == '':
ret = self._run_command(run_command_args, stdin=None,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
proc, stdout, stderr = ret
if proc.returncode == 0:
success, err = True, "Correct answer"
else:
err = stdout + "\n" + stderr
os.remove(remove_ref_output)
else:
err = "Error:"
try:
error_lines = main_err.splitlines()
for e in error_lines:
if ':' in e:
err = err + "\n" + e.split(":", 1)[1]
else:
err = err + "\n" + e
except:
err = err + "\n" + main_err
os.remove(remove_user_output)
else:
err = "Compilation Error:"
try:
error_lines = stdnt_stderr.splitlines()
for e in error_lines:
if ':' in e:
err = err + "\n" + e.split(":", 1)[1]
else:
err = err + "\n" + e
except:
err = err + "\n" + stdnt_stderr
return success, err
|