Commit bab5f36055ea9544520899e366629f54cdbe3f41
1 parent
bfedb0e2
Exists in
master
and in
1 other branch
- 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.
Showing
6 changed files
with
31 additions
and
15 deletions
Show diff stats
BUGS.md
1 | 1 | ||
2 | # BUGS | 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 | - permitir remover alunos que estão online para poderem comecar de novo. | 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 | - reload do teste recomeça a contagem no inicio do tempo. | 8 | - reload do teste recomeça a contagem no inicio do tempo. |
7 | - 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. | 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 | - 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). | 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,6 +14,9 @@ database: students.db | ||
14 | # Directory where the submitted and corrected test are stored for later review. | 14 | # Directory where the submitted and corrected test are stored for later review. |
15 | answers_dir: ans | 15 | answers_dir: ans |
16 | 16 | ||
17 | +# Server used to compile & execute code | ||
18 | +jobe_server: 192.168.1.85 | ||
19 | + | ||
17 | # --- optional settings: ----------------------------------------------------- | 20 | # --- optional settings: ----------------------------------------------------- |
18 | 21 | ||
19 | # Title of this test, e.g. course name, year or test number | 22 | # Title of this test, e.g. course name, year or test number |
@@ -37,6 +40,7 @@ show_points: true | @@ -37,6 +40,7 @@ show_points: true | ||
37 | # (default: no scaling, just use question points) | 40 | # (default: no scaling, just use question points) |
38 | scale: [0, 5] | 41 | scale: [0, 5] |
39 | 42 | ||
43 | + | ||
40 | # ---------------------------------------------------------------------------- | 44 | # ---------------------------------------------------------------------------- |
41 | # Base path applied to the questions files and all the scripts | 45 | # Base path applied to the questions files and all the scripts |
42 | # including question generators and correctors. | 46 | # including question generators and correctors. |
demo/questions/questions-tutorial.yaml
@@ -26,6 +26,7 @@ | @@ -26,6 +26,7 @@ | ||
26 | show_points: true # mostra cotação das perguntas (default: true) | 26 | show_points: true # mostra cotação das perguntas (default: true) |
27 | scale: [0, 20] # limites inferior e superior da escala (default: [0,20]) | 27 | scale: [0, 20] # limites inferior e superior da escala (default: [0,20]) |
28 | scale_points: true # normaliza cotações para a escala definida | 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 | debug: false # mostra informação de debug no browser | 30 | debug: false # mostra informação de debug no browser |
30 | 31 | ||
31 | # -------------------------------------------------------------------------- | 32 | # -------------------------------------------------------------------------- |
@@ -626,7 +627,6 @@ | @@ -626,7 +627,6 @@ | ||
626 | Escreva um programa em C que recebe uma string no standard input e | 627 | Escreva um programa em C que recebe uma string no standard input e |
627 | mostra a mensagem `hello ` seguida da string. | 628 | mostra a mensagem `hello ` seguida da string. |
628 | Por exemplo, se o input for `Maria`, o output deverá ser `hello Maria`. | 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 | language: c | 630 | language: c |
631 | correct: | 631 | correct: |
632 | - stdin: 'Maria' | 632 | - stdin: 'Maria' |
@@ -641,6 +641,10 @@ | @@ -641,6 +641,10 @@ | ||
641 | Se um caso incluir `stdin`, este será enviado para o programa e o `stdout` | 641 | Se um caso incluir `stdin`, este será enviado para o programa e o `stdout` |
642 | obtido será comparado com o declarado. A pergunta é considerada correcta se | 642 | obtido será comparado com o declarado. A pergunta é considerada correcta se |
643 | todos os outputs coincidirem. | 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 | answer: | | 648 | answer: | |
645 | #include <stdio.h> | 649 | #include <stdio.h> |
646 | int main() { | 650 | int main() { |
@@ -648,7 +652,7 @@ | @@ -648,7 +652,7 @@ | ||
648 | scanf("%s", name); | 652 | scanf("%s", name); |
649 | printf("hello %s", name); | 653 | printf("hello %s", name); |
650 | } | 654 | } |
651 | - server: 192.168.1.141 | 655 | + # server: 192.168.1.85 |
652 | language: c | 656 | language: c |
653 | correct: | 657 | correct: |
654 | - stdin: 'Maria' | 658 | - stdin: 'Maria' |
perguntations/questions.py
@@ -591,11 +591,8 @@ class QuestionTextArea(Question): | @@ -591,11 +591,8 @@ class QuestionTextArea(Question): | ||
591 | 591 | ||
592 | # ============================================================================ | 592 | # ============================================================================ |
593 | class QuestionCode(Question): | 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 | _outcomes = { | 598 | _outcomes = { |
@@ -669,13 +666,15 @@ class QuestionCode(Question): | @@ -669,13 +666,15 @@ class QuestionCode(Question): | ||
669 | return | 666 | return |
670 | logger.debug(self._outcomes[outcome]) | 667 | logger.debug(self._outcomes[outcome]) |
671 | 668 | ||
669 | + | ||
670 | + | ||
672 | if result['cmpinfo']: # compiler errors and warnings | 671 | if result['cmpinfo']: # compiler errors and warnings |
673 | self['comments'] = f'Erros de compilação:\n{result["cmpinfo"]}' | 672 | self['comments'] = f'Erros de compilação:\n{result["cmpinfo"]}' |
674 | self['grade'] = 0.0 | 673 | self['grade'] = 0.0 |
675 | return | 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 | self['grade'] = 0.0 | 678 | self['grade'] = 0.0 |
680 | return | 679 | return |
681 | 680 |
perguntations/templates/review-question.html
@@ -39,14 +39,14 @@ | @@ -39,14 +39,14 @@ | ||
39 | {{ round(q['grade'] * q['points'], 2) }} | 39 | {{ round(q['grade'] * q['points'], 2) }} |
40 | pontos | 40 | pontos |
41 | </p> | 41 | </p> |
42 | - <p class="text-success">{{ q['comments'] }}</p> | 42 | + <p class="text-success">{{ md(q['comments']) }}</p> |
43 | {% elif q['grade'] > 0.49 %} | 43 | {% elif q['grade'] > 0.49 %} |
44 | <p class="text-warning"> | 44 | <p class="text-warning"> |
45 | <i class="fas fa-exclamation-triangle fa-3x" aria-hidden="true"></i> | 45 | <i class="fas fa-exclamation-triangle fa-3x" aria-hidden="true"></i> |
46 | {{ round(q['grade'] * q['points'], 2) }} | 46 | {{ round(q['grade'] * q['points'], 2) }} |
47 | pontos | 47 | pontos |
48 | </p> | 48 | </p> |
49 | - <p class="text-warning">{{ q['comments'] }}</p> | 49 | + <p class="text-warning">{{ md(q['comments']) }}</p> |
50 | {% if q['solution'] %} | 50 | {% if q['solution'] %} |
51 | <hr> | 51 | <hr> |
52 | {{ md('**Solução:** \n\n' + q['solution']) }} | 52 | {{ md('**Solução:** \n\n' + q['solution']) }} |
@@ -57,7 +57,7 @@ | @@ -57,7 +57,7 @@ | ||
57 | {{ round(q['grade'] * q['points'], 2) }} | 57 | {{ round(q['grade'] * q['points'], 2) }} |
58 | pontos | 58 | pontos |
59 | </p> | 59 | </p> |
60 | - <p class="text-danger"><pre>{{ q['comments'] }}</pre></p> | 60 | + <p class="text-danger">{{ md(q['comments']) }}</p> |
61 | {% if q['solution'] %} | 61 | {% if q['solution'] %} |
62 | <hr> | 62 | <hr> |
63 | {{ md('**Solução:** \n\n' + q['solution']) }} | 63 | {{ md('**Solução:** \n\n' + q['solution']) }} |
@@ -101,7 +101,7 @@ | @@ -101,7 +101,7 @@ | ||
101 | <p class="text-secondary"> | 101 | <p class="text-secondary"> |
102 | <i class="fas fa-ban fa-3x" aria-hidden="true"></i> | 102 | <i class="fas fa-ban fa-3x" aria-hidden="true"></i> |
103 | {{ round(q['grade'] * q['points'], 2) }} pontos<br> | 103 | {{ round(q['grade'] * q['points'], 2) }} pontos<br> |
104 | - {{ q['comments'] }} | 104 | + {{ md(q['comments']) }} |
105 | {% if q['solution'] %} | 105 | {% if q['solution'] %} |
106 | <hr> | 106 | <hr> |
107 | {{ md('**Solução:** \n\n' + q['solution']) }} | 107 | {{ md('**Solução:** \n\n' + q['solution']) }} |
perguntations/testfactory.py
@@ -98,16 +98,23 @@ class TestFactory(dict): | @@ -98,16 +98,23 @@ class TestFactory(dict): | ||
98 | 98 | ||
99 | # make factory only for the questions used in the test | 99 | # make factory only for the questions used in the test |
100 | if question['ref'] in qrefs: | 100 | if question['ref'] in qrefs: |
101 | - question.setdefault('type', 'information') | 101 | + # question.setdefault('type', 'information') |
102 | question.update({ | 102 | question.update({ |
103 | 'filename': filename, | 103 | 'filename': filename, |
104 | 'path': dirname, | 104 | 'path': dirname, |
105 | 'index': i # position in the file, 0 based | 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 | self.question_factory[question['ref']] = QFactory(question) | 114 | self.question_factory[question['ref']] = QFactory(question) |
109 | 115 | ||
110 | # check if all the questions can be correctly generated | 116 | # check if all the questions can be correctly generated |
117 | + # TODO and corrected | ||
111 | try: | 118 | try: |
112 | self.question_factory[question['ref']].generate() | 119 | self.question_factory[question['ref']].generate() |
113 | except Exception as exc: | 120 | except Exception as exc: |