Skip to content

Commit 92c2449

Browse files
committed
Refactor error handling and messages
1 parent bbf335c commit 92c2449

File tree

2 files changed

+90
-26
lines changed

2 files changed

+90
-26
lines changed

src/constants.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
use std::fmt;
2+
3+
#[derive(Debug)]
4+
pub enum Message {
5+
BadOption,
6+
SOURCE1,
7+
SOURCE2,
8+
JSON1,
9+
JSON2,
10+
UnknownError,
11+
NoMismatch,
12+
RootMismatch,
13+
LeftExtra,
14+
RightExtra,
15+
Mismatch,
16+
}
17+
18+
impl fmt::Display for Message {
19+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
20+
let message = match self {
21+
Message::BadOption => "Invalid option.",
22+
Message::SOURCE1 => "Could not read source1.",
23+
Message::SOURCE2 => "Could not read source2.",
24+
Message::JSON1 => "Could not parse source1.",
25+
Message::JSON2 => "Could not parse source2.",
26+
Message::UnknownError => "",
27+
Message::NoMismatch => "No mismatch was found.",
28+
Message::RootMismatch => "Mismatch at root.",
29+
Message::LeftExtra => "Extra on left",
30+
Message::RightExtra => "Extra on right",
31+
Message::Mismatch => "Mismatched",
32+
};
33+
34+
write!(f, "{}", message)
35+
}
36+
}

src/main.rs

Lines changed: 54 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,57 +6,80 @@ use std::collections::HashMap;
66
use std::collections::HashSet;
77
use std::fmt;
88
use std::fs;
9+
use std::process;
910
use std::str::FromStr;
1011
use structopt::StructOpt;
12+
use constants::Message;
13+
14+
mod constants;
15+
16+
const HELP: &str = r#"
17+
Example:
18+
json_diff f source1.json source2.json
19+
json_diff d '{...}' '{...}'
20+
21+
Option:
22+
f : read input from json files
23+
d : read input from command line"#;
1124

1225
#[derive(Debug)]
1326
struct AppError {
14-
message: String,
27+
message: Message,
1528
}
1629
impl fmt::Display for AppError {
1730
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1831
write!(f, "{}", self.message)
1932
}
2033
}
2134

22-
enum CliOptions {
35+
enum InputReadMode {
2336
D,
2437
F,
2538
}
26-
impl FromStr for CliOptions {
39+
impl FromStr for InputReadMode {
2740
type Err = AppError;
2841
fn from_str(s: &str) -> Result<Self, Self::Err> {
2942
match s {
30-
"d" => Ok(CliOptions::D),
31-
"f" => Ok(CliOptions::F),
43+
"d" => Ok(InputReadMode::D),
44+
"f" => Ok(InputReadMode::F),
3245
_ => Err(Self::Err {
33-
message: "BAD option".to_string(),
46+
message: Message::BadOption,
3447
}),
3548
}
3649
}
3750
}
3851

3952
#[derive(StructOpt)]
53+
#[structopt(about = HELP)]
4054
struct Cli {
41-
option: CliOptions,
55+
read_mode: InputReadMode,
4256
source1: String,
4357
source2: String,
4458
}
4559

60+
fn error_exit(message: constants::Message) -> ! {
61+
eprintln!("{}", message);
62+
process::exit(1);
63+
}
64+
4665
fn main() {
4766
let args = Cli::from_args();
4867

49-
let (data1, data2) = match args.option {
50-
CliOptions::D => (args.source1, args.source2),
51-
CliOptions::F => {
52-
(fs::read_to_string(args.source1)
53-
.expect(&format!("Error occurred while reading source1")),
54-
fs::read_to_string(args.source2)
55-
.expect(&format!("Error occurred while reading source2")))
68+
let (data1, data2) = match args.read_mode {
69+
InputReadMode::D => (args.source1, args.source2),
70+
InputReadMode::F => {
71+
if let Ok(d1) = fs::read_to_string(args.source1) {
72+
if let Ok(d2) = fs::read_to_string(args.source2) {
73+
(d1, d2)
74+
} else {
75+
error_exit(Message::SOURCE2);
76+
}
77+
} else {
78+
error_exit(Message::SOURCE1);
79+
}
5680
}
5781
};
5882
display_output(compare_jsons(&data1, &data2));
59-
6083
}
6184

6285
fn display_output(result: Mismatch) {
@@ -66,42 +89,42 @@ fn display_output(result: Mismatch) {
6689
keys_in_both: KeyNode::Nil,
6790
};
6891
if no_mismatch == result {
69-
println!("No mismatch was found.");
92+
println!("{}", Message::NoMismatch);
7093
} else {
7194
match result.keys_in_both {
7295
KeyNode::Node(_) => {
7396
let mut keys = Vec::new();
7497
result.keys_in_both.absolute_keys(&mut keys, None);
75-
println!("Mismatched:");
98+
println!("{}:", Message::Mismatch);
7699
for key in keys {
77100
println!("{}", key);
78101
}
79102
}
80-
KeyNode::Value(_, _) => println!("Mismatch at root."),
103+
KeyNode::Value(_, _) => println!("{}", Message::RootMismatch),
81104
KeyNode::Nil => (),
82105
}
83106
match result.left_only_keys {
84107
KeyNode::Node(_) => {
85108
let mut keys = Vec::new();
86109
result.left_only_keys.absolute_keys(&mut keys, None);
87-
println!("Extra on left:");
110+
println!("{}:", Message::LeftExtra);
88111
for key in keys {
89112
println!("{}", key.red().bold());
90113
}
91114
}
92-
KeyNode::Value(_, _) => (), // TODO left_only_keys should never be Value type => Throw an error
115+
KeyNode::Value(_, _) => error_exit(Message::UnknownError),
93116
KeyNode::Nil => (),
94117
}
95118
match result.right_only_keys {
96119
KeyNode::Node(_) => {
97120
let mut keys = Vec::new();
98121
result.right_only_keys.absolute_keys(&mut keys, None);
99-
println!("Extra on right:");
122+
println!("{}:", Message::RightExtra);
100123
for key in keys {
101124
println!("{}", key.green().bold());
102125
}
103126
}
104-
KeyNode::Value(_, _) => (), // TODO right_only_keys should never be Value type => Throw an error
127+
KeyNode::Value(_, _) => error_exit(Message::UnknownError),
105128
KeyNode::Nil => (),
106129
}
107130
}
@@ -162,10 +185,15 @@ impl Mismatch {
162185
}
163186

164187
fn compare_jsons(a: &str, b: &str) -> Mismatch {
165-
let value1: Value = serde_json::from_str(a).unwrap();
166-
let value2: Value = serde_json::from_str(b).unwrap();
167-
168-
match_json(&value1, &value2)
188+
if let Ok(value1) = serde_json::from_str(a) {
189+
if let Ok(value2) = serde_json::from_str(b) {
190+
match_json(&value1, &value2)
191+
} else {
192+
error_exit(Message::JSON2);
193+
}
194+
} else {
195+
error_exit(Message::JSON1);
196+
}
169197
}
170198

171199
fn match_json(value1: &Value, value2: &Value) -> Mismatch {

0 commit comments

Comments
 (0)