summaryrefslogtreecommitdiff
path: root/testapp
diff options
context:
space:
mode:
authorankitjavalkar2015-04-24 14:25:26 +0530
committerankitjavalkar2015-04-26 21:11:52 +0530
commit8664a766406d6acf0d6a1688948153c407ea27f2 (patch)
tree7505ef02b5e36395fc7e92ff5cde7700f2025979 /testapp
parent17752a69114e7dbad266337e768013920aec8c0c (diff)
downloadonline_test-8664a766406d6acf0d6a1688948153c407ea27f2.tar.gz
online_test-8664a766406d6acf0d6a1688948153c407ea27f2.tar.bz2
online_test-8664a766406d6acf0d6a1688948153c407ea27f2.zip
Code Review: Code refactoring
- Rename files - Create function for @classmethod call - Fix current, add new testcases - Fix views to fetch solution/ref_code_path fields in question post save - Fix errors
Diffstat (limited to 'testapp')
-rw-r--r--testapp/docs/sample_questions.py84
-rw-r--r--testapp/docs/sample_questions.xml43
-rw-r--r--testapp/exam/bash_files/sample.args (renamed from testapp/docs/sample.args)0
-rwxr-xr-xtestapp/exam/bash_files/sample.sh (renamed from testapp/docs/sample.sh)0
-rwxr-xr-xtestapp/exam/code_server.py34
-rw-r--r--testapp/exam/evaluate_bash_code.py (renamed from testapp/exam/evaluate_bash.py)24
-rw-r--r--testapp/exam/evaluate_c_code.py (renamed from testapp/exam/evaluate_c.py)13
-rw-r--r--testapp/exam/evaluate_code.py (renamed from testapp/exam/test_code.py)24
-rw-r--r--testapp/exam/evaluate_cpp_code.py (renamed from testapp/exam/evaluate_cpp.py)13
-rw-r--r--testapp/exam/evaluate_java_code.py (renamed from testapp/exam/evaluate_java.py)22
-rw-r--r--testapp/exam/evaluate_python_code.py (renamed from testapp/exam/evaluate_python.py)16
-rw-r--r--testapp/exam/evaluate_scilab_code.py (renamed from testapp/exam/evaluate_scilab.py)15
-rw-r--r--testapp/exam/language_registry.py (renamed from testapp/exam/registry.py)6
-rw-r--r--testapp/exam/models.py30
-rw-r--r--testapp/exam/views.py19
-rw-r--r--testapp/exam/xmlrpc_clients.py6
-rw-r--r--testapp/test_server.py187
17 files changed, 298 insertions, 238 deletions
diff --git a/testapp/docs/sample_questions.py b/testapp/docs/sample_questions.py
deleted file mode 100644
index 60f32cb..0000000
--- a/testapp/docs/sample_questions.py
+++ /dev/null
@@ -1,84 +0,0 @@
-from datetime import date
-
-questions = [
-[Question(
- summary='Factorial',
- points=2,
- language='python',
- type='code',
- description='''
-Write a function called <code>fact</code> which takes a single integer argument
-(say <code>n</code>) and returns the factorial of the number.
-For example:<br/>
-<code>fact(3) -> 6</code>
-''',
- test='''
-assert fact(0) == 1
-assert fact(5) == 120
-''',
- snippet="def fact(num):"
- ),
-#Add tags here as a list of string.
-['Python','function','factorial'],
-],
-
-[Question(
- summary='Simple function',
- points=1,
- language='python',
- type='code',
- description='''Create a simple function called <code>sqr</code> which takes a single
-argument and returns the square of the argument. For example: <br/>
-<code>sqr(3) -> 9</code>.''',
- test='''
-import math
-assert sqr(3) == 9
-assert abs(sqr(math.sqrt(2)) - 2.0) < 1e-14
- ''',
- snippet="def sqr(num):"
- ),
-#Add tags here as a list of string.
-['Python','function'],
-],
-
-[Question(
- summary='Bash addition',
- points=2,
- language='bash',
- type='code',
- description='''Write a shell script which takes two arguments on the
- command line and prints the sum of the two on the output.''',
- test='''\
-docs/sample.sh
-docs/sample.args
-''',
- snippet="#!/bin/bash"
- ),
-#Add tags here as a list of string.
-[''],
-],
-
-[Question(
- summary='Size of integer in Python',
- points=0.5,
- language='python',
- type='mcq',
- description='''What is the largest integer value that can be represented
-in Python?''',
- options='''No Limit
-2**32
-2**32 - 1
-None of the above
-''',
- test = "No Limit"
- ),
-#Add tags here as a list of string.
-['mcq'],
-],
-
-] #list of questions ends here
-
-quiz = Quiz(start_date=date.today(),
- duration=10,
- description='Basic Python Quiz 1'
- )
diff --git a/testapp/docs/sample_questions.xml b/testapp/docs/sample_questions.xml
deleted file mode 100644
index 53c76f8..0000000
--- a/testapp/docs/sample_questions.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<question_bank>
-
-<question>
-<summary>
-Factorial
-</summary>
-<description>
-Write a function called "fact" which takes a single integer argument (say "n")
-and returns the factorial of the number.
-For example fact(3) -> 6
-</description>
-<points>2</points>
-<type>python</type>
-<test>
-assert fact(0) == 1
-assert fact(5) == 120
-</test>
-<options>
-</options>
-</question>
-
-<question>
-<summary>
-Simple function
-</summary>
-<description>
-Create a simple function called "sqr" which takes a single argument and
-returns the square of the argument
-For example sqr(3) -> 9.
-</description>
-<points>1</points>
-<type>python</type>
-<test>
-import math
-assert sqr(3) == 9
-assert abs(sqr(math.sqrt(2)) - 2.0) &lt; 1e-14
-</test>
-<options>
-</options>
-</question>
-
-
-</question_bank>
diff --git a/testapp/docs/sample.args b/testapp/exam/bash_files/sample.args
index 4d9f00d..4d9f00d 100644
--- a/testapp/docs/sample.args
+++ b/testapp/exam/bash_files/sample.args
diff --git a/testapp/docs/sample.sh b/testapp/exam/bash_files/sample.sh
index e935cb3..e935cb3 100755
--- a/testapp/docs/sample.sh
+++ b/testapp/exam/bash_files/sample.sh
diff --git a/testapp/exam/code_server.py b/testapp/exam/code_server.py
index db30798..111562a 100755
--- a/testapp/exam/code_server.py
+++ b/testapp/exam/code_server.py
@@ -32,16 +32,17 @@ import json
import importlib
# Local imports.
from settings import SERVER_PORTS, SERVER_TIMEOUT, SERVER_POOL_PORT
-from registry import registry
-from evaluate_python import EvaluatePython
-from evaluate_c import EvaluateC
-from evaluate_cpp import EvaluateCpp
-from evaluate_java import EvaluateJava
-from evaluate_scilab import EvaluateScilab
-from evaluate_bash import EvaluateBash
+from language_registry import registry
+from evaluate_python_code import EvaluatePythonCode
+from evaluate_c_code import EvaluateCCode
+from evaluate_cpp_code import EvaluateCppCode
+from evaluate_java_code import EvaluateJavaCode
+from evaluate_scilab_code import EvaluateScilabCode
+from evaluate_bash_code import EvaluateBashCode
MY_DIR = abspath(dirname(__file__))
+## Private Protocol ##########
def run_as_nobody():
"""Runs the current process as nobody."""
# Set the effective uid and to that of nobody.
@@ -60,10 +61,11 @@ class CodeServer(object):
self.port = port
self.queue = queue
- def check_code(self, info_parameter, language, in_dir=None):
- """Calls the TestCode SUb Class based on language to test the current code"""
- evaluate_code_class = registry.get_class(language)
- evaluate_code_instance = evaluate_code_class.from_json(info_parameter, language, in_dir)
+ ## Public Protocol ##########
+ def check_code(self, language, json_data, in_dir=None):
+ """Calls relevant EvaluateCode class based on language to check the answer code"""
+ evaluate_code_instance = self.create_class_instance(language, json_data, in_dir)
+
result = evaluate_code_instance.run_code()
# Put us back into the server pool queue since we are free now.
@@ -71,6 +73,14 @@ class CodeServer(object):
return json.dumps(result)
+ ## Public Protocol ##########
+ def create_class_instance(self, language, json_data, in_dir):
+ """Create instance of relevant EvaluateCode class based on language"""
+ cls = registry.get_class(language)
+ instance = cls.from_json(language, json_data, in_dir)
+ return instance
+
+ ## Public Protocol ##########
def run(self):
"""Run XMLRPC server, serving our methods."""
server = SimpleXMLRPCServer(("localhost", self.port))
@@ -110,6 +120,8 @@ class ServerPool(object):
p.start()
self.servers = servers
+ ## Public Protocol ##########
+
def get_server_port(self):
"""Get available server port from ones in the pool. This will block
till it gets an available server.
diff --git a/testapp/exam/evaluate_bash.py b/testapp/exam/evaluate_bash_code.py
index fd769cd..49f20fa 100644
--- a/testapp/exam/evaluate_bash.py
+++ b/testapp/exam/evaluate_bash_code.py
@@ -7,20 +7,22 @@ import subprocess
import importlib
# local imports
-from test_code import TestCode
-from registry import registry
+from evaluate_code import EvaluateCode
+from language_registry import registry
-class EvaluateBash(TestCode):
+class EvaluateBashCode(EvaluateCode):
"""Tests the Bash code obtained from Code Server"""
+ ## Public Protocol ##########
def evaluate_code(self):
- fpath = self.create_submit_code_file('submit.sh')
- submit_path = self.set_file_as_executable(fpath)
+ submit_path = self.create_submit_code_file('submit.sh')
+ self.set_file_as_executable(submit_path)
get_ref_path, get_test_case_path = self.ref_code_path.strip().split(',')
+ get_ref_path = get_ref_path.strip()
+ get_test_case_path = get_test_case_path.strip()
ref_path, test_case_path = self.set_test_code_file_path(get_ref_path, get_test_case_path)
- success = False
- success, err = self.check_bash_script(ref_path, submit_path,
+ success, err = self._check_bash_script(ref_path, submit_path,
test_case_path)
# Delete the created file.
@@ -28,7 +30,8 @@ class EvaluateBash(TestCode):
return success, err
- def check_bash_script(self, ref_path, submit_path,
+ ## Private Protocol ##########
+ def _check_bash_script(self, ref_path, submit_path,
test_case_path=None):
""" Function validates student script using instructor script as
reference. Test cases can optionally be provided. The first argument
@@ -61,6 +64,8 @@ class EvaluateBash(TestCode):
if not os.access(submit_path, os.X_OK):
return False, "Script %s is not executable" % submit_path
+ success = False
+
if test_case_path is None or "":
ret = self.run_command(ref_path, stdin=None,
stdout=subprocess.PIPE,
@@ -110,4 +115,5 @@ class EvaluateBash(TestCode):
stdnt_stdout+stdnt_stderr)
return False, err
-registry.register('bash', EvaluateBash) \ No newline at end of file
+
+registry.register('bash', EvaluateBashCode) \ No newline at end of file
diff --git a/testapp/exam/evaluate_c.py b/testapp/exam/evaluate_c_code.py
index 0700daa..d52beae 100644
--- a/testapp/exam/evaluate_c.py
+++ b/testapp/exam/evaluate_c_code.py
@@ -7,12 +7,13 @@ import subprocess
import importlib
# local imports
-from test_code import TestCode
-from registry import registry
+from evaluate_code import EvaluateCode
+from language_registry import registry
-class EvaluateC(TestCode):
+class EvaluateCCode(EvaluateCode):
"""Tests the C code obtained from Code Server"""
+ ## Public Protocol ##########
def evaluate_code(self):
submit_path = self.create_submit_code_file('submit.c')
get_ref_path = self.ref_code_path
@@ -42,6 +43,7 @@ class EvaluateC(TestCode):
return success, err
+ ## Public Protocol ##########
def check_code(self, ref_code_path, submit_code_path, compile_command,
compile_main, run_command_args, remove_user_output,
remove_ref_output):
@@ -64,7 +66,6 @@ class EvaluateC(TestCode):
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):
@@ -122,6 +123,7 @@ class EvaluateC(TestCode):
return success, err
+ ## Public Protocol ##########
def remove_null_substitute_char(self, string):
"""Returns a string without any null and substitute characters"""
stripped = ""
@@ -130,4 +132,5 @@ class EvaluateC(TestCode):
stripped = stripped + c
return ''.join(stripped)
-registry.register('c', EvaluateC) \ No newline at end of file
+
+registry.register('c', EvaluateCCode) \ No newline at end of file
diff --git a/testapp/exam/test_code.py b/testapp/exam/evaluate_code.py
index 8930f55..161c1a2 100644
--- a/testapp/exam/test_code.py
+++ b/testapp/exam/evaluate_code.py
@@ -21,6 +21,7 @@ MY_DIR = abspath(dirname(__file__))
class TimeoutException(Exception):
pass
+## Private Protocol ##########
def timeout_handler(signum, frame):
"""A handler for the ALARM signal."""
@@ -49,26 +50,28 @@ def delete_signal_handler():
###############################################################################
# `TestCode` class.
###############################################################################
-class TestCode(object):
+class EvaluateCode(object):
"""Tests the code obtained from Code Server"""
- def __init__(self, test_parameter, language, user_answer, ref_code_path=None, in_dir=None):
+ def __init__(self, test_case_data, language, user_answer, ref_code_path=None, in_dir=None):
msg = 'Code took more than %s seconds to run. You probably '\
'have an infinite loop in your code.' % SERVER_TIMEOUT
self.timeout_msg = msg
- self.test_parameter = test_parameter
+ self.test_case_data = test_case_data
self.language = language.lower()
self.user_answer = user_answer
self.ref_code_path = ref_code_path
self.in_dir = in_dir
+ ## Public Protocol ##########
+
@classmethod
- def from_json(cls, blob, language, in_dir):
- info_parameter = json.loads(blob)
- test_parameter = info_parameter.get("test_parameter")
- user_answer = info_parameter.get("user_answer")
- ref_code_path = info_parameter.get("ref_code_path")
+ def from_json(cls, language, json_data, in_dir):
+ json_data = json.loads(json_data)
+ test_case_data = json_data.get("test_case_data")
+ user_answer = json_data.get("user_answer")
+ ref_code_path = json_data.get("ref_code_path")
- instance = cls(test_parameter, language, user_answer, ref_code_path, in_dir)
+ instance = cls(Test_case_data, language, user_answer, ref_code_path, in_dir)
return instance
def run_code(self):
@@ -122,7 +125,6 @@ class TestCode(object):
def create_submit_code_file(self, file_name):
""" Write the code (`answer`) to a file and set the file path"""
- # File name/extension depending on the question language
submit_f = open(file_name, 'w')
submit_f.write(self.user_answer.lstrip())
submit_f.close()
@@ -177,6 +179,8 @@ class TestCode(object):
raise
return proc_compile, err
+ ## Private Protocol ##########
+
def _change_dir(self, in_dir):
if in_dir is not None and isdir(in_dir):
os.chdir(in_dir) \ No newline at end of file
diff --git a/testapp/exam/evaluate_cpp.py b/testapp/exam/evaluate_cpp_code.py
index cffe744..ed744d1 100644
--- a/testapp/exam/evaluate_cpp.py
+++ b/testapp/exam/evaluate_cpp_code.py
@@ -7,14 +7,14 @@ import subprocess
import importlib
# local imports
-from evaluate_c import EvaluateC
-from test_code import TestCode
-from registry import registry
+from evaluate_c_code import EvaluateCCode
+from evaluate_code import EvaluateCode
+from language_registry import registry
-
-class EvaluateCpp(EvaluateC, TestCode):
+class EvaluateCppCode(EvaluateCCode, EvaluateCode):
"""Tests the C code obtained from Code Server"""
+ ## Public Protocol ##########
def evaluate_code(self):
submit_path = self.create_submit_code_file('submitstd.cpp')
get_ref_path = self.ref_code_path
@@ -44,4 +44,5 @@ class EvaluateCpp(EvaluateC, TestCode):
return success, err
-registry.register('cpp', EvaluateCpp) \ No newline at end of file
+
+registry.register('cpp', EvaluateCppCode) \ No newline at end of file
diff --git a/testapp/exam/evaluate_java.py b/testapp/exam/evaluate_java_code.py
index d3d4e2a..9ddbbed 100644
--- a/testapp/exam/evaluate_java.py
+++ b/testapp/exam/evaluate_java_code.py
@@ -7,27 +7,26 @@ import subprocess
import importlib
# local imports
-from evaluate_c import EvaluateC
-from test_code import TestCode
-from registry import registry
+from evaluate_c_code import EvaluateCCode
+from evaluate_code import EvaluateCode
+from language_registry import registry
-
-class EvaluateJava(EvaluateC, TestCode):
+class EvaluateJavaCode(EvaluateCCode, EvaluateCode):
"""Tests the C code obtained from Code Server"""
+ ## Public Protocol ##########
def evaluate_code(self):
submit_path = self.create_submit_code_file('Test.java')
- get_ref_path = self.ref_code_path
- ref_path, test_case_path = self.set_test_code_file_path(get_ref_path)
+ ref_path, test_case_path = self.set_test_code_file_path(self.ref_code_path)
success = False
# Set file paths
java_student_directory = os.getcwd() + '/'
- java_ref_file_name = (ref_code_path.split('/')[-1]).split('.')[0]
+ java_ref_file_name = (ref_path.split('/')[-1]) #.split('.')[0]
# Set command variables
- compile_command = 'javac {0}'.format(submit_code_path),
- compile_main = 'javac {0} -classpath {1} -d {2}'.format(ref_code_path,
+ compile_command = 'javac {0}'.format(submit_path),
+ compile_main = 'javac {0} -classpath {1} -d {2}'.format(ref_path,
java_student_directory,
java_student_directory)
run_command_args = "java -cp {0} {1}".format(java_student_directory,
@@ -46,4 +45,5 @@ class EvaluateJava(EvaluateC, TestCode):
return success, err
-registry.register('java', EvaluateJava) \ No newline at end of file
+
+registry.register('java', EvaluateJavaCode) \ No newline at end of file
diff --git a/testapp/exam/evaluate_python.py b/testapp/exam/evaluate_python_code.py
index 3af82b6..2682897 100644
--- a/testapp/exam/evaluate_python.py
+++ b/testapp/exam/evaluate_python_code.py
@@ -6,12 +6,13 @@ from os.path import join
import importlib
# local imports
-from test_code import TestCode
-from registry import registry
+from evaluate_code import EvaluateCode
+from language_registry import registry
-class EvaluatePython(TestCode):
+
+class EvaluatePythonCode(EvaluateCode):
"""Tests the Python code obtained from Code Server"""
- # def evaluate_python_code(self):
+ ## Public Protocol ##########
def evaluate_code(self):
success = False
@@ -36,13 +37,13 @@ class EvaluatePython(TestCode):
del tb
return success, err
- # Private Protocol
+ ## Private Protocol ##########
def _create_test_case(self):
"""
Create assert based test cases in python
"""
test_code = ""
- for test_case in self.test_parameter:
+ for test_case in self.test_case_data:
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()) \
@@ -53,4 +54,5 @@ class EvaluatePython(TestCode):
test_code += tcode + "\n"
return test_code
-registry.register('python', EvaluatePython) \ No newline at end of file
+
+registry.register('python', EvaluatePythonCode) \ No newline at end of file
diff --git a/testapp/exam/evaluate_scilab.py b/testapp/exam/evaluate_scilab_code.py
index f4253ff..cc46605 100644
--- a/testapp/exam/evaluate_scilab.py
+++ b/testapp/exam/evaluate_scilab_code.py
@@ -7,13 +7,13 @@ import re
import importlib
# local imports
-from test_code import TestCode
-from registry import registry
+from evaluate_code import EvaluateCode
+from language_registry import registry
-class EvaluateScilab(TestCode):
+class EvaluateScilabCode(EvaluateCode):
"""Tests the Scilab code obtained from Code Server"""
- # def evaluate_scilab_code(self):
+ ## Public Protocol ##########
def evaluate_code(self):
submit_path = self.create_submit_code_file('function.sci')
ref_path, test_case_path = self.set_test_code_file_path()
@@ -44,7 +44,7 @@ class EvaluateScilab(TestCode):
return success, err
- # Private Protocol
+ ## Private Protocol ##########
def _remove_scilab_exit(self, string):
"""
Removes exit, quit and abort from the scilab code
@@ -60,6 +60,7 @@ class EvaluateScilab(TestCode):
new_string = new_string +'\n'+ new_line
return new_string, i
+ ## Private Protocol ##########
def _get_error(self, string):
"""
Fetches only the error from the string.
@@ -70,6 +71,7 @@ class EvaluateScilab(TestCode):
return obj.group()
return None
+ ## Private Protocol ##########
def _strip_output(self, out):
"""
Cleans whitespace from the output
@@ -80,4 +82,5 @@ class EvaluateScilab(TestCode):
strip_out = strip_out+"\n"+l.strip()
return strip_out
-registry.register('scilab', EvaluateScilab) \ No newline at end of file
+
+registry.register('scilab', EvaluateScilabCode) \ No newline at end of file
diff --git a/testapp/exam/registry.py b/testapp/exam/language_registry.py
index ef995ac..207cd21 100644
--- a/testapp/exam/registry.py
+++ b/testapp/exam/language_registry.py
@@ -1,14 +1,16 @@
#!/usr/bin/env python
-class Registry(object):
+class LanguageRegistry(object):
def __init__(self):
self._registry = {}
+ ## Public Protocol ##########
def get_class(self, language):
return self._registry[language]
+ ## Public Protocol ##########
def register(self, language, cls):
self._registry[language] = cls
-registry = Registry() \ No newline at end of file
+registry = LanguageRegistry() \ No newline at end of file
diff --git a/testapp/exam/models.py b/testapp/exam/models.py
index d0c9cc2..51e773a 100644
--- a/testapp/exam/models.py
+++ b/testapp/exam/models.py
@@ -88,17 +88,17 @@ class Question(models.Model):
tags = TaggableManager()
def consolidate_answer_data(self, test_cases, user_answer):
- test_case_parameter = []
- info_parameter = {}
+ test_case_data_dict = []
+ question_info_dict = {}
for test_case in test_cases:
kw_args_dict = {}
pos_args_list = []
- parameter_dict = {}
- parameter_dict['test_id'] = test_case.id
- parameter_dict['func_name'] = test_case.func_name
- parameter_dict['expected_answer'] = test_case.expected_answer
+ test_case_data = {}
+ test_case_data['test_id'] = test_case.id
+ test_case_data['func_name'] = test_case.func_name
+ test_case_data['expected_answer'] = test_case.expected_answer
if test_case.kw_args:
for args in test_case.kw_args.split(","):
@@ -109,17 +109,17 @@ class Question(models.Model):
for args in test_case.pos_args.split(","):
pos_args_list.append(args.strip())
- parameter_dict['kw_args'] = kw_args_dict
- parameter_dict['pos_args'] = pos_args_list
- test_case_parameter.append(parameter_dict)
+ test_case_data['kw_args'] = kw_args_dict
+ test_case_data['pos_args'] = pos_args_list
+ test_case_data_dict.append(test_case_data)
- # info_parameter['language'] = self.language
- info_parameter['id'] = self.id
- info_parameter['user_answer'] = user_answer
- info_parameter['test_parameter'] = test_case_parameter
- info_parameter['ref_code_path'] = self.ref_code_path
+ # question_info_dict['language'] = self.language
+ question_info_dict['id'] = self.id
+ question_info_dict['user_answer'] = user_answer
+ question_info_dict['test_parameter'] = test_case_data_dict
+ question_info_dict['ref_code_path'] = self.ref_code_path
- return json.dumps(info_parameter)
+ return json.dumps(question_info_dict)
def __unicode__(self):
return self.summary
diff --git a/testapp/exam/views.py b/testapp/exam/views.py
index 508b623..2542a28 100644
--- a/testapp/exam/views.py
+++ b/testapp/exam/views.py
@@ -286,7 +286,6 @@ def edit_question(request):
user = request.user
if not user.is_authenticated() or not is_moderator(user):
raise Http404('You are not allowed to view this page!')
-
question_list = request.POST.getlist('questions')
summary = request.POST.getlist('summary')
description = request.POST.getlist('description')
@@ -311,6 +310,8 @@ def edit_question(request):
question.active = active[j]
question.language = language[j]
question.snippet = snippet[j]
+ question.ref_code_path = ref_code_path[j]
+ question.solution = solution[j]
question.type = type[j]
question.save()
return my_redirect("/exam/manage/questions")
@@ -374,6 +375,8 @@ def add_question(request, question_id=None):
d.active = form['active'].data
d.language = form['language'].data
d.snippet = form['snippet'].data
+ d.ref_code_path = form['ref_code_path'].data
+ d.solution = form['solution'].data
d.save()
question = Question.objects.get(id=question_id)
for tag in question.tags.all():
@@ -428,6 +431,8 @@ def add_question(request, question_id=None):
form.initial['active'] = d.active
form.initial['language'] = d.language
form.initial['snippet'] = d.snippet
+ form.initial['ref_code_path'] = d.ref_code_path
+ form.initial['solution'] = d.solution
form_tags = d.tags.all()
form_tags_split = form_tags.values('name')
initial_tags = ""
@@ -953,9 +958,9 @@ 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':
- info_parameter = question.consolidate_answer_data(test, user_answer) \
- if question.type == 'code' else None
- correct, result = validate_answer(user, user_answer, question, info_parameter)
+ json_data = question.consolidate_answer_data(test, user_answer) \
+ if question.type == 'code' else None
+ correct, result = validate_answer(user, user_answer, question, json_data)
if correct:
new_answer.correct = correct
new_answer.marks = question.points
@@ -1000,7 +1005,7 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None):
questionpaper_id, success_msg)
-def validate_answer(user, user_answer, question, info_parameter=None):
+def validate_answer(user, user_answer, question, json_data=None):
"""
Checks whether the answer submitted by the user is right or wrong.
If right then returns correct = True, success and
@@ -1025,7 +1030,7 @@ def validate_answer(user, user_answer, question, info_parameter=None):
message = 'Correct answer'
elif question.type == 'code':
user_dir = get_user_dir(user)
- json_result = code_server.run_code(info_parameter, question.language, user_dir)
+ json_result = code_server.run_code(question.language, json_data, user_dir)
result = json.loads(json_result)
if result.get('success'):
correct = True
@@ -1247,6 +1252,8 @@ def show_all_questions(request):
form.initial['active'] = d.active
form.initial['language'] = d.language
form.initial['snippet'] = d.snippet
+ form.initial['ref_code_path'] = d.ref_code_path
+ form.initial['solution'] = d.solution
form_tags = d.tags.all()
form_tags_split = form_tags.values('name')
initial_tags = ""
diff --git a/testapp/exam/xmlrpc_clients.py b/testapp/exam/xmlrpc_clients.py
index 5d95cae..8f5642e 100644
--- a/testapp/exam/xmlrpc_clients.py
+++ b/testapp/exam/xmlrpc_clients.py
@@ -22,7 +22,7 @@ class CodeServerProxy(object):
pool_url = 'http://localhost:%d' % (SERVER_POOL_PORT)
self.pool_server = ServerProxy(pool_url)
- def run_code(self, info_parameter, language, user_dir):
+ def run_code(self, language, json_data, user_dir):
"""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
@@ -31,7 +31,7 @@ class CodeServerProxy(object):
Parameters
----------
- info_parameter contains;
+ json_data contains;
user_answer : str
The user's answer for the question.
test_code : str
@@ -50,7 +50,7 @@ class CodeServerProxy(object):
try:
server = self._get_server()
- result = server.check_code(info_parameter, language, user_dir)
+ result = server.check_code(language, json_data, user_dir)
except ConnectionError:
result = json.dumps({'success': False, 'error': 'Unable to connect to any code servers!'})
return result
diff --git a/testapp/test_server.py b/testapp/test_server.py
index c35c411..39995e1 100644
--- a/testapp/test_server.py
+++ b/testapp/test_server.py
@@ -1,97 +1,244 @@
import unittest
import os
-from exam import evaluate_c, evaluate_cpp, evaluate_bash, evaluate_python
+from exam import evaluate_c_code, evaluate_cpp_code, evaluate_java_code, evaluate_python_code, evaluate_scilab_code, evaluate_bash_code
+from exam.language_registry import registry
+from exam.settings import SERVER_TIMEOUT
-class TestPythonEvaluation(unittest.TestCase):
+class RegistryTestCase(unittest.TestCase):
+ def setUp(self):
+ self.registry_object = registry
+
+ def test_set_register(self):
+ self.registry_object.register("demo_language", "demo_object")
+ self.assertEquals(self.registry_object._registry["demo_language"], "demo_object")
+
+ def test_get_class(self):
+ self.test_set_register()
+ cls = self.registry_object.get_class("demo_language")
+ self.assertEquals(cls, "demo_object")
+
+
+###############################################################################
+class PythonEvaluationTestCases(unittest.TestCase):
def setUp(self):
self.language = "Python"
- self.test_parameter = [{"func_name": "add",
+ self.test_case_data = [{"func_name": "add",
"expected_answer": "5",
"test_id": u'null',
"pos_args": ["3", "2"],
"kw_args": {}
}]
+ self.timeout_msg = ("Code took more than {0} seconds to run. "
+ "You probably have an infinite loop in your code.").format(SERVER_TIMEOUT)
+
def test_correct_answer(self):
user_answer = "def add(a, b):\n\treturn a + b"""
- get_class = evaluate_python.EvaluatePython(self.test_parameter, self.language, user_answer, ref_code_path=None, in_dir=None)
+ get_class = evaluate_python_code.EvaluatePythonCode(self.test_case_data, self.language, user_answer, ref_code_path=None, in_dir=None)
result = get_class.run_code()
self.assertTrue(result.get("success"))
self.assertEqual(result.get("error"), "Correct answer")
def test_incorrect_answer(self):
user_answer = "def add(a, b):\n\treturn a - b"
- test_parameter = [{"func_name": "add",
+ test_case_data = [{"func_name": "add",
"expected_answer": "5",
"test_id": u'null',
"pos_args": ["3", "2"],
"kw_args": {}
}]
- get_class = evaluate_python.EvaluatePython(self.test_parameter, self.language, user_answer, ref_code_path=None, in_dir=None)
+ get_class = evaluate_python_code.EvaluatePythonCode(self.test_case_data, self.language, user_answer, ref_code_path=None, in_dir=None)
result = get_class.run_code()
self.assertFalse(result.get("success"))
self.assertEqual(result.get("error"), "AssertionError in: assert add(3, 2) == 5")
def test_infinite_loop(self):
user_answer = "def add(a, b):\n\twhile True:\n\t\tpass"""
- test_parameter = [{"func_name": "add",
+ test_case_data = [{"func_name": "add",
"expected_answer": "5",
"test_id": u'null',
"pos_args": ["3", "2"],
"kw_args": {}
}]
- get_class = evaluate_python.EvaluatePython(self.test_parameter, self.language, user_answer, ref_code_path=None, in_dir=None)
+ get_class = evaluate_python_code.EvaluatePythonCode(self.test_case_data, self.language, user_answer, ref_code_path=None, in_dir=None)
result = get_class.run_code()
self.assertFalse(result.get("success"))
- self.assertTrue("Code took more than" in result.get("error"))
+ self.assertEquals(result.get("error"), self.timeout_msg)
+
###############################################################################
-class TestCEvaluation(unittest.TestCase):
+class CEvaluationTestCases(unittest.TestCase):
def setUp(self):
self.language = "C"
self.ref_code_path = "c_cpp_files/main.cpp"
self.in_dir = "/tmp"
- self.test_parameter = []
+ self.test_case_data = []
+ self.timeout_msg = ("Code took more than {0} seconds to run. "
+ "You probably have an infinite loop in your code.").format(SERVER_TIMEOUT)
+
def test_correct_answer(self):
user_answer = "int add(int a, int b)\n{return a+b;}"
- get_class = evaluate_c.EvaluateC(self.test_parameter, self.language, user_answer, self.ref_code_path, self.in_dir)
+ get_class = evaluate_c_code.EvaluateCCode(self.test_case_data, self.language, user_answer, self.ref_code_path, self.in_dir)
result = get_class.run_code()
self.assertTrue(result.get("success"))
self.assertEqual(result.get("error"), "Correct answer")
- def test_incorrect_answer(self):
+ def test_compilation_error(self):
user_answer = "int add(int a, int b)\n{return a+b}"
- get_class = evaluate_c.EvaluateC(self.test_parameter, self.language, user_answer, self.ref_code_path, self.in_dir)
+ get_class = evaluate_c_code.EvaluateCCode(self.test_case_data, self.language, user_answer, self.ref_code_path, self.in_dir)
result = get_class.run_code()
self.assertFalse(result.get("success"))
self.assertTrue("Compilation Error" in result.get("error"))
+ def test_infinite_loop(self):
+ user_answer = "int add(int a, int b)\n{while(1>0){}}"
+ get_class = evaluate_c_code.EvaluateCCode(self.test_case_data, self.language, user_answer, self.ref_code_path, self.in_dir)
+ result = get_class.run_code()
+
+ self.assertFalse(result.get("success"))
+ self.assertEquals(result.get("error"), self.timeout_msg)
+
+
###############################################################################
-class TestCPPEvaluation(unittest.TestCase):
+class CppEvaluationTestCases(unittest.TestCase):
def setUp(self):
self.language = "CPP"
self.ref_code_path = "c_cpp_files/main.cpp"
self.in_dir = "/tmp"
- self.test_parameter = []
+ self.test_case_data = []
+ self.timeout_msg = ("Code took more than {0} seconds to run. "
+ "You probably have an infinite loop in your code.").format(SERVER_TIMEOUT)
+
def test_correct_answer(self):
user_answer = "int add(int a, int b)\n{return a+b;}"
- get_class = evaluate_cpp.EvaluateCpp(self.test_parameter, self.language, user_answer, self.ref_code_path, self.in_dir)
+ get_class = evaluate_cpp_code.EvaluateCppCode(self.test_case_data, self.language, user_answer, self.ref_code_path, self.in_dir)
result = get_class.run_code()
self.assertTrue(result.get("success"))
self.assertEqual(result.get("error"), "Correct answer")
- def test_incorrect_answer(self):
+ def test_compilation_error(self):
user_answer = "int add(int a, int b)\n{return a+b}"
- get_class = evaluate_cpp.EvaluateCpp(self.test_parameter, self.language, user_answer, self.ref_code_path, self.in_dir)
+ get_class = evaluate_cpp_code.EvaluateCppCode(self.test_case_data, self.language, user_answer, self.ref_code_path, self.in_dir)
result = get_class.run_code()
- error_msg = ""
self.assertFalse(result.get("success"))
self.assertTrue("Compilation Error" in result.get("error"))
+ def test_infinite_loop(self):
+ user_answer = "int add(int a, int b)\n{while(1>0){}}"
+ get_class = evaluate_cpp_code.EvaluateCppCode(self.test_case_data, self.language, user_answer, self.ref_code_path, self.in_dir)
+ result = get_class.run_code()
+
+ self.assertFalse(result.get("success"))
+ self.assertEquals(result.get("error"), self.timeout_msg)
+
+
+###############################################################################
+class BashEvaluationTestCases(unittest.TestCase):
+ def setUp(self):
+ self.language = "bash"
+ self.ref_code_path = "bash_files/sample.sh,bash_files/sample.args"
+ self.in_dir = "/tmp"
+ self.test_case_data = []
+ self.timeout_msg = ("Code took more than {0} seconds to run. "
+ "You probably have an infinite loop in your code.").format(SERVER_TIMEOUT)
+
+ def test_correct_answer(self):
+ user_answer = "#!/bin/bash\n[[ $# -eq 2 ]] && echo $(( $1 + $2 )) && exit $(( $1 + $2 ))"
+ get_class = evaluate_bash_code.EvaluateBashCode(self.test_case_data, self.language, user_answer, self.ref_code_path, self.in_dir)
+ result = get_class.run_code()
+
+ self.assertTrue(result.get("success"))
+ self.assertEqual(result.get("error"), "Correct answer")
+
+ def test_error(self):
+ user_answer = "#!/bin/bash\n[[ $# -eq 2 ]] && echo $(( $1 - $2 )) && exit $(( $1 - $2 ))"
+ get_class = evaluate_bash_code.EvaluateBashCode(self.test_case_data, self.language, user_answer, self.ref_code_path, self.in_dir)
+ result = get_class.run_code()
+
+ self.assertFalse(result.get("success"))
+ self.assertTrue("Error" in result.get("error"))
+
+ def test_infinite_loop(self):
+ user_answer = "#!/bin/bash\nwhile [ 1 ] ; do echo "" > /dev/null ; done"
+ get_class = evaluate_bash_code.EvaluateBashCode(self.test_case_data, self.language, user_answer, self.ref_code_path, self.in_dir)
+ result = get_class.run_code()
+
+ self.assertFalse(result.get("success"))
+ self.assertEquals(result.get("error"), self.timeout_msg)
+
+
+###############################################################################
+class JavaEvaluationTestCases(unittest.TestCase):
+ def setUp(self):
+ self.language = "java"
+ self.ref_code_path = "java_files/main_square.java"
+ self.in_dir = "/tmp"
+ self.test_case_data = []
+ self.timeout_msg = ("Code took more than {0} seconds to run. "
+ "You probably have an infinite loop in your code.").format(SERVER_TIMEOUT)
+
+ def test_correct_answer(self):
+ user_answer = "class Test {\n\tint square_num(int a) {\n\treturn a*a;\n\t}\n}"
+ get_class = evaluate_java_code.EvaluateJavaCode(self.test_case_data, self.language, user_answer, self.ref_code_path, self.in_dir)
+ result = get_class.run_code()
+
+ self.assertTrue(result.get("success"))
+ self.assertEqual(result.get("error"), "Correct answer")
+
+ def test_error(self):
+ user_answer = "class Test {\n\tint square_num(int a) {\n\treturn a*a"
+ get_class = evaluate_java_code.EvaluateJavaCode(self.test_case_data, self.language, user_answer, self.ref_code_path, self.in_dir)
+ result = get_class.run_code()
+
+ self.assertFalse(result.get("success"))
+ self.assertTrue("Error" in result.get("error"))
+
+ def test_infinite_loop(self):
+ user_answer = "class Test {\n\tint square_num(int a) {\n\t\twhile(0==0){\n\t\t}\n\t}\n}"
+ get_class = evaluate_java_code.EvaluateJavaCode(self.test_case_data, self.language, user_answer, self.ref_code_path, self.in_dir)
+ result = get_class.run_code()
+
+ self.assertFalse(result.get("success"))
+ self.assertEquals(result.get("error"), self.timeout_msg)
+
+
+###############################################################################
+class ScilabEvaluationTestCases(unittest.TestCase):
+ def setUp(self):
+ self.language = "scilab"
+ self.ref_code_path = "scilab_files/test_add.sce"
+ self.in_dir = "/tmp"
+ self.test_case_data = []
+
+ def test_correct_answer(self):
+ user_answer = "funcprot(0)\nfunction[c]=add(a,b)\n\tc=a+b;\nendfunction"
+ get_class = evaluate_scilab_code.EvaluateScilabCode(self.test_case_data, self.language, user_answer, self.ref_code_path, self.in_dir)
+ result = get_class.run_code()
+
+ self.assertTrue(result.get("success"))
+ self.assertEqual(result.get("error"), "Correct answer")
+
+ def test_correct_answer_2(self):
+ user_answer = "funcprot(0)\nfunction[c]=add(a,b)\n\tc=a-b;\nendfunction"
+ get_class = evaluate_scilab_code.EvaluateScilabCode(self.test_case_data, self.language, user_answer, self.ref_code_path, self.in_dir)
+ result = get_class.run_code()
+
+ self.assertTrue(result.get("success"))
+ self.assertEqual(result.get("error"), "Correct answer")
+
+ def test_error(self):
+ user_answer = "funcprot(0)\nfunction[c]=add(a,b)\n\t c=a+b;\ndis(\tendfunction"
+ get_class = evaluate_java_code.EvaluateJavaCode(self.test_case_data, self.language, user_answer, self.ref_code_path, self.in_dir)
+ result = get_class.run_code()
+
+ self.assertFalse(result.get("success"))
+ self.assertTrue("Error" in result.get("error"))
+
+
if __name__ == '__main__':
unittest.main() \ No newline at end of file