Structure de contenu Progression

Définitions :

Question :

La question est un exercice unique, validé par une série de tests.

Test :

Une validation effectuée pour prouver que l’étudiant a répondu correctement à la question. Au moins un test est nécessaire par question mais la plupart devraient en comporter plusieurs.

Ébauche :

Une ébauche de réponse proposée à l’étudiant. Au moins une ébauche est requise par question; plus d’une peuvent être fournies, par exemple, pour supporter plus d’un langage de programmation.

Composition des éléments d’une question

Question

Une question est constituée d’un ou plusieurs fichiers en format YAML.

Toute Question DOIT comporter l’ attribut suivant :

Nom Type Description
type str le type de question
    Les valeurs possibles sont :
    «prog» : - Programmation
    «sys» : - Administration système

Une Question PEUT comporter les attributs suivants :

Nom Type Format Valeur par défaut Description
titre str   «  » Le titre de la question.
niveau str   «  » Le niveau de difficulté de la question
objectif str   «  » L’objectif de la question
description str   «  » (réservé pour usage futur)
énoncé str ou liste de dict str markdown ou [ { titre: str, texte: str markdown }, … ] «  » L’énoncé de la question. Il s’agit de la tâche à réaliser. Si l’énoncé est un tableau de dictionnaires, chaque élément du tableau représente une page de l’énoncé comportant un titre et un texte en markdown
rétroactions dictionnaire de str markdown {} rétroactions générales à la question
auteur str   «  » Le nom du ou des auteurs de la question
licence str   «  » La licence sous laquelle est publiée la question

Rétroactions

Trois rétroactions sont prévues :

Nom Type Format Défaut Description
positive str markdown «  » rétroaction fournie lorsque la solution produit une réponse correcte.1
négative str markdown «  » rétroaction fournie lorsque la solution produit une réponse incorrecte.
erreur str markdown «  » rétroaction fournie lorsque la solution a provoqué une erreur.

Exemple avec énoncé simple :

type: prog

titre: Appeler une fonction paramétrée

objectif: Mettre en pratique la notion d'appel de fonction

énoncé: |
                La fonction `salutations` produit en sortie une salution autant de fois que la valeur reçue en paramètre.

                Utilisez-la pour faire produire en sortie «Bonjour le monde!» autant de fois que le nombre reçu en entrée.

rétroactions:
  positive: "**Très bien!** Vous avez maintenant appélé une fonction paramétrée"
  négative: Encore un petit effort
  erreur: Vérifiez la syntaxe d'un appel de fonction

Exemple avec énoncé sur deux pages :

type: prog

titre: Appeler une fonction paramétrée

objectif: Mettre en pratique la notion d'appel de fonction

énoncé:
        - titre: Mise en contexte
          texte: La fonction `salutations` produit en sortie une salution autant de fois que la valeur reçue en paramètre.
  - titre: À faire
          texte: Utilisez-la pour faire produire en sortie «Bonjour le monde!» autant de fois que le nombre reçu en entrée.

rétroactions:
  positive: "**Très bien!** Vous avez maintenant appélé une fonction paramétrée"
  négative: Encore un petit effort
  erreur: Vérifiez la syntaxe d'un appel de fonction

Questions Prog:

Une Question spécifiquement de type «prog» DOIT comporter les attributs suivants :

Nom Type Description
ébauches dictionnaire de str les descriptifs des programmes exécutables. Doit comporter au moins un élément.
    Clé: nom du langage de programmation
    Valeur: l’ébauche fournie initialement à l’étudiant
tests liste de TestProgs l’ensemble des tests de validation. Doit comporter au moins un élément.
  • Ébauche

    Pour chaque langage pris en charge par la question, une ébauche de départ doit être fournie. Le programme entier réside dans ce bloc de code, c’est ce code, placé dans un fichier unique qui sera exécuté.

    Les balises suivantes peuvent être utilisées pour contrôler la visibilité et la modification du code par l’étudiant. :

    +VISIBLE et -VISIBLE
    Contrôlent les parties visibles à l’étudiant.
    • En l’absence de toute balise, l’ensemble du fichier est visible.
    • En général, l’ébauche est visible entre une balise +VISIBLE et une balise -VISIBLE.
    • S’il n’y a pas de balise +VISIBLE avant une balise -VISIBLE, l’ébauche est visible jusqu’à la balise -VISIBLE.
    • S’il n’y a pas de balise -VISIBLE avant une balise +VISIBLE, l’ébauche est invisible jusqu’à la balise +VISIBLE.
    (no term)
    +TODO et -TODO contrôlent les parties modifiables par l’étudiant.
    • En l’absence de toute balise, l’ensemble du fichier est modifiable.
    • En général, l’ébauche est modifiable entre une balise +TODO et une balise -TODO.
    • S’il n’y a pas de balise +TODO avant une balise -TODO, l’ébauche est modifiable jusqu’à la balise -TODO.
    • S’il n’y a pas de balise -TODO avant une balise +TODO, l’ébauche est non-modifiable jusqu’à la balise +TODO.

    Toutes les parties invisibles (et de ce fait immuables) seront tout de même exécutées normalement. Elles peuvent servir à mettre en place certains éléments du programme sur lesquels on ne veut pas attirer l’attention de l’étudiant. Cependant, elles ne devraient pas servir à dissimuler des réponses puisqu’il sera toujours possible pour l’étudiant débrouillard de les rendre visibles.

Questions Système (bêta)

Une question spécifiquement de type «sys» DOIT comporter les attributs suivants :

Nom Type Description
image str Le nom d’une image de conteneur (docker) à utiliser comme contexte de résolution

Une question spécifiquement de type «sys» DOIT comporter un et un seul des deux attributs suivants :

Nom Type Description
tests liste de TestSys les tests de validation. Doit comporter au moins un élément.
réponse str La réponse courte à la question. Si réponse est délimitée par des `~`,
    elle est considérée comme une expression rationnelle. Sinon, il s’agit d’une chaîne standard.
    Pour réussir l’exercice, une chaîne correspondant à la réponse doit être soumise.

Une question spécifiquement de type «sys» PEUT comporter les attributs suivants :

Nom Type Défaut Description
utilisateur str ^[a-z][-a-z0-9_]*\$ Selon la définition de l’image Le nom de l’utilisateur qui démarre le conteneur
init str Un script d’initialisation de l’exercice À l’exécution du test, le script sera lancé dans le conteneur par l’interpréteur de commande par défaut
commande str sh La commande exécutée dans le terminal présenté à l’utilisateur
  • Images

    Les images utilisées par les question systèmes sont des images docker qui doivent être exécutables sans paramètres et pouvoir rester en arrière-plan. Spécifiquement, l’image est démarrée par la commande docker run -d <image>

    Dans le cas des images sans mode «service» (par exemple ubuntu), il est toujours possible de les utiliser en ajoutant une clause CMD sleep infinity à la définition de l’image.

    Si une commande HEALTHCHECK existe dans l’image, le terminal est démarré pour l’étudiant dès que le statut du conteneur passe à «healthy», sinon, il le sera après une attente maximale de 5s.

    Des variables d’environnement peuvent être utilisées par le conteneur si elles sont spécifiées lors de la construction de l’image par une clause ENV

Test

Chaque test PEUT contenir les attributs suivants :

Nom Type Format Défaut Description
nom str   «  » Nom du test
sortie str   «  » les sorties textuelles attendues produites par le test
rétroactions dictionnaire de str markdown {} rétroactions spécifiques au test. Les rétroactions spécifiques possibles sont les mêmes que les rétroactions générales
  • TestProg

    Pour une question de type «prog», un Test PEUT contenir les attributs suivants :

    Nom Type Format Défaut Description
    entrée str   «  » les entrées textuelles passés directement à l’entrée standard du programme
    params str markdown «  » les paramètres passés au programme au moment de l’exécution
    rétroactions dictionnaire de str   {} rétroactions spécifiques au test. Les rétroactions spécifiques possibles sont les mêmes que les rétroactions générales
    cachée bool   false Si vrai, la sortie attendue est remplacée par une chaîne vide.
  • TestSys (bêta)

    Pour une question de type «sys», un Test DOIT contenir les attributs suivants :

    Nom Type Description
    validation str Un script de validation du test

    Pour une question de type «sys», un Test PEUT contenir les attributs suivants :

    Nom Type Défaut Description
    utilisateur str ^[a-z][-a-z0-9_]*\$ Même que QuestionSys.utilisateur L’utilisateur utilisé pour exécuter le script de validation

Exemples complets :

  • Question Prog

    info.yml :

    type: prog
    
    titre: Appeler une fonction paramétrée
    
    objectif: Mettre en pratique la notion d'appel de fonction
    
    énoncé: |
                    La fonction `salutations` produit en sortie une salutation autant de fois que la valeur reçue en paramètre.
    
                    Utilisez-la pour faire produire en sortie «Bonjour le monde!» autant de fois que le nombre reçu en entrée.
    
    rétroactions:
      positive: "**Très bien!** Vous avez maintenant appélé une fonction paramétrée"
      négative: Encore un petit effort. Pour plus d'information sur l'appel des fonctions, voir [Appel de fonction](https://exemple.com/doc/lesfonctions.html)
      erreur: Vérifiez la syntaxe d'un appel de fonction
    
    ébauches:
     python: |
        #+VISIBLE
        nb_répétitions = int( input() )
              #+TODO
    
              #-TODO
              #-VISIBLE
     java: |
        import java.util.Scanner;
        public class exec {
        //+VISIBLE
        
        public static void main(String[] args) {
        
            Scanner input = new Scanner( System.in );
                    
            nb_répétitions = input.nextInt();
        //+TODO
        
    
        //-TODO
            }
        //-VISIBLE
        }
    
    tests:
     - nom: Une seule fois
       entrée: Bonjour le monde!
       params: -n 1
       sortie: Bonjour le monde!
     - nom: Trois fois
       entrée: Bonjour le monde!
       params: -n 3
       sortie: |
               Bonjour le monde!
               Bonjour le monde!
               Bonjour le monde!
     - nom: 0 fois
       entrée: Bonjour le monde!
       params: -n 0
       sortie: ""
       rétroactions:
         positive: Bien joué! 0 est aussi une entrée valable.
         négative: N'oublie pas les cas limites, 0 est aussi une entrée valable!
    

    Afin de limiter la taille et la complexité du fichier info.yml, il est possible d’inclure des fichiers YAML (.yml ou .yaml), texte (.txt) ou Markdown (.md) en utilisant la balise !include. L’exemple ci-haut peut donc être réduit à ceci :

    type: prog
    
    titre: Appeler une fonction paramétrée
    
    objectif: Mettre en pratique la notion d'appel de fonction
    
    énoncé: !include énoncé.md
                    
    rétroactions: !include rétroactions.yml
    
    ébauches:
      python: !include ébauches/ébauche.py
      java: !include ébauches/ébauche.java
    
    tests: !include tests/tous_les_tests.yml
    

    étant accompagné des fichiers suivants dans le même répertoire :

    énoncé.md

    La fonction `salutations` produit en sortie une salution autant de fois que la valeur reçue en paramètre.
    
    Utilisez-la pour faire produire en sortie «Bonjour le monde!» autant de fois que le nombre reçu en entrée.
    

    rétroactions.yml

    positive: "**Très bien!** Vous avez maintenant appélé une fonction paramétrée"
    négative: Encore un petit effort. Pour plus d'information sur l'appel des fonctions, voir [Appel de fonction](https://exemple.com/doc/lesfonctions.html)
    erreur: Vérifiez la syntaxe d'un appel de fonction
    

    ébauches/ébauche.py

    #+VISIBLE
    nb_répétitions = int( input() )
    #+TODO
    
    #-TODO
    #-VISIBLE
    

    ébauches/ébauche.java

    import java.util.Scanner;
    public class exec {
    //+VISIBLE
    
    public static void main(String[] args) {
    
            Scanner input = new Scanner( System.in );
                    
            nb_répétitions = input.nextInt();
    //+TODO
    
    
    //-TODO
            }
    //-VISIBLE
    }
    

    tests/tous_les_autres_tests.yml :

     - nom: Une seule fois
       entrée: Bonjour le monde!
       params: -n 1
       sortie: Bonjour le monde!
       rétroactions:
         positive: "**Bravo** champion!"
         négative: Encore *un* effort...
     - nom: Trois fois
       entrée: Bonjour le monde!
       params: -n 3
       sortie: |
               Bonjour le monde!
               Bonjour le monde!
               Bonjour le monde!
     - nom: 0 fois
       entrée: Bonjour le monde!
       params: -n 0
       sortie: ""
       rétroactions:
         positive: Bien joué! 0 est aussi une entrée valable.
         négative: N'oublie pas les cas limites, 0 est aussi une entrée valable!
     - nom: Trop de salutations
       entrée: Bonjour le monde!
       params: -n 1000000
       sortie: [un_million_de_bonjours.txt]
    
  • Question Sys
    • Exemple de réponse courte
      type: sys
      
      énoncé: Quel est le numéro d'utilisateur de Krusty?
      
      utilisateur: root
      init: |
        #!/bin/bash
        useradd krusty -u 1234
      
      réponse: 1234
      
    • Exemple de validation
      type: sys
      
      énoncé: Créez le répertoire config dans le répertoire utilisateur de Krusty
      
      utilisateur: root
      init: |
        #!/bin/bash
        useradd krusty -u 1234 -m
      
      tests:
        - nom: présence du répertoire config
          utilisateur: krusty
          validation: [ -d /home/krusty/config ] && echo ok
          sortie: ok
        - nom: nombre de fichiers dans le répertoire
          utilisateur: krusty
          validation: ls -a /home/krusty/ | wc -l
          sortie: 6
      

Références :

Notes de bas de page:

1

Certains symboles on une signification particulière en YAML ou en markdown. Le format YAML ayant préséance, pour les utiliser en markdown, utilisez les caractères les guillemets, le format yaml «bloc» ou inclure un fichier markdown :

Incorrect :

  positive: *Ceci est en gras*

Correct :
  positive: "*Ceci est en gras*"
  négative: |
      *Ceci est en gras*
  erreur: !include rétroaction_err.md