flagon-io/hello

public

Greets people from the command line. The sample repository for g1t.

hello/src/lib.rs

138 lines3,510 bytesCodeBlame
1//! Greetings.
2
3/// Parsed command-line options.
4#[derive(Debug, Default, PartialEq, Eq)]
5pub struct Options {
6 /// The name to greet, if one was given.
7 pub name: Option<String>,
8 /// Whether to upper-case the greeting (`--shout`).
9 pub shout: bool,
10}
11
12/// Parses command-line arguments (excluding the program name).
13///
14/// `--shout` sets [`Options::shout`]; other arguments starting with `--` are
15/// treated as flags and skipped. The name is the first remaining argument.
16pub fn parse_args<I: IntoIterator<Item = String>>(args: I) -> Options {
17 let mut options = Options::default();
18 for arg in args {
19 if arg == "--shout" {
20 options.shout = true;
21 } else if !arg.starts_with("--") && options.name.is_none() {
22 options.name = Some(arg);
23 }
24 }
25 options
26}
27
28/// `text` upper-cased.
29pub fn shout(text: &str) -> String {
30 text.to_uppercase()
31}
32
33/// The greeting for `name`.
34pub fn greeting(name: &str) -> String {
35 let trimmed = name.trim();
36 let display_name = if trimmed.is_empty() { "world" } else { trimmed };
37 format!("Hello, {display_name}!")
38}
39
40/// The farewell for `name`.
41pub fn farewell(name: &str) -> String {
42 let trimmed = name.trim();
43 let display_name = if trimmed.is_empty() { "world" } else { trimmed };
44 format!("Goodbye, {display_name}!")
45}
46
47#[cfg(test)]
48mod tests {
49 use super::*;
50
51 fn args(list: &[&str]) -> Vec<String> {
52 list.iter().map(|s| s.to_string()).collect()
53 }
54
55 #[test]
56 fn parse_args_no_args() {
57 assert_eq!(parse_args(args(&[])).name, None);
58 }
59
60 #[test]
61 fn parse_args_name() {
62 assert_eq!(parse_args(args(&["Ada"])).name.as_deref(), Some("Ada"));
63 }
64
65 #[test]
66 fn parse_args_skips_leading_flag() {
67 assert_eq!(
68 parse_args(args(&["--unknown", "Ada"])).name.as_deref(),
69 Some("Ada")
70 );
71 }
72
73 #[test]
74 fn parse_args_shout_defaults_off() {
75 assert!(!parse_args(args(&["Ada"])).shout);
76 }
77
78 #[test]
79 fn parse_args_shout_before_name() {
80 let options = parse_args(args(&["--shout", "Ada"]));
81 assert!(options.shout);
82 assert_eq!(options.name.as_deref(), Some("Ada"));
83 }
84
85 #[test]
86 fn parse_args_shout_after_name() {
87 let options = parse_args(args(&["Ada", "--shout"]));
88 assert!(options.shout);
89 assert_eq!(options.name.as_deref(), Some("Ada"));
90 }
91
92 #[test]
93 fn parse_args_shout_alone() {
94 let options = parse_args(args(&["--shout"]));
95 assert!(options.shout);
96 assert_eq!(options.name, None);
97 }
98
99 #[test]
100 fn shout_upper_cases_greeting() {
101 assert_eq!(shout(&greeting("Ada")), "HELLO, ADA!");
102 }
103
104 #[test]
105 fn greets_by_name() {
106 assert_eq!(greeting("Ada"), "Hello, Ada!");
107 }
108
109 #[test]
110 fn greets_world_with_empty_string() {
111 assert_eq!(greeting(""), "Hello, world!");
112 }
113
114 #[test]
115 fn greets_world_with_whitespace_only() {
116 assert_eq!(greeting(" "), "Hello, world!");
117 }
118
119 #[test]
120 fn trims_whitespace_from_name() {
121 assert_eq!(greeting(" Ada "), "Hello, Ada!");
122 }
123
124 #[test]
125 fn says_goodbye_by_name() {
126 assert_eq!(farewell("Ada"), "Goodbye, Ada!");
127 }
128
129 #[test]
130 fn says_goodbye_to_world_when_blank() {
131 assert_eq!(farewell(" "), "Goodbye, world!");
132 }
133
134 #[test]
135 fn farewell_trims_whitespace() {
136 assert_eq!(farewell(" Ada "), "Goodbye, Ada!");
137 }
138}