#[cfg(test)]
mod integ {
extern crate assert_fs;
extern crate claim;
extern crate git_bonsai;
use std::collections::HashSet;
use std::fs::File;
use structopt::StructOpt;
use assert_fs::prelude::*;
use claim::*;
use predicates::prelude::*;
use git_bonsai::app::{self, App, AppError, DEFAULT_BRANCH_CONFIG_KEY};
use git_bonsai::batchappui::BatchAppUi;
use git_bonsai::cliargs::CliArgs;
use git_bonsai::git::create_test_repository;
use git_bonsai::git::Repository;
fn create_repository() -> (assert_fs::TempDir, Repository) {
let dir = assert_fs::TempDir::new().unwrap();
let repo = create_test_repository(dir.path());
repo.set_config_key(DEFAULT_BRANCH_CONFIG_KEY, "master")
.unwrap();
(dir, repo)
}
fn clone_repository(url: &str) -> (assert_fs::TempDir, Repository) {
let dir = assert_fs::TempDir::new().unwrap();
let repo = Repository::clone(dir.path(), &url).unwrap();
(dir, repo)
}
fn create_branch(repo: &Repository, name: &str) {
repo.git("checkout", &["-b", name]).unwrap();
create_and_commit_file(&repo, name);
}
fn create_and_commit_file(repo: &Repository, name: &str) {
File::create(repo.path.join(name)).unwrap();
repo.git("add", &[name]).unwrap();
repo.git("commit", &["-m", &format!("Create file {}", name)])
.unwrap();
}
fn merge_branch(repo: &Repository, name: &str) {
repo.git("merge", &["--no-ff", name, "-m", "Merging branch"])
.unwrap();
}
fn run_git_bonsai(cwd: &str, argv: &[&str]) -> i32 {
let mut full_argv = vec!["git-bonsai"];
full_argv.extend(argv);
let args = CliArgs::from_iter(full_argv);
app::run(args, &cwd)
}
fn create_app(cwd: &str, argv: &[&str]) -> App {
let mut full_argv = vec!["git-bonsai"];
full_argv.extend(argv);
let ui = Box::new(BatchAppUi {});
let args = CliArgs::from_iter(full_argv);
App::new(&args, ui, &cwd)
}
macro_rules! assert_branches_eq {
($repo:expr, $expected_branches:expr) => {
let branches = $repo.list_branches().unwrap();
assert_eq!(branches, $expected_branches);
};
}
#[test]
fn no_op() {
let (dir, _repo) = create_repository();
let path_str = dir.path().to_str().unwrap();
let result = run_git_bonsai(&path_str, &["-y"]);
assert_eq!(result, 0);
}
#[test]
fn delete_merged_branch() {
let (dir, repo) = create_repository();
let path_str = dir.path().to_str().unwrap();
create_branch(&repo, "topic1");
create_branch(&repo, "topic2");
repo.checkout("master").unwrap();
merge_branch(&repo, "topic1");
assert_branches_eq!(&repo, &["master", "topic1", "topic2"]);
{
let app = create_app(&path_str, &[]);
assert_ok!(app.remove_merged_branches());
}
assert_branches_eq!(&repo, &["master", "topic2"]);
}
#[test]
fn skip_protected_branch() {
let (dir, repo) = create_repository();
let path_str = dir.path().to_str().unwrap();
create_branch(&repo, "protected");
repo.checkout("master").unwrap();
merge_branch(&repo, "protected");
assert_branches_eq!(&repo, &["master", "protected"]);
{
let app = create_app(&path_str, &["-x", "protected"]);
assert_ok!(app.remove_merged_branches());
}
assert_branches_eq!(&repo, &["master", "protected"]);
{
let app = create_app(&path_str, &[]);
assert_ok!(app.remove_merged_branches());
}
assert_branches_eq!(&repo, &["master"]);
}
#[test]
fn update_branch() {
let (source_dir, source_repo) = create_repository();
let (clone_dir, _clone_repo) = clone_repository(source_dir.path().to_str().unwrap());
let clone_dir_str = clone_dir.path().to_str().unwrap();
create_and_commit_file(&source_repo, "new");
let result = run_git_bonsai(&clone_dir_str, &["-y"]);
assert_eq!(result, 0);
clone_dir.child("new").assert(predicate::path::exists());
}
#[test]
fn identical_sha1_no_other_branch() {
let (dir, repo) = create_repository();
let path_str = dir.path().to_str().unwrap();
create_branch(&repo, "topic1");
repo.git("branch", &["topic2", "topic1"]).unwrap();
repo.git("branch", &["topic3", "topic1"]).unwrap();
let app = create_app(&path_str, &[]);
assert_ok!(app.delete_identical_branches());
assert_branches_eq!(&repo, &["master", "topic1"]);
}
#[test]
fn identical_sha1_contained_in_master() {
let (dir, repo) = create_repository();
let path_str = dir.path().to_str().unwrap();
repo.git("branch", &["topic1"]).unwrap();
repo.git("branch", &["topic2"]).unwrap();
let app = create_app(&path_str, &[]);
assert_ok!(app.delete_identical_branches());
assert_branches_eq!(&repo, &["master"]);
}
#[test]
fn skip_worktree_branches() {
let (source_dir, source_repo) = create_repository();
create_branch(&source_repo, "topic1");
source_repo.checkout("master").unwrap();
let (clone_dir, clone_repo) = clone_repository(source_dir.path().to_str().unwrap());
let clone_path_str = clone_dir.path().to_str().unwrap();
let worktree_dir = assert_fs::TempDir::new().unwrap();
let worktree_path_str = worktree_dir.path().to_str().unwrap();
clone_repo
.git("worktree", &["add", worktree_path_str, "topic1"])
.unwrap();
let worktree_repo = Repository::new(worktree_dir.path());
worktree_repo.checkout("topic1").unwrap();
let app = create_app(&clone_path_str, &[]);
assert_ok!(app.update_tracking_branches());
}
#[test]
fn safe_delete_branch() {
let (dir, repo) = create_repository();
repo.git("branch", &["test"]).unwrap();
repo.checkout("master").unwrap();
let app = create_app(&dir.path().to_str().unwrap(), &[]);
let result = app.safe_delete_branch("test");
assert_eq!(result, Ok(()));
assert_eq!(repo.list_branches().unwrap(), &["master"]);
}
#[test]
fn cant_delete_unique_branch() {
let (dir, repo) = create_repository();
create_branch(&repo, "test");
repo.checkout("master").unwrap();
let app = create_app(&dir.path().to_str().unwrap(), &[]);
let result = app.safe_delete_branch("test");
assert_eq!(result, Err(AppError::UnsafeDelete));
assert_eq!(repo.list_branches().unwrap(), &["master", "test"]);
}
#[test]
fn test_protected_branches_from_git_config() {
let (dir, repo) = create_repository();
create_branch(&repo, "test");
repo.checkout("master").unwrap();
repo.git(
"config",
&["--add", "git-bonsai.protected-branches", "custom1"],
)
.unwrap();
repo.git(
"config",
&["--add", "git-bonsai.protected-branches", "custom2"],
)
.unwrap();
let mut app = create_app(&dir.path().to_str().unwrap(), &[]);
app.add_default_branch_to_protected_branches().unwrap();
let expected_branches: HashSet<String> = ["custom1", "custom2", "master"]
.iter()
.map(|x| x.to_string())
.collect();
assert_eq!(app.get_protected_branches(), expected_branches);
}
}