Skip to content

Commit e68188b

Browse files
committed
Add tests to diff.rs
1 parent 01628eb commit e68188b

File tree

1 file changed

+121
-42
lines changed

1 file changed

+121
-42
lines changed

src/diff.rs

Lines changed: 121 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,105 +1,184 @@
11
use crate::undo;
22

3-
use std::collections::HashMap;
3+
use std::collections::BTreeMap;
44
use std::env;
55

6+
trait Logger {
7+
fn print(&mut self, value: String);
8+
}
9+
struct StdoutLogger;
10+
11+
impl Logger for StdoutLogger {
12+
fn print(&mut self, value: String) {
13+
println!("{}", value);
14+
}
15+
}
16+
617
/// print a diff of the env
718
pub fn run(verbose: bool, color: bool, shadowenv_data: String) -> i32 {
8-
let mut parts = shadowenv_data.splitn(2, ":");
19+
run_with_logger(
20+
&mut StdoutLogger {},
21+
env::vars().collect(),
22+
verbose,
23+
color,
24+
shadowenv_data,
25+
)
26+
}
27+
28+
fn run_with_logger(
29+
logger: &mut dyn Logger,
30+
env_vars: Vec<(String, String)>,
31+
verbose: bool,
32+
color: bool,
33+
shadowenv_data: String,
34+
) -> i32 {
35+
let mut parts = shadowenv_data.splitn(2, ':');
936
let _prev_hash = parts.next();
1037
let json_data = parts.next().unwrap_or("{}");
1138
let shadowenv_data = undo::Data::from_str(json_data).unwrap();
12-
let mut scalars = HashMap::new();
13-
for scalar in shadowenv_data.scalars {
14-
scalars.insert(scalar.name.clone(), scalar);
15-
}
16-
let mut lists = HashMap::new();
17-
for list in shadowenv_data.lists {
18-
lists.insert(list.name.clone(), list);
19-
}
20-
for (name, value) in env::vars() {
39+
let mut scalars = shadowenv_data
40+
.scalars
41+
.iter()
42+
.map(|s| (s.name.clone(), s))
43+
.collect::<BTreeMap<_, _>>();
44+
let mut lists = shadowenv_data
45+
.lists
46+
.iter()
47+
.map(|s| (s.name.clone(), s))
48+
.collect::<BTreeMap<_, _>>();
49+
50+
for (name, value) in env_vars {
2151
if let Some(scalar) = scalars.remove(&name) {
22-
diff_scalar(&scalar, color)
52+
diff_scalar(logger, &scalar, color)
2353
} else if let Some(list) = lists.remove(&name) {
24-
diff_list(&list, &value, color)
54+
diff_list(logger, &list, &value, color)
2555
} else if verbose {
26-
print_verbose(&name, &value)
56+
print_verbose(logger, &name, &value)
2757
}
2858
}
29-
for (_name, scalar) in &scalars {
30-
diff_scalar(&scalar, color)
31-
}
32-
for (_name, list) in &lists {
33-
diff_list(&list, &"".to_string(), color)
34-
}
59+
scalars
60+
.iter()
61+
.for_each(|(_name, scalar)| diff_scalar(logger, scalar, color));
62+
lists
63+
.iter()
64+
.for_each(|(_name, list)| diff_list(logger, list, "", color));
3565
0
3666
}
3767

38-
fn diff_list(list: &undo::List, current: &str, color: bool) {
68+
fn diff_list(logger: &mut dyn Logger, list: &undo::List, current: &str, color: bool) {
3969
let formatted_deletions: Vec<String> = if color {
4070
list.deletions
4171
.iter()
42-
.map(|x| "\x1b[48;5;52m".to_string() + &x + &"\x1b[0;91m".to_string())
72+
.map(|x| "\x1b[48;5;52m".to_string() + x + "\x1b[0;91m")
4373
.collect()
4474
} else {
4575
list.deletions.clone()
4676
};
4777
let mut prefix = formatted_deletions.join(":");
48-
let items = current.split(":").collect::<Vec<&str>>();
49-
let items = items
50-
.into_iter()
78+
79+
let items = current
80+
.split(':')
5181
.skip_while(|x| list.additions.contains(&x.to_string()));
5282
let items: Vec<&str> = items.collect();
5383
let suffix = items.join(":");
54-
if suffix != "" && prefix != "" {
84+
if !suffix.is_empty() && !prefix.is_empty() {
5585
prefix += ":";
5686
}
57-
diff_remove(&list.name, &(prefix + &suffix), color);
87+
diff_remove(logger, &list.name, &(prefix + &suffix), color);
5888

59-
let items = current.split(":").collect::<Vec<&str>>();
60-
let items = items.into_iter().map(|x| {
89+
let items = current.split(':').map(|x| {
6190
if list.additions.contains(&x.to_string()) && color {
62-
"\x1b[48;5;22m".to_string() + &x + &("\x1b[0;92m".to_string())
91+
"\x1b[48;5;22m".to_string() + x + "\x1b[0;92m"
6392
} else {
6493
x.to_string()
6594
}
6695
});
6796
let items: Vec<String> = items.collect();
6897
let newline = items.join(":");
69-
diff_add(&list.name, &newline, color);
98+
diff_add(logger, &list.name, &newline, color);
7099
}
71100

72-
fn diff_scalar(scalar: &undo::Scalar, color: bool) {
101+
fn diff_scalar(logger: &mut dyn Logger, scalar: &undo::Scalar, color: bool) {
73102
if let Some(value) = &scalar.original {
74-
diff_remove(&scalar.name, &value, color);
103+
diff_remove(logger, &scalar.name, value, color);
75104
}
76105
if let Some(value) = &scalar.current {
77-
diff_add(&scalar.name, &value, color);
106+
diff_add(logger, &scalar.name, value, color);
78107
}
79108
}
80109

81-
fn diff_add(name: &str, value: &str, color: bool) {
110+
fn diff_add(logger: &mut dyn Logger, name: &str, value: &str, color: bool) {
82111
if color {
83112
// Clearing to EOL with \x1b[K prevents a weird issue where a wrapped line uses the last
84113
// non-null background color for the newline character, filling the rest of the space in the
85114
// line.
86-
println!("\x1b[92m+ {}={}\x1b[0m\x1b[K", name, value);
115+
logger.print(format!("\x1b[92m+ {}={}\x1b[0m\x1b[K", name, value));
87116
} else {
88-
println!("+ {}={}", name, value);
117+
logger.print(format!("+ {}={}", name, value));
89118
}
90119
}
91120

92-
fn diff_remove(name: &str, value: &str, color: bool) {
121+
fn diff_remove(logger: &mut dyn Logger, name: &str, value: &str, color: bool) {
93122
if color {
94123
// Clearing to EOL with \x1b[K prevents a weird issue where a wrapped line uses the last
95124
// non-null background colour for the newline character, filling the rest of the space in the
96125
// line.
97-
println!("\x1b[91m- {}={}\x1b[0m\x1b[K", name, value);
126+
logger.print(format!("\x1b[91m- {}={}\x1b[0m\x1b[K", name, value));
98127
} else {
99-
println!("- {}={}", name, value);
128+
logger.print(format!("- {}={}", name, value));
100129
}
101130
}
102131

103-
fn print_verbose(name: &str, value: &str) {
104-
println!(" {}={}", name, value)
132+
fn print_verbose(logger: &mut dyn Logger, name: &str, value: &str) {
133+
logger.print(format!(" {}={}", name, value))
134+
}
135+
136+
#[cfg(test)]
137+
mod tests {
138+
use super::*;
139+
#[derive(Default)]
140+
struct DummyLogger(Vec<String>);
141+
impl Logger for DummyLogger {
142+
fn print(&mut self, value: String) {
143+
self.0.push(value);
144+
}
145+
}
146+
147+
#[test]
148+
fn nominal_test() {
149+
let mut logger = DummyLogger::default();
150+
151+
let env_vars = vec![(
152+
"MANPATH".to_string(),
153+
"/opt/homebrew/share/man:/opt/homebrew/share/man".to_string(),
154+
)];
155+
156+
let data = r#"8a3f0f24bc3fd12d:{"scalars":[{"name":"REDIS_URL","original":null,"current":"redis://web.railgun:6379/0"},{"name":"CPPFLAGS","original":null,"current":"-DPNG_ARM_NEON_OPT=0"},{"name":"NVM_BIN","original":null,"current":"/Users/xade/.nvm/versions/node/v16.14.2/bin"},{"name":"NVM_PATH","original":null,"current":"/Users/xade/.nvm/versions/node/v16.14.2/lib/node"},{"name":"NVM_DIR","original":null,"current":"/Users/xade/.nvm"},{"name":"NGINX_HOST","original":null,"current":"web.railgun"},{"name":"HOST_BIND_IP","original":null,"current":"192.168.64.1"},{"name":"REDIS_PORT","original":null,"current":"6379"},{"name":"REDIS_HOST","original":null,"current":"web.railgun"},{"name":"NGINX_PORT","original":null,"current":"80"},{"name":"HOST_WEBPACK_IP","original":null,"current":"192.168.64.254"}],"lists":[{"name":"MANPATH","additions":["/Users/xade/.nvm/versions/node/v16.14.2/share/man"],"deletions":[]},{"name":"PATH","additions":["/opt/homebrew/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/bin","/Users/xade/.dev/yarn/1.22.15/bin","/Users/xade/.nvm/versions/node/v16.14.2/bin","/opt/homebrew/opt/[email protected]/bin"],"deletions":[]},{"name":"PKG_CONFIG_PATH","additions":["/opt/homebrew/lib/pkgconfig","/opt/homebrew/opt/zstd/lib/pkgconfig","/opt/homebrew/opt/xz/lib/pkgconfig","/opt/homebrew/opt/sqlite/lib/pkgconfig","/opt/homebrew/opt/readline/lib/pkgconfig","/opt/homebrew/opt/[email protected]/lib/pkgconfig","/opt/homebrew/opt/pcre2/lib/pkgconfig","/opt/homebrew/opt/[email protected]/lib/pkgconfig","/opt/homebrew/opt/lz4/lib/pkgconfig","/opt/homebrew/opt/libsodium/lib/pkgconfig","/opt/homebrew/opt/libevent/lib/pkgconfig","/opt/homebrew/opt/icu4c/lib/pkgconfig","/opt/homebrew/opt/glog/lib/pkgconfig","/opt/homebrew/opt/gflags/lib/pkgconfig","/opt/homebrew/opt/folly/lib/pkgconfig","/opt/homebrew/opt/fmt/lib/pkgconfig","/usr/lib/pkgconfig"],"deletions":[]}]}"#;
157+
let result = run_with_logger(&mut logger, env_vars, true, false, data.to_string());
158+
159+
let expected: Vec<_> = vec![
160+
"- MANPATH=/opt/homebrew/share/man:/opt/homebrew/share/man",
161+
"+ MANPATH=/opt/homebrew/share/man:/opt/homebrew/share/man",
162+
"+ CPPFLAGS=-DPNG_ARM_NEON_OPT=0",
163+
"+ HOST_BIND_IP=192.168.64.1",
164+
"+ HOST_WEBPACK_IP=192.168.64.254",
165+
"+ NGINX_HOST=web.railgun",
166+
"+ NGINX_PORT=80",
167+
"+ NVM_BIN=/Users/xade/.nvm/versions/node/v16.14.2/bin",
168+
"+ NVM_DIR=/Users/xade/.nvm",
169+
"+ NVM_PATH=/Users/xade/.nvm/versions/node/v16.14.2/lib/node",
170+
"+ REDIS_HOST=web.railgun",
171+
"+ REDIS_PORT=6379",
172+
"+ REDIS_URL=redis://web.railgun:6379/0",
173+
"- PATH=",
174+
"+ PATH=",
175+
"- PKG_CONFIG_PATH=",
176+
"+ PKG_CONFIG_PATH=",
177+
]
178+
.iter()
179+
.map(ToString::to_string)
180+
.collect();
181+
assert_eq!(result, 0);
182+
assert_eq!(logger.0, expected);
183+
}
105184
}

0 commit comments

Comments
 (0)