summaryrefslogtreecommitdiff
path: root/testapp/exam
diff options
context:
space:
mode:
Diffstat (limited to 'testapp/exam')
-rwxr-xr-xtestapp/exam/code_server.py62
-rw-r--r--testapp/exam/models.py32
-rw-r--r--testapp/exam/views.py70
-rw-r--r--testapp/exam/xmlrpc_clients.py6
4 files changed, 47 insertions, 123 deletions
diff --git a/testapp/exam/code_server.py b/testapp/exam/code_server.py
index c070986..c34971f 100755
--- a/testapp/exam/code_server.py
+++ b/testapp/exam/code_server.py
@@ -68,8 +68,7 @@ class CodeServer(object):
'have an infinite loop in your code.' % SERVER_TIMEOUT
self.timeout_msg = msg
- def run_python_code(self, answer, test_code, test_parameter, in_dir=None): ####
- # def run_python_code(self, answer, test_code, in_dir=None): ####
+ def run_python_code(self, answer, test_parameter, in_dir=None):
"""Tests given Python function (`answer`) with the `test_code`
supplied. If the optional `in_dir` keyword argument is supplied
it changes the directory to that directory (it does not change
@@ -92,9 +91,8 @@ class CodeServer(object):
success = False
tb = None
- test_code_eval = ""
+ test_code = ""
for test_case in test_parameter:
- # for key, val in test_case.iteritems():
pos_args = ", ".join(str(i) for i in test_case.get('pos_args')) if test_case.get('pos_args') \
else ""
kw_args = ", ".join(str(k+"="+a) for k, a in test_case.get('kw_args').iteritems()) \
@@ -102,12 +100,12 @@ class CodeServer(object):
args = pos_args + ", " + kw_args if pos_args and kw_args else pos_args or kw_args
tcode = "assert {0}({1}) == {2}" \
.format(test_case.get('func_name'), args, test_case.get('expected_answer'))
- test_code_eval += tcode + "\n"
+ test_code += tcode + "\n"
try:
submitted = compile(answer, '<string>', mode='exec')
g = {}
exec submitted in g
- _tests = compile(test_code_eval, '<string>', mode='exec')
+ _tests = compile(test_code, '<string>', mode='exec')
exec _tests in g
except TimeoutException:
err = self.timeout_msg
@@ -134,10 +132,10 @@ class CodeServer(object):
# Put us back into the server pool queue since we are free now.
self.queue.put(self.port)
- return success, err
+ result = {'success': success, 'error': err}
+ return result
- # def run_bash_code(self, answer, test_code, test_parameter, in_dir=None): ####
- def run_bash_code(self, answer, test_code, in_dir=None): ####
+ def run_bash_code(self, answer, test_parameter, in_dir=None):
"""Tests given Bash code (`answer`) with the `test_code` supplied.
The testcode should typically contain two lines, the first is a path to
@@ -172,7 +170,12 @@ class CodeServer(object):
submit_path = abspath(submit_f.name)
_set_exec(submit_path)
- ref_path, test_case_path = test_code.strip().splitlines()
+ # ref path and path to arguments is a comma seperated string obtained
+ #from ref_code_path field in TestCase Mode
+ path_list = test_parameter.get('ref_code_path').split(',')
+ ref_path = path_list[0].strip() if path_list[0] else ""
+ test_case_path = path_list[1].strip() if path_list[1] else ""
+
if not ref_path.startswith('/'):
ref_path = join(MY_DIR, ref_path)
if not test_case_path.startswith('/'):
@@ -205,7 +208,8 @@ class CodeServer(object):
# Put us back into the server pool queue since we are free now.
self.queue.put(self.port)
- return success, err
+ result = {'success': success, 'error': err}
+ return result
def _run_command(self, cmd_args, *args, **kw):
"""Run a command in a subprocess while blocking, the process is killed
@@ -246,6 +250,8 @@ class CodeServer(object):
the required permissions are not given to the file(s).
"""
+ if not ref_script_path:
+ return False, "No Test Script path found"
if not isfile(ref_script_path):
return False, "No file at %s" % ref_script_path
if not isfile(submit_script_path):
@@ -255,7 +261,7 @@ class CodeServer(object):
if not os.access(submit_script_path, os.X_OK):
return False, 'Script %s is not executable' % submit_script_path
- if test_case_path is None:
+ if test_case_path is None or "":
ret = self._run_command(ref_script_path, stdin=None,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
@@ -304,8 +310,7 @@ class CodeServer(object):
stdnt_stdout+stdnt_stderr)
return False, err
- # def run_c_code(self, answer, test_code, test_parameter, in_dir=None): ####
- def run_c_code(self, answer, test_code, in_dir=None): ####
+ def run_c_code(self, answer, test_parameter, in_dir=None):
"""Tests given C code (`answer`) with the `test_code` supplied.
The testcode is a path to the reference code.
@@ -335,7 +340,7 @@ class CodeServer(object):
submit_f.close()
submit_path = abspath(submit_f.name)
- ref_path = test_code.strip()
+ ref_path = test_parameter.get('ref_code_path').strip()
if not ref_path.startswith('/'):
ref_path = join(MY_DIR, ref_path)
@@ -365,7 +370,8 @@ class CodeServer(object):
# Put us back into the server pool queue since we are free now.
self.queue.put(self.port)
- return success, err
+ result = {'success': success, 'error': err}
+ return result
def _compile_command(self, cmd, *args, **kw):
"""Compiles C/C++/java code and returns errors if any.
@@ -457,8 +463,7 @@ class CodeServer(object):
err = err + "\n" + stdnt_stderr
return success, err
- # def run_cplus_code(self, answer, test_code, test_parameter, in_dir=None): ####
- def run_cplus_code(self, answer, test_code, in_dir=None): ####
+ def run_cplus_code(self, answer, test_parameter, in_dir=None):
"""Tests given C++ code (`answer`) with the `test_code` supplied.
The testcode is a path to the reference code.
@@ -488,7 +493,7 @@ class CodeServer(object):
submit_f.close()
submit_path = abspath(submit_f.name)
- ref_path = test_code.strip()
+ ref_path = test_parameter.get('ref_code_path').strip()
if not ref_path.startswith('/'):
ref_path = join(MY_DIR, ref_path)
@@ -518,10 +523,10 @@ class CodeServer(object):
# Put us back into the server pool queue since we are free now.
self.queue.put(self.port)
- return success, err
+ result = {'success': success, 'error': err}
+ return result
- # def run_java_code(self, answer, test_code, test_parameter, in_dir=None): ####
- def run_java_code(self, answer, test_code, in_dir=None): ####
+ def run_java_code(self, answer, test_parameter, in_dir=None):
"""Tests given java code (`answer`) with the `test_code` supplied.
The testcode is a path to the reference code.
@@ -552,7 +557,7 @@ class CodeServer(object):
submit_f.close()
submit_path = abspath(submit_f.name)
- ref_path = test_code.strip()
+ ref_path = test_parameter.get('ref_code_path').strip()
if not ref_path.startswith('/'):
ref_path = join(MY_DIR, ref_path)
@@ -666,7 +671,8 @@ class CodeServer(object):
err = err + "\n" + e
except:
err = err + "\n" + stdnt_stderr
- return success, err
+ result = {'success': success, 'error': err}
+ return result
def _remove_null_substitute_char(self, string):
"""Returns a string without any null and substitute characters"""
@@ -676,8 +682,7 @@ class CodeServer(object):
stripped = stripped + c
return ''.join(stripped)
- # def run_scilab_code(self, answer, test_code, test_parameter, in_dir=None): ####
- def run_scilab_code(self, answer, test_code, in_dir=None): ####
+ def run_scilab_code(self, answer, test_parameter, in_dir=None):
"""Tests given Scilab function (`answer`) with the `test_code`
supplied. If the optional `in_dir` keyword argument is supplied
it changes the directory to that directory (it does not change
@@ -718,7 +723,7 @@ class CodeServer(object):
submit_f.close()
submit_path = abspath(submit_f.name)
- ref_path = test_code.strip()
+ ref_path = test_parameter.get('ref_code_path').strip()
if not ref_path.startswith('/'):
ref_path = join(MY_DIR, ref_path)
@@ -766,7 +771,8 @@ class CodeServer(object):
# Put us back into the server pool queue since we are free now.
self.queue.put(self.port)
- return success, err
+ result = {'success': success, 'error': err}
+ return result
def _remove_scilab_exit(self, string):
"""
diff --git a/testapp/exam/models.py b/testapp/exam/models.py
index 4eeceac..4b8f737 100644
--- a/testapp/exam/models.py
+++ b/testapp/exam/models.py
@@ -94,6 +94,7 @@ class Question(models.Model):
parameter_dict['func_name'] = i.func_name
parameter_dict['expected_answer'] = i.expected_answer
parameter_dict['ref_code_path'] = i.ref_code_path
+ parameter_dict['language'] = self.language
if i.kw_args:
for args in i.kw_args.split(","):
@@ -444,34 +445,3 @@ class TestCase(models.Model):
# Test case path to system test code applicable for CPP, C, Java and Scilab
ref_code_path = models.TextField(blank=True)
-
- # Is this Test Case public or not. If it is not
- # public it will not be visible to the user
- # public = models.BooleanField(default=False)
-
- # def consolidate_test_cases(self):
- # test_case_parameter= {}
- # kw_args_dict = {}
- # pos_args_list = []
-
- # for i in self:
- # test_case_parameter.setdefault(i.id, {})
- # test_case_parameter[i.id]['func_name'] = i.func_name
- # test_case_parameter[i.id]['expected_answer'] = i.expected_answer
-
- # for args in i.kw_args.split(","):
- # key, val = args.split("=")
- # kw_args_dict[key.strip()] = val.strip()
-
-
- # for args in i.pos_args.split(","):
- # pos_args_list.append(args.strip())
-
- # test_case_parameter[i.id]['kw_args'] = kw_args_dict
- # test_case_parameter[i.id]['pos_args'] = pos_args_list
-
- # # test_case_parameter[i.id]['kw_args'] = i.kw_args
- # # test_case_parameter[i.id]['pos_args'] = i.pos_args
-
- # return test_case_parameter
-
diff --git a/testapp/exam/views.py b/testapp/exam/views.py
index ac2668c..be0d292 100644
--- a/testapp/exam/views.py
+++ b/testapp/exam/views.py
@@ -853,44 +853,6 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None):
test = TestCase.objects.filter(question=question)
test_parameter = question.consolidate_test_cases(test)
- # ####
- # for i in TestCase.objects.all():
- # print "=====$$$$$=====KEY", i.kw_args
- # print "=====$$$$$=====POS", i.pos_args
- # print "=====$$$$$=====FUNC", i.func_name
-
- # test_case_parameters = {}
- # kw_args_dict = {}
- # pos_args_list = []
-
- # for i in TestCase.objects.all():
- # test_case_parameters.setdefault(i.id, {})
- # test_case_parameters[i.id]['func_name'] = i.func_name
- # test_case_parameters[i.id]['expected_answer'] = i.expected_answer
-
- # for args in i.kw_args.split(","):
- # key, val = args.split("=")
- # kw_args_dict[key.strip()] = val.strip()
-
-
- # for args in i.pos_args.split(","):
- # pos_args_list.append(args.strip())
-
- # test_case_parameters[i.id]['kw_args'] = kw_args_dict
- # test_case_parameters[i.id]['pos_args'] = pos_args_list
-
- # print "######-----####-----", test_case_parameters
-
- # test_obj = TestCase.objects.filter(question=question)
- # test_parameter = []
- # for i in test_obj:
- # d = {}
- # d['test_func_name'] = i.test_func_name
- # d['test_keyword_args'] = i.test_keyword_args
- # d['test_pos_args'] = i.test_pos_args
- # d['test_expected_answer'] = i.test_expected_answer
- # test_parameter.append(d)
- # ####
snippet_code = request.POST.get('snippet')
user_code = request.POST.get('answer')
skip = request.POST.get('skip', None)
@@ -903,19 +865,6 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None):
next_q = paper.skip()
return show_question(request, next_q, attempt_num, questionpaper_id)
- # ### of the form addnum(1, 2, one=2, two=2)
- # test_code_eval = ""
- # for param in test_parameter:
- # # print "TESTCASE----OUTLOOP", literal_eval(test_case['test_keyword_args'])
-
- # tcode = "assert {0}({1}, {2})\n""" \
- # .format(param.get('test_func_name'), param.get('test_pos_args'), param.get('test_keyword_args'))
- # # .format(", ".join(str(i) for i in test_case['test_pos_args']),
- # # ", ".join(str(key+"="+arg) for key, arg in eval(test_case['test_keyword_args']).iteritems()))
- # test_code_eval = "\n".join(tcode)
-
- # print test_code_eval
-
# Add the answer submitted, regardless of it being correct or not.
if question.type == 'mcq':
user_answer = request.POST.get('answer')
@@ -944,7 +893,7 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None):
# questions, we obtain the results via XML-RPC with the code executed
# safely in a separate process (the code_server.py) running as nobody.
if not question.type == 'upload':
- correct, success, err_msg = validate_answer(user, user_answer, question, test_parameter)
+ correct, result = validate_answer(user, user_answer, question, test_parameter)
if correct:
new_answer.correct = correct
new_answer.marks = question.points
@@ -955,7 +904,7 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None):
new_answer.save()
time_left = paper.time_left()
- if not success: # Should only happen for non-mcq questions.
+ if not result.get('success'): # Should only happen for non-mcq questions.
if time_left == 0:
reason = 'Your time is up!'
return complete(request, reason, attempt_num, questionpaper_id)
@@ -970,8 +919,7 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None):
if old_answer:
old_answer[0].answer = user_code
old_answer[0].save()
- context = {'question': question, 'questions': questions,
- 'error_message': err_msg,
+ context = {'question': question, 'error_message': result.get('error'),
'paper': paper, 'last_attempt': user_code,
'quiz_name': paper.question_paper.quiz.description,
'time_left': time_left, 'to_attempt': to_attempt,
@@ -990,7 +938,7 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None):
questionpaper_id, success_msg)
-def validate_answer(user, user_answer, question, test_parameter):####
+def validate_answer(user, user_answer, question, test_parameter):
"""
Checks whether the answer submitted by the user is right or wrong.
If right then returns correct = True, success and
@@ -999,9 +947,9 @@ def validate_answer(user, user_answer, question, test_parameter):####
only one attempt are allowed for them.
For code questions success is True only if the answer is correct.
"""
- success = True
+
+ result = {'success': True, 'error': 'Incorrect answer'}
correct = False
- message = 'Incorrect answer'
if user_answer is not None:
if question.type == 'mcq':
@@ -1015,11 +963,11 @@ def validate_answer(user, user_answer, question, test_parameter):####
message = 'Correct answer'
elif question.type == 'code':
user_dir = get_user_dir(user)
- success, message = code_server.run_code(user_answer, question.test, test_parameter, user_dir, question.language) ####
- if success:
+ result = code_server.run_code(user_answer, test_parameter, user_dir, question.language)
+ if result.get('success'):
correct = True
- return correct, success, message
+ return correct, result
def quit(request, attempt_num=None, questionpaper_id=None):
diff --git a/testapp/exam/xmlrpc_clients.py b/testapp/exam/xmlrpc_clients.py
index 320d627..692fbb5 100644
--- a/testapp/exam/xmlrpc_clients.py
+++ b/testapp/exam/xmlrpc_clients.py
@@ -29,7 +29,7 @@ class CodeServerProxy(object):
"scilab": "run_scilab_code",
}
- def run_code(self, answer, test_code, test_parameter, user_dir, language): ####
+ def run_code(self, answer, test_parameter, user_dir, language):
"""Tests given code (`answer`) with the `test_code` supplied. If the
optional `in_dir` keyword argument is supplied it changes the directory
to that directory (it does not change it back to the original when
@@ -55,9 +55,9 @@ class CodeServerProxy(object):
try:
server = self._get_server()
method = getattr(server, method_name)
- result = method(answer, test_code, test_parameter, user_dir) ####
+ result = method(answer, test_parameter, user_dir) ####
except ConnectionError:
- result = [False, 'Unable to connect to any code servers!']
+ result = {'success': False, 'error': 'Unable to connect to any code servers!'}
return result
def _get_server(self):