How to do it...

  1. In the bin folder, create a file called interior_mutability.rs.

  2. Add the following code and run it with cargo test --bin interior_mutability:

1    trait EmailSender { 
2 fn send_mail(&self, msg: &Email) -> Option<String>;
3 }
4
5 #[derive(Debug, Clone)]
6 struct Email {
7 from: String,
8 to: String,
9 msg: String,
10 }
11
12 #[derive(Debug)]
13 struct Customer {
14 address: String,
15 wants_news: bool,
16 }
17
18 // Send news to every customer that wants to receive them
19 fn publish_news(msg: &str, sender: &EmailSender, customers: &
[Customer]) -> Option<i32> {
20 let mut count = 0;
21 let mut mail = Email {
22 from: "Rust Newsletter".to_string(),
23 to: "".to_string(),
24 msg: msg.to_string(),
25 };
26 for customer in customers {
27 if !customer.wants_news {
28 continue;
29 }
30 mail.to = customer.address.to_string();
31 if sender.send_mail(&mail).is_none() {
32 return None;
33 }
34 count += 1;
35 }
36 Some(count)
37 }
38
39 fn main() {
40 // No code running as we are concentrating on the tests instead
41 }
42
43
44 #[cfg(test)]
45 mod tests {
46 use super::*;
47 use std::cell::RefCell;
48
49 struct MockEmailSender {
50 // sent_mails can be modified even if MockEmailSender is
immutable
51 sent_mails: RefCell<Vec<Email>>,
52 }
53 impl MockEmailSender {
54 fn new() -> Self {
55 MockEmailSender {
56 sent_mails: RefCell::new(Vec::new()),
57 }
58 }
59 }
60
61 impl EmailSender for MockEmailSender {
62 fn send_mail(&self, msg: &Email) -> Option<String> {
63 // Borrow sent_mails mutably
64 self.sent_mails.borrow_mut().push(msg.clone());
65 Some("200 OK".to_string())
66 }
67 }
68
69 #[test]
70 fn sends_zero_to_zero_customers() {
71 let sent = publish_news("hello world!",
&MockEmailSender::new(), &[]);
72 assert_eq!(Some(0), sent);
73 }
74
75 #[test]
76 fn sends_one_to_one_willing() {
77 let customer = Customer {
78 address: "[email protected]".to_string(),
79 wants_news: true,
80 };
81 let sent = publish_news("hello world!",
&MockEmailSender::new(), &[customer]);
82 assert_eq!(Some(1), sent);
83 }
84
85 #[test]
86 fn sends_none_to_unwilling() {
87 let customer_one = Customer {
88 address: "[email protected]".to_string(),
89 wants_news: false,
90 };
91 let customer_two = Customer {
92 address: "[email protected]".to_string(),
93 wants_news: false,
94 };
95 let sent = publish_news(
96 "hello world!",
97 &MockEmailSender::new(),
98 &[customer_one, customer_two],
99 );
100 assert_eq!(Some(0), sent);
101 }
102
103 #[test]
104 fn sends_correct_mail() {
105 let customer = Customer {
106 address: "[email protected]".to_string(),
107 wants_news: true,
108 };
109 let sender = MockEmailSender::new();
110 publish_news("hello world!", &sender, &
[customer]).expect("Failed to send mail");
111
112 // Borrow sent_mails immutable
113 let mails = sender.sent_mails.borrow();
114 assert_eq!(1, mails.len());
115 assert_eq!("Rust Newsletter", mails[0].from);
116 assert_eq!("[email protected]", mails[0].to);
117 assert_eq!("hello world!", mails[0].msg);
118 }
119 }
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.116.118.229