use std::env;
use std::fs;
use std::iter;
use std::path::Path;
use std::process::Command;
use crates::git_checks_core::{BranchCheck, Check, CheckResult, TopicCheck};
use crates::git_workarea::{CommitId, GitContext, Identity};
use crates::itertools;
#[cfg(feature = "config")]
use crates::serde_json;
use crates::tempdir::TempDir;
pub use crates::git_checks_core::GitCheckConfiguration;
pub const FILLER_COMMIT: &str = "d02f015907371738253a22b9a7fec78607a969b2";
pub const TARGET_COMMIT: &str = "27ff3ef5532d76afa046f76f4dd8f588dc3e83c3";
pub const SUBMODULE_TARGET_COMMIT: &str = "fe90ee22ae3ce4b4dc41f8d0876e59355ff1e21c";
fn make_context() -> GitContext {
let gitdir = Path::new(concat!(env!("CARGO_MANIFEST_DIR"), "/../.git"));
if !gitdir.exists() {
panic!("The tests must be run from a git checkout.");
}
GitContext::new(gitdir)
}
pub fn make_temp_dir(test_name: &str) -> TempDir {
let mut working_dir = env::current_exe().unwrap();
working_dir.pop();
TempDir::new_in(working_dir, test_name).unwrap()
}
pub fn make_context_submodule(gitdir: &Path, commit: &CommitId) -> GitContext {
let gitdir = gitdir.join("origin");
let clone = Command::new("git")
.arg("clone")
.arg(concat!(env!("CARGO_MANIFEST_DIR"), "/../.git"))
.arg(&gitdir)
.output()
.unwrap();
if !clone.status.success() {
panic!(
"origin clone failed: {}",
String::from_utf8_lossy(&clone.stderr),
);
}
let ctx = GitContext::new(gitdir.join(".git"));
let checkout = ctx
.git()
.arg("checkout")
.arg(commit.as_str())
.current_dir(&gitdir)
.output()
.unwrap();
if !checkout.status.success() {
panic!(
"checkout failed: {}",
String::from_utf8_lossy(&checkout.stderr),
);
}
let submodule_update = ctx
.git()
.arg("submodule")
.arg("update")
.arg("--init")
.current_dir(&gitdir)
.output()
.unwrap();
if !submodule_update.status.success() {
panic!(
"submodule update failed: {}",
String::from_utf8_lossy(&submodule_update.stderr),
);
}
ctx
}
fn test_check_custom<'a>(
ctx: &GitContext,
test_name: &str,
topic: &str,
base: &str,
conf: &GitCheckConfiguration<'a>,
) -> CheckResult {
conf.run_topic(
&ctx,
test_name,
&CommitId::new(base),
&CommitId::new(topic),
&Identity::new("Rust Git Checks Tests", "rust-git-checks@example.com"),
)
.unwrap()
.into()
}
pub fn test_check_base<'a>(
test_name: &str,
topic: &str,
base: &str,
conf: &GitCheckConfiguration<'a>,
) -> CheckResult {
let ctx = make_context();
test_check_custom(&ctx, test_name, topic, base, conf)
}
pub fn test_check<'a>(
test_name: &str,
topic: &str,
conf: &GitCheckConfiguration<'a>,
) -> CheckResult {
test_check_base(test_name, topic, TARGET_COMMIT, conf)
}
pub fn test_check_submodule_base<'a>(
test_name: &str,
topic: &str,
base: &str,
conf: &GitCheckConfiguration<'a>,
) -> CheckResult {
let tempdir = make_temp_dir(test_name);
let ctx = make_context_submodule(tempdir.path(), &CommitId::new(base));
test_check_custom(&ctx, test_name, topic, base, conf)
}
pub fn test_check_submodule<'a>(
test_name: &str,
topic: &str,
conf: &GitCheckConfiguration<'a>,
) -> CheckResult {
test_check_submodule_base(test_name, topic, SUBMODULE_TARGET_COMMIT, conf)
}
pub fn test_check_submodule_base_configure<'a>(
test_name: &str,
topic: &str,
base: &str,
conf: &GitCheckConfiguration<'a>,
module: &str,
) -> CheckResult {
let tempdir = make_temp_dir(test_name);
let ctx = make_context_submodule(tempdir.path(), &CommitId::new(base));
let moduledir = ctx.gitdir().join("modules").join(module);
fs::create_dir_all(moduledir).unwrap();
test_check_custom(&ctx, test_name, topic, base, conf)
}
pub fn test_check_submodule_configure<'a>(
test_name: &str,
topic: &str,
conf: &GitCheckConfiguration<'a>,
module: &str,
) -> CheckResult {
test_check_submodule_base_configure(test_name, topic, SUBMODULE_TARGET_COMMIT, conf, module)
}
fn no_strings<'a>() -> iter::Empty<&'a String> {
iter::empty()
}
pub fn test_result_warnings(result: CheckResult, warnings: &[&str]) {
itertools::assert_equal(result.warnings(), warnings);
itertools::assert_equal(result.alerts(), no_strings());
itertools::assert_equal(result.errors(), no_strings());
assert_eq!(result.temporary(), false);
assert_eq!(result.allowed(), false);
assert_eq!(result.pass(), true);
}
pub fn test_result_errors(result: CheckResult, errors: &[&str]) {
itertools::assert_equal(result.warnings(), no_strings());
itertools::assert_equal(result.alerts(), no_strings());
itertools::assert_equal(result.errors(), errors);
assert_eq!(result.temporary(), false);
assert_eq!(result.allowed(), false);
assert_eq!(result.pass(), false);
}
pub fn test_result_ok(result: CheckResult) {
itertools::assert_equal(result.warnings(), no_strings());
itertools::assert_equal(result.alerts(), no_strings());
itertools::assert_equal(result.errors(), no_strings());
assert_eq!(result.temporary(), false);
assert_eq!(result.allowed(), false);
assert_eq!(result.pass(), true);
}
pub fn make_check_conf<T>(check: &T) -> GitCheckConfiguration
where
T: Check,
{
let mut conf = GitCheckConfiguration::new();
conf.add_check(check);
conf
}
pub fn run_check<T>(name: &str, commit: &str, check: T) -> CheckResult
where
T: Check,
{
let conf = make_check_conf(&check);
test_check(name, commit, &conf)
}
pub fn run_check_ok<T>(name: &str, commit: &str, check: T)
where
T: Check,
{
test_result_ok(run_check(name, commit, check));
}
pub fn make_branch_check_conf<T>(check: &T) -> GitCheckConfiguration
where
T: BranchCheck,
{
let mut conf = GitCheckConfiguration::new();
conf.add_branch_check(check);
conf
}
pub fn run_branch_check<T>(name: &str, commit: &str, check: T) -> CheckResult
where
T: BranchCheck,
{
let conf = make_branch_check_conf(&check);
test_check(name, commit, &conf)
}
pub fn run_branch_check_ok<T>(name: &str, commit: &str, check: T)
where
T: BranchCheck,
{
test_result_ok(run_branch_check(name, commit, check));
}
pub fn make_topic_check_conf<T>(check: &T) -> GitCheckConfiguration
where
T: TopicCheck,
{
let mut conf = GitCheckConfiguration::new();
conf.add_topic_check(check);
conf
}
pub fn run_topic_check<T>(name: &str, commit: &str, check: T) -> CheckResult
where
T: TopicCheck,
{
let conf = make_topic_check_conf(&check);
test_check(name, commit, &conf)
}
pub fn run_topic_check_ok<T>(name: &str, commit: &str, check: T)
where
T: TopicCheck,
{
test_result_ok(run_topic_check(name, commit, check));
}
#[cfg(feature = "config")]
pub fn check_missing_json_field(err: serde_json::Error, field: &str) {
assert!(!err.is_io());
assert!(!err.is_syntax());
assert!(err.is_data());
assert!(!err.is_eof());
let msg = format!("{}", err);
if msg != format!("missing field `{}`", field) {
println!(
"Error message doesn't match. Was a new required field added? ({})",
msg,
);
}
}