/** @module lib/outils/basthon/analyse */
// cf commit 3e37ce84 (du 23/02/2022) pour une version qui utilise directement pyodide.runPython
/**
* Retourne un message de diagnostic du code de l’élève (vide s’il est identique au code voulu), en utilisant directement le pyodide chargé par basthon
* @param {Gui} gui
* @param {string} codeRef Le code de référence (celui qui est dans l’éditeur devrait sortir la même chose en console que celui-ci)
* @param {Object} variables la liste des variables à affecter avant de lancer le code de l’élève ou celui de référence
* @return {Promise<string>}
*/
export async function getDiagMessage (gui, codeRef, variables) {
// vire les lignes vides, les commentaires et les affectations de nos variables
// (on aurait pu faire directement un replace sur la string sans l’éclater en lignes, mais c’est plus lisible donc moins buggé comme ça)
const vars = Object.keys(variables)
const stripVarRegexp = vars.length ? new RegExp(`^\\s*(${vars.join('|')})\\s*=`) : /./ // si pas de variables une regex qui match n’importe quel caractère
const stripCommentRegexp = /^\s#/
const cleanCode = code => code.split('\n').filter(line => !stripVarRegexp.test(line) && !stripCommentRegexp.test(line)).join('\n')
await gui.loaded()
// le script de l’élève
const codeEleve = gui.getContent()
// on démarre le code par l’affectation des variables
const codeDebut = variables ? Object.entries(variables).map(([cle, valeur]) => `${cle} = ${valeur}`).join('\n') : ''
// on ote les saisies de l’algo eleve
const codeEleveTest = codeDebut + '\n' + cleanCode(codeEleve)
// on ote les saisies de l’algo secret
const codeRefTest = codeDebut + '\n' + cleanCode(codeRef)
// et on l’exécute
const { stdErr: stdErrRef, stdOut: stdOutRef } = await gui.eval(codeRefTest)
if (stdErrRef) {
console.error(stdErrRef)
throw Error('Le code de référence fourni est invalide')
}
// on affiche le résultat du code de l’élève en console
gui.shell.clear(true)
gui.showShell()
gui.shell.launch(codeEleveTest, false) // attention, ça émet un événement mais n’est pas une fct async, donc ça lance un truc qui va tourner en arrière plan
// et on l’évalue
const { stdErr, stdOut } = await gui.eval(codeEleveTest)
// y’a un pb
if (stdErr) {
let diag = 'Ton programme a bogué pour ' + codeEleveTest
const iErr = stdErr.lastIndexOf(' line ')
if (iErr >= 0) {
diag += '\n>>>' + stdErr.substring(iErr)
}
return diag
}
// pas d’erreurs, on regarde si la sortie est celle attendue
if (stdOut === stdOutRef) return ''
// on explique l’échec (pas d’erreur mais pas le résultat attendu)
let diag = 'Résultat faux pour le code :\n' + codeEleveTest
diag += '\n' + 'ta réponse : ' + stdOut
diag += '\n' + 'la bonne réponse : ' + stdOutRef
return diag
}