mod common;
use common::Environment;

#[test]
fn create_environment() -> anyhow::Result<()> {
    let e = Environment::new()?;
    assert!(e.gnupg_state().exists());
    assert!(e.git_state().exists());
    Ok(())
}

fn merge_unrelated_repo(signed: bool) -> anyhow::Result<()>
{
    // Test if we can merge two unrelated repos.
    //
    // If `signed` is true, then we only test the case that there are
    // multiple roots; both repos use the same policy and all commits
    // are signed.
    //
    // If `signed` is false, then we sign the commits in one
    // repository, and in the other not only do we not sign the
    // commits, we don't even have a policy.

    let (e, root) = Environment::scooby_gang_bootstrap(None)?;

    e.git(&["checkout", "-b", "main"])
        .expect("can create branch");

    // Create some commits in the first repo.
    for i in 0..3 {
        e.git_commit(
            &[(&format!("repo-1-commit-{}", i + 1), Some(b"xxx"))],
            &format!("repo-1 commit #{}", i + 1),
            Some(&e.willow_release)).unwrap();
        assert!(e.sq_git(&["log", "--trust-root", &root,
                           &format!("{}..", root)])
                .is_ok());
    }

    let repo2 = e.scratch_state().join("repo2");
    let repo2 = repo2.as_path();
    e.init_repo(repo2).expect("Can init repo");
    let root2 = if signed {
        e.scooby_gang_bootstrap_in(repo2, None).expect("Can bootstrap repo")
    } else {
        e.git_commit_in(
            repo2,
            &[(&format!("repo-2-commit-0"), Some(b"xxx"))],
            "repo-2 commit #0",
            None).unwrap()
    };

    e.git_in(repo2, &["checkout", "-b", "main"])
        .expect("can create branch");

    // Create some commits in the second repo.
    for i in 0..3 {
        e.git_commit_in(
            repo2,
            &[(&format!("repo-2-commit-{}", i + 1), Some(b"xxx"))],
            &format!("repo-2 commit #{}", i + 1),
            if signed { Some(&e.willow_release) } else { None }).unwrap();
        assert_eq!(
            e.sq_git_in(repo2,
                        &["log", "--trust-root", &root2,
                          &format!("{}..", root2)])
                .is_ok(),
            signed);
    }

    // Add the second repo as a remote.
    e.git(&["remote", "add", "repo2", &repo2.display().to_string()])
        .expect("can add remote");
    e.git(&["fetch"]).expect("can fetch");

    // Merge the two repositories' main branches.
    e.git_merge_no_ff(&["main", "repo2/main"],
                      "Merging the two repositories",
                      Some(&e.willow_release),
                      &["--allow-unrelated-histories"])
        .expect("can merge");

    e.git_log_graph().expect("can run git log");

    assert!(e.sq_git(&["log", "--trust-root", &root])
            .is_ok());
    assert_eq!(
        e.sq_git(&["log", "--trust-root", &root2])
            .is_ok(),
        signed);

    Ok(())
}

#[test]
fn merge_unrelated_repo_signed_signed() -> anyhow::Result<()> {
    merge_unrelated_repo(true)
}
#[test]
fn merge_unrelated_repo_signed_unsigned() -> anyhow::Result<()> {
    merge_unrelated_repo(false)
}
