Skip to content

Commit

Permalink
fix: return non-zero exit code in expected error cases
Browse files Browse the repository at this point in the history
* When trying to delete coauthor but no coauthor found with given key
* When trying to mob with co-author key but no co-author found with given key
* When trying to select co-author for mob session but no co-author added

Improves names of tests to be more precise and clearer
  • Loading branch information
Mubashwer committed Mar 27, 2024
1 parent 410fbed commit 215586a
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 95 deletions.
19 changes: 6 additions & 13 deletions src/cli.rs
Expand Up @@ -45,24 +45,19 @@ enum Commands {
Coauthor(Coauthor),
}

pub fn run(
coauthor_repo: &impl CoauthorRepo,
out: &mut impl Write,
err: &mut impl Write,
) -> Result<(), Box<dyn Error>> {
pub fn run(coauthor_repo: &impl CoauthorRepo, out: &mut impl Write) -> Result<(), Box<dyn Error>> {
let cli = Cli::parse();
run_inner(&cli, coauthor_repo, out, err)
run_inner(&cli, coauthor_repo, out)
}

fn run_inner(
cli: &Cli,
coauthor_repo: &impl CoauthorRepo,
out: &mut impl Write,
err: &mut impl Write,
) -> Result<(), Box<dyn Error>> {
match &cli.command {
None => cli.mob.handle(coauthor_repo, out, err)?,
Some(Commands::Coauthor(coauthor)) => coauthor.handle(coauthor_repo, out, err)?,
None => cli.mob.handle(coauthor_repo, out)?,
Some(Commands::Coauthor(coauthor)) => coauthor.handle(coauthor_repo, out)?,
}
Ok(())
}
Expand Down Expand Up @@ -94,8 +89,7 @@ mod tests {
};

let mut out = Vec::new();
let mut err = Vec::new();
run_inner(&cli, &mock_coauthor_repo, &mut out, &mut err)?;
run_inner(&cli, &mock_coauthor_repo, &mut out)?;

Ok(())
}
Expand Down Expand Up @@ -130,8 +124,7 @@ mod tests {
};

let mut out = Vec::new();
let mut err = Vec::new();
run_inner(&cli, &mock_coauthor_repo, &mut out, &mut err)?;
run_inner(&cli, &mock_coauthor_repo, &mut out)?;

Ok(())
}
Expand Down
31 changes: 12 additions & 19 deletions src/commands/coauthor.rs
Expand Up @@ -27,12 +27,11 @@ impl Coauthor {
&self,
coauthor_repo: &impl CoauthorRepo,
out: &mut impl Write,
err: &mut impl Write,
) -> Result<(), Box<dyn std::error::Error>> {
if let Some(key) = self.delete.as_deref() {
match coauthor_repo.get(key)? {
Some(_) => coauthor_repo.remove(key)?,
None => writeln!(err, "No co-author found with key: {key}")?,
None => return Err(format!("No co-author found with key: {key}").into()),
}
}
if self.list {
Expand Down Expand Up @@ -79,15 +78,15 @@ mod tests {
};

let mut out = Vec::new();
let mut err = Vec::new();
coauthor_cmd.handle(&mock_coauthor_repo, &mut out, &mut err)?;
coauthor_cmd.handle(&mock_coauthor_repo, &mut out)?;

assert!(out.is_empty());

Ok(())
}

#[test]
fn test_error_message_shown_when_trying_to_delete_coauthor_with_non_existing_coauthor_key(
) -> Result<(), Box<dyn std::error::Error>> {
fn test_delete_coauthor_when_coauthor_not_found() -> Result<(), Box<dyn std::error::Error>> {
let key = "em";
let mut mock_coauthor_repo = MockCoauthorRepo::new();
mock_coauthor_repo
Expand All @@ -103,13 +102,10 @@ mod tests {
};

let mut out = Vec::new();
let mut err = Vec::new();
coauthor_cmd.handle(&mock_coauthor_repo, &mut out, &mut err)?;
let result = coauthor_cmd.handle(&mock_coauthor_repo, &mut out);

assert_eq!(
err,
format!("No co-author found with key: {key}\n").as_bytes()
);
assert!(result
.is_err_and(|err| err.to_string() == format!("No co-author found with key: {key}")));

Ok(())
}
Expand Down Expand Up @@ -137,8 +133,7 @@ mod tests {
};

let mut out = Vec::new();
let mut err = Vec::new();
coauthor_cmd.handle(&mock_coauthor_repo, &mut out, &mut err)?;
coauthor_cmd.handle(&mock_coauthor_repo, &mut out)?;

assert_eq!(out, format!("{name} <{email}>\n").as_bytes());

Expand Down Expand Up @@ -167,16 +162,15 @@ mod tests {
};

let mut out = Vec::new();
let mut err = Vec::new();
coauthor_cmd.handle(&mock_coauthor_repo, &mut out, &mut err)?;
coauthor_cmd.handle(&mock_coauthor_repo, &mut out)?;

assert_eq!(out, expected_output.as_bytes());

Ok(())
}

#[test]
fn test_list_coauthors_when_list_is_empty() -> Result<(), Box<dyn std::error::Error>> {
fn test_list_coauthors_when_no_coauthors_added() -> Result<(), Box<dyn std::error::Error>> {
let mut mock_coauthor_repo = MockCoauthorRepo::new();
mock_coauthor_repo
.expect_list()
Expand All @@ -190,8 +184,7 @@ mod tests {
};

let mut out = Vec::new();
let mut err = Vec::new();
coauthor_cmd.handle(&mock_coauthor_repo, &mut out, &mut err)?;
coauthor_cmd.handle(&mock_coauthor_repo, &mut out)?;

assert_eq!(out, b"");

Expand Down
61 changes: 22 additions & 39 deletions src/commands/mob.rs
Expand Up @@ -33,7 +33,6 @@ impl Mob {
&self,
coauthor_repo: &impl CoauthorRepo,
out: &mut impl Write,
err: &mut impl Write,
) -> Result<(), Box<dyn Error>> {
if self.clear {
coauthor_repo.clear_mob()?;
Expand Down Expand Up @@ -64,11 +63,9 @@ impl Mob {
Some([]) => {
let coauthors = coauthor_repo.list(false)?;
if coauthors.is_empty() {
writeln!(
err,
"No co-author(s) found. At least one co-author must be added"
)?;
return Ok(());
return Err(
"No co-author(s) found. At least one co-author must be added".into(),
);
}

let result = MultiSelect::new("Select active co-author(s):", coauthors)
Expand All @@ -94,7 +91,7 @@ impl Mob {
coauthor_repo.add_to_mob(&coauthor)?;
coauthors.push(coauthor);
}
None => writeln!(err, "No co-author found with key: {key}")?,
None => return Err(format!("No co-author found with key: {key}").into()),
}
}

Expand All @@ -117,7 +114,7 @@ mod tests {
use mockall::predicate;

#[test]
fn test_clear_mob_session() -> Result<(), Box<dyn Error>> {
fn test_clear_mob() -> Result<(), Box<dyn Error>> {
let mut mock_coauthor_repo = MockCoauthorRepo::new();
mock_coauthor_repo
.expect_clear_mob()
Expand All @@ -132,14 +129,13 @@ mod tests {
};

let mut out = Vec::new();
let mut err = Vec::new();
mob_cmd.handle(&mock_coauthor_repo, &mut out, &mut err)?;
mob_cmd.handle(&mock_coauthor_repo, &mut out)?;

Ok(())
}

#[test]
fn test_list_mob_coauthors() -> Result<(), Box<dyn Error>> {
fn test_list_mob() -> Result<(), Box<dyn Error>> {
let coauthors = vec![
"Leo Messi <leo.messi@example.com>".to_owned(),
"Emi Martinez <emi.martinez@example.com>".to_owned(),
Expand All @@ -161,16 +157,15 @@ mod tests {
};

let mut out = Vec::new();
let mut err = Vec::new();
mob_cmd.handle(&mock_coauthor_repo, &mut out, &mut err)?;
mob_cmd.handle(&mock_coauthor_repo, &mut out)?;

assert_eq!(out, expected_output.as_bytes());

Ok(())
}

#[test]
fn test_list_mob_coauthors_when_mob_session_is_empty() -> Result<(), Box<dyn Error>> {
fn test_list_mob_when_mob_session_is_empty() -> Result<(), Box<dyn Error>> {
let mut mock_coauthor_repo = MockCoauthorRepo::new();
mock_coauthor_repo
.expect_list_mob()
Expand All @@ -185,8 +180,7 @@ mod tests {
};

let mut out = Vec::new();
let mut err = Vec::new();
mob_cmd.handle(&mock_coauthor_repo, &mut out, &mut err)?;
mob_cmd.handle(&mock_coauthor_repo, &mut out)?;

assert_eq!(out, b"");

Expand Down Expand Up @@ -214,8 +208,7 @@ mod tests {
};

let mut out = Vec::new();
let mut err = Vec::new();
mob_cmd.handle(&mock_coauthor_repo, &mut out, &mut err)?;
mob_cmd.handle(&mock_coauthor_repo, &mut out)?;

assert_eq!(out, b"Co-authored-by: Leo Messi <leo.messi@example.com>\nCo-authored-by: Emi Martinez <emi.martinez@example.com>\n");

Expand All @@ -238,17 +231,15 @@ mod tests {
};

let mut out = Vec::new();
let mut err = Vec::new();
mob_cmd.handle(&mock_coauthor_repo, &mut out, &mut err)?;
mob_cmd.handle(&mock_coauthor_repo, &mut out)?;

assert_eq!(out, b"");

Ok(())
}

#[test]
fn test_error_message_shown_when_trying_to_mob_given_coauthors_list_is_empty(
) -> Result<(), Box<dyn Error>> {
fn test_mob_with_given_no_coauthors_added() -> Result<(), Box<dyn Error>> {
let coauthors = vec![];

let mut mock_coauthor_repo = MockCoauthorRepo::new();
Expand All @@ -266,19 +257,16 @@ mod tests {
};

let mut out = Vec::new();
let mut err = Vec::new();
mob_cmd.handle(&mock_coauthor_repo, &mut out, &mut err)?;
let result = mob_cmd.handle(&mock_coauthor_repo, &mut out);

assert_eq!(
err,
b"No co-author(s) found. At least one co-author must be added\n"
);
assert!(result.is_err_and(|err| err.to_string()
== "No co-author(s) found. At least one co-author must be added".to_string()));

Ok(())
}

#[test]
fn test_adding_coauthors_to_mob_session_by_keys() -> Result<(), Box<dyn Error>> {
fn test_mob_with_by_keys() -> Result<(), Box<dyn Error>> {
let keys = vec!["lm".to_owned(), "em".to_owned()];
let coauthors = [
"Leo Messi <leo.messi@example.com>",
Expand Down Expand Up @@ -319,17 +307,15 @@ mod tests {
};

let mut out = Vec::new();
let mut err = Vec::new();
mob_cmd.handle(&mock_coauthor_repo, &mut out, &mut err)?;
mob_cmd.handle(&mock_coauthor_repo, &mut out)?;

assert_eq!(out, format!("{}\n", coauthors.join("\n")).as_bytes());

Ok(())
}

#[test]
fn test_error_message_shown_when_trying_to_mob_while_passing_non_existing_coauthor_key(
) -> Result<(), Box<dyn Error>> {
fn test_mob_with_by_key_when_coauthor_not_found() -> Result<(), Box<dyn Error>> {
let key = "lm";

let mut mock_coauthor_repo = MockCoauthorRepo::new();
Expand All @@ -351,13 +337,10 @@ mod tests {
};

let mut out = Vec::new();
let mut err = Vec::new();
mob_cmd.handle(&mock_coauthor_repo, &mut out, &mut err)?;
let result = mob_cmd.handle(&mock_coauthor_repo, &mut out);

assert_eq!(
err,
format!("No co-author found with key: {key}\n").as_bytes()
);
assert!(result
.is_err_and(|err| err.to_string() == format!("No co-author found with key: {key}")));

Ok(())
}
Expand Down
8 changes: 2 additions & 6 deletions src/main.rs
@@ -1,13 +1,9 @@
use git_mob_tool::{cli, coauthor_repo::GitConfigCoauthorRepo};
use std::{
error::Error,
io::{stderr, stdout},
};
use std::{error::Error, io::stdout};

fn main() -> Result<(), Box<dyn Error>> {
let coauthor_repo = GitConfigCoauthorRepo {};
let out = &mut stdout();
let err = &mut stderr();
cli::run(&coauthor_repo, out, err)?;
cli::run(&coauthor_repo, out)?;
Ok(())
}
8 changes: 5 additions & 3 deletions tests/coauthor.rs
Expand Up @@ -110,12 +110,14 @@ fn test_delete_coauthor(ctx: TestContextCli) -> Result<(), Box<dyn Error>> {

#[test_context(TestContextCli, skip_teardown)]
#[test]
fn test_delete_coauthor_no_coauthor_found(ctx: TestContextCli) -> Result<(), Box<dyn Error>> {
fn test_delete_coauthor_when_coauthor_not_found(ctx: TestContextCli) -> Result<(), Box<dyn Error>> {
ctx.git()
.args(["mob", "coauthor", "--delete", "lm"])
.assert()
.success()
.stderr(predicate::str::diff("No co-author found with key: lm\n"));
.failure()
.stderr(predicate::str::diff(
"Error: \"No co-author found with key: lm\"\n",
));

Ok(())
}

0 comments on commit 215586a

Please sign in to comment.