# -*- coding: utf-8 -*-
# $Id: Prolog.py 1634 2013-04-12 15:36:36Z amelung $
#
# Copyright (c) 2007-2011 Otto-von-Guericke-Universität Magdeburg
#
# This file is part of ECSpooler.
import logging
# local imports
# The packages that the model and student solution will be put in
# The name of the wrapper class that performs the semantic check
# load Prolog functions to do tests
# try:
# simpleTest = file(join(dirname(__file__), 'simpleTest.pl'), 'r').read()
# except IOError, ioe:
# raise ioe
# simpleTest = ''
# This code *should* throw up if 'simpleTest.pl' cannot be loaded.
WRAPPER_TEMPLATE = \
""":- use_module('%s').
:- use_module('%s').
join([], _, '').
join([X], _, O) :- swritef(O, '%%w', [X]).
join([X|R], I, O) :- join(R, I, JR), swritef(O, '%%w%%w%%w', [X, I, JR]).
format_res1_sub([], [], []).
format_res1_sub([N|Rn], [V|Rv], [O|Ro]) :- format_res1_sub(Rn, Rv, Ro),
swritef(O, '%%w <- %%w', [N, V]).
format_res1([], 'Yes').
format_res1(V, O) :- format_res1_sub([${strTestVarNames}], V, A),
join(A, ', ', B),
swritef(O, '{%%w}', [B]).
format_res([], 'No').
format_res(I, O) :- maplist(format_res1, I, T), join(T, ' or ', O).
first_solution_or_nil(Pred, []) :- \+ call(Pred, _).
first_solution_or_nil(Pred, [X]) :- call(Pred, X).
${helpFunctions}
model([${testVarNames}]) :- %s:${testData}
student([${testVarNames}]) :- %s:${testData}
display_res(Model_results, Student_results, Equal) :-
format_res(Model_results, FMs),
format_res(Student_results, FSs),
writef('isEqual=%%w;;expected=%%w;;received=%%w', [Equal, FMs, FSs]).
${testFunction}
# input schema
'modelSolution',
),
'helpFunctions',
),
'testData',
#accessor = # must return a list; default is one element per line
'A function call consists of the ' +
'function name (given in the exercise directives) ' +
'and test data as parameters of this funtion. '+
'Each function call must be written in a single line.',
),
))
# testSchema
'simple',
),
'permutation',
),
'predicate',
),
))
def non_null_str(s):
"""
"""
"""
A backend class for checking Prolog programs by comparing
student and model solution on given test data.
"""
"""
This constructor is needed to reset the logging environment.
"""
'\s+Goal \(directive\) failed: user: .*',
if m:
return msg
# -- check syntax ---------------------------------------------------------
"""
Replace module name in students' submission.
@see: ProgrammingBackend._preProcessCheckSyntax
@return: modified source code and new module name
"""
#result = (":- module('%s', []).\n\n" % PrologConf.NS_STUDENT) + src
#cname = PrologConf.NS_STUDENT
#return result, PrologConf.NS_STUDENT
return src, NS_STUDENT
"""
@see: AbtractSimpleBackend._postProcessCheckSyntax
"""
# search for path, filename and line numbers result is
# something like [('Tutor1.java:7', '7'), ('Tutor1.java:7',
# '7')]
# replace each filename and line number
# The column number is stored in `match[3]', but we don't
# use it because the value reported by SWI-Prolog isn't
# reliable. It seems to be like this: If the error is in
# the first line of a rule, the column number is always 0.
# If the error is in any other line, the column number is
# correct.
'line %d: %s' %
1)
return message
# -- check semantics ------------------------------------------------------
"""
Return the list of unique variable names that are used in the
test data. For
foo(1, 2, X, Y, X)
return ['X', 'Y'].
"""
# remove duplicates but preserve order
uniq = []
return uniq
"""
Pre process student's submissions and semantic check wrapper code.
Override this method if you need to reformat the wrapper code or
the student's submission.
"""
"""
Runs sematic test on a Prolog program.
Remember: Before we can run the wrapper code we have to compile it!!
@return: a BackendResult object with result code and value
"""
# test for available test specs
msg = 'No test specification selected.'
# test for defined repeat fields in the schema definition
assert repeatFields, 'No RepeatField found.'
# test for available test data
msg = 'No test data defined.'
# 1. get model solution and student's submission
assert non_null_str(model), \
"Semantic check requires valid 'model solution' (%s)" % \
assert non_null_str(submission), \
"Semantic check requires valid 'student solution' (%s)" % \
# define return values
feedback = ''
# run selected test specifications
if not solved: break
# write solution to a file
files = {} #XXX not used
# replace module name in the solution
# write solution to a file
ns,
# get the interpreter
# 4.1. set wrapper source
# 4.2. get values for all other input fields from schema
# which are available in the job data
# 4.3 set test function
# 4.4. run with all test data
for t in testdata:
# and now add repeatable data values
# substitute the test data placeholder with the actual
# test data
# replace the variables name used in the test data
# list of variable names as variables
# list of variable names as strings
# remove all remaining placeholders
#log.debug('WRAPPER IS:\n%s' % wrapper)
# write and execute wrapper
try:
# write module for wrapper
# run the wrapper
except Exception, e:
msg = 'Internal error during semantic check: %s: %s' % \
#return (0, msg)
# an error occured
#log.error("ORIGINAL: %s" % result)
result = "\nYour submission failed. Test " \
"case was: '%s' (%s)" \
"\n\n Received result: %s"\
#return (0, result)
# has the students' solution passed this tests?
else:
# TODO: i18n
feedback = "\nYour submission failed. Test " \
"case was: '%s' (%s)" \
feedback += '\n\n Expected results: %s\n ' \
'Received results: %s' \
break # means: end testing right now
# end inner for loop
#end out for loop
if solved:
# TODO: i18n
feedback = '\nYour submission passed all tests.'
#return ([0, 1][solved], feedback)