Booléens
Les deux valeurs booléennes sont : « vrais » et « faux ». Respectivement #t
ou #true
et #f
ou #false
dans Guile.
Dans un contexte de test conditionnel, « vrai » signifie toute expression autre que #f
ou #false
Je t’invite à créer un nouveau répertoire dans l’espace de travail dédié à ce chapitre : ~/Workspace/guile-handbook/booleans
.
Écrire le test d’abord
Création d’un fichier booleans-test.scm
:
(use-modules (srfi srfi-64)
(booleans))
(test-begin "harness")
(test-equal "true-inverted-returns-false"
#f
(boolean-invert #t))
(test-end "harness")
Essayer et lancer le test
guile -L . booleans-test.scm
Erreur de compilation !
;;; note: auto-compilation is enabled, set GUILE_AUTO_COMPILE=0
;;; or pass the --no-auto-compile argument to disable.
;;; compiling /home/jeko/Workspace/guile-handbook/booleans/booleans-test.scm
;;; WARNING: compilation of /home/jeko/Workspace/guile-handbook/booleans/booleans-test.scm failed:
;;; no code for module (booleans)
Écrire le minimum de code pour faire compiler le test et vérifier la raison de son échec
Les erreurs de compilation peuvent être vues comme des tests rouges. Dans la tradition du TDD, il est primordial de n’ajouter que le strict nécessaire de code pour corriger ces erreurs.
Ici, le compilateur indique que le module booleans
n’existe pas. Je le crée pour corriger cette erreur et le relance immédiatement le test.
Création d’un fichier booleans.scm
:
(define-module (booleans))
Une nouvelle erreur survient ! Cette fois-ci, ça compile, mais je suis averti que la variable boolean-invert
n’est pas liée (autrement dit, elle n’est pas définie). Je l’ajoute à mon module précédemment créé et je ré-exécute le test.
Modification du fichier booleans.scm
:
(define-module (booleans))
(define-public (boolean-invert bool)
0)
Plus d’erreur ou d’avertissement à la compilation. Le test échoue et tu peux vérifier la raison de l’échec dans le rapport harness.log
. Un rapide coup d’oeil me confirme que la raison de l’échec est que le test true-inverted-returns-false
attend la valeur #f
alors que la procédure boolean-invert
retourne 0
.
$ cat harness.log
%%%% Starting test harness
Group begin: harness
Test begin:
test-name: "true-inverted-returns-false"
source-file: "booleans-test.scm"
source-line: 6
source-form: (test-equal "true-inverted-returns-false" #f (boolean-invert #t))
Test end:
result-kind: fail
actual-value: 0
expected-value: #f
Group end: harness
# of unexpected failures 1
Faire passer le test
Je modifie la procédure boolean-invert
afin qu’elle retourne la valeur #f
comme attendue par le test.
Modification du fichier booleans.scm
:
(define-module (booleans))
(define-public (boolean-invert bool)
#f)
L'exécution du test affiche le message suivant :
$ guile -L . booleans-test.scm
;;; note: source file /home/jeko/Workspace/guile-handbook/booleans/booleans-test.scm
;;; newer than compiled /home/jeko/.cache/guile/ccache/3.0-LE-8-4.3/home/jeko/Workspace/guile-handbook/booleans/booleans-test.scm.go
;;; note: auto-compilation is enabled, set GUILE_AUTO_COMPILE=0
;;; or pass the --no-auto-compile argument to disable.
;;; compiling /home/jeko/Workspace/guile-handbook/booleans/booleans-test.scm
;;; compiled /home/jeko/.cache/guile/ccache/3.0-LE-8-4.3/home/jeko/Workspace/guile-handbook/booleans/booleans-test.scm.go
%%%% Starting test harness (Writing full log to "harness.log")
# of expected passes 1
Le test passe !
Réusinage
Il n'y a pas grand-chose à faire pour si peu de code.
Docstring
J'en profite pour te parler des docstrings. Ces chaines de caractères apportent un peu d'explication à l'utilisateur au besoin :
- dans le REPL, avec la commande
,describe
- dans Emacs
Ce sont des chaines de caractère placées en deuxième position dans la liste des paramètres lors de la définition d'une variable ou d'une procédure avec define
, define*
ou define-public
(j'en passe et des meilleurs).
Ajoutons une docstring à la procédure boolean-invert
!
Modification du fichier booleans.scm
:
(define-module (booleans))
(define-public (boolean-invert bool)
"Returns the opposite value of the given boolean."
#f)
Écrire le test d’abord
Le premier test vérifiait que appeler la procédure boolean-invert
avec le paramètre #t
retourne #f
. Le prochain test vérifiera l’inverse.
Modification du fichier booleans-test.scm
:
(use-modules (srfi srfi-64)
(booleans))
(test-begin "harness")
(test-equal "true-inverted-returns-false"
#f
(boolean-invert #t))
(test-equal "false-inverted-returns-true"
#t
(boolean-invert #f))
(test-end "harness")
Essayer et lancer le test
$ guile -L . booleans-test.scm
Ça compile sans problème !
Écrire le minimum de code pour faire compiler le test et vérifier la raison de son échec
Le test ne passe pas.
booleans-test.scm:10: FAIL false-inverted-returns-true
Je vérifie que la raison de l’échec est celle que j’attends. C’est-à-dire que le test false-inverted-returns-true
attend la valeur #t
mais obtient #f
.
Test begin:
test-name: "false-inverted-returns-true"
source-file: "booleans-test.scm"
source-line: 10
source-form: (test-equal "false-inverted-returns-true" #t (boolean-invert #f))
Test end:
result-kind: fail
actual-value: #f
expected-value: #t
C'est confirmé.
Faire passer le test
Ajoutons le minimum de code suffisant à faire passer le test :
(define-module (booleans))
(define-public (boolean-invert bool)
"Returns the opposite value of the given boolean."
(if bool
#f
#t))
Je réexécute les tests et…
%%%% Starting test harness (Writing full log to "harness.log")
# of expected passes 2
Tout est OK !
Réusinage
Comme tu t’en doutais, il existe un procédure toute prête pour inverser un booléen :
(define-module (booleans))
(define-public (boolean-invert bool)
"Returns the opposite value of the given boolean."
(not bool))
Je relance une dernière fois les tests pour vérifier que ce réusinage n’a rien cassé :
%%%% Starting test harness (Writing full log to "harness.log")
# of expected passes 2
Tout est bon !
Conclusion
Ce que l’on a couvert dans ce chapitre :
- Encore plus de pratique du TDD
- Quelques notions sur les booléens
- Écrire du code auto-documenté grâce aux docstrings