Skip to content
Snippets Groups Projects
Verified Commit b76f3e9f authored by orestis.malaspin's avatar orestis.malaspin
Browse files

i think my work here is done

parent 5d8eb026
No related branches found
No related tags found
2 merge requests!34Switches part05 and part06,!31Adds part05summary
Pipeline #25453 passed
...@@ -8,8 +8,7 @@ Les concepts abordés dans cet exemple sont: ...@@ -8,8 +8,7 @@ Les concepts abordés dans cet exemple sont:
1. [La documentation.](#la-documentation) 1. [La documentation.](#la-documentation)
2. [Les tests.](#les-tests) 2. [Les tests.](#les-tests)
3. [Les tests de documentation.](#les-tests-de-documentation) 3. [Les outils en plus du compilateur](#les-outils-en-plus-du-compilateur)
4. [Les outils en plus du compilateur](#les-outils-en-plus-du-compilateur)
## Discussion ## Discussion
...@@ -89,18 +88,130 @@ ligne de documentation (on peut également utiliser la syntaxe `/*! ... */`), co ...@@ -89,18 +88,130 @@ ligne de documentation (on peut également utiliser la syntaxe `/*! ... */`), co
#### Markdown #### Markdown
La documentation supporte la syntaxe du [Common Markdown](https://commonmark.org/) La documentation supporte la syntaxe du [Common Markdown](https://commonmark.org/) comme on peut le voir dans le code ci-dessus. On a en particulier
la possibilité de mettre des titres avec des `#` ou du code avec des code fences. Il est également possible de mettre des liens vers
d'autres parties de la documentation (avec les annotations tu type `[MyStruct]`) ce qui fait de la syntaxe un outil très puissant et intégré fortement au processus de développement.
#### Génération de la documentation #### Génération de la documentation
Tout ce travail Tout ce travail d'annotation du code source permet d'utiliser `rustdoc` qui est un outil puissant de génération de documentation
sous la forme principal d'un site web. Dans le répertoire où se trouve le fichier `Cargo.toml`, on peut exécuter la commande
```bash
cargo doc
```
et cela va générer la documentation dans un sous répertoire du projet. On peut également automatiquement ouvrir la
documentation dans un navigateur à l'aide de la commande
```bash
cargo doc --open
```
### Les tests ### Les tests
### Les tests de documentation La documentation aide grandement à la (ré-)utilisation d'une librairie et à son développement (collaboratif ou non).
Durant le processus de développement, il est également très utile (et important) d'écrire des tests pour le code.
Rust propose un framework de tests totalement intégré au langage. On peut ainsi très facilement écrire
des fonctions de test en ajoutant l'annotation #[test] directement au dessus de n'importe quelle fonction
```rust,ignore
{{#include ../../codes/rust_lang/part05/src/main.rs:test_creation}}
```
La fonction `test_creation()` sera automatiquement appelée lors de l'appel à la commande
```bash
cargo test
```
Aucune fonction non annotée par `#[test]` n'est appelée quand on exécute `cargo test`.
Si la fonction se termine sans erreur, le test est réussi (il est échoué si la fonction
s'arrête en cours de route).
On voit dans la fonction `test_creation()` l'appel à la macro `assert!()` qui prend en argument
une expression booléenne, ici `n1 == SomethingOrNothing::Nothing` dans le premier appel.
Si l'expression prend la valeur `true`, le code continue normalement son exécution, sinon
il fait appel à la macro `panic!()!` et l'exécution est interrompue et un code d'erreur est retourné par le programme.
Dans l'appel à `n1 == SomethingOrNothing::Nothing`, on constate qu'on a besoin de vérifier
si `n1` est égale à `SomethingOrNothing::Nothing`. L'opérateur `==` n'est pas implémenté
pour les types complexes, ainsi le code suivant ne compile pas
```rust,compile_fail
enum SomethingOrNothing<T> {
Nothing,
Something(T),
}
fn main() {
let n1 = SomethingOrNothing::<i32>::Nothing;
let b = n1 == SomethingOrNothing::<i32>::Nothing;
}
```
et nous donne un message d'erreur incluant
```bash
note: an implementation of `PartialEq<_>` might be missing for `SomethingOrNothing<i32>`
```
Ainsi, on doit implémenter le trait `PartialEq` pour le type `SomethingOrNothing<T>`,
qui permet de tester l'égalité entre deux instances d'un type
```rust
{{#include ../../codes/rust_lang/part05/src/main.rs:something_or_nothing}}
{{#include ../../codes/rust_lang/part05/src/main.rs:partial_eq}}
fn main() {
let n1 = SomethingOrNothing::<i32>::Nothing;
assert!(n1 == SomethingOrNothing::<i32>::Nothing);
}
```
On constate que dans notre implémentation, il est nécessaire que `T` implémente également
le trait `PartialEq`. Ainsi, deux `Nothing` sont égales, un `Nothing` et un `Something` sont différentes, et seulement quand les deux valeurs encapsuleés dans deux `Something` sont égales
alors nous avons égalité.
On peut également vouloir construire des tests qui échouent comme dans l'exemple ci-dessous
```rust,ignore
{{#include ../../codes/rust_lang/part05/src/main.rs:test_should_fail}}
```
où on a annoté le test avec un `#[should_panic]`. Ce test, bien qu'il panique, sera considéré
comme réussi.
Finalement, il y a également la possibilité de regroupes les tests dans un module séparé
comme ci-dessous
```rust,ignore
{{#include ../../codes/rust_lang/part05/src/main.rs:cfg_test}}
```
Pour ce faire, il faut créer un module, `mod test` et l'annoter avec une configuration spéciale `#[cfg(test)]`. Cela permet de séparer les tests totalement du reste du code et devoir
importer les différentes implémentations.
#### Rapport sur l'exécution des tests
Lors de l'appel à `cargo test` tous les tests sont exécutés et un rapport est généré. Sur
[ce code](#le-code), on obtient
```bash
$ cargo est
Compiling part05 v0.1.0 (/rust-101/codes/rust_lang/part05)
Finished test [unoptimized + debuginfo] target(s) in 0.52s
Running unittests src/main.rs (target/debug/deps/part05-5a74a11c06bd3179)
running 5 tests
test test_min ... ok
test test_creation ... ok
test tests::test_min ... ok
test tests::test_min_something_or_nothing ... ok
test test_failure_creation - should panic ... ok
test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
```
### Les outils en plus du compilateur ### Les outils en plus du compilateur
La chaîne de compilation Rust vient avec deux autres outils très pratiques (en plus de `cargo` et `rustdoc`): `rustfmt` un formatteur de code, et `clippy` un linter.
#### `rustfmt`
Rust a fait le choix fasciste de définir des tas de conventions pour le nommage
des variables, des types, etc. L'outil `rustfmt` permet de formatter automatiquement
le code pour avoir un style uniforme au travers de tout votre code et ainsi améliorer
sa lisibilité.
#### `clippy`
L'outil `clippy` est un détecteur automatique de mauvaise pratiques de codage, telles que définies
par la communauté du Rust. Il permet d'écrire du code le plus idiomatique possible
et en général d'éviter des mauvaises pratiques et/ou de simplifier
le code avec des *patterns* connus.
## Le code ## Le code
```rust ```rust
......
...@@ -49,6 +49,7 @@ enum SomethingOrNothing<T> { ...@@ -49,6 +49,7 @@ enum SomethingOrNothing<T> {
} }
// ANCHOR_END: something_or_nothing // ANCHOR_END: something_or_nothing
// ANCHOR: static_function
impl<T: std::fmt::Display> SomethingOrNothing<T> { impl<T: std::fmt::Display> SomethingOrNothing<T> {
/// A static function that prints the content of a SomethingOrNothing. /// A static function that prints the content of a SomethingOrNothing.
fn print(&self) { fn print(&self) {
...@@ -58,16 +59,18 @@ impl<T: std::fmt::Display> SomethingOrNothing<T> { ...@@ -58,16 +59,18 @@ impl<T: std::fmt::Display> SomethingOrNothing<T> {
} }
} }
} }
// ANCHOR_END: static_function
// ANCHOR: static_function // ANCHOR: default
impl<T> Default for SomethingOrNothing<T> { impl<T> Default for SomethingOrNothing<T> {
/// By Default a [SomethingOrNothing] is a nothing. /// By Default a [SomethingOrNothing] is a nothing.
fn default() -> Self { fn default() -> Self {
SomethingOrNothing::Nothing SomethingOrNothing::Nothing
} }
} }
// ANCHOR_END: static_function // ANCHOR_END: default
// ANCHOR: partial_eq
impl<T: PartialEq> PartialEq for SomethingOrNothing<T> { impl<T: PartialEq> PartialEq for SomethingOrNothing<T> {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
match (self, other) { match (self, other) {
...@@ -79,6 +82,7 @@ impl<T: PartialEq> PartialEq for SomethingOrNothing<T> { ...@@ -79,6 +82,7 @@ impl<T: PartialEq> PartialEq for SomethingOrNothing<T> {
} }
} }
} }
// ANCHOR_END: partial_eq
// ANCHOR: minimum // ANCHOR: minimum
/// The [Minimum] trait computes the minimum value between two values of a type /// The [Minimum] trait computes the minimum value between two values of a type
...@@ -170,6 +174,7 @@ fn main() { ...@@ -170,6 +174,7 @@ fn main() {
min.print(); min.print();
} }
// ANCHOR: test_creation
#[test] #[test]
fn test_creation() { fn test_creation() {
let n1: SomethingOrNothing<i32> = SomethingOrNothing::default(); let n1: SomethingOrNothing<i32> = SomethingOrNothing::default();
...@@ -177,7 +182,9 @@ fn test_creation() { ...@@ -177,7 +182,9 @@ fn test_creation() {
let n2: SomethingOrNothing<i32> = SomethingOrNothing::Something(1); let n2: SomethingOrNothing<i32> = SomethingOrNothing::Something(1);
assert!(n2 == SomethingOrNothing::Something(1)); assert!(n2 == SomethingOrNothing::Something(1));
} }
// ANCHOR_END: test_creation
// ANCHOR: test_should_fail
#[test] #[test]
#[should_panic] #[should_panic]
fn test_failure_creation() { fn test_failure_creation() {
...@@ -185,6 +192,7 @@ fn test_failure_creation() { ...@@ -185,6 +192,7 @@ fn test_failure_creation() {
assert!(n2 == SomethingOrNothing::Nothing); assert!(n2 == SomethingOrNothing::Nothing);
assert!(n2 == SomethingOrNothing::Something(2)); assert!(n2 == SomethingOrNothing::Something(2));
} }
// ANCHOR_END: test_should_fail
#[test] #[test]
fn test_min() { fn test_min() {
...@@ -193,6 +201,7 @@ fn test_min() { ...@@ -193,6 +201,7 @@ fn test_min() {
assert!(min == SomethingOrNothing::Something(-1)); assert!(min == SomethingOrNothing::Something(-1));
} }
// ANCHOR: cgf_test
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#[test] #[test]
...@@ -216,3 +225,4 @@ mod tests { ...@@ -216,3 +225,4 @@ mod tests {
assert!(z.min(z) == z); assert!(z.min(z) == z);
} }
} }
// ANCHOR_END: cgf_test
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment