diff --git a/rust/tests/banner_test/Cargo.lock b/rust/tests/banner_test/Cargo.lock new file mode 100644 index 00000000..585ef531 --- /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 00000000..7f992125 --- /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 00000000..c0500785 --- /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 00000000..7c71d7d5 --- /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 00000000..cd7019e9 --- /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 00000000..394a074f --- /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 00000000..fbb752c6 --- /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 00000000..3d3c9f42 --- /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 00000000..186fe157 --- /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 00000000..21a3eb4f --- /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 00000000..dd5627fa --- /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 00000000..6685e5a2 --- /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 00000000..a780a192 --- /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 00000000..0e66dff7 --- /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 00000000..7dde7fad --- /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 00000000..e8c66fec --- /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 00000000..48ea8173 --- /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 00000000..46274a8d --- /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 00000000..96620325 --- /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 00000000..f4fb40ac --- /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 00000000..955cc920 --- /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 00000000..7a10ca74 --- /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 00000000..1fbf15c0 --- /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 00000000..d970a526 --- /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 00000000..c2398e29 --- /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 00000000..a263be69 --- /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 00000000..05c2b114 --- /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 00000000..894679a3 --- /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 00000000..0f7fc5e2 --- /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 00000000..a1ffdc8b --- /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 00000000..9e26dfee --- /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 00000000..2341ac78 --- /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 00000000..9dfc54f5 --- /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 00000000..e6454b0c --- /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 00000000..1c86b25f --- /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 00000000..9e13f696 --- /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 00000000..cb24962c --- /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 00000000..fd96b59d --- /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 00000000..8839639a --- /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 00000000..249a3caa --- /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