diff --git a/Dockerfile b/Dockerfile index a2fd7f3b..d99a8c13 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ ### Test Image specific config -FROM rust:1.85-slim-bookworm +FROM rust:1.86-slim-bookworm RUN apt-get update RUN apt-get -y install pkg-config libssl-dev moreutils diff --git a/solutions/borrow_box/src/lib.rs b/solutions/borrow_box/src/lib.rs index 08dac0ad..0d0e37db 100644 --- a/solutions/borrow_box/src/lib.rs +++ b/solutions/borrow_box/src/lib.rs @@ -1,139 +1,59 @@ +use std::cmp::Ordering; + #[derive(Debug, Clone, Eq, PartialEq)] pub struct GameSession { pub id: u32, - pub p1: (String, u16), - pub p2: (String, u16), - pub nb_games: u16, + pub p1: (String, u32), + pub p2: (String, u32), + pub nb_games: u32, } impl GameSession { - // create the box - pub fn new(id: u32, p1_name: String, p2_name: String, nb_games: u16) -> Box { - Box::new(GameSession { + #[inline] + pub fn new(id: u32, p1_name: String, p2_name: String, nb_games: u32) -> GameSession { + GameSession { id, - p1: (p1_name, 0), - p2: (p2_name, 0), + p1: (p1_name, Default::default()), + p2: (p2_name, Default::default()), nb_games, - }) - } - - // read from the box using the reference `&` - // return only the player that as the bigger score - pub fn read_winner(&self) -> (String, u16) { - if self.p1.1 > self.p2.1 { - self.p1.clone() - } else if self.p1.1 < self.p2.1 { - self.p2.clone() - } else { - (String::from("Same score! tied"), self.p2.1) } } - pub fn update_score(&mut self, user_name: String) { - if self.p1.1 + self.p2.1 < self.nb_games - && self.p1.1 * 2 <= self.nb_games - && self.p2.1 * 2 <= self.nb_games - { - if self.p1.0 == user_name { - self.p1.1 += 1; - } else if self.p2.0 == user_name { - self.p2.1 += 1; - } + #[inline] + pub fn read_winner(&self) -> Option<&(String, u32)> { + match self.p1.1.cmp(&self.p2.1) { + Ordering::Greater => Some(&self.p1), + Ordering::Less => Some(&self.p2), + Ordering::Equal => None, } } - pub fn delete(self) -> String { - String::from(format!("game deleted: id -> {:?}", self.id)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - fn create_games() -> Vec> { - vec![ - GameSession::new(0, String::from("player1"), String::from("player2"), 1), - GameSession::new(1, String::from("Alice"), String::from("Mark"), 3), - GameSession::new(2, String::from("Jack"), String::from("Miller"), 5), - ] - } - - #[test] - fn test_create() { - let games = create_games(); - assert_eq!( - *games[0], - GameSession { - id: 0, - p1: (String::from("player1"), 0), - p2: (String::from("player2"), 0), - nb_games: 1 - } - ); - assert_eq!( - *games[1], - GameSession { - id: 1, - p1: (String::from("Alice"), 0), - p2: (String::from("Mark"), 0), - nb_games: 3 - } - ); - assert_eq!( - *games[2], - GameSession { - id: 2, - p1: (String::from("Jack"), 0), - p2: (String::from("Miller"), 0), - nb_games: 5 - } - ); + #[inline] + fn game_ended(&self) -> bool { + self.p1.1 * 2 > self.nb_games + || self.p2.1 * 2 > self.nb_games + || self.p1.1 + self.p2.1 == self.nb_games } - #[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 nb_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)); + pub fn update_score(&mut self, user_name: &str) { + if self.game_ended() { + return; + } - 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) - ); + let player = if self.p1.0 == user_name { + &mut self.p1 + } else if self.p2.0 == user_name { + &mut self.p2 + } else { + return; + }; - games[2].update_score(String::from("Jack")); - assert_eq!(games[2].read_winner(), (String::from("Jack"), 3)); + player.1 += 1; } - #[test] - fn test_delete() { - let game = GameSession::new(0, String::from("Alice"), String::from("Mark"), 3); - let game1 = GameSession::new(23, String::from("Jack"), String::from("Miller"), 1); + pub fn delete(self) -> String { + let id = self.id; - assert_eq!(game.delete(), String::from("game deleted: id -> 0")); - assert_eq!(game1.delete(), String::from("game deleted: id -> 23")); + format!("game deleted: id -> {id}") } - - // #[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/solutions/bowling_score/src/lib.rs b/solutions/bowling_score/src/lib.rs index 159f3a39..d8b267c5 100644 --- a/solutions/bowling_score/src/lib.rs +++ b/solutions/bowling_score/src/lib.rs @@ -5,10 +5,10 @@ pub enum Error { } pub struct BowlingGame { - rolls: Vec, - pins_left: u16, - rolls_in_frame: u16, - fill_balls: u16, + rolls: Vec, + pins_left: u32, + rolls_in_frame: u32, + fill_balls: u32, } impl BowlingGame { @@ -21,7 +21,7 @@ impl BowlingGame { } } - pub fn roll(&mut self, pins: u16) -> Result<(), Error> { + pub fn roll(&mut self, pins: u32) -> Result<(), Error> { if pins > self.pins_left { return Err(Error::NotEnoughPinsLeft); } else if self.rolls.len() >= 20 && self.fill_balls == 0 { @@ -48,7 +48,7 @@ impl BowlingGame { Ok(()) } - fn strike_or_spare(&mut self, pins: u16) { + fn strike_or_spare(&mut self, pins: u32) { if self.rolls_in_frame == 2 { self.rolls_in_frame -= 1; self.rolls.push(0); @@ -61,7 +61,7 @@ impl BowlingGame { } } - pub fn score(&self) -> Option { + pub fn score(&self) -> Option { if self.rolls.len() < 20 || self.fill_balls != 0 { return None; } diff --git a/solutions/box_it/src/lib.rs b/solutions/box_it/src/lib.rs index 87f3e7cf..d69a1902 100644 --- a/solutions/box_it/src/lib.rs +++ b/solutions/box_it/src/lib.rs @@ -1,106 +1,15 @@ -/* -## 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 - -### Notions - -- https://doc.rust-lang.org/book/ch15-00-smart-pointers.html -- https://doc.rust-lang.org/book/ch15-01-box.html - -*/ -fn convert(s: &str) -> u32 { - let mut a = s.to_string(); - a.pop(); - let n = a.parse::().unwrap(); - (n * 1000.0) as u32 -} - -pub fn transform_and_save_on_heap(s: String) -> Box> { - let mut v: Vec = Vec::new(); - - for token in s.split_whitespace() { - if token.contains("k") { - v.push(convert(token)); - } else { - v.push(token.parse::().unwrap()); - } - } - Box::new(v) -} - -pub fn take_value_ownership(a: Box>) -> Vec { - *a -} - -/* -// Example : - -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))); - // output : - // | Box value : [6800, 13500] - // | size occupied in the stack : 8 bytes - // | value : [6800, 13500] - // | size occupied in the stack : 24 bytes - - // 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); - } +pub fn parse_into_boxed(s: String) -> Vec> { + s.split_ascii_whitespace() + .map(|v| { + if let Some(v) = v.strip_suffix('k') { + Box::new((v.parse::().unwrap() * 1000.) as _) + } else { + Box::new(v.parse().unwrap()) + } + }) + .collect() +} + +pub fn into_unboxed(a: Vec>) -> Vec { + a.into_iter().map(|b| *b).collect() } diff --git a/solutions/box_recursion/src/lib.rs b/solutions/box_recursion/src/lib.rs index 373732c2..44a7d5be 100644 --- a/solutions/box_recursion/src/lib.rs +++ b/solutions/box_recursion/src/lib.rs @@ -1,4 +1,23 @@ -#[derive(Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum Role { + CEO, + Manager, + Worker, +} + +impl From<&str> for Role { + #[inline] + fn from(role: &str) -> Self { + match role { + "CEO" => Role::CEO, + "Manager" => Role::Manager, + "Normal Worker" => Role::Worker, + _ => unreachable!(), + } + } +} + +#[derive(Default, Debug)] pub struct WorkEnvironment { pub grade: Link, } @@ -7,23 +26,25 @@ pub type Link = Option>; #[derive(Debug)] pub struct Worker { - pub role: String, + pub role: Role, pub name: String, pub next: Link, } impl WorkEnvironment { - pub fn new() -> WorkEnvironment { - WorkEnvironment { grade: None } + #[inline] + pub fn new() -> Self { + Self::default() } - pub fn add_worker(&mut self, role: String, name: String) { - let new_node = Box::new(Worker { - role: role, - name: name, + pub fn add_worker(&mut self, name: &str, role: &str) { + let worker = Worker { + role: Role::from(role), + name: name.to_owned(), next: self.grade.take(), - }); - self.grade = Some(new_node); + }; + + self.grade = Some(Box::new(worker)); } pub fn remove_worker(&mut self) -> Option { @@ -33,9 +54,9 @@ impl WorkEnvironment { }) } - pub fn last_worker(&self) -> Option<(String, String)> { + pub fn last_worker(&self) -> Option<(String, Role)> { self.grade .as_ref() - .map(|node| (node.name.clone(), node.role.clone())) + .map(|node| (node.name.clone(), node.role)) } } diff --git a/solutions/drop_the_thread/src/lib.rs b/solutions/drop_the_thread/src/lib.rs index 63c9a25f..c138fec6 100644 --- a/solutions/drop_the_thread/src/lib.rs +++ b/solutions/drop_the_thread/src/lib.rs @@ -1,23 +1,24 @@ use std::cell::{Cell, RefCell}; -#[derive(Debug, Default, Clone, Eq, PartialEq)] -pub struct Workers { +#[derive(Debug, Default)] +pub struct ThreadPool { pub drops: Cell, pub states: RefCell>, } -impl Workers { - pub fn new() -> Workers { - Workers::default() +impl ThreadPool { + #[inline] + pub fn new() -> Self { + Default::default() } - pub fn new_worker(&self, c: String) -> (usize, Thread) { - let g = Thread::new_thread(self.track_worker(), c, self); + pub fn new_thread(&self, c: String) -> (usize, Thread) { + let g = Thread::new(self.thread_len(), c, self); self.states.borrow_mut().push(false); (g.pid, g) } - pub fn track_worker(&self) -> usize { + pub fn thread_len(&self) -> usize { self.states.borrow().len() } @@ -25,7 +26,7 @@ impl Workers { self.states.borrow()[id] } - pub fn add_drop(&self, id: usize) { + pub fn drop_thread(&self, id: usize) { if self.is_dropped(id) { panic!("{:?} is already dropped", id) } @@ -34,29 +35,28 @@ impl Workers { } } -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug)] pub struct Thread<'a> { pub pid: usize, pub cmd: String, - pub parent: &'a Workers, + pub parent: &'a ThreadPool, } impl<'a> Thread<'a> { - pub fn new_thread(p: usize, c: String, t: &'a Workers) -> Thread { - Thread { + #[inline] + pub fn new(p: usize, c: String, t: &'a ThreadPool) -> Self { + Self { pid: p, cmd: c, parent: t, } } - pub fn skill(self) { - drop(self); - } + pub fn skill(self) {} } -impl<'a> Drop for Thread<'a> { +impl Drop for Thread<'_> { fn drop(&mut self) { - self.parent.add_drop(self.pid); + self.parent.drop_thread(self.pid); } } diff --git a/solutions/how_many_references/src/lib.rs b/solutions/how_many_references/src/lib.rs index beaa4e16..6b14c015 100644 --- a/solutions/how_many_references/src/lib.rs +++ b/solutions/how_many_references/src/lib.rs @@ -1,172 +1,27 @@ -/* -## how many references +use std::rc::Rc; -### Instructions - -Create the following functions : - -- `add_element` 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 - -### Notions - -- https://doc.rust-lang.org/book/ch15-04-rc.html -- https://doc.rust-lang.org/std/rc/struct.Rc.html - -*/ - -pub use std::rc::Rc; - -#[derive(Debug)] pub struct Node { pub ref_list: Vec>, } impl Node { - pub fn new(ref_list: Vec>) -> Node { - Node { ref_list: ref_list } + #[inline] + pub fn new(ref_list: Vec>) -> Self { + Self { ref_list } } - pub fn add_element(&mut self, v: Rc) { - self.ref_list.push(v); + #[inline] + pub fn add_element(&mut self, element: Rc) { + self.ref_list.push(element); } - pub fn rm_all_ref(&mut self, v: Rc) { - self.ref_list.retain(|x| is_same_allocate(x, &v)); + #[inline] + pub fn rm_all_ref(&mut self, element: Rc) { + self.ref_list.retain(|e| !Rc::ptr_eq(&element, e)); } } -fn is_same_allocate(x: &Rc, v: &Rc) -> bool { - if is_eq(x, v) { - return v != x; - } - return true; -} - -pub fn how_many_references(value: &Rc) -> usize { - Rc::strong_count(value) -} - -fn is_eq(value: &Rc, cmp: &Rc) -> bool { - Rc::ptr_eq(value, cmp) -} - -/* -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_element(b.clone()); - new_node.add_element(a.clone()); - new_node.add_element(c.clone()); - new_node.add_element(a.clone()); - - println!("a: {:?}", how_many_references(&a)); - println!("b: {:?}", how_many_references(&b)); - println!("c: {:?}", how_many_references(&c)); - /* - output: - a: 4 - b: 2 - c: 2 - */ - 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)); - /* - output: - a: 1 - b: 2 - c: 2 - */ -} -*/ - -#[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_element(a.clone()); - new_node.add_element(b.clone()); - new_node.add_element(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_element(b.clone()); - new_node.add_element(a.clone()); - new_node.add_element(c.clone()); - new_node.add_element(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); - } +#[inline] +pub fn how_many_references(ref_list: &Rc) -> usize { + Rc::strong_count(ref_list) } diff --git a/solutions/ref_cell/src/lib.rs b/solutions/ref_cell/src/lib.rs index 6378588d..f1ac4f4a 100644 --- a/solutions/ref_cell/src/lib.rs +++ b/solutions/ref_cell/src/lib.rs @@ -1,302 +1,49 @@ -/* -## ref_cell +use std::{cell::RefCell, rc::Rc}; -### Instructions - -#### First part (messenger.rs) - -Create a module named `messenger`. This module will be able to inform a user of how many references of a given value they are using. -The main objective of this module is to limit how many times a value is referenced. - -For this module the following must be created: - -Implement `Logger`: a trait which implements the following three functions: - -```rust -fn warning(&self, msg: &str); -fn info(&self, msg: &str); -fn error(&self, msg: &str); -``` - -Implement the `Tracker` structure with the following fields: - -- `logger`: a reference to `Logger`. -- `value`: the count of how many times the value was referenced. It should not exceed `max`. -- `max`: the max count of references. - -Add the following associated functions to `Tracker`: - -- `new`: that initializes the structure. -- `set_value`: that sets the `value`. It should compare the number of references to `value` and `max` to work out the percentage used. It should write to the following traits if it exceeds the specified usage percentage: - - percentage >= 100%: `"Error: you are over your quota!"` should be written to `error`. - - percentage >= 70% and percentage < 100%: `"Warning: you have used up over X% of your quota! Proceeds with precaution"` should be written to `warning`, where `X` should be replaced with the calculated percentage. -- `peek`: that will take a peek at how much usage the variable already has. It should write `"Info: you are using up to X% of your quota"` to the `info` trait function. `X` should be replaced with the calculated percentage. - -### Second part (lib.rs) - -Now that you've created `messenger`, you can now create the following: - -Create the `Worker` structure with the following fields: - -- `track_value`: which is the value that will be tracked by the tracker. -- `mapped_messages`: that will store the latest messages from the `Logger` trait functions. This will be a HashMap. The key will represent the type of message (`info`, `error` or `warning`), and the value will be the actual message. -- `all_messages`: that will be a vector of **all** messages sent. - -Create the following associated functions for `Worker`: - -- `new`: that initializes a `Worker` structure. -- `Logger`: 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 field of the `Worker` structure. - -You must use **interior mutability**, this means it must be possible to mutate data, even when there are immutable references to that data. Consequently, the user will not need to use the keyword `mut`. _tip:_ RefCell. - -### Usage - -Here is a program to test your function, - -```rust -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()); +pub struct Tracker { + pub messages: RefCell>, + value: RefCell, + max: usize, } -``` -And its output: - -```console -$ cargo run -("Info", "you are using up to 40% of your quota") -("Warning", "you have used up over 90% of your quota! Proceeds with precaution") -("Error", "you are over your quota!") -[ - "Info: you are using up to 40% of your quota", - "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!" -] -$ -``` - -### Notions - -- [std::cell::RefCell](https://doc.rust-lang.org/std/cell/struct.RefCell.html) -- [Struct std::rc::Rc](https://doc.rust-lang.org/std/rc/struct.Rc.html) - - -*/ - -mod messenger; -pub use messenger::*; -pub use std::collections::HashMap; - -#[derive(Clone, Debug)] -pub struct Worker { - pub track_value: Rc, - pub mapped_messages: RefCell>, - pub all_messages: RefCell>, -} - -impl Worker { - pub fn new(s: usize) -> Worker { - Worker { - track_value: Rc::new(s), - mapped_messages: RefCell::new(HashMap::new()), - all_messages: RefCell::new(vec![]), - } - } -} - -impl Logger for Worker { - fn warning(&self, message: &str) { - let v: Vec<&str> = message.split(": ").collect(); - self.mapped_messages - .borrow_mut() - .insert(v[0].to_string(), v[1].to_string()); - self.all_messages.borrow_mut().push(message.to_string()); - } - fn info(&self, message: &str) { - let v: Vec<&str> = message.split(": ").collect(); - self.mapped_messages - .borrow_mut() - .insert(v[0].to_string(), v[1].to_string()); - self.all_messages.borrow_mut().push(message.to_string()); +impl Tracker { + #[inline] + fn convert_percentage(max: usize, v: usize) -> usize { + (100 * v) / max } - fn error(&self, message: &str) { - let v: Vec<&str> = message.split(": ").collect(); - self.mapped_messages - .borrow_mut() - .insert(v[0].to_string(), v[1].to_string()); - self.all_messages.borrow_mut().push(message.to_string()); - } -} -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_module() { - #[derive(Clone, Debug)] - struct TestMs { - value: Rc, - ms: RefCell>, - correct: Vec, + #[inline] + pub fn new(max: usize) -> Self { + Self { + value: Default::default(), + max, + messages: Default::default(), } + } - 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()); - } + pub fn set_value(&self, value: &Rc) { + let count = Rc::strong_count(value); + if count > self.max { + self.messages + .borrow_mut() + .push("Error: You can't go over your quota!".to_owned()); + return; } - let l = TestMs { - value: Rc::new(115), - ms: RefCell::new(vec![]), - correct: vec![ - String::from("Info: you are using up to 40% of your quota"), - String::from( - "Warning: you have used up over 80% of your quota! Proceeds with precaution", - ), - String::from("Error: you are over your quota!"), - ], - }; + self.value.replace(count); + let percentage_of_max = Self::convert_percentage(self.max, count); - 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]) + if percentage_of_max >= 70 { + self.messages.borrow_mut().push(format!( + "Warning: You have used up over {percentage_of_max}% of your quota!" + )); } } - #[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 to 83% of your quota" - ); - - 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 to 91% of your quota" - ); - - 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 to 40% of your quota", - "Warning: you have used up over 80% of your quota! Proceeds with precaution", - "Info: you are using up to 80% of your quota", - "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]); - } + pub fn peek(&self, value: &Rc) { + let percentage_of_max = Self::convert_percentage(self.max, Rc::strong_count(value)); + self.messages.borrow_mut().push(format!( + "Info: This value would use {percentage_of_max}% of your quota" + )); } } diff --git a/solutions/ref_cell/src/messenger.rs b/solutions/ref_cell/src/messenger.rs deleted file mode 100644 index cae23f0b..00000000 --- a/solutions/ref_cell/src/messenger.rs +++ /dev/null @@ -1,52 +0,0 @@ -pub use std::cell::RefCell; -pub use std::rc::Rc; - -pub trait Logger { - fn warning(&self, msg: &str); - fn info(&self, msg: &str); - fn error(&self, msg: &str); -} - -#[derive(Debug, Clone)] -pub struct Tracker<'a, T: Logger> { - logger: &'a T, - value: RefCell, - max: usize, -} - -impl<'a, T> Tracker<'a, T> -where - T: Logger, -{ - pub fn new(logger: &T, max: usize) -> Tracker { - Tracker { - logger, - value: RefCell::new(0), - max, - } - } - - pub fn set_value(&self, value: &Rc) { - self.value.replace(Rc::strong_count(value)); - let percentage_of_max = convert_percentage(self.max, Rc::strong_count(&value)); - - if percentage_of_max >= 100 { - self.logger.error("Error: you are over your quota!"); - return; - } else if percentage_of_max >= 70 { - self.logger - .warning(&format!("Warning: you have used up over {percentage_of_max}% of your quota! Proceeds with precaution")); - } - } - - pub fn peek(&self, value: &Rc) { - let percentage_of_max = convert_percentage(self.max, Rc::strong_count(&value)); - self.logger.info(&format!( - "Info: you are using up to {percentage_of_max}% of your quota" - )) - } -} - -fn convert_percentage(max: usize, v: usize) -> usize { - (100 * v) / max -} diff --git a/tests/borrow_box_test/src/lib.rs b/tests/borrow_box_test/src/lib.rs new file mode 100644 index 00000000..59aaf772 --- /dev/null +++ b/tests/borrow_box_test/src/lib.rs @@ -0,0 +1,66 @@ +use borrow_box::*; + +#[inline] +fn games() -> [GameSession; 3] { + [ + GameSession::new(0, "player1".to_owned(), "player2".to_owned(), 1), + GameSession::new(1, "Alice".to_owned(), "Mark".to_owned(), 3), + GameSession::new(2, "Jack".to_owned(), "Miller".to_owned(), 5), + ] +} + +#[test] +fn test_update_and_read() { + let mut games = games(); + games[0].update_score("player1"); + assert_eq!(games[0].read_winner(), Some(&("player1".to_owned(), 1))); + + games[0].update_score("player2"); + // this will stay the same because the nb_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(), Some(&("player1".to_owned(), 1))); + + games[2].update_score("Jack"); + games[2].update_score("Jack"); + games[2].update_score("Miller"); + games[2].update_score("Miller"); + assert_eq!(games[2].read_winner(), None); + + games[2].update_score("Jack"); + assert_eq!(games[2].read_winner(), Some(&("Jack".to_owned(), 3))); +} + +#[test] +fn test_stop_updating() { + let mut games = games(); + games[0].update_score("player1"); + games[0].update_score("player1"); + assert_eq!(games[0].read_winner(), Some(&("player1".to_owned(), 1))); + + games[2].update_score("Jack"); + games[2].update_score("Jack"); + games[2].update_score("Jack"); + games[2].update_score("Jack"); + games[2].update_score("Jack"); + assert_eq!(games[2].read_winner(), Some(&("Jack".to_owned(), 3))); +} + +#[test] +fn test_delete() { + let game = GameSession::new(0, "Alice".to_owned(), "Mark".to_owned(), 3); + let game1 = GameSession::new(23, "Jack".to_owned(), "Miller".to_owned(), 1); + + assert_eq!(game.delete(), String::from("game deleted: id -> 0")); + assert_eq!(game1.delete(), String::from("game deleted: id -> 23")); +} + +#[test] +fn test_different_name() { + let mut game = GameSession::new(0, "Alice".to_owned(), "Mark".to_owned(), 3); + + game.update_score("Mark"); + assert_eq!(game.read_winner(), Some(&("Mark".to_owned(), 1))); + + game.update_score("Miller"); + assert_eq!(game.read_winner(), Some(&("Mark".to_owned(), 1))); +} diff --git a/tests/borrow_box_test/src/main.rs b/tests/borrow_box_test/src/main.rs deleted file mode 100644 index fa5994cc..00000000 --- a/tests/borrow_box_test/src/main.rs +++ /dev/null @@ -1,144 +0,0 @@ -use borrow_box::*; - -fn main() { - let mut game = GameSession::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 nb_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![ - GameSession::new(0, String::from("player1"), String::from("player2"), 1), - GameSession::new(1, String::from("Alice"), String::from("Mark"), 3), - GameSession::new(2, String::from("Jack"), String::from("Miller"), 5), - ] - } - - #[test] - fn test_create() { - let games = create_games(); - assert_eq!( - *games[0], - GameSession { - id: 0, - p1: (String::from("player1"), 0), - p2: (String::from("player2"), 0), - nb_games: 1 - } - ); - assert_eq!( - *games[1], - GameSession { - id: 1, - p1: (String::from("Alice"), 0), - p2: (String::from("Mark"), 0), - nb_games: 3 - } - ); - assert_eq!( - *games[2], - GameSession { - id: 2, - p1: (String::from("Jack"), 0), - p2: (String::from("Miller"), 0), - nb_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 nb_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_stop_updating() { - let mut games = create_games(); - games[0].update_score(String::from("player1")); - games[0].update_score(String::from("player1")); - 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("Jack")); - games[2].update_score(String::from("Jack")); - games[2].update_score(String::from("Jack")); - assert_eq!(games[2].read_winner(), (String::from("Jack"), 3)); - } - - #[test] - fn test_delete() { - let game = GameSession::new(0, String::from("Alice"), String::from("Mark"), 3); - let game1 = GameSession::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] - fn test_different_name() { - let mut game = GameSession::new(0, String::from("Alice"), String::from("Mark"), 3); - - game.update_score(String::from("Mark")); - assert_eq!(game.read_winner(), (String::from("Mark"), 1)); - - game.update_score(String::from("Miller")); - assert_eq!(game.read_winner(), (String::from("Mark"), 1)); - } - - // #[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/tests/bowling_score_test/src/lib.rs b/tests/bowling_score_test/src/lib.rs new file mode 100644 index 00000000..31604b69 --- /dev/null +++ b/tests/bowling_score_test/src/lib.rs @@ -0,0 +1,91 @@ +use bowling_score::*; + +#[test] +fn test_subject_example() { + let mut game = BowlingGame::new(); + let _ = game.roll(0); + let _ = game.roll(10); + let _ = game.roll(10); + let _ = game.roll(5); + let _ = game.roll(5); + let _ = game.roll(10); + let _ = game.roll(10); + let _ = game.roll(10); + let _ = game.roll(10); + let _ = game.roll(10); + let _ = game.roll(10); + let _ = game.roll(10); + let _ = game.roll(2); + let _ = game.roll(8); + + assert_eq!(Some(252), game.score()); +} + +#[test] +fn test_not_enough_pins() { + let mut game = BowlingGame::new(); + assert_eq!(game.roll(11), Err(Error::NotEnoughPinsLeft)); + let _ = game.roll(6); + assert_eq!(game.roll(5), Err(Error::NotEnoughPinsLeft)); +} + +#[test] +fn test_perfect_game() { + let mut game = BowlingGame::new(); + for _ in 0..12 { + let _ = game.roll(10); + } + assert_eq!(game.score(), Some(300)); +} + +#[test] +fn test_game_already_complete() { + let mut game = BowlingGame::new(); + for _ in 0..10 { + let _ = game.roll(0); + let _ = game.roll(0); + } + assert_eq!(game.roll(0), Err(Error::GameComplete)); +} + +#[test] +fn test_only_one_fill_ball_after_spare() { + let mut game = BowlingGame::new(); + for _ in 0..9 { + let _ = game.roll(0); + let _ = game.roll(0); + } + assert!(game.roll(5).is_ok()); + assert!(game.roll(5).is_ok()); + assert!(game.roll(2).is_ok()); + assert_eq!(game.roll(0), Err(Error::GameComplete)); + assert_eq!(Some(12), game.score()); +} + +#[test] +fn test_two_fill_balls_after_strike() { + let mut game = BowlingGame::new(); + for _ in 0..9 { + let _ = game.roll(0); + let _ = game.roll(0); + } + assert!(game.roll(10).is_ok()); + assert!(game.roll(1).is_ok()); + assert!(game.roll(1).is_ok()); + assert_eq!(game.roll(0), Err(Error::GameComplete)); + assert_eq!(Some(12), game.score()); +} + +#[test] +fn test_no_more_balls_after_fill_balls_even_on_strikes() { + let mut game = BowlingGame::new(); + for _ in 0..9 { + let _ = game.roll(0); + let _ = game.roll(0); + } + assert!(game.roll(10).is_ok()); + assert!(game.roll(10).is_ok()); + assert!(game.roll(10).is_ok()); + assert_eq!(game.roll(0), Err(Error::GameComplete)); + assert_eq!(Some(30), game.score()); +} diff --git a/tests/bowling_score_test/src/main.rs b/tests/bowling_score_test/src/main.rs deleted file mode 100644 index 40b46f8f..00000000 --- a/tests/bowling_score_test/src/main.rs +++ /dev/null @@ -1,122 +0,0 @@ -use bowling_score::*; - -fn main() -> Result<(), Error> { - let mut game = BowlingGame::new(); - game.roll(0)?; // frame 1 - game.roll(10)?; // frame 1: spare - game.roll(10)?; // frame 2: strike - game.roll(5)?; // frame 3 - game.roll(5)?; // frame 3: spare - game.roll(10)?; // frame 4: strike - game.roll(10)?; // frame 5: strike - game.roll(10)?; // frame 6: strike - game.roll(10)?; // frame 7: strike - game.roll(10)?; // frame 8: strike - game.roll(10)?; // frame 9: strike - game.roll(10)?; // frame 10: strike - game.roll(2)?; // fill ball 1 - game.roll(8)?; // fill ball 2 - println!("{:?}", game.score()); - - let mut perfect_game = BowlingGame::new(); - for _ in 0..12 { - perfect_game.roll(10)?; - } - println!("{:?}", perfect_game.score()); - Ok(()) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_subject_example() { - let mut game = BowlingGame::new(); - let _ = game.roll(0); - let _ = game.roll(10); - let _ = game.roll(10); - let _ = game.roll(5); - let _ = game.roll(5); - let _ = game.roll(10); - let _ = game.roll(10); - let _ = game.roll(10); - let _ = game.roll(10); - let _ = game.roll(10); - let _ = game.roll(10); - let _ = game.roll(10); - let _ = game.roll(2); - let _ = game.roll(8); - - assert_eq!(Some(252), game.score()); - } - - #[test] - fn test_not_enough_pins() { - let mut game = BowlingGame::new(); - assert_eq!(game.roll(11), Err(Error::NotEnoughPinsLeft)); - let _ = game.roll(6); - assert_eq!(game.roll(5), Err(Error::NotEnoughPinsLeft)); - } - - #[test] - fn test_perfect_game() { - let mut game = BowlingGame::new(); - for _ in 0..12 { - let _ = game.roll(10); - } - assert_eq!(game.score(), Some(300)); - } - - #[test] - fn test_game_already_complete() { - let mut game = BowlingGame::new(); - for _ in 0..10 { - let _ = game.roll(0); - let _ = game.roll(0); - } - assert_eq!(game.roll(0), Err(Error::GameComplete)); - } - - #[test] - fn test_only_one_fill_ball_after_spare() { - let mut game = BowlingGame::new(); - for _ in 0..9 { - let _ = game.roll(0); - let _ = game.roll(0); - } - assert!(game.roll(5).is_ok()); - assert!(game.roll(5).is_ok()); - assert!(game.roll(2).is_ok()); - assert_eq!(game.roll(0), Err(Error::GameComplete)); - assert_eq!(Some(12), game.score()); - } - - #[test] - fn test_two_fill_balls_after_strike() { - let mut game = BowlingGame::new(); - for _ in 0..9 { - let _ = game.roll(0); - let _ = game.roll(0); - } - assert!(game.roll(10).is_ok()); - assert!(game.roll(1).is_ok()); - assert!(game.roll(1).is_ok()); - assert_eq!(game.roll(0), Err(Error::GameComplete)); - assert_eq!(Some(12), game.score()); - } - - #[test] - fn test_no_more_balls_after_fill_balls_even_on_strikes() { - let mut game = BowlingGame::new(); - for _ in 0..9 { - let _ = game.roll(0); - let _ = game.roll(0); - } - assert!(game.roll(10).is_ok()); - assert!(game.roll(10).is_ok()); - assert!(game.roll(10).is_ok()); - assert_eq!(game.roll(0), Err(Error::GameComplete)); - assert_eq!(Some(30), game.score()); - } -} diff --git a/tests/box_it_test/src/lib.rs b/tests/box_it_test/src/lib.rs new file mode 100644 index 00000000..7179476b --- /dev/null +++ b/tests/box_it_test/src/lib.rs @@ -0,0 +1,47 @@ +use std::{fmt::Debug, mem}; + +use box_it::*; + +fn run_test(s: &str, expected: T, predicate: impl FnOnce(String) -> T) { + let new = predicate(s.to_owned()); + + assert_eq!(new, expected); + assert_eq!(mem::size_of_val(&new), mem::size_of::()); +} + +#[test] +fn test_transform() { + run_test( + "5.5k 8.9k 32", + vec![Box::new(5500), Box::new(8900), Box::new(32)], + parse_into_boxed, + ); + run_test( + "6.8k 13.5k", + vec![Box::new(6800), Box::new(13500)], + parse_into_boxed, + ); + run_test( + "20.3k 3.8k 7.7k 992", + vec![ + Box::new(20300), + Box::new(3800), + Box::new(7700), + Box::new(992), + ], + parse_into_boxed, + ); +} + +#[test] +fn test_take_value_from_box() { + run_test("5.5k 8.9k 32", vec![5500, 8900, 32], |v| { + into_unboxed(parse_into_boxed(v)) + }); + run_test("6.8k 13.5k", vec![6800, 13500], |v| { + into_unboxed(parse_into_boxed(v)) + }); + run_test("20.3k 3.8k 7.7k 992", vec![20300, 3800, 7700, 992], |v| { + into_unboxed(parse_into_boxed(v)) + }); +} diff --git a/tests/box_it_test/src/main.rs b/tests/box_it_test/src/main.rs deleted file mode 100644 index 394a3b4c..00000000 --- a/tests/box_it_test/src/main.rs +++ /dev/null @@ -1,62 +0,0 @@ -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/tests/box_recursion_test/src/lib.rs b/tests/box_recursion_test/src/lib.rs new file mode 100644 index 00000000..54da9619 --- /dev/null +++ b/tests/box_recursion_test/src/lib.rs @@ -0,0 +1,77 @@ +use box_recursion::*; + +#[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("Marie", "CEO"); + list.remove_worker(); + assert!(list.grade.is_none()); +} + +#[test] +fn test_two_workers() { + let mut list = WorkEnvironment::new(); + list.add_worker("Marie", "CEO"); + list.add_worker("Monica", "Manager"); + list.remove_worker(); + + assert_eq!(list.grade.as_ref().unwrap().role, Role::CEO); + assert_eq!(list.grade.as_ref().unwrap().name, "Marie".to_owned()); +} + +#[test] +fn test_more_workers() { + let mut list = WorkEnvironment::new(); + list.add_worker("Marie", "CEO"); + list.add_worker("Monica", "Manager"); + list.add_worker("Ana", "Normal Worker"); + list.add_worker("Alice", "Normal Worker"); + list.remove_worker(); + + assert_eq!(list.grade.as_ref().unwrap().role, Role::Worker); + assert_eq!(list.grade.as_ref().unwrap().name, "Ana".to_owned()); + + list.remove_worker(); + list.remove_worker(); + + assert_eq!(list.grade.as_ref().unwrap().role, Role::CEO); + assert_eq!(list.grade.as_ref().unwrap().name, "Marie".to_owned()); +} + +#[test] +fn test_last_worker() { + let mut list = WorkEnvironment::new(); + list.add_worker("Marie", "CEO"); + list.add_worker("Monica", "Manager"); + list.add_worker("Ana", "Normal Worker"); + list.add_worker("Alice", "Normal Worker"); + + assert_eq!( + list.last_worker(), + Some(("Alice".to_owned(), Role::Worker)) + ); + + list.remove_worker(); + assert_eq!( + list.last_worker(), + Some(("Ana".to_owned(), Role::Worker)) + ); + + list.remove_worker(); + assert_eq!( + list.last_worker(), + Some(("Monica".to_owned(), Role::Manager)) + ); + + list.remove_worker(); + assert_eq!( + list.last_worker(), + Some(("Marie".to_owned(), Role::CEO)) + ); +} diff --git a/tests/box_recursion_test/src/main.rs b/tests/box_recursion_test/src/main.rs deleted file mode 100644 index 7ebfa031..00000000 --- a/tests/box_recursion_test/src/main.rs +++ /dev/null @@ -1,98 +0,0 @@ -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.last_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().role, "CEO"); - assert_eq!(list.grade.as_ref().unwrap().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().role, "Normal Worker"); - assert_eq!(list.grade.as_ref().unwrap().name, "Ana"); - - list.remove_worker(); - list.remove_worker(); - assert_eq!(list.grade.as_ref().unwrap().role, "CEO"); - assert_eq!(list.grade.as_ref().unwrap().name, "Marie"); - } - - #[test] - fn test_last_worker() { - 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.last_worker().unwrap(), - (String::from("Alice"), String::from("Normal Worker")) - ); - - list.remove_worker(); - assert_eq!( - list.last_worker().unwrap(), - (String::from("Ana"), String::from("Normal Worker")) - ); - - list.remove_worker(); - assert_eq!( - list.last_worker().unwrap(), - (String::from("Monica"), String::from("Manager")) - ); - - list.remove_worker(); - assert_eq!( - list.last_worker().unwrap(), - (String::from("Marie"), String::from("CEO")) - ); - } -} diff --git a/tests/drop_the_thread_test/src/lib.rs b/tests/drop_the_thread_test/src/lib.rs new file mode 100644 index 00000000..c748faa3 --- /dev/null +++ b/tests/drop_the_thread_test/src/lib.rs @@ -0,0 +1,64 @@ +use std::rc::Rc; + +use drop_the_thread::*; + +#[test] +fn tests_drops_are_correct() { + let worker = ThreadPool::new(); + let (pid, thread) = worker.new_thread(String::from("gnome-shell")); + let (pid0, thread0) = worker.new_thread(String::from("i3")); + let (pid1, thread1) = worker.new_thread(String::from("shell")); + let (pid2, thread2) = worker.new_thread(String::from("spotify")); + + thread.skill(); + assert_eq!(worker.drops.get(), 1); + 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); + + thread1.skill(); + thread2.skill(); + + assert_eq!(worker.drops.get(), 4); +} + +#[test] +fn test_drops_only_happen_without_further_references() { + let worker = ThreadPool::new(); + let (_, thread) = worker.new_thread(String::from("Xorg")); + let thread = Rc::new(thread); + + { + let _thread_clone = Rc::clone(&thread); + } + + assert_eq!(worker.drops.get(), 0); +} + +#[test] +#[should_panic(expected = "0 is already dropped")] +fn test_dropping_dropped_thread_panics() { + let worker = ThreadPool::new(); + let (_pid, thread) = worker.new_thread(String::from("gsd-rfkill")); + thread.skill(); + + let thread_clone = Thread { + pid: 0, + cmd: "gsd-rfkill".to_owned(), + parent: &worker, + }; + thread_clone.skill(); +} diff --git a/tests/drop_the_thread_test/src/main.rs b/tests/drop_the_thread_test/src/main.rs deleted file mode 100644 index b00b3335..00000000 --- a/tests/drop_the_thread_test/src/main.rs +++ /dev/null @@ -1,72 +0,0 @@ -use drop_the_thread::*; - -fn main() { -} - -#[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/tests/how_many_references_test/src/lib.rs b/tests/how_many_references_test/src/lib.rs new file mode 100644 index 00000000..306c7edd --- /dev/null +++ b/tests/how_many_references_test/src/lib.rs @@ -0,0 +1,79 @@ +use std::rc::Rc; + +use how_many_references::*; + +#[test] +fn test_add_element() { + let a = Rc::new("a".to_owned()); + let b = Rc::new("b".to_owned()); + let c = Rc::new("c".to_owned()); + + let mut new_node = Node::new(vec![Rc::clone(&a)]); + new_node.add_element(Rc::clone(&a)); + new_node.add_element(Rc::clone(&b)); + new_node.add_element(Rc::clone(&c)); + + assert_eq!(new_node.ref_list, vec![Rc::clone(&a), a, b, c]); +} + +#[test] +fn test_how_many_references() { + let a = Rc::new("a".to_owned()); + let b = Rc::new("b".to_owned()); + let c = Rc::new("c".to_owned()); + let d = Rc::new("d".to_owned()); + + let mut new_node = Node::new(Vec::new()); + new_node.add_element(b.clone()); + new_node.add_element(a.clone()); + new_node.add_element(c.clone()); + new_node.add_element(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("a".to_owned()); + let b = Rc::new("b".to_owned()); + let c = Rc::new("c".to_owned()); + let d = Rc::new("d".to_owned()); + + let a1 = Rc::new("a".to_owned()); + let b1 = Rc::new("b".to_owned()); + let c1 = Rc::new("c".to_owned()); + let d1 = Rc::new("d".to_owned()); + + 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/tests/how_many_references_test/src/main.rs b/tests/how_many_references_test/src/main.rs deleted file mode 100644 index c794e6ab..00000000 --- a/tests/how_many_references_test/src/main.rs +++ /dev/null @@ -1,103 +0,0 @@ -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_element(b.clone()); - new_node.add_element(a.clone()); - new_node.add_element(c.clone()); - new_node.add_element(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_element(a.clone()); - new_node.add_element(b.clone()); - new_node.add_element(c.clone()); - - assert_eq!(new_node.ref_list, 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_element(b.clone()); - new_node.add_element(a.clone()); - new_node.add_element(c.clone()); - new_node.add_element(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/tests/ref_cell_test/src/lib.rs b/tests/ref_cell_test/src/lib.rs new file mode 100644 index 00000000..bf4662b3 --- /dev/null +++ b/tests/ref_cell_test/src/lib.rs @@ -0,0 +1,87 @@ +use std::{cell::RefCell, rc::Rc}; + +use ref_cell::*; + +#[test] +fn test_one() { + let expected_messages = [ + "Info: This value would use 40% of your quota", + "Warning: You have used up over 80% of your quota!", + "Warning: You have used up over 100% of your quota!", + "Error: You can't go over your quota!", + ]; + + let value = Rc::new(42); + + let track = Tracker::new(5); + let _v = Rc::clone(&value); + track.peek(&value); // 40% + let _v = Rc::clone(&value); + let _v = Rc::clone(&value); + track.set_value(&value); // 80% + let _v = Rc::clone(&value); + track.set_value(&value); // 100% + let _v = Rc::clone(&value); + track.set_value(&value); // >100% + + assert_eq!(track.messages.borrow().as_slice(), expected_messages); +} + +#[test] +fn test_two() { + let value = Rc::new(100); + + let track = Tracker::new(12); + let _v = Rc::clone(&value); + let _v = Rc::clone(&value); + let _v = Rc::clone(&value); + let _v = Rc::clone(&value); + let _v = Rc::clone(&value); + let _v = Rc::clone(&value); + let _v = Rc::clone(&value); + let _v = Rc::clone(&value); + + track.set_value(&value); + + let _v = Rc::clone(&value); + + track.set_value(&value); + assert_eq!( + track.messages.borrow().last().unwrap(), + "Warning: You have used up over 83% of your quota!" + ); + + track.peek(&value); + assert_eq!( + track.messages.borrow().last().unwrap(), + "Info: This value would use 83% of your quota" + ); + + let _v = Rc::clone(&value); + track.peek(&value); + assert_eq!( + track.messages.borrow().last().unwrap(), + "Info: This value would use 91% of your quota" + ); + + let _v = Rc::clone(&value); + track.set_value(&value); + assert_eq!( + track.messages.borrow().last().unwrap(), + "Warning: You have used up over 100% of your quota!" + ); + + let _v = Rc::clone(&value); + + track.peek(&value); + assert_eq!( + track.messages.borrow().last().unwrap(), + "Info: This value would use 108% of your quota" + ); + + track.set_value(&value); + assert_eq!( + track.messages.borrow().last().unwrap(), + "Error: You can't go over your quota!" + ); +} diff --git a/tests/ref_cell_test/src/main.rs b/tests/ref_cell_test/src/main.rs deleted file mode 100644 index 455242de..00000000 --- a/tests/ref_cell_test/src/main.rs +++ /dev/null @@ -1,176 +0,0 @@ -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 to 40% of your quota"), - 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 to 83% of your quota" - ); - - 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 to 91% of your quota" - ); - - 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 to 40% of your quota", - "Warning: you have used up over 80% of your quota! Proceeds with precaution", - "Info: you are using up to 80% of your quota", - "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]); - } - } -}