~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to ivle/webapp/tutorial/test/TestFramework.py

  • Committer: William Grant
  • Date: 2009-02-23 23:47:02 UTC
  • mfrom: (1099.1.211 new-dispatch)
  • Revision ID: grantw@unimelb.edu.au-20090223234702-db4b1llly46ignwo
Merge from lp:~ivle-dev/ivle/new-dispatch.

Pretty much everything changes. Reread the setup docs. Backup your databases.
Every file is now in a different installed location, the configuration system
is rewritten, the dispatch system is rewritten, URLs are different, the
database is different, worksheets and exercises are no longer on the
filesystem, we use a templating engine, jail service protocols are rewritten,
we don't repeat ourselves, we have authorization rewritten, phpBB is gone,
and probably lots of other things that I cannot remember.

This is certainly the biggest commit I have ever made, and hopefully
the largest I ever will.

Show diffs side-by-side

added added

removed removed

Lines of Context:
118
118
    true = classmethod(lambda *x: True)
119
119
    false = classmethod(lambda *x: False)
120
120
 
121
 
    def __init__(self, pass_msg, fail_msg, default='match'):
 
121
    def __init__(self, test_case):
122
122
        """Initialise with descriptions (pass,fail) and a default behavior for output
123
123
        If default is match, unspecified files are matched exactly
124
124
        If default is ignore, unspecified files are ignored
125
125
        The default default is match.
126
126
        """
127
 
        self._pass_msg = pass_msg
128
 
        self._fail_msg = fail_msg
129
 
        self._default = default
130
 
        if default == 'ignore':
 
127
        self._pass_msg = test_case.passmsg
 
128
        self._fail_msg = test_case.failmsg
 
129
        self._default = test_case.test_default
 
130
        if self._default == 'ignore':
131
131
            self._default_func = self.true
132
132
        else:
133
133
            self._default_func = self.match
138
138
        self._exception_test = ('check', self._default_func)
139
139
        self._result_test = ('check', self._default_func)
140
140
        self._code_test = ('check', self._default_func)
 
141
        
 
142
        for part in test_case.parts:
 
143
            if part.part_type =="file":
 
144
                self.add_file_test(part)
 
145
            elif part.part_type =="stdout":
 
146
                self.add_stdout_test(part)
 
147
            elif part.part_type =="stderr":
 
148
                self.add_stderr_test(part)
 
149
            elif part.part_type =="result":
 
150
                self.add_result_test(part)
 
151
            elif part.part_type =="exception":
 
152
                self.add_exception_test(part)
 
153
            elif part.part_type =="code":
 
154
                self.add_code_test(part)
141
155
 
142
156
    def _set_default_function(self, function, test_type):
143
157
        """"Ensure test type is valid and set function to a default
191
205
        for filename, (test_type, function) in self._file_tests.items():
192
206
            self._file_tests[filename] = (test_type, self._validate_function(function, included_code))
193
207
            
194
 
    def add_result_test(self, function, test_type='norm'):
 
208
    def add_result_test(self, part):
195
209
        "Test part that compares function return values"
196
 
        function = self._set_default_function(function, test_type)
197
 
        self._result_test = (test_type, function)
 
210
        function = self._set_default_function(part.data, part.test_type)
 
211
        self._result_test = (part.test_type, function)
198
212
            
199
 
    def add_stdout_test(self, function, test_type='norm'):
 
213
    def add_stdout_test(self, part):
200
214
        "Test part that compares stdout"
201
 
        function = self._set_default_function(function, test_type)
202
 
        self._stdout_test = (test_type, function)
203
 
 
204
 
    def add_stderr_test(self, function, test_type='norm'):
205
 
        "Test part that compares stderr"
206
 
        function = self._set_default_function(function, test_type)
207
 
        self._stderr_test = (test_type, function)
208
 
 
209
 
    def add_exception_test(self, function, test_type='norm'):
210
 
        "Test part that compares stderr"
211
 
        function = self._set_default_function(function, test_type)
212
 
        self._exception_test = (test_type, function)
213
 
 
214
 
    def add_file_test(self, filename, function, test_type='norm'):
 
215
        function = self._set_default_function(part.data, part.test_type)
 
216
        self._stdout_test = (part.test_type, function)
 
217
 
 
218
    def add_stderr_test(self, part):
 
219
        "Test part that compares stderr"
 
220
        function = self._set_default_function(part.data, part.test_type)
 
221
        self._stderr_test = (part.test_type, function)
 
222
 
 
223
    def add_exception_test(self, part):
 
224
        "Test part that compares stderr"
 
225
        function = self._set_default_function(part.data, part.test_type)
 
226
        self._exception_test = (part.test_type, function)
 
227
 
 
228
    def add_file_test(self, part):
215
229
        "Test part that compares the contents of a specified file"
216
 
        function = self._set_default_function(function, test_type)
217
 
        self._file_tests[filename] = (test_type, function)
 
230
        function = self._set_default_function(part.data, part.test_type)
 
231
        self._file_tests[part.filename] = (part.test_type, function)
218
232
 
219
 
    def add_code_test(self, function, test_type='norm'):
 
233
    def add_code_test(self, part):
220
234
        "Test part that examines the supplied code"
221
 
        function = self._set_default_function(function, test_type)
222
 
        self._code_test = (test_type, function)
 
235
        function = self._set_default_function(part.data, part.test_type)
 
236
        self._code_test = (part.test_type, function)
223
237
 
224
238
    def _check_output(self, solution_output, attempt_output, test_type, f):
225
239
        """Compare solution output and attempt output using the
307
321
    """
308
322
    A set of tests with a common inputs
309
323
    """
310
 
    def __init__(self, console, name='', function=None, stdin='', filespace=None, global_space=None):
 
324
    def __init__(self, console, suite):
311
325
        """Initialise with name and optionally, a function to test (instead of the entire script)
312
326
        The inputs stdin, the filespace and global variables can also be specified at
313
327
        initialisation, but may also be set later.
314
328
        """
315
329
        self._console = console
316
 
 
317
 
        if global_space == None:
318
 
            global_space = {}
319
 
        if filespace == None:
320
 
            filespace = {}
321
 
        
322
 
        self._name = name
323
 
        
 
330
        self._name = suite.description
 
331
        
 
332
        function = suite.function
324
333
        if function == '': function = None
325
334
        self._function = function
326
335
        self._list_args = []
327
336
        self._keyword_args = {}
328
337
        
329
 
        self.set_stdin(stdin)
330
 
        self._filespace = testfilespace.TestFilespace(filespace)
331
 
        self._global_space = global_space
 
338
        self.set_stdin(suite.stdin)
 
339
        self._filespace = testfilespace.TestFilespace(None)
 
340
        self._global_space = {}
332
341
        self._parts = []
333
342
        self._allowed_exceptions = set()
 
343
        
 
344
        args = {}
 
345
        for var in suite.variables:
 
346
            if var.var_type == "file":
 
347
                self.add_file(var)
 
348
            elif var.var_type == "var":
 
349
                self.add_variable(var)
 
350
            elif var.var_type == "arg":
 
351
                args[var.arg_no] = var
 
352
            elif var.var_type == "exception":
 
353
                self.add_exception(var)
 
354
        
 
355
        for i in xrange(len(args)):
 
356
            self.add_arg(args[i])
 
357
        for test_case in suite.test_cases:
 
358
            self.add_part(TestCasePart(test_case))
334
359
 
335
360
    def set_stdin(self, stdin):
336
361
        """ Set the given string as the stdin for this test case"""
337
362
        # stdin must have a newline at the end for raw_input to work properly
338
 
        if stdin[-1:] != '\n':
339
 
            stdin += '\n'
 
363
        if stdin is not None:
 
364
            if stdin[-1:] != '\n':
 
365
                stdin += '\n'
 
366
        else:
 
367
            stdin = ""
340
368
        self._stdin = stdin
341
369
 
342
 
    def add_file(self, filename, data):
 
370
    def add_file(self, filevar):
343
371
        """ Insert the given filename-data pair into the filespace for this test case"""
344
372
        # TODO: Add the file to the console
345
 
        self._filespace.add_file(filename, data)
 
373
        self._filespace.add_file(filevar.var_name, "")
346
374
        
347
 
    def add_variable(self, variable, value):
 
375
    def add_variable(self, var):
348
376
        """ Add the given varibale-value pair to the initial global environment
349
377
        for this test case. The value is the string repr() of an actual value.
350
378
        Throw an exception if the value cannot be paresed.
351
379
        """
352
380
        
353
381
        try:
354
 
            self._global_space[variable] = eval(value)
 
382
            self._global_space[var.var_name] = eval(var.var_value)
355
383
        except:
356
 
            raise TestCreationError("Invalid value for variable %s: %s" %(variable, value))
 
384
            raise TestCreationError("Invalid value for variable %s: %s" 
 
385
                                    %(var.var_name, var.var_value))
357
386
 
358
 
    def add_arg(self, value, name=None):
 
387
    def add_arg(self, var):
359
388
        """ Add a value to the argument list. This only applies when testing functions.
360
389
        By default arguments are not named, but if they are, they become keyword arguments.
361
390
        """
362
391
        try:
363
 
            if name == None or name == '':
364
 
                self._list_args.append(eval(value))
 
392
            if var.var_name == None or var.var_name == '':
 
393
                self._list_args.append(eval(var.var_value))
365
394
            else:
366
 
                self._keyword_args[name] = value
 
395
                self._keyword_args[var.var_name] = var.var_value
367
396
        except:
368
 
            raise TestCreationError("Invalid value for function argument: %s" %value)
 
397
            raise TestCreationError("Invalid value for function argument: %s" %var.var_value)
369
398
 
370
399
    def add_exception(self, exception_name):
371
 
        self._allowed_exceptions.add(exception_name)
 
400
        self._allowed_exceptions.add(var.var_name)
372
401
        
373
402
    def add_part(self, test_part):
374
403
        """ Add a TestPart to this test case"""
406
435
                solution_data = self._run_function(self._function,
407
436
                    self._list_args, self._keyword_args, solution)
408
437
                
409
 
        except:
410
 
            raise ScriptExecutionError(sys.exc_info())
 
438
        except Exception, e:
 
439
            raise e #ScriptExecutionError(sys.exc_info())
411
440
 
412
441
        # Run student attempt
413
442
        try:
523
552
    """
524
553
    The complete collection of test cases for a given exercise
525
554
    """
526
 
    def __init__(self, name, console, solution=None):
 
555
    def __init__(self, exercise, console):
527
556
        """Initialise with the name of the test suite (the exercise name) and the solution.
528
557
        The solution may be specified later.
529
558
        """
530
 
        self._solution = solution
531
 
        self._name = name
 
559
        self._solution = exercise.solution
 
560
        self._name = exercise.id
 
561
        self._exercise = exercise
532
562
        self._tests = []
533
563
        self._console = console
534
 
        self.add_include_code("")
535
 
 
536
 
    def add_solution(self, solution):
537
 
        " Specify the solution script for this exercise "
538
 
        self._solution = solution
 
564
        self.add_include_code(exercise.include)
 
565
        
 
566
        for test_case in exercise.test_suites:
 
567
            new_case = TestCase(console, test_case)
 
568
            self.add_case(new_case)
539
569
 
540
570
    def has_solution(self):
541
571
        " Returns true if a solution has been provided "
558
588
            raise TestCreationError("Bad include code")
559
589
 
560
590
        self._include_space = include_space
561
 
    
 
591
 
562
592
    def add_case(self, test_case):
563
593
        """ Add a TestCase, then validate all functions inside test case
564
594
        now that the include code is known
595
625
        return exercise_dict
596
626
 
597
627
    def get_name(self):
598
 
        return self._name
599
 
 
600
 
##def get_function(filename, function_name):
601
 
##      import compiler
602
 
##      mod = compiler.parseFile(filename)
603
 
##      for node in mod.node.nodes:
604
 
##              if isinstance(node, compiler.ast.Function) and node.name == function_name:
605
 
##                      return node
606
 
##  
 
628
        return self._names