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: |