Commit bab5f36055ea9544520899e366629f54cdbe3f41

Authored by Miguel Barão
1 parent bfedb0e2
Exists in master and in 1 other branch dev

- jobe_server on the test.yaml applies as default JOBE server for all questions,…

… but can be overriden.
- comments are parsed by markdown when reviewing tests.
BUGS.md
1 1  
2 2 # BUGS
3 3  
  4 +- em caso de timeout na submissão (e.g. JOBE ou script nao responde) a correcção não termina e o teste não é guardado.
  5 +- QuestionCode falta reportar nos comments os vários erros que podem ocorrer (timeout, etc)
4 6 - permitir remover alunos que estão online para poderem comecar de novo.
5   -- grade gives internal server error
  7 +- grade gives internal server error??
6 8 - reload do teste recomeça a contagem no inicio do tempo.
7 9 - em admin, quando scale_max não é 20, as cores das barras continuam a reflectir a escala 0,20. a tabela teste na DB não tem a escala desse teste.
8 10 - em grade.html as barras estao normalizadas para os limites scale_min e max do teste actual e nao dos testes realizados no passado (tabela test devia guardar a escala).
... ...
demo/demo.yaml
... ... @@ -14,6 +14,9 @@ database: students.db
14 14 # Directory where the submitted and corrected test are stored for later review.
15 15 answers_dir: ans
16 16  
  17 +# Server used to compile & execute code
  18 +jobe_server: 192.168.1.85
  19 +
17 20 # --- optional settings: -----------------------------------------------------
18 21  
19 22 # Title of this test, e.g. course name, year or test number
... ... @@ -37,6 +40,7 @@ show_points: true
37 40 # (default: no scaling, just use question points)
38 41 scale: [0, 5]
39 42  
  43 +
40 44 # ----------------------------------------------------------------------------
41 45 # Base path applied to the questions files and all the scripts
42 46 # including question generators and correctors.
... ...
demo/questions/questions-tutorial.yaml
... ... @@ -26,6 +26,7 @@
26 26 show_points: true # mostra cotação das perguntas (default: true)
27 27 scale: [0, 20] # limites inferior e superior da escala (default: [0,20])
28 28 scale_points: true # normaliza cotações para a escala definida
  29 + jobe_server: moodle-jobe.uevora.pt # server used to compile & execute code
29 30 debug: false # mostra informação de debug no browser
30 31  
31 32 # --------------------------------------------------------------------------
... ... @@ -626,7 +627,6 @@
626 627 Escreva um programa em C que recebe uma string no standard input e
627 628 mostra a mensagem `hello ` seguida da string.
628 629 Por exemplo, se o input for `Maria`, o output deverá ser `hello Maria`.
629   - server: 127.0.0.1 # replace by appropriate address
630 630 language: c
631 631 correct:
632 632 - stdin: 'Maria'
... ... @@ -641,6 +641,10 @@
641 641 Se um caso incluir `stdin`, este será enviado para o programa e o `stdout`
642 642 obtido será comparado com o declarado. A pergunta é considerada correcta se
643 643 todos os outputs coincidirem.
  644 +
  645 + Por defeito é o usado o servidor JOBE declarado no teste. Para usar outro
  646 + diferente nesta pergunta usa-se a opção `server: 127.0.0.1` com o endereço
  647 + apropriado.
644 648 answer: |
645 649 #include <stdio.h>
646 650 int main() {
... ... @@ -648,7 +652,7 @@
648 652 scanf("%s", name);
649 653 printf("hello %s", name);
650 654 }
651   - server: 192.168.1.141
  655 + # server: 192.168.1.85
652 656 language: c
653 657 correct:
654 658 - stdin: 'Maria'
... ...
perguntations/questions.py
... ... @@ -591,11 +591,8 @@ class QuestionTextArea(Question):
591 591  
592 592 # ============================================================================
593 593 class QuestionCode(Question):
594   - '''An instance of QuestionCode will always have the keys:
595   - type (str)
596   - text (str)
597   - correct (str with script to run)
598   - answer (None or an actual answer)
  594 + '''
  595 + Submits answer to a JOBE server to compile and run against the test cases.
599 596 '''
600 597  
601 598 _outcomes = {
... ... @@ -669,13 +666,15 @@ class QuestionCode(Question):
669 666 return
670 667 logger.debug(self._outcomes[outcome])
671 668  
  669 +
  670 +
672 671 if result['cmpinfo']: # compiler errors and warnings
673 672 self['comments'] = f'Erros de compilação:\n{result["cmpinfo"]}'
674 673 self['grade'] = 0.0
675 674 return
676 675  
677   - if result['stdout'] != expected['stdout']:
678   - self['comments'] = 'O output gerado é diferente do esperado.'
  676 + if result['stdout'] != expected.get('stdout', ''):
  677 + self['comments'] = 'O output gerado é diferente do esperado.' # FIXME mostrar porque?
679 678 self['grade'] = 0.0
680 679 return
681 680  
... ...
perguntations/templates/review-question.html
... ... @@ -39,14 +39,14 @@
39 39 {{ round(q['grade'] * q['points'], 2) }}
40 40 pontos
41 41 </p>
42   - <p class="text-success">{{ q['comments'] }}</p>
  42 + <p class="text-success">{{ md(q['comments']) }}</p>
43 43 {% elif q['grade'] > 0.49 %}
44 44 <p class="text-warning">
45 45 <i class="fas fa-exclamation-triangle fa-3x" aria-hidden="true"></i>
46 46 {{ round(q['grade'] * q['points'], 2) }}
47 47 pontos
48 48 </p>
49   - <p class="text-warning">{{ q['comments'] }}</p>
  49 + <p class="text-warning">{{ md(q['comments']) }}</p>
50 50 {% if q['solution'] %}
51 51 <hr>
52 52 {{ md('**Solução:** \n\n' + q['solution']) }}
... ... @@ -57,7 +57,7 @@
57 57 {{ round(q['grade'] * q['points'], 2) }}
58 58 pontos
59 59 </p>
60   - <p class="text-danger"><pre>{{ q['comments'] }}</pre></p>
  60 + <p class="text-danger">{{ md(q['comments']) }}</p>
61 61 {% if q['solution'] %}
62 62 <hr>
63 63 {{ md('**Solução:** \n\n' + q['solution']) }}
... ... @@ -101,7 +101,7 @@
101 101 <p class="text-secondary">
102 102 <i class="fas fa-ban fa-3x" aria-hidden="true"></i>
103 103 {{ round(q['grade'] * q['points'], 2) }} pontos<br>
104   - {{ q['comments'] }}
  104 + {{ md(q['comments']) }}
105 105 {% if q['solution'] %}
106 106 <hr>
107 107 {{ md('**Solução:** \n\n' + q['solution']) }}
... ...
perguntations/testfactory.py
... ... @@ -98,16 +98,23 @@ class TestFactory(dict):
98 98  
99 99 # make factory only for the questions used in the test
100 100 if question['ref'] in qrefs:
101   - question.setdefault('type', 'information')
  101 + # question.setdefault('type', 'information')
102 102 question.update({
103 103 'filename': filename,
104 104 'path': dirname,
105 105 'index': i # position in the file, 0 based
106 106 })
  107 + if question['type'] == 'code' and 'server' not in question:
  108 + try:
  109 + question['server'] = self['jobe_server']
  110 + except KeyError as exc:
  111 + msg = f'Missing JOBE server in "{question["ref"]}"'
  112 + raise TestFactoryException(msg)
107 113  
108 114 self.question_factory[question['ref']] = QFactory(question)
109 115  
110 116 # check if all the questions can be correctly generated
  117 + # TODO and corrected
111 118 try:
112 119 self.question_factory[question['ref']].generate()
113 120 except Exception as exc:
... ...