2
# IVLE - Informatics Virtual Learning Environment
3
# Copyright (C) 2007-2009 The University of Melbourne
5
# This program is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 2 of the License, or
8
# (at your option) any later version.
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
# Author: Nicholas Chadwick
21
"""Script to upload an exercise file into the database"""
24
import xml.dom.minidom as minidom
26
from ivle.database import Exercise, TestSuite, TestCase, get_store
28
class XMLMalformedError(Exception):
29
"""Error thrown when encountering malformed data."""
31
def __init__(self, text):
34
def getTextData(element):
35
""" Get the text and cdata inside an element
36
Leading and trailing whitespace are stripped
39
for child in element.childNodes:
40
if child.nodeType == child.CDATA_SECTION_NODE:
42
if child.nodeType == child.TEXT_NODE:
47
def add_test_suite(suite_node, suite_num, store):
48
"""Given a test suite element, get all the cases it contains."""
51
for case_node in suite_node.getElementsByTagName('function'):
53
cases.append(add_test_case(case_node, case_num, store))
54
new_suite = TestSuite()
55
new_suite.description = suite_node.getAttribute('name')
56
new_suite.seq_no = suite_num
57
for testcase in cases:
58
new_suite.test_cases.add(testcase)
63
def add_test_case(case_node, case_num, store):
64
"""Given a test case, generate its data"""
65
# First perform basic error checks
66
if not case_node.tagName == 'function':
67
raise XMLMalformedError(case_node.tagName + ' node')
68
case_data = case_node.getElementsByTagName('code')
70
case_data = case_node.getElementsByTagName('stdout')
72
raise XMLMalformedError()
73
case_data = case_data[0]
74
#Now create the object to hold the data
75
new_test_case = TestCase()
76
new_test_case.passmsg = case_node.getAttribute('pass')
77
new_test_case.failmsg = case_node.getAttribute('fail')
78
new_test_case.init = case_node.getAttribute('default')
79
new_test_case.code_type = case_data.getAttribute('type')
80
new_test_case.code = getTextData(case_data)
81
new_test_case.testtype = case_data.tagName
82
new_test_case.seq_no = case_num
83
store.add(new_test_case)
88
filedom = minidom.parse(xmlfile)
90
sys.exit('ivle-addexercise: error opening file ' + xmlfile + ': ' + e[1])
93
for child in filedom.childNodes:
94
if child.nodeType == child.ELEMENT_NODE and child.tagName == 'exercise':
97
sys.exit('ivle-addexercise: error parsing XML: root node must be "exercise"')
99
exercisename = exercise.getAttribute('name')
101
partial_solution = None
104
test_suite_nodes = []
105
for child in exercise.childNodes:
106
if child.nodeType != child.ELEMENT_NODE:
108
if child.tagName == 'solution':
109
if solution is not None:
110
sys.exit('ivle-addexercise: error parsing XML: multiple "solution" nodes')
111
solution = getTextData(child)
112
elif child.tagName == 'include':
113
if include_code is not None:
114
sys.exit('ivle-addexercise: error parsing XML: multiple "include" nodes')
115
include_code = getTextData(child)
116
elif child.tagName == 'partial':
117
if partial_solution is not None:
118
sys.exit('ivle-addexercise: error parsing XML: multiple "include" nodes')
119
partial_solution = getTextData(child)
120
elif child.tagName == 'case':
121
test_suite_nodes.append(child)
122
elif child.tagName == 'desc':
123
description = getTextData(child)
126
sys.exit("ivle-addexercise: error parsing XML: No solution given")
127
if len(test_suite_nodes) == 0:
128
sys.exit("ivle-addexercise: error parsing XML:")
131
new_exercise = Exercise()
132
new_exercise.id = unicode(xmlfile)
133
new_exercise.name = exercisename
134
new_exercise.partial = partial_solution
135
new_exercise.solution = solution
136
new_exercise.include = include_code
137
new_exercise.description = description
138
new_exercise.partial = partial_solution
139
store.add(new_exercise)
141
for suite in test_suite_nodes:
142
new_exercise.test_suites.add(add_test_suite(suite, suite_num, store))
145
store.add(new_exercise)