From e170a345d0291cb15dc681f81964208db3f42162 Mon Sep 17 00:00:00 2001 From: lee Date: Mon, 28 Dec 2020 15:55:34 +0000 Subject: [PATCH 1/3] quest-04: readme and tests --- rust/tests/banner_test/Cargo.lock | 12 ++ rust/tests/banner_test/Cargo.toml | 10 ++ rust/tests/banner_test/src/main.rs | 88 ++++++++++ rust/tests/boxing_todo_test/Cargo.lock | 96 ++++++++++ rust/tests/boxing_todo_test/Cargo.toml | 12 ++ rust/tests/boxing_todo_test/src/main.rs | 99 +++++++++++ rust/tests/cipher_test/Cargo.lock | 12 ++ rust/tests/cipher_test/Cargo.toml | 10 ++ rust/tests/cipher_test/src/main.rs | 24 +++ rust/tests/error_type_test/Cargo.lock | 98 +++++++++++ rust/tests/error_type_test/Cargo.toml | 10 ++ rust/tests/error_type_test/src/main.rs | 136 +++++++++++++++ rust/tests/handling_test/Cargo.lock | 12 ++ rust/tests/handling_test/Cargo.toml | 10 ++ rust/tests/handling_test/a.txt | 1 + rust/tests/handling_test/src/main.rs | 63 +++++++ rust/tests/panic_test/Cargo.lock | 12 ++ rust/tests/panic_test/Cargo.toml | 10 ++ rust/tests/panic_test/src/main.rs | 29 +++ rust/tests/profanity_filter_test/Cargo.lock | 99 +++++++++++ rust/tests/profanity_filter_test/Cargo.toml | 11 ++ rust/tests/profanity_filter_test/src/main.rs | 77 ++++++++ rust/tests/question_mark_test/Cargo.lock | 12 ++ rust/tests/question_mark_test/Cargo.toml | 10 ++ rust/tests/question_mark_test/src/main.rs | 47 +++++ rust/tests/unwrap_and_expect_test/Cargo.lock | 12 ++ rust/tests/unwrap_and_expect_test/Cargo.toml | 10 ++ rust/tests/unwrap_and_expect_test/src/main.rs | 49 ++++++ subjects/banner/README.md | 110 ++++++++++++ subjects/boxing_todo/README.md | 165 ++++++++++++++++++ subjects/boxing_todo/malformed_object.json | 1 + subjects/boxing_todo/todo.json | 7 + subjects/boxing_todo/todo_empty.json | 4 + subjects/cipher/README.md | 47 +++++ subjects/error_type/README.md | 124 +++++++++++++ subjects/handling/README.md | 48 +++++ subjects/panic/README.md | 34 ++++ subjects/profanity_filter/README.md | 81 +++++++++ subjects/question_mark/README.md | 70 ++++++++ subjects/unwrap_or_expect/README.md | 66 +++++++ 40 files changed, 1828 insertions(+) create mode 100644 rust/tests/banner_test/Cargo.lock create mode 100644 rust/tests/banner_test/Cargo.toml create mode 100644 rust/tests/banner_test/src/main.rs create mode 100644 rust/tests/boxing_todo_test/Cargo.lock create mode 100644 rust/tests/boxing_todo_test/Cargo.toml create mode 100644 rust/tests/boxing_todo_test/src/main.rs create mode 100644 rust/tests/cipher_test/Cargo.lock create mode 100644 rust/tests/cipher_test/Cargo.toml create mode 100644 rust/tests/cipher_test/src/main.rs create mode 100644 rust/tests/error_type_test/Cargo.lock create mode 100644 rust/tests/error_type_test/Cargo.toml create mode 100644 rust/tests/error_type_test/src/main.rs create mode 100644 rust/tests/handling_test/Cargo.lock create mode 100644 rust/tests/handling_test/Cargo.toml create mode 100644 rust/tests/handling_test/a.txt create mode 100644 rust/tests/handling_test/src/main.rs create mode 100644 rust/tests/panic_test/Cargo.lock create mode 100644 rust/tests/panic_test/Cargo.toml create mode 100644 rust/tests/panic_test/src/main.rs create mode 100644 rust/tests/profanity_filter_test/Cargo.lock create mode 100644 rust/tests/profanity_filter_test/Cargo.toml create mode 100644 rust/tests/profanity_filter_test/src/main.rs create mode 100644 rust/tests/question_mark_test/Cargo.lock create mode 100644 rust/tests/question_mark_test/Cargo.toml create mode 100644 rust/tests/question_mark_test/src/main.rs create mode 100644 rust/tests/unwrap_and_expect_test/Cargo.lock create mode 100644 rust/tests/unwrap_and_expect_test/Cargo.toml create mode 100644 rust/tests/unwrap_and_expect_test/src/main.rs create mode 100644 subjects/banner/README.md create mode 100644 subjects/boxing_todo/README.md create mode 100644 subjects/boxing_todo/malformed_object.json create mode 100644 subjects/boxing_todo/todo.json create mode 100644 subjects/boxing_todo/todo_empty.json create mode 100644 subjects/cipher/README.md create mode 100644 subjects/error_type/README.md create mode 100644 subjects/handling/README.md create mode 100644 subjects/panic/README.md create mode 100644 subjects/profanity_filter/README.md create mode 100644 subjects/question_mark/README.md create mode 100644 subjects/unwrap_or_expect/README.md diff --git a/rust/tests/banner_test/Cargo.lock b/rust/tests/banner_test/Cargo.lock new file mode 100644 index 000000000..585ef531a --- /dev/null +++ b/rust/tests/banner_test/Cargo.lock @@ -0,0 +1,12 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "banner" +version = "0.1.0" + +[[package]] +name = "banner_test" +version = "0.1.0" +dependencies = [ + "banner", +] diff --git a/rust/tests/banner_test/Cargo.toml b/rust/tests/banner_test/Cargo.toml new file mode 100644 index 000000000..7f9921254 --- /dev/null +++ b/rust/tests/banner_test/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "banner_test" +version = "0.1.0" +authors = ["lee "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +banner = { path = "../../../../rust-piscine-solutions/banner"} diff --git a/rust/tests/banner_test/src/main.rs b/rust/tests/banner_test/src/main.rs new file mode 100644 index 000000000..c05007856 --- /dev/null +++ b/rust/tests/banner_test/src/main.rs @@ -0,0 +1,88 @@ +use std::collections::HashMap; +use banner::*; + +fn main() { + let mut handler = FlagsHandler { flags: HashMap::new() }; + + let d = Flag::opt_flag("division", "divides the values, formula (a / b)"); + let r = Flag::opt_flag( + "remainder", + "remainder of the division between two values, formula (a % b)", + ); + + handler.add_flag((d.short_hand, d.long_hand), div); + handler.add_flag((r.short_hand, r.long_hand), rem); + + println!("{:?}", handler.exec_func(("-d".to_string(), "--division".to_string()), &["1.0", "2.0"])); + // output: "0.5" + + println!("{:?}",handler.exec_func(("-r".to_string(), "--remainder".to_string()), &["2.0", "2.0"])); + // output: "0.0" + + println!("{:?}",handler.exec_func(("-d".to_string(), "--division".to_string()), &["a", "2.0"])); + // output: "invalid float literal" + + println!("{:?}",handler.exec_func(("-r".to_string(), "--remainder".to_string()), &["2.0", "fd"])); + // output: "invalid float literal" +} + +#[cfg(test)] +mod tests { + use super::*; + + fn init() -> FlagsHandler { + let d = Flag::opt_flag("division", "divides two numbers"); + let r = Flag::opt_flag( + "remainder", + "gives the remainder of the division between two numbers", + ); + let mut handler = FlagsHandler { flags: HashMap::new() }; + + handler.add_flag((d.short_hand, d.long_hand), div); + handler.add_flag((r.short_hand, r.long_hand), rem); + return handler; + } + + #[test] + fn ok_test() { + let mut handler = init(); + assert_eq!( + handler.exec_func(("-d".to_string(), "--division".to_string()), &["1.0", "2.0"]), + "0.5" + ); + assert_eq!( + handler.exec_func(("-r".to_string(), "--remainder".to_string()), &["2.0", "2.0"]), + "0" + ); + assert_eq!( + handler.exec_func(("-d".to_string(), "--division".to_string()), &["12.323", "212.32"]), + "0.05803975" + ); + assert_eq!( + handler.exec_func(("-r".to_string(), "--remainder".to_string()), &["12.323", "212.32"]), + "12.323" + ); + } + + #[test] + fn error_test() { + let mut handler = init(); + assert_eq!( + handler.exec_func(("-d".to_string(), "--division".to_string()), &["a", "2.0"]), + "invalid float literal" + ); + assert_eq!( + handler.exec_func(("-r".to_string(), "--remainder".to_string()), &["2.0", "f"]), + "invalid float literal" + ); + assert_eq!( + handler.exec_func(("-d".to_string(), "--division".to_string()), &["1.0", "0.0"]), + "inf" + ); + assert_eq!( + handler.exec_func(("-r".to_string(), "--remainder".to_string()), &["2.0", "0.0"]), + "NaN" + ); + } +} + diff --git a/rust/tests/boxing_todo_test/Cargo.lock b/rust/tests/boxing_todo_test/Cargo.lock new file mode 100644 index 000000000..7c71d7d5a --- /dev/null +++ b/rust/tests/boxing_todo_test/Cargo.lock @@ -0,0 +1,96 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "boxing_todo" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "boxing_todo_test" +version = "0.1.0" +dependencies = [ + "boxing_todo", + "serde", + "serde_json", +] + +[[package]] +name = "itoa" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" + +[[package]] +name = "proc-macro2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "serde" +version = "1.0.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1500e84d27fe482ed1dc791a56eddc2f230046a040fa908c08bda1d9fb615779" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "syn" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9802ddde94170d186eeee5005b798d9c159fa970403f1be19976d0cfb939b72" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" diff --git a/rust/tests/boxing_todo_test/Cargo.toml b/rust/tests/boxing_todo_test/Cargo.toml new file mode 100644 index 000000000..cd7019e93 --- /dev/null +++ b/rust/tests/boxing_todo_test/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "boxing_todo_test" +version = "0.1.0" +authors = ["lee "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +boxing_todo = { path = "../../../../rust-piscine-solutions/boxing_todo"} +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" diff --git a/rust/tests/boxing_todo_test/src/main.rs b/rust/tests/boxing_todo_test/src/main.rs new file mode 100644 index 000000000..394a074f2 --- /dev/null +++ b/rust/tests/boxing_todo_test/src/main.rs @@ -0,0 +1,99 @@ +use boxing_todo::*; + +// Note that you can create some todo list your self to test it, but you can find the JSON files that +// are being tested [here](https://github.com/01-edu/public/blob/master/subjects/boxing_todo) +fn main() { + let todos = TodoList::get_todo("todo.json"); + match todos { + Ok(list) => println!("{:?}", list), + Err(e) => { + println!("{}{:?}", e.description(), e.cause()); + } + } + + let todos = TodoList::get_todo("malforned_object.json"); + match todos { + Ok(list) => println!("{:?}", list), + Err(e) => { + println!("{}{:?}", e.description(), e.cause().unwrap()); + } + } + + let todos = TodoList::get_todo("permission_err.json"); + match todos { + Ok(list) => println!("{:?}", list), + Err(e) => { + println!("{}{:?}", e.description(), e.cause().unwrap()); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::fs::File; + use std::fs; + + fn new_todo(s: String, v: Vec) -> TodoList { + TodoList { title: s, tasks: v } + } + fn run(s: &TodoList, f: &str) -> Result> { + serde_json::to_writer(&File::create(f)?, s)?; + let result = TodoList::get_todo(f); + fs::remove_file(f)?; + return result; + } + + #[test] + fn test_good_todo() { + let file_name = "todo.json"; + let good_struct = new_todo( + String::from("todo list for something"), + vec![ + Task { id: 0, description: "do this".to_string(), level: 0 }, + Task { id: 1, description: "do that".to_string(), level: 5 }, + ], + ); + let result = run(&good_struct, file_name).unwrap(); + + assert_eq!(result.title, good_struct.title); + assert_eq!(&result.tasks, &good_struct.tasks); + } + + #[test] + fn test_empty_tasks() { + let file_name = "empty_tasks.json"; + let result = run(&new_todo(String::from("empty tasks"), vec![]), file_name).unwrap_err(); + + assert_eq!(result.to_string(), "Failed to parses todo"); + assert_eq!(result.description(), "Todo List parse failed: "); + assert!(!result.cause().is_some()); + } + #[test] + fn test_read() { + let result = TodoList::get_todo("no_file.json").unwrap_err(); + + assert_eq!(result.to_string(), "Failed to read todo file"); + assert_eq!(result.description(), "Todo List read failed: "); + } + + #[test] + #[should_panic(expected = "Malformed(Error(\"missing field `title`\", line: 1, column: 2))")] + fn test_malformed_json() { + #[derive(Serialize, Deserialize)] + struct Mal {}; + let file_name = "malformed.json"; + let malformed: Mal = serde_json::from_str(r#"{}"#).unwrap(); + serde_json::to_writer(&File::create(file_name).unwrap(), &malformed).unwrap(); + let result = TodoList::get_todo(file_name); + fs::remove_file(file_name).unwrap(); + + result.unwrap_or_else(|e| panic!("{:?}", e)); + } + + #[test] + #[should_panic(expected = "ReadErr { child_err: Os { code: 2, kind: NotFound, message: \"No such file or directory\" } }")] + fn test_read_error() { + TodoList::get_todo("no_file.json").unwrap_or_else(|e| panic!("{:?}", e)); + } +} diff --git a/rust/tests/cipher_test/Cargo.lock b/rust/tests/cipher_test/Cargo.lock new file mode 100644 index 000000000..fbb752c63 --- /dev/null +++ b/rust/tests/cipher_test/Cargo.lock @@ -0,0 +1,12 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "cipher" +version = "0.1.0" + +[[package]] +name = "cipher_test" +version = "0.1.0" +dependencies = [ + "cipher", +] diff --git a/rust/tests/cipher_test/Cargo.toml b/rust/tests/cipher_test/Cargo.toml new file mode 100644 index 000000000..3d3c9f422 --- /dev/null +++ b/rust/tests/cipher_test/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "cipher_test" +version = "0.1.0" +authors = ["lee "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +cipher = { path = "../../../../rust-piscine-solutions/cipher"} diff --git a/rust/tests/cipher_test/src/main.rs b/rust/tests/cipher_test/src/main.rs new file mode 100644 index 000000000..186fe157e --- /dev/null +++ b/rust/tests/cipher_test/src/main.rs @@ -0,0 +1,24 @@ +use cipher::*; + +fn main() { + println!("{:?}", cipher("1Hello 2world!", "1Svool 2dliow!")); + println!("{:?}", cipher("1Hello 2world!", "svool")); + println!("{:?}", cipher("", "svool")); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_cipher() { + assert_eq!(cipher("1Hello 2world!", "1Svool 2dliow!"), Some(Ok(true))); + assert_eq!(cipher("", "1Svool 2dliow!"), None); + assert_eq!(cipher("1Hello 2world!", ""), None); + assert_eq!(cipher("1Hello 2world!", "1svool 2dliow!"), Some(Err(CipherError { validation: false, expected: String::from("1Svool 2dliow!") }))); + assert_eq!(cipher("asdasd", "zhwzhw"), Some(Ok(true))); + assert_eq!(cipher("asdasd", "lkdas"), Some(Err(CipherError { validation: false, expected: String::from("zhwzhw") }))); + assert_eq!(cipher("3(/&%fsd 32das", "3(/&%uhw 32wzh"), Some(Ok(true))); + assert_eq!(cipher("3(/&%sd 32das", "3(/&%uhw 32wzh"), Some(Err(CipherError { validation: false, expected: String::from("3(/&%hw 32wzh") }))); + } +} \ No newline at end of file diff --git a/rust/tests/error_type_test/Cargo.lock b/rust/tests/error_type_test/Cargo.lock new file mode 100644 index 000000000..21a3eb4f7 --- /dev/null +++ b/rust/tests/error_type_test/Cargo.lock @@ -0,0 +1,98 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "time", + "winapi", +] + +[[package]] +name = "error_type" +version = "0.1.0" +dependencies = [ + "chrono", +] + +[[package]] +name = "error_type_test" +version = "0.1.0" +dependencies = [ + "error_type", +] + +[[package]] +name = "libc" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi", + "winapi", +] + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/rust/tests/error_type_test/Cargo.toml b/rust/tests/error_type_test/Cargo.toml new file mode 100644 index 000000000..dd5627fa3 --- /dev/null +++ b/rust/tests/error_type_test/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "error_type_test" +version = "0.1.0" +authors = ["lee "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +error_type = { path = "../../../../rust-piscine-solutions/error_type"} diff --git a/rust/tests/error_type_test/src/main.rs b/rust/tests/error_type_test/src/main.rs new file mode 100644 index 000000000..6685e5a22 --- /dev/null +++ b/rust/tests/error_type_test/src/main.rs @@ -0,0 +1,136 @@ +use error_type::*; + +#[allow(dead_code)] +fn create_date(date: &str) -> NaiveDate { + NaiveDate::parse_from_str(date, "%Y-%m-%d").unwrap() +} + +fn main() { + let mut form_output = Form::new( + String::from("Lee"), + String::from("Silva"), + create_date("2015-09-05"), + SexType::Male, + String::from("Africa"), + String::from("qwqwsa1dty_")); + + println!("{:?}", form_output); + println!("{:?}", form_output.validate().unwrap()); + + form_output.first_name = String::from(""); + println!("{:?}", form_output.validate().unwrap_err()); + + form_output.first_name = String::from("as"); + form_output.password = String::from("dty_1"); + println!("{:?}", form_output.validate().unwrap_err()); + + form_output.password = String::from("asdasASd(_"); + println!("{:?}", form_output.validate().unwrap_err()); + + form_output.password = String::from("asdasASd123SA"); + println!("{:?}", form_output.validate().unwrap_err()); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[derive(Debug)] + struct TestForm<'a> { + form: Form, + validation: Result, FErr> + } + + impl <'a> TestForm<'_> { + // all test cases + fn new() -> Vec> { + vec![ + TestForm { + form : Form::new( + String::from("Katy"), + String::from("Silva"), + create_date("2015-09-05"), + SexType::Female, + String::from("Africa"), + String::from("qwTw12&%$3sa1dty_")), + validation: Ok(vec!["Valid first name", "Valid password"]), + }, + TestForm { + form : Form::new( + String::from(""), + String::from("Bear"), + create_date("2015-09-05"), + SexType::Male, + String::from("Africa"), + String::from("qwTw12&%$3sa1dty_")), + validation: Err(FErr { + form_values: (String::from("first_name"), + String::from("")), + date: Utc::now().format("%Y-%m-%d %H:%M:%S").to_string(), + err: String::from("No user name")}), + }, + TestForm { + form : Form::new( + String::from("Someone"), + String::from("Bear"), + create_date("2015-09-05"), + SexType::Male, + String::from("Africa"), + String::from("12345")), + validation: Err(FErr { + form_values: (String::from("password"), String::from("12345")), + date: Utc::now().format("%Y-%m-%d %H:%M:%S").to_string(), + err: String::from("At least 8 characters") }), + }, + TestForm { + form : Form::new( + String::from("Someone"), + String::from("Bear"), + create_date("2015-09-05"), + SexType::Male, + String::from("Africa"), + String::from("sdASDsrW")), + validation: Err(FErr { + form_values: (String::from("password"), String::from("sdASDsrW")), + date: Utc::now().format("%Y-%m-%d %H:%M:%S").to_string(), + err: String::from("Combination of different ASCII character types (numbers, letters and none alphanumeric characters)") }), + }, + TestForm { + form : Form::new( + String::from("Someone"), + String::from("Bear"), + create_date("2015-09-05"), + SexType::Female, + String::from("Africa"), + String::from("dsGE1SAD213")), + validation: Err(FErr { + form_values: (String::from("password"), String::from("dsGE1SAD213")), + date: Utc::now().format("%Y-%m-%d %H:%M:%S").to_string(), + err: String::from("Combination of different ASCII character types (numbers, letters and none alphanumeric characters)") }), + }, + TestForm { + form : Form::new( + String::from("Someone"), + String::from("Bear"), + create_date("2015-09-05"), + SexType::Female, + String::from("Africa"), + String::from("dsaSD&%DF!?=")), + validation: Err(FErr { + form_values: (String::from("password"), String::from("dsaSD&%DF!?=")), + date: Utc::now().format("%Y-%m-%d %H:%M:%S").to_string(), + err: String::from("Combination of different ASCII character types (numbers, letters and none alphanumeric characters)") }), + } + ] + } + } + + #[test] + fn test_error_type() { + let form_cases = TestForm::new(); + + for v in form_cases { + assert_eq!(v.form.validate(), v.validation); + } + } +} \ No newline at end of file diff --git a/rust/tests/handling_test/Cargo.lock b/rust/tests/handling_test/Cargo.lock new file mode 100644 index 000000000..a780a192c --- /dev/null +++ b/rust/tests/handling_test/Cargo.lock @@ -0,0 +1,12 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "handling" +version = "0.1.0" + +[[package]] +name = "handling_test" +version = "0.1.0" +dependencies = [ + "handling", +] diff --git a/rust/tests/handling_test/Cargo.toml b/rust/tests/handling_test/Cargo.toml new file mode 100644 index 000000000..0e66dff73 --- /dev/null +++ b/rust/tests/handling_test/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "handling_test" +version = "0.1.0" +authors = ["lee "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +handling = { path = "../../../../rust-piscine-solutions/handling"} diff --git a/rust/tests/handling_test/a.txt b/rust/tests/handling_test/a.txt new file mode 100644 index 000000000..7dde7fadf --- /dev/null +++ b/rust/tests/handling_test/a.txt @@ -0,0 +1 @@ +content to be written \ No newline at end of file diff --git a/rust/tests/handling_test/src/main.rs b/rust/tests/handling_test/src/main.rs new file mode 100644 index 000000000..e8c66fecd --- /dev/null +++ b/rust/tests/handling_test/src/main.rs @@ -0,0 +1,63 @@ +use std::fs::{File, OpenOptions}; +use std::io::prelude::*; +use std::io::{ErrorKind, Write}; +use handling::*; + +fn main() { + let path = "a.txt"; + File::create(path).unwrap(); + open_or_create(path, "content to be written"); + + let mut file = File::open(path).unwrap(); + + let mut s = String::new(); + file.read_to_string(&mut s).unwrap(); + println!("{}", s); + // output: content to be written +} + +#[cfg(test)] +mod tests { + use super::*; + use std::fs; + use std::panic; + + fn get_file_content(filename: &str) -> String { + let mut file = File::open(filename).unwrap(); + let mut s = String::new(); + file.read_to_string(&mut s).unwrap(); + fs::remove_file(filename).unwrap(); + return s; + } + + #[test] + fn test_if_file_exists() { + let filename = "test_existing_file.txt"; + let content = "hello world!"; + File::create(filename).unwrap(); + open_or_create(filename, content); + + assert_eq!(content, get_file_content(filename)); + } + + #[test] + fn test_create_file() { + let file = "no_existing_file.txt"; + let content = "hello world!"; + open_or_create(file, content); + + assert_eq!(content, get_file_content(file)); + } + #[test] + fn test_error_case() { + let filename = "hello.txt"; + File::create(filename).unwrap(); + let mut perms = fs::metadata(filename).unwrap().permissions(); + perms.set_readonly(true); + fs::set_permissions(filename, perms).unwrap(); + + let result = panic::catch_unwind(|| open_or_create(filename, "test")); + fs::remove_file(filename).unwrap(); + assert!(result.is_err()); + } +} diff --git a/rust/tests/panic_test/Cargo.lock b/rust/tests/panic_test/Cargo.lock new file mode 100644 index 000000000..48ea81737 --- /dev/null +++ b/rust/tests/panic_test/Cargo.lock @@ -0,0 +1,12 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "panic" +version = "0.1.0" + +[[package]] +name = "panic_test" +version = "0.1.0" +dependencies = [ + "panic", +] diff --git a/rust/tests/panic_test/Cargo.toml b/rust/tests/panic_test/Cargo.toml new file mode 100644 index 000000000..46274a8d6 --- /dev/null +++ b/rust/tests/panic_test/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "panic_test" +version = "0.1.0" +authors = ["lee "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +panic = { path = "../../../../rust-piscine-solutions/panic"} \ No newline at end of file diff --git a/rust/tests/panic_test/src/main.rs b/rust/tests/panic_test/src/main.rs new file mode 100644 index 000000000..966203251 --- /dev/null +++ b/rust/tests/panic_test/src/main.rs @@ -0,0 +1,29 @@ +use panic::*; +use std::fs::{self, File}; + +fn main() { + let filename = "created.txt"; + File::create(filename).unwrap(); + let a = open_file(filename); + println!("{:?}", a); + fs::remove_file(filename).unwrap(); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[should_panic] + fn test_opening() { + open_file("file.txt"); + } + + #[test] + fn test_opening_existing() { + let filename = "created.txt"; + File::create(filename).unwrap(); + open_file(filename); + fs::remove_file(filename).unwrap(); + } +} diff --git a/rust/tests/profanity_filter_test/Cargo.lock b/rust/tests/profanity_filter_test/Cargo.lock new file mode 100644 index 000000000..f4fb40ac4 --- /dev/null +++ b/rust/tests/profanity_filter_test/Cargo.lock @@ -0,0 +1,99 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "time", + "winapi", +] + +[[package]] +name = "libc" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "profanity_filter" +version = "0.1.0" +dependencies = [ + "chrono", +] + +[[package]] +name = "profanity_filter_test" +version = "0.1.0" +dependencies = [ + "chrono", + "profanity_filter", +] + +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi", + "winapi", +] + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/rust/tests/profanity_filter_test/Cargo.toml b/rust/tests/profanity_filter_test/Cargo.toml new file mode 100644 index 000000000..955cc920b --- /dev/null +++ b/rust/tests/profanity_filter_test/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "profanity_filter_test" +version = "0.1.0" +authors = ["lee "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +profanity_filter = { path = "../../../../rust-piscine-solutions/profanity_filter"} +chrono = "0.4.19" diff --git a/rust/tests/profanity_filter_test/src/main.rs b/rust/tests/profanity_filter_test/src/main.rs new file mode 100644 index 000000000..7a10ca749 --- /dev/null +++ b/rust/tests/profanity_filter_test/src/main.rs @@ -0,0 +1,77 @@ +use profanity_filter::*; + +fn main() { + let m0 = Message::new("hello there".to_string(), "toby".to_string(), format_date()); + println!("{:?}", check_ms(&m0)); + // output: (true, "hello there") + + let m1 = Message::new("".to_string(), "toby".to_string(), format_date()); + println!("{:?}", check_ms(&m1)); + // output: (false, "ERROR: illegal") + + let m2 = Message::new("you are stupid".to_string(), "toby".to_string(), format_date()); + println!("{:?}", check_ms(&m2)); + // output: (false, "ERROR: illegal") + + let m3 = Message::new("stupid".to_string(), "toby".to_string(), format_date()); + println!("{:?}", check_ms(&m3)); + // output: (false, "ERROR: illegal") +} + +#[cfg(test)] +mod tests { + use super::*; + use chrono::prelude::Utc; + + fn test_format() -> String { + Utc::now().format("%a %b %e %T %Y").to_string() + } + + #[test] + fn test_time_format() { + assert_eq!(format_date(), test_format()); + } + + #[test] + fn test_error_ms() { + let v = vec![ + Message::new("".to_string(), "toby".to_string(), format_date()), + Message::new("stupid".to_string(), "jack".to_string(), format_date()), + Message::new( + "you are stupid".to_string(), + "jacob".to_string(), + format_date(), + ), + ]; + for value in v { + let (t, _) = check_ms(&value); + assert!(!t); + } + } + + #[test] + fn test_ok_ms() { + let v = vec![ + Message::new( + "get out of the car".to_string(), + "police".to_string(), + format_date(), + ), + Message::new("no!".to_string(), "thief".to_string(), format_date()), + Message::new( + "get the werewolf".to_string(), + "police".to_string(), + format_date(), + ), + Message::new( + "wait the wha...".to_string(), + "thief".to_string(), + format_date(), + ), + ]; + for value in v { + let (t, _) = check_ms(&value); + assert!(t); + } + } +} diff --git a/rust/tests/question_mark_test/Cargo.lock b/rust/tests/question_mark_test/Cargo.lock new file mode 100644 index 000000000..1fbf15c08 --- /dev/null +++ b/rust/tests/question_mark_test/Cargo.lock @@ -0,0 +1,12 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "question_mark" +version = "0.1.0" + +[[package]] +name = "question_mark_test" +version = "0.1.0" +dependencies = [ + "question_mark", +] diff --git a/rust/tests/question_mark_test/Cargo.toml b/rust/tests/question_mark_test/Cargo.toml new file mode 100644 index 000000000..d970a5261 --- /dev/null +++ b/rust/tests/question_mark_test/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "question_mark_test" +version = "0.1.0" +authors = ["lee "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +question_mark = { path = "../../../../rust-piscine-solutions/question_mark"} diff --git a/rust/tests/question_mark_test/src/main.rs b/rust/tests/question_mark_test/src/main.rs new file mode 100644 index 000000000..c2398e29e --- /dev/null +++ b/rust/tests/question_mark_test/src/main.rs @@ -0,0 +1,47 @@ +use question_mark::*; + +fn main() { + let a = One { + first_layer : Some(Two { + second_layer: Some(Three { + third_layer: Some(Four { + fourth_layer: Some(1000) + }) + }) + }) + }; + + // output: 1000 + println!("{:?}", match a.get_fourth_layer() { + Some(e) => e, + None => 0 + }) +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_value() { + let a = One { + first_layer : Some(Two { + second_layer: Some(Three { + third_layer: Some(Four { + fourth_layer: Some(1000) + }) + }) + }) + }; + let b = One { + first_layer : Some(Two { + second_layer: Some(Three { + third_layer: Some(Four { + fourth_layer: Some(3) + }) + }) + }) + }; + assert_eq!(a.get_fourth_layer(), Some(1000)); + assert_eq!(b.get_fourth_layer(), Some(3)); + } +} diff --git a/rust/tests/unwrap_and_expect_test/Cargo.lock b/rust/tests/unwrap_and_expect_test/Cargo.lock new file mode 100644 index 000000000..a263be698 --- /dev/null +++ b/rust/tests/unwrap_and_expect_test/Cargo.lock @@ -0,0 +1,12 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "unwrap_and_expect" +version = "0.1.0" + +[[package]] +name = "unwrap_and_expect_test" +version = "0.1.0" +dependencies = [ + "unwrap_and_expect", +] diff --git a/rust/tests/unwrap_and_expect_test/Cargo.toml b/rust/tests/unwrap_and_expect_test/Cargo.toml new file mode 100644 index 000000000..05c2b114e --- /dev/null +++ b/rust/tests/unwrap_and_expect_test/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "unwrap_and_expect_test" +version = "0.1.0" +authors = ["lee "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +unwrap_and_expect = { path = "../../../../rust-piscine-solutions/unwrap_and_expect"} diff --git a/rust/tests/unwrap_and_expect_test/src/main.rs b/rust/tests/unwrap_and_expect_test/src/main.rs new file mode 100644 index 000000000..894679a3e --- /dev/null +++ b/rust/tests/unwrap_and_expect_test/src/main.rs @@ -0,0 +1,49 @@ +use unwrap_and_expect::*; + +fn main() { + println!("{:?}", unwrap_or(vec![1, 3, 2, 5])); + println!("{:?}", unwrap_or(vec![1, 3, 5])); + println!("{:?}", unwrap_err(vec![1, 3, 2, 5])); + println!("{:?}", unwrap(vec![1, 3, 5])); + println!("{:?}", unwrap_or_else(vec![1, 3, 5])); + println!("{:?}", unwrap_or_else(vec![3, 2, 6, 5])); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[should_panic(expected = "ERROR : (\"There is a even value in the vector!\", [2])")] + fn test_expect() { + expect(vec![1, 3, 2, 5]); + } + #[test] + #[should_panic(expected = "called `Result::unwrap()` on an `Err` value: (\"There is a even value in the vector!\", [2])")] + fn test_unwrap() { + unwrap(vec![1, 3, 2, 5]); + } + #[test] + #[should_panic] + fn test_unwrap_err() { + unwrap_err(vec![1, 3, 5]); + } + #[test] + fn test_unwrap_or() { + assert_eq!(unwrap_or(vec![1, 3, 2, 5]), vec![]); + } + #[test] + fn test_unwrap_or_else() { + assert_eq!(unwrap_or_else(vec![1, 3, 5]), vec![2, 4, 6]); + assert_eq!(unwrap_or_else(vec![6, 8, 3, 2, 5, 4]), vec![6, 8, 2, 4]); + } + #[test] + fn test_ok() { + assert_eq!(expect(vec![1, 3, 5]), vec![2, 4, 6]); + assert_eq!(unwrap_or(vec![1, 3, 5]), vec![2, 4, 6]); + assert_eq!(unwrap_or_else(vec![1, 3, 5]), vec![2, 4, 6]); + assert_eq!(unwrap(vec![1, 3, 5]), vec![2, 4, 6]); + assert_eq!(unwrap_err(vec![1, 2, 3, 4, 5]).0, "There is a even value in the vector!"); + assert_eq!(unwrap_err(vec![1, 2, 3, 4, 5]).1, vec![2, 4]); + } +} diff --git a/subjects/banner/README.md b/subjects/banner/README.md new file mode 100644 index 000000000..0f7fc5e29 --- /dev/null +++ b/subjects/banner/README.md @@ -0,0 +1,110 @@ +## banner + +### Instructions + +`Result` is a better version of the `Option` type that describes possible error instead +of possible absence + +Create a structure called `Flag` that as the following elements: + +- short_hand: String +- long_hand: String +- desc: String + +This structure must have associated to it a function called `opt_flag` that initializes the structure. +Receiving two references strings and returns the structure `Flag`. It should be used like this: + +```rust + let d = Flag::opt_flag("diff", "gives the difference between two numbers"); + + println!("short hand: {}, long hand: {}, description: {}", d.short_hand, d.long_hand, d.desc); + // output: "short hand: -d, long hand: --diff, description: gives the difference between two numbers" +``` + +It will be given a second structure called `FlagsHandler` that has just one element: `flags: HashMap<(String, String), Callback>` +And the following functions associated to it, for you to complete : + +- `add_flag`, that adds to the HashMap the flag and the Callback function. +- `exec_func`, that executes the function using the flag provided and returns the result, that can + be either a string with the value from the callback or an error. + +It will also be provided a `type` called `Callback` being a function that is going to be used in the structure +and functions above. This function will be the callback for the flag associated to it. + +You will have to create the following callback functions : + +- `div`, that converts the reference strings to `float`s and returns the `Result`, being the division of the `float`s or the standard (std) error: `ParseFloatError`. +- `rem`, that converts the reference strings to `float`s and returns the `Result`, being the remainder of the division of the `float`s or the standard (std) error `ParseFloatError`. + +### Expected Function + +```rust +use std::collections::HashMap; + +pub type Callback = fn(&str, &str) -> Result; + +pub struct FlagsHandler { + pub flags: HashMap<(String, String), Callback>, +} + +impl FlagsHandler { + pub fn add_flag(&mut self, flag: (String, String), func: Callback) {} + pub fn exec_func(&mut self, flag: (String, String), argv: &[&str]) -> String {} + } +} + +pub struct Flag { + // expected public fields +} + +impl Flag { + pub fn opt_flag(l_h: &str, d: &str) -> Flag {} +} + +pub fn div(a: &str, b: &str) -> Result {} +pub fn rem(a: &str, b: &str) -> Result {} + +``` + +### Usage + +Here is a program to test your function + +```rust +fn main() { + let mut handler = FlagsHandler { flags: HashMap::new() }; + + let d = Flag::opt_flag("division", "divides the values, formula (a / b)"); + let r = Flag::opt_flag( + "remainder", + "remainder of the division between two values, formula (a % b)", + ); + + handler.add_flag((d.short_hand, d.long_hand), div); + handler.add_flag((r.short_hand, r.long_hand), rem); + + println!("{:?}", handler.exec_func(("-d".to_string(), "--division".to_string()), &["1.0", "2.0"])); + + println!("{:?}",handler.exec_func(("-r".to_string(), "--remainder".to_string()), &["2.0", "2.0"])); + + println!("{:?}",handler.exec_func(("-d".to_string(), "--division".to_string()), &["a", "2.0"])); + + println!("{:?}",handler.exec_func(("-r".to_string(), "--remainder".to_string()), &["2.0", "fd"])); +} +``` + +And its output: + +```console +student@ubuntu:~/[[ROOT]]/test$ cargo run +"0.5" +"0" +"invalid float literal" +"invalid float literal" +student@ubuntu:~/[[ROOT]]/test$ +``` + +### Notions + +- https://doc.rust-lang.org/rust-by-example/error/result.html +- https://docs.rs/getopts/0.2.18/getopts/struct.Options.html#method.optflag diff --git a/subjects/boxing_todo/README.md b/subjects/boxing_todo/README.md new file mode 100644 index 000000000..a1ffdc8b9 --- /dev/null +++ b/subjects/boxing_todo/README.md @@ -0,0 +1,165 @@ +## boxing_todo + +### Instructions + +The objective is to do an api to parse a list of *todos* that is organized in a JSON file, +handling all possible errors in a multiple error system. + +Organization of the JSON file: + +```json +{ + "title" : "TODO LIST FOR PISCINE RUST", + "tasks": [ + { "id": 0, "description": "do this", "level": 0 }, + { "id": 1, "description": "do that", "level": 5 } + ] +} +``` + +Create a module in another file called **error.rs** that handles the boxing of errors. +This module must implement an `enum` called `ParseErr` that will take care of the +parsing errors, it must have the following elements: + +- Empty +- Malformed, that has a dynamic boxed error as element + +A structure called `ReadErr` that will take care of the reading errors, having just an element called `child_err` of type `Box`. + +For each data structure you will have to implement a function called `fmt` for the trait `Display` that writes +out the message **"Fail to parse todo"** in case it's a parsing error, otherwise it writes the message +**"Failed to read todo file"**. +And for the `Error` trait the following functions: + +- `description` that returns a string literal that says: + - "Todo List parse failed: " for the `ParseErr` + - "Todo List read failed: " for the `ReadErr`. + +- `cause` that returns an `Option` with the error: + - For the `ReadErr` it must just return the option with the error + - For the `ParseErr` it will return an option that can be `None` if the tasks are **empty** otherwise the error, if + the parsing is **malformed**. + +In the **lib** file you will have to implement a function called `get_todo` that receives a string and returns a Result +that can be the structure `TodoList` or a boxing error. This function must be able to deserialize the json file, +basically it must parse and read the JSON file and return the `TodoList` if everything is fine otherwise the error. + +### Expected Function + +For **error.rs** + +```rust +use std::fmt; +use std::fmt::Display; +use std::error::Error; + +pub enum ParseErr { + // expected public fields +} + +// required by error trait +impl Display for ParseErr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + } +} + +pub struct ReadErr { + // expected public fields +} + +// required by error trait +impl Display for ReadErr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + } +} + +impl Error for ReadErr { + fn description(&self) -> &str {} + fn cause(&self) -> Option<&dyn Error> {} +} + +impl Error for ParseErr { + fn description(&self) -> &str {} + fn cause(&self) -> Option<&dyn Error> {} +} + +``` + +for **lib.rs** + +```rust +mod error; +use error::{ ParseErr, ReadErr }; +use std::error::Error; +use serde::{ Deserialize, Serialize }; + +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] +pub struct Task { + id: u32, + description: String, + level: u32, +} + +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] +pub struct TodoList { + title: String, + tasks: Vec, +} + +impl TodoList { + pub fn get_todo(path: &str) -> Result> {} +} +``` + +### Usage + +Here is a program to test your function. +Note that you can create some todo list your self to test it, but you can find the JSON files that +are being tested [here](https://github.com/01-edu/public/blob/master/subjects/boxing_todo) + +```rust +mod lib; +use lib::{ TodoList }; + +fn main() { + let todos = TodoList::get_todo("todo.json"); + match todos { + Ok(list) => println!("{:?}", list), + Err(e) => { + println!("{}{:?}", e.description(), e.cause()); + } + } + + let todos = TodoList::get_todo("no_todo_list.json"); + match todos { + Ok(list) => println!("{:?}", list), + Err(e) => { + println!("{}{:?}", e.description(), e.cause()); + } + } + + let todos = TodoList::get_todo("malformed_object.json"); + match todos { + Ok(list) => println!("{:?}", list), + Err(e) => { + println!("{}{:?}", e.description(), e.cause().unwrap()); + } + } +} +``` + +And its output: + +```console +student@ubuntu:~/[[ROOT]]/test$ cargo run +TodoList { title: "TODO LIST FOR PISCINE RUST", tasks: [Task { id: 0, description: "do this", level: 0 }, Task { id: 1, description: "do that", level: 5 }] } +Todo List parse failed: None +Todo List parse failed: Malformed(Error("missing field `title`", line: 1, column: 2)) +student@ubuntu:~/[[ROOT]]/test$ +``` + +### Notions + +- https://serde.rs/ +- https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/boxing_errors.html +- https://doc.rust-lang.org/stable/rust-by-example/trait/dyn.html diff --git a/subjects/boxing_todo/malformed_object.json b/subjects/boxing_todo/malformed_object.json new file mode 100644 index 000000000..9e26dfeeb --- /dev/null +++ b/subjects/boxing_todo/malformed_object.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/subjects/boxing_todo/todo.json b/subjects/boxing_todo/todo.json new file mode 100644 index 000000000..2341ac78b --- /dev/null +++ b/subjects/boxing_todo/todo.json @@ -0,0 +1,7 @@ +{ + "title" : "TODO LIST FOR PISCINE RUST", + "tasks": [ + { "id": 0, "description": "do this", "level": 0 }, + { "id": 1, "description": "do that", "level": 5 } + ] +} \ No newline at end of file diff --git a/subjects/boxing_todo/todo_empty.json b/subjects/boxing_todo/todo_empty.json new file mode 100644 index 000000000..9dfc54f58 --- /dev/null +++ b/subjects/boxing_todo/todo_empty.json @@ -0,0 +1,4 @@ +{ + "title" : "TODO LIST FOR PISCINE RUST", + "tasks": [] +} \ No newline at end of file diff --git a/subjects/cipher/README.md b/subjects/cipher/README.md new file mode 100644 index 000000000..e6454b0c2 --- /dev/null +++ b/subjects/cipher/README.md @@ -0,0 +1,47 @@ +## cipher + +### Instructions + +The Atbash cipher is a encryption method in which each letter of a word is replaced with its mirror letter in the alphabet + +Your objective is to create a function called `cipher` this must return a Result wrapped in an Option, this result should return either a boolean +or an Error being the structure `CipherError`. This structure should be the error type for the function `cipher` + +This function should compare the original string wih the ciphered string. returning true if the cipher is correct otherwise the error type +CipherErr with the a true or false if it is validated and the proper atbash cipher. + +### Expected Function + +```rust + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct CipherError { + // expected public fields +} +impl CipherError { + pub fn new(validation: bool, expected: String) -> CipherError {} +} +pub fn cipher(original: &str, ciphered: &str) -> Option> {} +``` + +### Usage + +Here is a program to test your function + +```rust +fn main() { + println!("{:?}", cipher("1Hello 2world!", "1Svool 2dliow!")); + println!("{:?}", cipher("1Hello 2world!", "svool")); + println!("{:?}", cipher("", "svool")); +} +``` + +And its output: + +```console +student@ubuntu:~/[[ROOT]]/test$ cargo run +Some(Ok(true)) +Some(Err(CipherError { validation: false, expected: "1Svool 2dliow!" })) +None +student@ubuntu:~/[[ROOT]]/test$ +``` diff --git a/subjects/error_type/README.md b/subjects/error_type/README.md new file mode 100644 index 000000000..1c86b25f0 --- /dev/null +++ b/subjects/error_type/README.md @@ -0,0 +1,124 @@ +## error types + +### Instructions + +For this exercise you will have to implement an **error type**. + +The main objective is to create a form validator, where you must implement a +error type. This must validate the password and the first name. The +first name must not be empty and the password must have at least 8 char and a combination of alphanumeric and none alphanumeric ASCII characters + +ex: "asDd123=%" => good + "asgfD" => error + "asdsdf2" => error + "sad_#$" => error + +Create a structure called `Form` that will have the following fields: + +- `first_name`, that will be a string +- `last_name`, that will be a string +- `birth`, of type `NaiveDate` that will convert a string "2015-09-05" to a date of that format +- `sex`, SexType that must be a `enum` with the fields `Male` and `Female` +- `birth_location`, that will be a string +- `password`, that will be a string + +You must also implement for this structure a function to initialize the structure, `new` and a function called +`validate` that will validate the form + +For the error type you must create a type struct called `FErr`, that will be the type for the error +It must have the fields: + +- `form_values`, this will be a tuple of strings that will save the value that the user inserted into the form + +ex: ("password", "asdaSD_") + ("first_name", "someone") + +- `date`, that will have the date that the error occurred in the format "2020-12-14 09:33:41" +- `err`, that will have the error description: + - "No user name" + - "At least 8 characters" + - "Combination of different ASCII character types (numbers, letters and none alphanumeric characters)" + +### Expected Function + +```rust +pub use chrono::{Utc, NaiveDate}; + +// this will be the structure that wil handle the errors +#[derive(Debug, Eq, PartialEq)] +pub struct FErr { + // expected public fields +} +impl FErr { + pub fn new(name: String, error: String, err: String) -> FErr {} +} + +#[derive(Debug, Eq, PartialEq)] +pub enum SexType { + // expected public fields +} +#[derive(Debug, Eq, PartialEq)] +pub struct Form { + // expected public fields +} + +impl Form { + pub fn new(first_name: String, + last_name: String, + birth: NaiveDate, + sex: SexType, + birth_location: String, + password: String) -> Form {} + pub fn validate(&self) -> Result, FErr> {} +} +``` + +### Usage + +Here is a program to test your function + +```rust +fn main() { + let mut form_output = Form::new( + String::from("Alice"), + String::from("Bear"), + create_date("2015-09-05"), + SexType::Male, + String::from("Africa"), + String::from("qwqwsa1dty_")); + + println!("{:?}", form_output); + println!("{:?}", form_output.validate().unwrap()); + + form_output.first_name = String::from(""); + println!("{:?}", form_output.validate().unwrap_err()); + + form_output.first_name = String::from("as"); + form_output.password = String::from("dty_1"); + println!("{:?}", form_output.validate().unwrap_err()); + + form_output.password = String::from("asdasASd(_"); + println!("{:?}", form_output.validate().unwrap_err()); + + form_output.password = String::from("asdasASd123SA"); + println!("{:?}", form_output.validate().unwrap_err()); +} +``` + +And its output: + +```console +student@ubuntu:~/[[ROOT]]/test$ cargo run +Form { first_name: "Lee", last_name: "Silva", birth: 2015-09-05, sex: Male, birth_location: "Africa", password: "qwqwsa1dty_" } +["Valid first name", "Valid password"] +FErr { form_values: ("first_name", ""), date: "2020-12-28 13:29:11", err: "No user name" } +FErr { form_values: ("password", "dty_1"), date: "2020-12-28 13:29:11", err: "At least 8 characters" } +FErr { form_values: ("password", "asdasASd(_"), date: "2020-12-28 13:29:11", err: "Combination of different ASCII character types (numbers, letters and none alphanumeric characters)" } +FErr { form_values: ("password", "asdasASd123SA"), date: "2020-12-28 13:29:11", err: "Combination of different ASCII character types (numbers, letters and none alphanumeric characters)" } +student@ubuntu:~/[[ROOT]]/test$ +``` + +### Notions + +- https://doc.rust-lang.org/rust-by-example/error/multiple_error_types/define_error_type.html +- https://docs.rs/chrono/0.4.19/chrono/naive/struct.NaiveDate.html diff --git a/subjects/handling/README.md b/subjects/handling/README.md new file mode 100644 index 000000000..9e13f6962 --- /dev/null +++ b/subjects/handling/README.md @@ -0,0 +1,48 @@ +## handling + +### Instructions + +Write a function, called `open_or_create` that as two arguments: + +- `file : &str` which is the name of the files +- `content: &str` being the content to be written into the file + +This functions should try to open a file, if it does not exist creates it. +You should panic, with the error, in case something goes wrong. + +### Expected Function + +```rust +pub fn open_or_create(s: &str, content: &str) {} +``` + +### Usage + +Here is a program to test your function + +```rust +fn main() { + let path = "a.txt"; + File::create(path).unwrap(); + open_or_create(path, "content to be written"); + + let mut file = File::open(path).unwrap(); + + let mut s = String::new(); + file.read_to_string(&mut s).unwrap(); + println!("{}", s); +} +``` + +And its output: + +```console +student@ubuntu:~/[[ROOT]]/test$ cargo run +content to be written +student@ubuntu:~/[[ROOT]]/test$ +``` + +### Notions + +- https://doc.rust-lang.org/std/io/enum.ErrorKind.html +- https://doc.rust-lang.org/std/fs/struct.File.html diff --git a/subjects/panic/README.md b/subjects/panic/README.md new file mode 100644 index 000000000..cb24962c1 --- /dev/null +++ b/subjects/panic/README.md @@ -0,0 +1,34 @@ +## panic + +### Instructions + +Write a function that tries to open a file and panics if the file +doesn't exist + +### Expected Function + +```rust +pub fn open_file(s: &str) -> File {} +``` + +### Usage + +Here is a program to test your function + +```rust +fn main() { + let filename = "created.txt"; + File::create(filename).unwrap(); + let a = open_file(filename); + println!("{:?}", a); + fs::remove_file(filename).unwrap(); +} +``` + +And its output: + +```console +student@ubuntu:~/[[ROOT]]/test$ cargo run +File { fd: 3, path: "[[ROOT]]/a.txt", read: true, write: false } +student@ubuntu:~/[[ROOT]]/test$ +``` diff --git a/subjects/profanity_filter/README.md b/subjects/profanity_filter/README.md new file mode 100644 index 000000000..fd96b59d1 --- /dev/null +++ b/subjects/profanity_filter/README.md @@ -0,0 +1,81 @@ +## profanity filter + +### Instructions + +Sometimes it is more desirable to catch the failure of some parts of a program instead +of just calling panic. + +For this exercise you will have to create a message blocker, where you must block the word `stupid` + +You will have to create a structure called `Message`, this structure +must have the following elements: + +- content: String +- user: String +- time_sent: String + +The struct must also have a implementation of 2 functions associated to it: + +- `new`, that initializes the structure +- `send_ms`, that only has its implementation type (**self**) as argument and returns an option. + This function must return `None` if the content of the message is either **empty** or contains the + word **stupid**. Otherwise it returns the content of the message. + +You will have to create two more functions that aren't associated to any structure: + +- `check_ms` that receives as parameters the reference to the structure `Message` and returns a tuple, +containing a `bool` and a `string`. This function will execute the function `send_ms` and if the result +of the option is `None` it should return (false, "ERROR: illegal"). Otherwise it returns `true` and the +content of the message sent. +- `date_format` that creates and formats the date and time that the message was sent, the format should +look like this: **Mon Oct 5 10:22:19 2020** + +### Expected Function + +```rust +pub struct Message {} + +impl Message { + pub fn new(ms: String, u: String, t: String) -> Message {} + pub fn send_ms(&self) -> Option<&str> {} +} + +pub fn check_ms(ms: &Message) -> (bool, &str) {} +pub fn format_date() -> String {} +``` + +### Usage + +Here is a program to test your function + +```rust +fn main() { + let m0 = Message::new("hello there".to_string(), "toby".to_string(), format_date()); + println!("{:?}", check_ms(&m0)); + + let m1 = Message::new("".to_string(), "toby".to_string(), format_date()); + println!("{:?}", check_ms(&m1)); + + let m2 = Message::new("you are stupid".to_string(), "toby".to_string(), format_date()); + println!("{:?}", check_ms(&m2)); + + let m3 = Message::new("stupid".to_string(), "toby".to_string(), format_date()); + println!("{:?}", check_ms(&m3)); +} +``` + +And its output: + +```console +student@ubuntu:~/[[ROOT]]/test$ cargo run +(true, "hello there") +(false, "ERROR: illegal") +(false, "ERROR: illegal") +(false, "ERROR: illegal") +student@ubuntu:~/[[ROOT]]/test$ +``` + +### Notions + +- https://docs.rs/chrono/0.4.19/chrono/ +- https://doc.rust-lang.org/stable/book/ch06-01-defining-an-enum.html?highlight=option#the-option-enum-and-its-advantages-over-null-values diff --git a/subjects/question_mark/README.md b/subjects/question_mark/README.md new file mode 100644 index 000000000..8839639a2 --- /dev/null +++ b/subjects/question_mark/README.md @@ -0,0 +1,70 @@ +## question_mark + +### Instructions + +You will have to create 3 structures: + +- `One`, that contains one element called `first_layer` it should be an `Option` for the structure `Two`. +- `Two`, that contains one element called `second_layer` it should be an `Option` for the structure `Three`. +- `Three`, that contains one element called `third_layer` it should be an `Option` for the structure `Four`. +- `Four`, that contains one element called `fourth_layer` it should be an `u16` that is an `Option`. + +Beside the structure you must create a function named `get_fourth_layer` that is associated to the `One` structure. +This function should return the `Option` value in the `Four` structure. + +### Expected Function + +```rust +pub struct One { + // expected public fields +} +pub struct Two { + // expected public fields +} +pub struct Three { + // expected public fields +} +pub struct Four { + // expected public fields +} + +impl One { + pub fn get_fourth_layer(&self) -> Option {} +} +``` + +### Usage + +Here is a program to test your function + +```rust +fn main() { + let a = One { + first_layer : Some(Two { + second_layer: Some(Three { + third_layer: Some(Four { + fourth_layer: Some(1000) + }) + }) + }) + }; + + // output: 1000 + println!("{:?}", match a.get_fourth_layer() { + Some(e) => e, + None => 0 + }) +} +``` + +And its output: + +```console +student@ubuntu:~/[[ROOT]]/test$ cargo run +1000 +student@ubuntu:~/[[ROOT]]/test$ +``` + +### Notions + +- https://doc.rust-lang.org/stable/rust-by-example/error/option_unwrap/question_mark.html diff --git a/subjects/unwrap_or_expect/README.md b/subjects/unwrap_or_expect/README.md new file mode 100644 index 000000000..249a3caa3 --- /dev/null +++ b/subjects/unwrap_or_expect/README.md @@ -0,0 +1,66 @@ +## unwrap + +### Instructions + +It will be given a function called **odd_to_even**, that returns an `Result`. If its an error it will +return a tuple with a string, indicating the error, and a vector with the elements that justifies the error + +The objective is to execute the `odd_to_even` function and handle the error given by it + +Create the following functions that receives a vector : + +- `expect` that returns the error adding the sting "ERROR " +- `unwrap_or` that in case of error returns an empty vector +- `unwrap_err` that returns error if its `Ok` and returns the + string containing the error in case of `Err` +- `unwrap` that unwraps the `Result` +- `unwrap_or_else` that in case of error returns a the vector that justifies the error + +### Expected Function + +```rust +pub fn odd_to_even(data: Vec) -> Result, (String, Vec)> {} +pub fn expect(v: Vec) -> Vec {} +pub fn unwrap_or(v: Vec) -> Vec {} +pub fn unwrap_err(v: Vec) -> (String, Vec) {} +pub fn unwrap(v: Vec) -> Vec {} +pub fn unwrap_or_else(v: Vec) -> Vec {} +``` + +### Usage + +Here is a program to test your function + +```rust +fn main() { + // this will give an expect error + // println!("{:?}", expect(vec![1, 3, 2, 5])); + println!("{:?}", unwrap_or(vec![1, 3, 2, 5])); + println!("{:?}", unwrap_or(vec![1, 3, 5])); + println!("{:?}", unwrap_err(vec![1, 3, 2, 5])); + // this will give an error that is unwraped + // println!("{:?}", unwrap_err(vec![1, 3, 5])); + println!("{:?}", unwrap(vec![1, 3, 5])); + // this will give an error + // println!("{:?}", unwrap(vec![1, 3, 2, 5])); + println!("{:?}", unwrap_or_else(vec![1, 3, 5])); + println!("{:?}", unwrap_or_else(vec![3, 2, 6, 5])); +} +``` + +And its output: + +```console +student@ubuntu:~/[[ROOT]]/test$ cargo run +[] +[2, 4, 6] +("There is a even value in the vector!", [2]) +[2, 4, 6] +[2, 4, 6] +[2, 6] +student@ubuntu:~/[[ROOT]]/test$ +``` + +### Notions + +- https://doc.rust-lang.org/std/?search=unwrap From 6bd54ffb5c0211609eb591a8f0a9802325586045 Mon Sep 17 00:00:00 2001 From: lee Date: Mon, 28 Dec 2020 17:11:42 +0000 Subject: [PATCH 2/3] quest 08: tests and subject --- rust/tests/borrow_box_test/Cargo.lock | 12 ++ rust/tests/borrow_box_test/Cargo.toml | 10 ++ rust/tests/borrow_box_test/src/main.rs | 91 ++++++++++ rust/tests/box_it_test/Cargo.lock | 12 ++ rust/tests/box_it_test/Cargo.toml | 10 ++ rust/tests/box_it_test/src/main.rs | 56 +++++++ rust/tests/box_recursion_test/Cargo.lock | 12 ++ rust/tests/box_recursion_test/Cargo.toml | 10 ++ rust/tests/box_recursion_test/src/main.rs | 98 +++++++++++ rust/tests/drop_the_thread_test/Cargo.lock | 12 ++ rust/tests/drop_the_thread_test/Cargo.toml | 10 ++ rust/tests/drop_the_thread_test/src/main.rs | 87 ++++++++++ .../tests/how_many_references_test/Cargo.lock | 12 ++ .../tests/how_many_references_test/Cargo.toml | 10 ++ .../how_many_references_test/src/main.rs | 103 ++++++++++++ rust/tests/ref_cell_test/Cargo.lock | 12 ++ rust/tests/ref_cell_test/Cargo.toml | 10 ++ rust/tests/ref_cell_test/src/main.rs | 158 ++++++++++++++++++ subjects/borrow_box/README.md | 83 +++++++++ subjects/box_it/README.md | 53 ++++++ subjects/box_recursion/README.md | 79 +++++++++ subjects/drop_the_thread/README.md | 109 ++++++++++++ subjects/how_many_references/README.md | 78 +++++++++ subjects/ref_cell/README.md | 112 +++++++++++++ 24 files changed, 1239 insertions(+) create mode 100644 rust/tests/borrow_box_test/Cargo.lock create mode 100644 rust/tests/borrow_box_test/Cargo.toml create mode 100644 rust/tests/borrow_box_test/src/main.rs create mode 100644 rust/tests/box_it_test/Cargo.lock create mode 100644 rust/tests/box_it_test/Cargo.toml create mode 100644 rust/tests/box_it_test/src/main.rs create mode 100644 rust/tests/box_recursion_test/Cargo.lock create mode 100644 rust/tests/box_recursion_test/Cargo.toml create mode 100644 rust/tests/box_recursion_test/src/main.rs create mode 100644 rust/tests/drop_the_thread_test/Cargo.lock create mode 100644 rust/tests/drop_the_thread_test/Cargo.toml create mode 100644 rust/tests/drop_the_thread_test/src/main.rs create mode 100644 rust/tests/how_many_references_test/Cargo.lock create mode 100644 rust/tests/how_many_references_test/Cargo.toml create mode 100644 rust/tests/how_many_references_test/src/main.rs create mode 100644 rust/tests/ref_cell_test/Cargo.lock create mode 100644 rust/tests/ref_cell_test/Cargo.toml create mode 100644 rust/tests/ref_cell_test/src/main.rs create mode 100644 subjects/borrow_box/README.md create mode 100644 subjects/box_it/README.md create mode 100644 subjects/box_recursion/README.md create mode 100644 subjects/drop_the_thread/README.md create mode 100644 subjects/how_many_references/README.md create mode 100644 subjects/ref_cell/README.md diff --git a/rust/tests/borrow_box_test/Cargo.lock b/rust/tests/borrow_box_test/Cargo.lock new file mode 100644 index 000000000..c1ff1ef08 --- /dev/null +++ b/rust/tests/borrow_box_test/Cargo.lock @@ -0,0 +1,12 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "borrow_box" +version = "0.1.0" + +[[package]] +name = "borrow_box_test" +version = "0.1.0" +dependencies = [ + "borrow_box", +] diff --git a/rust/tests/borrow_box_test/Cargo.toml b/rust/tests/borrow_box_test/Cargo.toml new file mode 100644 index 000000000..9d448ad95 --- /dev/null +++ b/rust/tests/borrow_box_test/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "borrow_box_test" +version = "0.1.0" +authors = ["lee "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +borrow_box = { path = "../../../../rust-piscine-solutions/borrow_box"} diff --git a/rust/tests/borrow_box_test/src/main.rs b/rust/tests/borrow_box_test/src/main.rs new file mode 100644 index 000000000..beed01414 --- /dev/null +++ b/rust/tests/borrow_box_test/src/main.rs @@ -0,0 +1,91 @@ +use borrow_box::*; + +fn main() { + let mut game = Game::new(0, String::from("Joao"), String::from("Susana"), 5); + println!("{:?}", game.read_winner()); + // output : ("Same score! tied", 0) + + game.update_score(String::from("Joao")); + game.update_score(String::from("Joao")); + game.update_score(String::from("Susana")); + game.update_score(String::from("Susana")); + println!("{:?}", game.read_winner()); + // output : ("Same score! tied", 2) + + game.update_score(String::from("Joao")); + // this one will not count because it already 5 games played, the nbr_of_games + game.update_score(String::from("Susana")); + + println!("{:?}", game.read_winner()); + // output : ("Joao", 3) + + println!("{:?}", game.delete()); + // output : "game deleted: id -> 0" + + // game.read_winner(); + // this will give error + // because the game was dropped, no longer exists on the heap +} +#[cfg(test)] +mod tests { + use super::*; + + fn create_games() -> Vec> { + vec![ + Game::new(0, String::from("player1"), String::from("player2"), 1), + Game::new(1, String::from("Alice"), String::from("Mark"), 3), + Game::new(2, String::from("Jack"), String::from("Miller"), 5) + ] + } + + #[test] + fn test_create() { + let games = create_games(); + assert_eq!(*games[0], Game {id: 0, p1: (String::from("player1"), 0), p2: (String::from("player2"), 0), nbr_of_games: 1}); + assert_eq!(*games[1], Game {id: 1, p1: (String::from("Alice"), 0), p2: (String::from("Mark"), 0), nbr_of_games: 3}); + assert_eq!(*games[2], Game {id: 2, p1: (String::from("Jack"), 0), p2: (String::from("Miller"), 0), nbr_of_games: 5}); + } + + #[test] + fn test_update_and_read() { + let mut games = create_games(); + games[0].update_score(String::from("player1")); + assert_eq!(games[0].read_winner(), (String::from("player1"), 1)); + + games[0].update_score(String::from("player2")); + // this will stay the same because the nbr_of_games is 1 so if one + // of the players wins just once it will no longer increment the score + assert_eq!(games[0].read_winner(), (String::from("player1"), 1)); + + games[2].update_score(String::from("Jack")); + games[2].update_score(String::from("Jack")); + games[2].update_score(String::from("Miller")); + games[2].update_score(String::from("Miller")); + // tie between players + assert_eq!(games[2].read_winner(), (String::from("Same score! tied"), 2)); + + games[2].update_score(String::from("Jack")); + assert_eq!(games[2].read_winner(), (String::from("Jack"), 3)); + } + + #[test] + fn test_delete() { + let game = Game::new(0, String::from("Alice"), String::from("Mark"), 3); + let game1 = Game::new(23, String::from("Jack"), String::from("Miller"), 1); + + assert_eq!(game.delete(), String::from("game deleted: id -> 0")); + assert_eq!(game1.delete(), String::from("game deleted: id -> 23")); + } + + // #[test] + // #[should_panic] + // fn test_delete_ownership() { + // let game = new(0, String::from("Alice"), String::from("Mark"), 3); + // { + // let a = &game; + // // error! cant destroy boxed while the inner value is borrowed later in scope + // delete(game); + // read_winner(&a); + // } + // } +} diff --git a/rust/tests/box_it_test/Cargo.lock b/rust/tests/box_it_test/Cargo.lock new file mode 100644 index 000000000..f322a385d --- /dev/null +++ b/rust/tests/box_it_test/Cargo.lock @@ -0,0 +1,12 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "box_it" +version = "0.1.0" + +[[package]] +name = "box_it_test" +version = "0.1.0" +dependencies = [ + "box_it", +] diff --git a/rust/tests/box_it_test/Cargo.toml b/rust/tests/box_it_test/Cargo.toml new file mode 100644 index 000000000..98d330508 --- /dev/null +++ b/rust/tests/box_it_test/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "box_it_test" +version = "0.1.0" +authors = ["lee "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +box_it = { path = "../../../../rust-piscine-solutions/box_it"} diff --git a/rust/tests/box_it_test/src/main.rs b/rust/tests/box_it_test/src/main.rs new file mode 100644 index 000000000..c69033f8e --- /dev/null +++ b/rust/tests/box_it_test/src/main.rs @@ -0,0 +1,56 @@ +use box_it::*; + +fn main() { + let new_str = String::from("5.5k 8.9k 32"); + + // creating a variable and we save it in the Heap + let a_h = transform_and_save_on_heap(new_str); + println!("Box value : {:?}", &a_h); + println!("size occupied in the stack : {:?} bytes", (std::mem::size_of_val(&a_h))); + + let a_b_v = take_value_ownership(a_h); + println!("value : {:?}", &a_b_v); + println!("size occupied in the stack : {:?} bytes", (std::mem::size_of_val(&a_b_v))); + // whenever the box, in this case "a_h", goes out of scope it will be deallocated, freed +} + +#[cfg(test)] +mod tests { + use super::*; + use std::mem; + + #[test] + fn test_transform() { + let new_str = String::from("5.5k 8.9k 32"); + let new_str_1 = String::from("6.8k 13.5k"); + let new_str_2 = String::from("20.3k 3.8k 7.7k 992"); + + let a = transform_and_save_on_heap(new_str); + let b = transform_and_save_on_heap(new_str_1); + let c = transform_and_save_on_heap(new_str_2); + + assert_eq!(a, Box::new(vec![5500, 8900, 32])); + assert_eq!(b, Box::new(vec![6800, 13500])); + assert_eq!(c, Box::new(vec![20300, 3800, 7700, 992])); + assert_eq!(mem::size_of_val(&a), 8); + assert_eq!(mem::size_of_val(&b), 8); + assert_eq!(mem::size_of_val(&c), 8); + } + + #[test] + fn test_take_value_from_box() { + let new_str = String::from("5.5k 8.9k 32"); + let new_str_1 = String::from("6.8k 13.5k"); + let new_str_2 = String::from("20.3k 3.8k 7.7k 992"); + let a = take_value_ownership(transform_and_save_on_heap(new_str)); + let b = take_value_ownership(transform_and_save_on_heap(new_str_1)); + let c = take_value_ownership(transform_and_save_on_heap(new_str_2)); + + assert_eq!(a, vec![5500, 8900, 32]); + assert_eq!(b, vec![6800, 13500]); + assert_eq!(c, vec![20300, 3800, 7700, 992]); + assert_eq!(mem::size_of_val(&a), 24); + assert_eq!(mem::size_of_val(&b), 24); + assert_eq!(mem::size_of_val(&c), 24); + } +} diff --git a/rust/tests/box_recursion_test/Cargo.lock b/rust/tests/box_recursion_test/Cargo.lock new file mode 100644 index 000000000..1e77a0dc3 --- /dev/null +++ b/rust/tests/box_recursion_test/Cargo.lock @@ -0,0 +1,12 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "box_recursion" +version = "0.1.0" + +[[package]] +name = "box_recursion_test" +version = "0.1.0" +dependencies = [ + "box_recursion", +] diff --git a/rust/tests/box_recursion_test/Cargo.toml b/rust/tests/box_recursion_test/Cargo.toml new file mode 100644 index 000000000..db29730c5 --- /dev/null +++ b/rust/tests/box_recursion_test/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "box_recursion_test" +version = "0.1.0" +authors = ["lee "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +box_recursion = { path = "../../../../rust-piscine-solutions/box_recursion"} diff --git a/rust/tests/box_recursion_test/src/main.rs b/rust/tests/box_recursion_test/src/main.rs new file mode 100644 index 000000000..6de2aa07d --- /dev/null +++ b/rust/tests/box_recursion_test/src/main.rs @@ -0,0 +1,98 @@ +use box_recursion::*; + +fn main() { + let mut list = WorkEnvironment::new(); + list.add_worker(String::from("CEO"), String::from("Marie")); + list.add_worker(String::from("Manager"), String::from("Monica")); + list.add_worker(String::from("Normal Worker"), String::from("Ana")); + list.add_worker(String::from("Normal Worker"), String::from("Alice")); + println!("{:?}", list); + + println!("{:?}", list.search_worker()); + + list.remove_worker(); + list.remove_worker(); + list.remove_worker(); + list.remove_worker(); + println!("{:?}", list); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_new() { + let list = WorkEnvironment::new(); + assert!(list.grade.is_none()); + } + + #[test] + fn test_one_worker() { + let mut list = WorkEnvironment::new(); + list.add_worker(String::from("CEO"), String::from("Marie")); + list.remove_worker(); + assert!(list.grade.is_none()); + } + + #[test] + fn test_two_workers() { + let mut list = WorkEnvironment::new(); + list.add_worker(String::from("CEO"), String::from("Marie")); + list.add_worker(String::from("Manager"), String::from("Monica")); + list.remove_worker(); + + assert_eq!(list.grade.as_ref().unwrap().worker_type, "CEO"); + assert_eq!(list.grade.as_ref().unwrap().worker_name, "Marie"); + } + + #[test] + fn test_more_workers() { + let mut list = WorkEnvironment::new(); + list.add_worker(String::from("CEO"), String::from("Marie")); + list.add_worker(String::from("Manager"), String::from("Monica")); + list.add_worker(String::from("Normal Worker"), String::from("Ana")); + list.add_worker(String::from("Normal Worker"), String::from("Alice")); + list.remove_worker(); + + assert_eq!(list.grade.as_ref().unwrap().worker_type, "Normal Worker"); + assert_eq!(list.grade.as_ref().unwrap().worker_name, "Ana"); + + list.remove_worker(); + list.remove_worker(); + assert_eq!(list.grade.as_ref().unwrap().worker_type, "CEO"); + assert_eq!(list.grade.as_ref().unwrap().worker_name, "Marie"); + } + + #[test] + fn test_search() { + let mut list = WorkEnvironment::new(); + list.add_worker(String::from("CEO"), String::from("Marie")); + list.add_worker(String::from("Manager"), String::from("Monica")); + list.add_worker(String::from("Normal Worker"), String::from("Ana")); + list.add_worker(String::from("Normal Worker"), String::from("Alice")); + + assert_eq!( + list.search_worker().unwrap(), + (String::from("Alice"), String::from("Normal Worker")) + ); + + list.remove_worker(); + assert_eq!( + list.search_worker().unwrap(), + (String::from("Ana"), String::from("Normal Worker")) + ); + + list.remove_worker(); + assert_eq!( + list.search_worker().unwrap(), + (String::from("Monica"), String::from("Manager")) + ); + + list.remove_worker(); + assert_eq!( + list.search_worker().unwrap(), + (String::from("Marie"), String::from("CEO")) + ); + } +} diff --git a/rust/tests/drop_the_thread_test/Cargo.lock b/rust/tests/drop_the_thread_test/Cargo.lock new file mode 100644 index 000000000..2bd03a8ea --- /dev/null +++ b/rust/tests/drop_the_thread_test/Cargo.lock @@ -0,0 +1,12 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "drop_the_thread" +version = "0.1.0" + +[[package]] +name = "drop_the_thread_test" +version = "0.1.0" +dependencies = [ + "drop_the_thread", +] diff --git a/rust/tests/drop_the_thread_test/Cargo.toml b/rust/tests/drop_the_thread_test/Cargo.toml new file mode 100644 index 000000000..875b19074 --- /dev/null +++ b/rust/tests/drop_the_thread_test/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "drop_the_thread_test" +version = "0.1.0" +authors = ["lee "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +drop_the_thread = { path = "../../../../rust-piscine-solutions/drop_the_thread"} diff --git a/rust/tests/drop_the_thread_test/src/main.rs b/rust/tests/drop_the_thread_test/src/main.rs new file mode 100644 index 000000000..f28825491 --- /dev/null +++ b/rust/tests/drop_the_thread_test/src/main.rs @@ -0,0 +1,87 @@ +use drop_the_thread::*; +use std::rc::Rc; + +fn main() { + let worker = Workers::new(); + let (id, thread) = worker.new_worker(String::from("command")); + let (id1, thread1) = worker.new_worker(String::from("command1")); + + thread.skill(); + + println!("{:?}", (worker.is_dropped(id), id, &worker.drops)); + // output: (true, 0, Cell { value: 1 }) + + thread1.skill(); + println!("{:?}", (worker.is_dropped(id1), id1, &worker.drops)); + // output: (true, 1, Cell { value: 2 }) + + let (id2, thread2) = worker.new_worker(String::from("command2")); + let thread2 = Rc::new(thread2); + let thread2_clone = thread2.clone(); + + // thread2_clone.skill(); + drop(thread2_clone); + + println!("{:?}", (worker.is_dropped(id2), id2, &worker.drops, Rc::strong_count(&thread2))); + // (false, 2, Cell { value: 2 }, 1) +} + +#[cfg(test)] +mod tests { + use super::*; + use std::rc::Rc; + + #[test] + fn test_is_dropped_and_drops() { + let worker = Workers::new(); + let (pid, thread) = worker.new_worker(String::from("gnome-shell")); + let (pid0, thread0) = worker.new_worker(String::from("i3")); + let (pid1, thread1) = worker.new_worker(String::from("shell")); + let (pid2, thread2) = worker.new_worker(String::from("spotify")); + + thread.skill(); + assert_eq!(worker.drops.get(), 1_usize); + thread0.skill(); + + assert!(worker.is_dropped(pid), "{} should have been dropped", pid); + assert!(worker.is_dropped(pid0), "{} should have been dropped", pid0); + assert!(!worker.is_dropped(pid1), "{} should not have been dropped", pid1); + assert!(!worker.is_dropped(pid2), "{} should not have been dropped", pid2); + + assert_eq!(worker.drops.get(), 2_usize); + + thread1.skill(); + thread2.skill(); + + assert_eq!(worker.drops.get(), 4_usize); + } + + #[test] + fn test_using_rc() { + // will create a new reference to the thread + // this will test the following + // if we drop the cloned value the RC will decrease + // but the thread will not be dropped! + let worker = Workers::new(); + let (_, thread) = worker.new_worker(String::from("Xorg")); + let thread = Rc::new(thread); + let thread_clone = thread.clone(); + + assert_eq!(Rc::strong_count(&thread), 2); + + drop(thread_clone); + + assert_eq!(Rc::strong_count(&thread), 1); + } + + #[test] + #[should_panic(expected = "0 is already dropped")] + fn test_drop_same_thread() { + // test if we drop the same thread after it was already been dropped + let worker = Workers::new(); + let (pid, thread) = worker.new_worker(String::from("gsd-rfkill")); + let thread_clone = thread.clone(); + thread.skill(); + thread_clone.skill(); + } +} diff --git a/rust/tests/how_many_references_test/Cargo.lock b/rust/tests/how_many_references_test/Cargo.lock new file mode 100644 index 000000000..a7356cd1d --- /dev/null +++ b/rust/tests/how_many_references_test/Cargo.lock @@ -0,0 +1,12 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "how_many_references" +version = "0.1.0" + +[[package]] +name = "how_many_references_test" +version = "0.1.0" +dependencies = [ + "how_many_references", +] diff --git a/rust/tests/how_many_references_test/Cargo.toml b/rust/tests/how_many_references_test/Cargo.toml new file mode 100644 index 000000000..e2a00417c --- /dev/null +++ b/rust/tests/how_many_references_test/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "how_many_references_test" +version = "0.1.0" +authors = ["lee "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +how_many_references = { path = "../../../../rust-piscine-solutions/how_many_references"} diff --git a/rust/tests/how_many_references_test/src/main.rs b/rust/tests/how_many_references_test/src/main.rs new file mode 100644 index 000000000..7ccbddad9 --- /dev/null +++ b/rust/tests/how_many_references_test/src/main.rs @@ -0,0 +1,103 @@ +use how_many_references::*; + +fn main() { + let a = Rc::new(String::from("a")); + let b = Rc::new(String::from("b")); + let c = Rc::new(String::from("c")); + + let a1 = Rc::new(String::from("a")); + + let mut new_node = Node::new(vec![a.clone()]); + new_node.add_ele(b.clone()); + new_node.add_ele(a.clone()); + new_node.add_ele(c.clone()); + new_node.add_ele(a.clone()); + + println!("a: {:?}", how_many_references(&a)); + println!("b: {:?}", how_many_references(&b)); + println!("c: {:?}", how_many_references(&c)); + new_node.rm_all_ref(a1.clone()); + new_node.rm_all_ref(a.clone()); + + println!("a: {:?}", how_many_references(&a)); + println!("b: {:?}", how_many_references(&b)); + println!("c: {:?}", how_many_references(&c)); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_add_ele() { + let a = Rc::new(String::from("a")); + let b = Rc::new(String::from("b")); + let c = Rc::new(String::from("c")); + + let mut new_node = Node::new(vec![a.clone()]); + new_node.add_ele(a.clone()); + new_node.add_ele(b.clone()); + new_node.add_ele(c.clone()); + + assert_eq!(new_node.value, vec![a.clone(), a, b, c]); + } + #[test] + fn test_how_many_references() { + let a = Rc::new(String::from("a")); + let b = Rc::new(String::from("b")); + let c = Rc::new(String::from("c")); + let d = Rc::new(String::from("d")); + let mut new_node = Node::new(vec![]); + new_node.add_ele(b.clone()); + new_node.add_ele(a.clone()); + new_node.add_ele(c.clone()); + new_node.add_ele(a.clone()); + + assert_eq!(how_many_references(&d), 1); + assert_eq!(how_many_references(&a), 3); + assert_eq!(how_many_references(&b), 2); + assert_eq!(how_many_references(&c), 2); + } + + #[test] + fn test_rm_all_ref() { + let a = Rc::new(String::from("a")); + let b = Rc::new(String::from("b")); + let c = Rc::new(String::from("c")); + let d = Rc::new(String::from("d")); + + let a1 = Rc::new(String::from("a")); + let b1 = Rc::new(String::from("b")); + let c1 = Rc::new(String::from("c")); + let d1 = Rc::new(String::from("d")); + let mut new_node = Node::new(vec![ + d.clone(), + d.clone(), + b.clone(), + a.clone(), + c.clone(), + a.clone(), + d.clone(), + ]); + + new_node.rm_all_ref(a1.clone()); + assert_eq!(how_many_references(&a), 3); + new_node.rm_all_ref(a.clone()); + assert_eq!(how_many_references(&a), 1); + + new_node.rm_all_ref(b1.clone()); + assert_eq!(how_many_references(&b), 2); + new_node.rm_all_ref(b.clone()); + assert_eq!(how_many_references(&b), 1); + + new_node.rm_all_ref(c1.clone()); + assert_eq!(how_many_references(&c), 2); + new_node.rm_all_ref(c.clone()); + assert_eq!(how_many_references(&c), 1); + + new_node.rm_all_ref(d1.clone()); + assert_eq!(how_many_references(&d), 4); + new_node.rm_all_ref(d.clone()); + assert_eq!(how_many_references(&d), 1); + } +} diff --git a/rust/tests/ref_cell_test/Cargo.lock b/rust/tests/ref_cell_test/Cargo.lock new file mode 100644 index 000000000..04f405cbe --- /dev/null +++ b/rust/tests/ref_cell_test/Cargo.lock @@ -0,0 +1,12 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "ref_cell" +version = "0.1.0" + +[[package]] +name = "ref_cell_test" +version = "0.1.0" +dependencies = [ + "ref_cell", +] diff --git a/rust/tests/ref_cell_test/Cargo.toml b/rust/tests/ref_cell_test/Cargo.toml new file mode 100644 index 000000000..acacc6db1 --- /dev/null +++ b/rust/tests/ref_cell_test/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "ref_cell_test" +version = "0.1.0" +authors = ["lee "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +ref_cell = { path = "../../../../rust-piscine-solutions/ref_cell"} diff --git a/rust/tests/ref_cell_test/src/main.rs b/rust/tests/ref_cell_test/src/main.rs new file mode 100644 index 000000000..9ba1908e1 --- /dev/null +++ b/rust/tests/ref_cell_test/src/main.rs @@ -0,0 +1,158 @@ +use ref_cell::*; + +fn main() { + // initialize the worker + let Logger = Worker::new(1); + + // initialize the tracker, with the max number of + // called references as 10 + let track = Tracker::new(&Logger, 10); + + let _a = Logger.track_value.clone(); // |\ + let _a1 = Logger.track_value.clone(); // | -> increase the Rc to 4 references + let _a2 = Logger.track_value.clone(); // |/ + + // take a peek of how much we already used from our quota + track.peek(&Logger.track_value); + + let _b = Logger.track_value.clone(); // |\ + let _b1 = Logger.track_value.clone(); // | -> increase the Rc to 8 references + let _b2 = Logger.track_value.clone(); // | / + let _b3 = Logger.track_value.clone(); // |/ + + // this will set the value and making a verification of + // how much we already used of our quota + track.set_value(&Logger.track_value); + + let _c = Logger.track_value.clone(); // | -> increase the Rc to 9 references + + // this will set the value and making a verification of + // how much we already used of our quota + track.set_value(&Logger.track_value); + + let _c1 = Logger.track_value.clone(); // | -> increase the Rc to 10 references, this will be the limit + + track.set_value(&Logger.track_value); + + for (k ,v) in Logger.mapped_messages.into_inner() { + println!("{:?}", (k ,v)); + } + println!("{:?}", Logger.all_messages.into_inner()); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_module() { + #[derive(Clone, Debug)] + struct TestMs { + value: Rc, + ms: RefCell>, + correct: Vec, + } + + impl Logger for TestMs { + fn warning(&self, message: &str) { + self.ms.borrow_mut().push(message.to_string()); + } + fn info(&self, message: &str) { + self.ms.borrow_mut().push(message.to_string()); + } + fn error(&self, message: &str) { + self.ms.borrow_mut().push(message.to_string()); + } + } + + let l = TestMs { + value: Rc::new(115), + ms: RefCell::new(vec![]), + correct: vec![ + String::from("Info: you are using up too 40% of your quote"), + String::from("Warning: you have used up over 80% of your quota! Proceeds with precaution"), + String::from("Error: you are over your quota!") + ], + }; + + let track = Tracker::new(&l, 5); + let _a = l.value.clone(); + track.peek(&l.value); // 40% + let _a1 = l.value.clone(); + let _a2 = l.value.clone(); + track.set_value(&l.value); // 80% + let _a3 = l.value.clone(); + track.set_value(&l.value); // 100% + + for (i, v) in l.ms.into_inner().iter().enumerate() { + assert_eq!(v, &l.correct[i]) + } + } + + #[test] + fn test_module_usage_hasmap() { + let log = Worker::new(1000); + let track = Tracker::new(&log, 12); + let _clone_test = log.track_value.clone(); + let _clone_test1 = log.track_value.clone(); + let _clone_test2 = log.track_value.clone(); + let _clone_test3 = log.track_value.clone(); + let _clone_test4 = log.track_value.clone(); + let _clone_test5 = log.track_value.clone(); + let _clone_test6 = log.track_value.clone(); + let _clone_test7 = log.track_value.clone(); + + // warning: 75% of the quota + track.set_value(&log.track_value); + assert_eq!(log.mapped_messages.borrow().get("Warning").unwrap(), "you have used up over 75% of your quota! Proceeds with precaution"); + + let _clone_test8 = log.track_value.clone(); + + // warning: 83% of the quota <- most resent of the messages last onw to be added to the hashmap + track.set_value(&log.track_value); + assert_eq!(log.mapped_messages.borrow().get("Warning").unwrap(), "you have used up over 83% of your quota! Proceeds with precaution"); + + // info: 83% + track.peek(&log.track_value); + assert_eq!(log.mapped_messages.borrow().get("Info").unwrap(), "you are using up too 83% of your quote"); + + let _clone_test9 = log.track_value.clone(); + // info: 91% + track.peek(&log.track_value); + assert_eq!(log.mapped_messages.borrow().get("Info").unwrap(), "you are using up too 91% of your quote"); + + let _clone_test10 = log.track_value.clone(); + // error: passed the quota + track.set_value(&log.track_value); + assert_eq!(log.mapped_messages.borrow().get("Error").unwrap(), "you are over your quota!"); + } + + #[test] + fn test_module_usage_vector() { + let correct = vec![ + "Info: you are using up too 40% of your quote", + "Warning: you have used up over 80% of your quota! Proceeds with precaution", + "Info: you are using up too 80% of your quote", "Error: you are over your quota!" + ]; + let log = Worker::new(1); + let track = Tracker::new(&log, 5); + let _a = log.track_value.clone(); + // info: 40% + track.peek(&log.track_value); + let _a1 = log.track_value.clone(); + let _a2 = log.track_value.clone(); + + // warning: 80% + track.set_value(&log.track_value); + // info: 80% + track.peek(&log.track_value); + let _a3 = log.track_value.clone(); + + // error: passed the quota + track.set_value(&log.track_value); + + for (i, v) in log.all_messages.into_inner().iter().enumerate() { + assert_eq!(v, correct[i]); + } + } +} diff --git a/subjects/borrow_box/README.md b/subjects/borrow_box/README.md new file mode 100644 index 000000000..c7cdafc56 --- /dev/null +++ b/subjects/borrow_box/README.md @@ -0,0 +1,83 @@ +## borrow box + +### Instructions + +You will have to create a **CRUD** functionality. Therefore creating the following functions : + +- `new`, that receives two players and initializes them with a name and a score. This functions should + return the structure wrapped in a Box. + +- `read_winner`, returns a tuple with the name and the score of the player who is winning. + In case none of the players are winning, it should return the same tuple with the string "Same score! tied" and the tied score. + + - `update_score`, that receives the name of a player. + This function should increment the score of the player. The score should only be increased if it does not pass the `nbr_of_games`. + Example: if the nbr_of_games is 3 then the game should be best out of three. So if one play as 2 wins then + he is the winner and the function should not increase the score anymore for either players. + +- `delete`, that takes the ownership of the boxed game and returning a string : "Game deleted: id -> 0". + +### Expected Function + +```rust +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct Game { + // expected public fields +} +impl Game { + pub fn new(i: u32, pl1: String, pl2: String, n: u16) -> Box {} + pub fn read_winner(&self) -> (String, u16) {} + pub fn update_score(&mut self, user_name: String) {} + pub fn delete(self) -> String {} +} +``` + +### Usage + +Here is a program to test your function + +```rust +fn main() { + let mut game = Game::create_game(0, String::from("Joao"), String::from("Susana"), 5); + println!("{:?}", game.read_winner()); + // output : ("Same score! tied", 0) + + game.update_score(String::from("Joao")); + game.update_score(String::from("Joao")); + game.update_score(String::from("Susana")); + game.update_score(String::from("Susana")); + println!("{:?}", game.read_winner()); + // output : ("Same score! tied", 2) + + game.update_score(String::from("Joao")); + // this one will not count because it already 5 games played, the nbr_of_games + game.update_score(String::from("Susana")); + + println!("{:?}", game.read_winner()); + // output : ("Joao", 3) + + game.delete(); + println!("{:?}", game.delete()); + // output : "game deleted: id -> 0" + + // game.read_winner(); + // this will give error + // because the game was dropped, no longer exists on the heap +} +``` + +And its output: + +```console +student@ubuntu:~/[[ROOT]]/test$ cargo run +("Same score! tied", 0) +("Same score! tied", 2) +("Joao", 3) +"game deleted: id -> 0" +student@ubuntu:~/[[ROOT]]/test$ +``` + + +### Notions + +- https://doc.rust-lang.org/book/ch15-01-box.html diff --git a/subjects/box_it/README.md b/subjects/box_it/README.md new file mode 100644 index 000000000..369f01deb --- /dev/null +++ b/subjects/box_it/README.md @@ -0,0 +1,53 @@ +## box_it + +### Instructions + +Create the following functions: + +- `transform_and_save_on_heap`, that receives a string with a number (that can or not have a k (kilo) suffix) + and transforms those numbers into `u32` and inserts it into a vector that must be saved in the heap using **Box**. + +- `take_value_ownership`, that takes the value (unboxed value) form the box and returns it + +### Expected Function + +```rust +pub fn transform_and_save_on_heap(s: String) -> Box> {} +pub fn take_value_ownership(a: Box>) -> Vec {} +``` + +### Usage + +Here is a program to test your function + +```rust +fn main() { + let new_str = String::from("5.5k 8.9k 32"); + + // creating a variable and we save it in the Heap + let a_h = transform_and_save_on_heap(new_str); + println!("Box value : {:?}", &a_h); + println!("size occupied in the stack : {:?} bytes", (std::mem::size_of_val(&a_h))); + + let a_b_v = take_value_ownership(a_h); + println!("value : {:?}", &a_b_v); + println!("size occupied in the stack : {:?} bytes", (std::mem::size_of_val(&a_b_v))); + // whenever the box, in this case "a_h", goes out of scope it will be deallocated, freed +} +``` + +And its output: + +```console +student@ubuntu:~/[[ROOT]]/test$ cargo run +Box value : [6800, 13500] +size occupied in the stack : 8 bytes +value : [6800, 13500] +size occupied in the stack : 24 bytes +student@ubuntu:~/[[ROOT]]/test$ +``` + +### Notions + +- https://doc.rust-lang.org/book/ch15-00-smart-pointers.html +- https://doc.rust-lang.org/book/ch15-01-box.html diff --git a/subjects/box_recursion/README.md b/subjects/box_recursion/README.md new file mode 100644 index 000000000..1f8679249 --- /dev/null +++ b/subjects/box_recursion/README.md @@ -0,0 +1,79 @@ +## box_recursion + +### Instructions + +Using the given code create the following functions: + +- `new` that will initialize the `WorkEnvironment` as `None` +- `add_worker`, that receives two strings, one being the type of worker and the other the name of the worker. +- `remove_worker`, that removes the last worker that was placed in the `WorkEnvironment`, this functions should + return a `Option` with the name of the worker. +- `search_worker`, that return a tuple with the name and type of worker. + +You must also create a type called `Link` this will be the connection of the structures `WorkEnvironment` and `Worker`. +Do not forget that this will be a recursion type and it must point to `None` if there is no workers. + +### Expected Function + +```rust +pub struct WorkEnvironment { + pub grade: Link, +} + +pub type Link = + +pub struct Worker { + pub worker_type: String, + pub worker_name: String, + pub next_worker: Link, +} + +impl WorkEnvironment { + pub fn new() -> WorkEnvironment {} + pub fn add_worker(&mut self, t: String, name: String) {} + pub fn remove_worker(&mut self) -> Option {} + pub fn search_worker(&self) -> Option<(String, String)> {} +} + + +``` + +### Usage + +Here is a program to test your function + +```rust +fn main() { + let mut list = WorkEnvironment::new(); + list.add_worker(String::from("CEO"), String::from("Marie")); + list.add_worker(String::from("Manager"), String::from("Monica")); + list.add_worker(String::from("Normal Worker"), String::from("Ana")); + list.add_worker(String::from("Normal Worker"), String::from("Alice")); + println!("{:?}", list); + + println!("{:?}", list.search_worker()); + + list.remove_worker(); + list.remove_worker(); + list.remove_worker(); + list.remove_worker(); + println!("{:?}", list); +} +``` + +And its output: + +```console +student@ubuntu:~/[[ROOT]]/test$ cargo run +WorkEnvironment { grade: Some(Worker { worker_type: "Normal Worker", worker_name: "Alice", next_worker: Some(Worker { worker_type: "Normal Worker", worker_name: "Ana", next_worker: Some(Worker { worker_type: "Manager", worker_name: "Monica", next_worker: Some(Worker { worker_type: "CEO", worker_name: "Marie", next_worker: None }) }) }) }) } +Some(("Alice", "Normal Worker")) +WorkEnvironment { grade: None } +student@ubuntu:~/[[ROOT]]/test$ +``` + +### Notions + +- https://doc.rust-lang.org/rust-by-example/custom_types/enum.html +- https://doc.rust-lang.org/book/ch15-01-box.html +- https://doc.rust-lang.org/std/option/ +- https://doc.rust-lang.org/book/ch15-01-box.html \ No newline at end of file diff --git a/subjects/drop_the_thread/README.md b/subjects/drop_the_thread/README.md new file mode 100644 index 000000000..5d034154d --- /dev/null +++ b/subjects/drop_the_thread/README.md @@ -0,0 +1,109 @@ +## drop_the_thread + +### Instructions + +"Interior mutability is a design pattern in Rust that allows you to mutate data even when there are immutable references to that data" + +You must create a Drop checker API. For this you must create: + +- Two structures: + - `Workers` that will have two fields: + - `drops` that will save the number of dropped threads + - `states` that will save a state of multiple threads. + If the thread is not dropped, the state will be false otherwise true. + - `Thread` that will have the following fields: + - `pid`, the id of the thread + - `cmd`, the name of the thread + - `parent`, that will be the link to the structure `Workers` (Tip: this must be a reference to the structure Workers) + +- Implementation of each structure: + - `Workers` : + - `new`, that creates a default worker + - `new_worker`, that returns a tuple with the `pid` and a new `Thread`, + this function must receive a `String` being the `cmd` + - `is_dropped`, that receives a `pid` and returns a `bool` that indicates the state of the thread by using the `pid` + - `track_worker`, it should return a `usize`, that will be the last available index of the `states` vector, being the new next thread + - `add_drop`, this function must be **called by the `Drop` trait**. It will receive a `pid` that will be used to change the + state of the thread. If the state of that thread is `true` then it will panic with the message ("Cannot drop {}, because its already dropped", pid). + Otherwise it should change the state to true and increment the `drops` field by one. + + - `Thread`: + - `new_thread`, that initializes a new thread + - `skill`, that drops the thread + +- You must implement for the structure `Thread` the `Drop` trait. In this trait you must call the function `add_drop` so that the state of the thread changes + +### Expected Function + +```rust +use std::cell::{RefCell, Cell}; + +#[derive(Debug, Default, Clone, Eq, PartialEq)] +pub struct Workers { + pub drops: Cell, + pub state: RefCell> +} + +impl Workers { + pub fn new() -> Workers {} + pub fn new_worker(&self, c: String) -> (usize, Thread) {} + pub fn track_worker(&self) -> usize {} + pub fn is_dropped(&self, id: usize) -> bool {} + pub fn add_drop(&self, id: usize) {} +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct Thread<'a> { + // expected public fields +} + +impl<'a> Thread<'a> { + pub fn new_thread(p: usize, c: String, t: &'a Workers) -> Thread {} + pub fn skill(self) {} +} +``` + +### Usage + +Here is a program to test your function + +```rust +use std::rc::Rc; + +fn main() { + let worker = Workers::new(); + let (id, thread) = worker.new_worker(String::from("command")); + let (id1, thread1) = worker.new_worker(String::from("command1")); + + thread.skill(); + + println!("{:?}", (worker.is_dropped(id), id, &worker.drops)); + + thread1.skill(); + println!("{:?}", (worker.is_dropped(id1), id1, &worker.drops)); + + let (id2, thread2) = worker.new_worker(String::from("command2")); + let thread2 = Rc::new(thread2); + let thread2_clone = thread2.clone(); + + drop(thread2_clone); + + println!("{:?}", (worker.is_dropped(id2), id2, &worker.drops, Rc::strong_count(&thread2))); +} +``` + +And its output: + +```console +student@ubuntu:~/[[ROOT]]/test$ cargo run +(true, 0, Cell { value: 1 }) +(true, 1, Cell { value: 2 }) +(false, 2, Cell { value: 2 }, 1) +student@ubuntu:~/[[ROOT]]/test$ +``` + +### Notions + +- https://doc.bccnsoft.com/docs/rust-1.36.0-docs-html/std/ops/trait.Drop.html +- https://doc.rust-lang.org/std/cell/struct.RefCell.html +- https://doc.rust-lang.org/book/ch15-05-interior-mutability.html diff --git a/subjects/how_many_references/README.md b/subjects/how_many_references/README.md new file mode 100644 index 000000000..578156323 --- /dev/null +++ b/subjects/how_many_references/README.md @@ -0,0 +1,78 @@ +## how many references + +### Instructions + +Create the following functions : + +- `add_ele` that adds an element to the value in the `Node` +- `how_many_references` that returns how many times the value is referenced in the code +- `rm_all_ref` that receives a `Rc` and removes all elements from the vector that + are equal to that value, this should only happen if the two Rcs point to the same allocation + +### Expected Function + +```rust +pub use std::rc::Rc; + +pub struct Node { + pub value: Vec>, +} + +impl Node { + pub fn new(value: Vec>) -> Node { + Node { value: value } + } + pub fn add_ele(&mut self, v: Rc) {} + pub fn rm_all_ref(&mut self, v: Rc) {} +} + +pub fn how_many_references(value: &Rc) -> usize {} +``` + +### Usage + +Here is a program to test your function + +```rust +fn main() { + let a = Rc::new(String::from("a")); + let b = Rc::new(String::from("b")); + let c = Rc::new(String::from("c")); + + let a1 = Rc::new(String::from("a")); + + let mut new_node = Node::new(vec![a.clone()]); + new_node.add_ele(b.clone()); + new_node.add_ele(a.clone()); + new_node.add_ele(c.clone()); + new_node.add_ele(a.clone()); + + println!("a: {:?}", how_many_references(&a)); + println!("b: {:?}", how_many_references(&b)); + println!("c: {:?}", how_many_references(&c)); + new_node.rm_all_ref(a1.clone()); + new_node.rm_all_ref(a.clone()); + + println!("a: {:?}", how_many_references(&a)); + println!("b: {:?}", how_many_references(&b)); + println!("c: {:?}", how_many_references(&c)); +} +``` + +And its output: + +```console +student@ubuntu:~/[[ROOT]]/test$ cargo run +a: 4 +b: 2 +c: 2 +a: 1 +b: 2 +c: 2 +student@ubuntu:~/[[ROOT]]/test$ +``` + +### Notions + +- https://doc.rust-lang.org/book/ch15-04-rc.html +- https://doc.rust-lang.org/std/rc/struct.Rc.html diff --git a/subjects/ref_cell/README.md b/subjects/ref_cell/README.md new file mode 100644 index 000000000..7507201e3 --- /dev/null +++ b/subjects/ref_cell/README.md @@ -0,0 +1,112 @@ +## ref_cell + +### Instructions + +### 1º part + +Create a module called `messenger`. This module will be able to inform a user of how much references of a given value he is using. +The main objective for this module is to limit how many times a value is referenced. + +For the module you must create the following: + +- A trait `Logger` that implements three functions: `warning`, `info`, `error`. All function should receive a reference to themselves and a string literal. + +```rust + fn warning(&self, msg: &str); + fn info(&self, msg: &str); + fn error(&self, msg: &str); +``` + +- A structure called `Tracker`, that must have the fields: `logger` being a reference to the `Logger`, `value` being the count of how many times the value was referenced, + `max` being the max count of references the actual value can achieve. + +- An implementation of three functions that are associated to the `Tracker` structure: + - `new` that will initialize the structure + - `set_value` that sets the value to the `Tracker` structure and writes to the trait functions. This should be done comparing the **max** and the number of referenced of the actual value. + If the percentage is equal or greater to 100% of the limit usage, it should write **"Error: you are over your quota!"** to the `error` function + If the percentage is equal or greater to 70% of the limit usage, it should write **("Warning: you have used up over {}% of your quota! Proceeds with precaution", )** to the `warning` function + - `peek` that will take a peek of how much usage the variable already has. It should write **("Info: you are using up too {}% of your quote", )** to the `info` function + +### 2ª part + +Afterwards you must use the module `messenger` and create the following: + +- A structure `Worker` that has the fields: + - `track_value` this will be the value that will be tracked by the tracker. + - `mapped_messages` that will have the latest messages. This must be a HashMap with the key being the type of message + sent by the logger (info, error or warning) and the value being the message + - `all_messages` that will be a vector of all messages sent. +- A `new` function that initializes the structure `Worker` +- To use the trait `Logger` you must implement it for the Worker structure. Each function (warning, error and info) must insert the message to the + respective fields of the structure Worker. + +You must use **interior mutability**, this means it must be able to mutate data even when there are immutable references to that data. + +So the user doesn't need to use the keyword `mut` (tip: RefCell) + +### Usage + +Here is a program to test your function + +```rust +fn main() { + // initialize the worker + let Logger = Worker::new(1); + + // initialize the tracker, with the max number of + // called references as 10 + let track = Tracker::new(&Logger, 10); + + let _a = Logger.track_value.clone(); // |\ + let _a1 = Logger.track_value.clone(); // | -> increase the Rc to 4 references + let _a2 = Logger.track_value.clone(); // |/ + + // take a peek of how much we already used from our quota + track.peek(&Logger.track_value); + + let _b = Logger.track_value.clone(); // |\ + let _b1 = Logger.track_value.clone(); // | -> increase the Rc to 8 references + let _b2 = Logger.track_value.clone(); // | / + let _b3 = Logger.track_value.clone(); // |/ + + // this will set the value and making a verification of + // how much we already used of our quota + track.set_value(&Logger.track_value); + + let _c = Logger.track_value.clone(); // | -> increase the Rc to 9 references + + // this will set the value and making a verification of + // how much we already used of our quota + track.set_value(&Logger.track_value); + + let _c1 = Logger.track_value.clone(); // | -> increase the Rc to 10 references, this will be the limit + + track.set_value(&Logger.track_value); + + for (k ,v) in Logger.mapped_messages.into_inner() { + println!("{:?}", (k ,v)); + } + println!("{:?}", Logger.all_messages.into_inner()); +} +``` + +And its output: + +```console +student@ubuntu:~/[[ROOT]]/test$ cargo run +("Info", "you are using up too 40% of your quote") +("Warning", "you have used up over 90% of your quota! Proceeds with precaution") +("Error", "you are over your quota!") +[ + "Info: you are using up too 40% of your quote", + "Warning: you have used up over 80% of your quota! Proceeds with precaution", + "Warning: you have used up over 90% of your quota! Proceeds with precaution", + "Error: you are over your quota!" +] +student@ubuntu:~/[[ROOT]]/test$ +``` + +### Notions + +- https://doc.rust-lang.org/std/cell/struct.RefCell.html +- https://doc.rust-lang.org/std/rc/struct.Rc.html From e70d46f49a7af2576ad18926dd0d83cfef101250 Mon Sep 17 00:00:00 2001 From: lee Date: Mon, 28 Dec 2020 17:30:38 +0000 Subject: [PATCH 3/3] quest 8: adding tests and subjects --- rust/tests/project_motion_test/Cargo.lock | 12 ++ rust/tests/project_motion_test/Cargo.toml | 10 ++ rust/tests/project_motion_test/src/main.rs | 56 +++++++++ rust/tests/sales_test/Cargo.lock | 12 ++ rust/tests/sales_test/Cargo.toml | 10 ++ rust/tests/sales_test/src/main.rs | 133 +++++++++++++++++++++ subjects/project_motion/README.md | 70 +++++++++++ subjects/sales/README.md | 101 ++++++++++++++++ 8 files changed, 404 insertions(+) create mode 100644 rust/tests/project_motion_test/Cargo.lock create mode 100644 rust/tests/project_motion_test/Cargo.toml create mode 100644 rust/tests/project_motion_test/src/main.rs create mode 100644 rust/tests/sales_test/Cargo.lock create mode 100644 rust/tests/sales_test/Cargo.toml create mode 100644 rust/tests/sales_test/src/main.rs create mode 100644 subjects/project_motion/README.md create mode 100644 subjects/sales/README.md diff --git a/rust/tests/project_motion_test/Cargo.lock b/rust/tests/project_motion_test/Cargo.lock new file mode 100644 index 000000000..5e0f535fa --- /dev/null +++ b/rust/tests/project_motion_test/Cargo.lock @@ -0,0 +1,12 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "project_motion" +version = "0.1.0" + +[[package]] +name = "project_motion_test" +version = "0.1.0" +dependencies = [ + "project_motion", +] diff --git a/rust/tests/project_motion_test/Cargo.toml b/rust/tests/project_motion_test/Cargo.toml new file mode 100644 index 000000000..b088cb338 --- /dev/null +++ b/rust/tests/project_motion_test/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "project_motion_test" +version = "0.1.0" +authors = ["lee "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +project_motion = { path = "../../../../rust-piscine-solutions/project_motion"} diff --git a/rust/tests/project_motion_test/src/main.rs b/rust/tests/project_motion_test/src/main.rs new file mode 100644 index 000000000..13d4c1461 --- /dev/null +++ b/rust/tests/project_motion_test/src/main.rs @@ -0,0 +1,56 @@ +use project_motion::*; + +fn main() { + let mut obj = Object::throw_object(50.0, 150.0); + println!("{:?}", obj.next()); + println!("{:?}", obj.next()); + println!("{:?}", obj.next()); + println!("{:?}", obj.next()); + println!("{:?}", obj.next()); + println!("{:?}", obj.next()); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_short_distance() { + let mut object = Object::throw_object(50.0, 20.0); + + assert_eq!(object.next(), Some(Object { distance: 50.0, velocity: 50.0, height: 15.1, time: 1.0 })); + assert_eq!(object, Object { distance: 50.0, velocity: 50.0, height: 15.1, time: 1.0 }); + + assert!(object.next().is_none(), "{:?} instead of None", object); + assert!(object.next().is_none(), "{:?} instead of None", object); + } + + #[test] + fn test_media_distance() { + let mut object = Object::throw_object(100.0, 30.0); + + assert_eq!(object.next(), Some(Object { distance: 100.0, velocity: 100.0, height: 25.1, time: 1.0 })); + assert_eq!(object, Object { distance: 100.0, velocity: 100.0, height: 25.1, time: 1.0 }); + + assert_eq!(object.next(), Some(Object { distance: 200.0, velocity: 100.0, height: 5.5, time: 2.0 })); + assert_eq!(object, Object { distance: 200.0, velocity: 100.0, height: 5.5, time: 2.0 }); + + assert!(object.next().is_none(), "{:?} instead of None", object); + } + + #[test] + fn test_long_distance() { + let mut object = Object::throw_object(120.0, 100.0); + + assert_eq!(object.next(), Some(Object { distance: 120.0, velocity: 120.0, height: 95.1, time: 1.0 })); + assert_eq!(object, Object { distance: 120.0, velocity: 120.0, height: 95.1, time: 1.0 }); + + assert_eq!(object.next(), Some(Object { distance: 240.0, velocity: 120.0, height: 75.5, time: 2.0 })); + assert_eq!(object, Object { distance: 240.0, velocity: 120.0, height: 75.5, time: 2.0 }); + + assert_eq!(object.next(), Some(Object { distance: 360.0, velocity: 120.0, height: 31.4, time: 3.0 })); + assert_eq!(object, Object { distance: 360.0, velocity: 120.0, height: 31.4, time: 3.0 }); + + assert!(object.next().is_none(), "{:?} instead of None", object); + } +} diff --git a/rust/tests/sales_test/Cargo.lock b/rust/tests/sales_test/Cargo.lock new file mode 100644 index 000000000..b3dffd2fc --- /dev/null +++ b/rust/tests/sales_test/Cargo.lock @@ -0,0 +1,12 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "sales" +version = "0.1.0" + +[[package]] +name = "sales_test" +version = "0.1.0" +dependencies = [ + "sales", +] diff --git a/rust/tests/sales_test/Cargo.toml b/rust/tests/sales_test/Cargo.toml new file mode 100644 index 000000000..42d70f492 --- /dev/null +++ b/rust/tests/sales_test/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "sales_test" +version = "0.1.0" +authors = ["lee "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +sales = { path = "../../../../rust-piscine-solutions/sales"} diff --git a/rust/tests/sales_test/src/main.rs b/rust/tests/sales_test/src/main.rs new file mode 100644 index 000000000..ded9b1d9e --- /dev/null +++ b/rust/tests/sales_test/src/main.rs @@ -0,0 +1,133 @@ +use sales::*; + +fn main() { + let store = Store::new(vec![ + (String::from("product A"), 1.23), + (String::from("product B"), 23.1), + (String::from("product C"), 3.12)]); + + println!("{:?}", store); + // output: + // Store { products: [("product A", 1.23), ("product B", 23.1), ("product C", 3.12)] } + + let mut cart = Cart::new(); + cart.insert_item(&store, String::from("product A")); + cart.insert_item(&store, String::from("product B")); + cart.insert_item(&store, String::from("product C")); + + println!("{:?}", cart.generate_receipt()); + // output: + // [1.17, 2.98, 22.07] + + println!("{:?}", cart); + // output: + // Cart { items: [("product A", 1.23), ("product B", 23.1), ("product C", 3.12)], receipt: [1.17, 2.98, 22.07] } +} +#[cfg(test)] +mod tests { + use super::*; + + #[derive(Debug)] + struct Tests { + store: Store, + carts: Vec<(Cart, Vec)>, + } + + fn add_items(s: &Store, items: Vec<&str>, c: &mut Cart) { + for item in items.iter() { + c.insert_item(s, item.to_string()); + } + } + + impl Tests { + fn new() -> Tests { + let store = Store::new(vec![ + (String::from("product A"), 1.23), + (String::from("product B"), 23.1), + (String::from("product C"), 3.12), + (String::from("product D"), 9.75), + (String::from("product E"), 1.75), + (String::from("product F"), 23.75), + (String::from("product G"), 2.75), + (String::from("product H"), 1.64), + (String::from("product I"), 15.23), + (String::from("product J"), 2.10), + (String::from("product K"), 54.91), + (String::from("product L"), 43.99), + ]); + + let mut c = Cart::new(); + let mut c1 = Cart::new(); + let mut c2 = Cart::new(); + let mut c3 = Cart::new(); + add_items(&store, vec!["product A", "product B", "product C"], &mut c); + let sol = vec![1.17, 2.98, 22.07]; + add_items( + &store, + vec![ + "product A", + "product B", + "product C", + "product D", + "product E", + "product F", + "product G", + ], + &mut c1, + ); + let sol1 = vec![1.17, 1.67, 2.62, 2.98, 9.31, 22.05, 22.67]; + add_items( + &store, + vec![ + "product A", + "product B", + "product C", + "product D", + "product E", + "product F", + "product G", + "product H", + "product I", + ], + &mut c2, + ); + let sol2 = vec![1.16, 1.55, 1.65, 2.6, 2.94, 9.2, 14.38, 21.8, 22.42]; + add_items( + &store, + vec![ + "product A", + "product B", + "product C", + "product D", + "product E", + "product F", + "product G", + "product H", + "product I", + "product J", + "product K", + "product L", + ], + &mut c3, + ); + let sol3 = vec![ + 1.18, 1.58, 1.69, 2.02, 2.65, 3.01, 9.39, 14.67, 22.25, 22.88, 42.38, 52.89, + ]; + + Tests { + store, + carts: vec![(c, sol), (c1, sol1), (c2, sol2), (c3, sol3)], + } + } + } + + #[test] + fn test_generate_receipt() { + let cases = Tests::new(); + + for (mut c, sol) in cases.carts.into_iter() { + assert_eq!(c.generate_receipt(), sol); + assert_eq!(c.receipt, sol); + } + } +} diff --git a/subjects/project_motion/README.md b/subjects/project_motion/README.md new file mode 100644 index 000000000..dbf21ae28 --- /dev/null +++ b/subjects/project_motion/README.md @@ -0,0 +1,70 @@ +## project_motion + +### Instructions + +For this exercise you will have to create a [projectile motion](https://cimg2.ck12.org/datastreams/f-d%3Abb024be6673110b31e78b46819e792adaed8dc661e082a61f0a6d64e%2BIMAGE%2BIMAGE.1). + +You will be provided with a structure called `Object` that will have all variables that are +essential for the projectile physics. (distance, velocity, height, time) + +You must implement : + +- A function `throw_object` that will initialize the Object with a given velocity and height. +- The trait Iterator with the `.next()` in which it must calculate the next position of the object after 1 second. + It will return an `Option` with the Object, It will return `None` if the object already reached the floor. + +### Expected Function + +```rust + +#[derive(Debug, Clone, PartialEq)] +pub struct Object { + pub distance: f32, + pub velocity: f32, + pub height: f32, + pub time: f32, +} + +impl Object { + pub fn throw_object(velocity: f32, height: f32) -> Object {} +} + +impl Iterator for Object { + // next +} + +``` + +### Usage + +Here is a program to test your function + +```rust +fn main() { + let mut obj = Object::throw_object(50.0, 150.0); + println!("{:?}", obj.next()); + println!("{:?}", obj.next()); + println!("{:?}", obj.next()); + println!("{:?}", obj.next()); + println!("{:?}", obj.next()); + println!("{:?}", obj.next()); +} +``` + +And its output: + +```console +student@ubuntu:~/[[ROOT]]/test$ cargo run +Some(Object { distance: 50.0, velocity: 50.0, height: 145.1, time: 1.0 }) +Some(Object { distance: 100.0, velocity: 50.0, height: 125.5, time: 2.0 }) +Some(Object { distance: 150.0, velocity: 50.0, height: 81.4, time: 3.0 }) +Some(Object { distance: 200.0, velocity: 50.0, height: 3.0, time: 4.0 }) +None +None +student@ubuntu:~/[[ROOT]]/test$ +``` + +### Notions + +- https://doc.rust-lang.org/std/iter/trait.Iterator.html +- https://doc.rust-lang.org/rust-by-example/trait/iter.html diff --git a/subjects/sales/README.md b/subjects/sales/README.md new file mode 100644 index 000000000..477e5f599 --- /dev/null +++ b/subjects/sales/README.md @@ -0,0 +1,101 @@ +## sales + +### Instructions + +You will have to create a shopping system, where you will have a : + +- Store that will save all the products in it +- Cart that will have `items`, that the client will buy, and a `receipt` + +This store is having a promotion, "Buy three and get one for free" (the free item must be the cheapest). The receipt must not present +any value as 0, so you will have to apply the promotion to all items instead. + +### Expected Function + +```rust + +#[derive(Debug, Clone)] +pub struct Store { + pub products: Vec<(String, f32)>, +} +impl Store { + pub fn new(products: Vec<(String, f32)>) -> Store { + Store { products } + } +} + +#[derive(Debug, Clone)] +pub struct Cart { + // expected public fields +} +impl Cart { + pub fn new() -> Cart {} + pub fn insert_item(&mut self, s: &Store, ele: String) {} + pub fn get_prices(&self) -> Vec {} + pub fn generate_receipt(&mut self) -> Vec {} +} + +``` + +### Example + +`[1.23, 3.12, 23.1]` -> receipt will be `[1.17, 2.98, 22.07]` + +So `1.17 + 2.98 + 22.07 == 3.12 + 23.1 + 0` + +This is a percentage calculation, and it can be applied to a set of three items. +If the client purchase 9 items it will be applied the promotion, three for free, to all items + +|--------------| |---------------| |---------------| +`[1.23, 23.1, 3.12, 9.75, 1.75, 23.75, 2.75, 1.64, 15.23]` -> receipt will be `[1.16, 1.55, 1.65, 2.6, 2.94, 9.2, 14.38, 21.8, 22.42]` + +|--------| |--------| |--------| +`[3.12, 9.75, 1.75, 23.75, 2.75, 1.64, 15.23]` -> receipt will be `[1.54, 1.65, 2.59, 2.94, 9.18, 14.34, 22.36]` + +and so on... (hint: Closures is the way) + +You will have to implement for the Cart structure the following function: + +- `new`, that will initialize the cart +- `insert_item`, that will receive a reference to `Store` and a `String`. Just like the name says you will + have to insert the item to the cart +- `generate_receipt`, that returns a vector of sorted floats. This function must generate the receipt just +like the example above, using the promotion. Also saving the result in the filed `receipt`. + +### Usage + +Here is a program to test your function + +```rust +fn main() { + let store = Store::new(vec![ + (String::from("product A"), 1.23), + (String::from("product B"), 23.1), + (String::from("product C"), 3.12)]); + + println!("{:?}", store); + + let mut cart = Cart::new(); + cart.insert_item(&store, String::from("product A")); + cart.insert_item(&store, String::from("product B")); + cart.insert_item(&store, String::from("product C")); + + println!("{:?}", cart.generate_receipt()); + + println!("{:?}", cart); +} +``` + +And its output: + +```console +student@ubuntu:~/[[ROOT]]/test$ cargo run +Store { products: [("product A", 1.23), ("product B", 23.1), ("product C", 3.12)] } +[1.17, 2.98, 22.07] +Cart { items: [("product A", 1.23), ("product B", 23.1), ("product C", 3.12)], receipt: [1.17, 2.98, 22.07] } +student@ubuntu:~/[[ROOT]]/test$ +``` + +### Notions + +- https://doc.rust-lang.org/rust-by-example/fn/closures.html