gcd-cli 1.2.0

gcd-cli tools for managing and using GCD. GCD stands for GitChangeDirectory, as it primary goal is to quickly change between git project folders.
Documentation
use assert_cmd::prelude::*;
use predicates::prelude::*;
use std::fs;
use std::process::Command;
use std::error::Error;

pub const TEST_DATABASE_FILE: &'static str = "./testdb/gcd-test.db";

fn add_current_folder() -> Result<(), Box<dyn Error>> {
    let mut init_cmd = Command::cargo_bin("./gcd-add")?;
    init_cmd.arg("-d")
        .arg(TEST_DATABASE_FILE)
        .assert()
        .stdout(predicate::str::is_empty())
        .stderr(predicate::str::is_empty())
        .success();
    Ok(())
}

fn add_current_folder_failed() -> Result<(), Box<dyn Error>> {
    let mut init_cmd = Command::cargo_bin("./gcd-add")?;
    init_cmd.arg("-d")
        .arg(TEST_DATABASE_FILE)
        .assert()
        .stdout(predicate::str::is_empty())
        .stderr(predicate::str::contains(
            "UNIQUE constraint failed: projects.name",
        ))
        .failure();
    Ok(())
}

fn add_alias(alias: &str) -> Result<(), Box<dyn Error>> {
    let mut init_cmd = Command::cargo_bin("./gcd-alias")?;
    init_cmd.arg("-d")
        .arg(TEST_DATABASE_FILE)
        .arg(alias)
        .assert()
        .stdout(predicate::str::is_empty())
        .stderr(predicate::str::is_empty())
        .success();
    Ok(())
}

fn add_alias_failed() -> Result<(), Box<dyn Error>> {
    let mut init_cmd = Command::cargo_bin("./gcd-alias")?;
    init_cmd.arg("-d")
        .arg(TEST_DATABASE_FILE)
        .arg("alias")
        .assert()
        .stdout(predicate::str::is_empty())
        .stderr(predicate::str::contains(
            "Failed to set alias alias for project",
        ))
        .failure();
    Ok(())
}

fn list_aliasses_contains(alias: &str) -> Result<(), Box<dyn Error>> {
    let mut init_cmd = Command::cargo_bin("./gcd-alias")?;
    init_cmd.arg("--list")
        .arg("-d")
        .arg(TEST_DATABASE_FILE)
        .assert()
        .stdout(predicate::str::contains(alias))
        .stderr(predicate::str::is_empty())
        .success();
    Ok(())
}

fn list_aliasses_isempty() -> Result<(), Box<dyn Error>> {
    let mut init_cmd = Command::cargo_bin("./gcd-alias")?;
    init_cmd.arg("--list")
        .arg("-d")
        .arg(TEST_DATABASE_FILE)
        .assert()
        .stdout(predicate::str::is_empty())
        .stderr(predicate::str::is_empty())
        .success();

    Ok(())
}

fn remove_alias() -> Result<(), Box<dyn Error>> {
    let mut init_cmd = Command::cargo_bin("./gcd-alias")?;
    init_cmd.arg("-d")
        .arg(TEST_DATABASE_FILE)
        .arg("--remove")
        // .arg(alias)
        .assert()
        .stdout(predicate::str::is_empty())
        .stderr(predicate::str::is_empty())
        .success();

    Ok(())
}

fn remove_alias_failed() -> Result<(), Box<dyn Error>> {
    let mut init_cmd = Command::cargo_bin("./gcd-alias")?;
    init_cmd.arg("-d")
        .arg(TEST_DATABASE_FILE)
        .arg("--remove")
        .arg("testalias2")
        .assert()
        .stdout(predicate::str::is_empty())
        .stderr(predicate::str::contains(
            "Failed to remove alias testalias2, alias not found.",
        ))
        .failure();

    Ok(())
}

fn delete_project() -> Result<(), Box<dyn Error>> {
    let mut init_cmd = Command::cargo_bin("./gcd-delete")?;
    init_cmd.arg("-d")
        .arg(TEST_DATABASE_FILE)
        .assert()
        .stdout(predicate::str::is_empty())
        .stderr(predicate::str::is_empty())
        .success();

    Ok(())
}


#[test]
fn integration_add_get_update() -> Result<(), Box<dyn std::error::Error>> {
    fs::copy("./testdb/gcd-empty.db", TEST_DATABASE_FILE)?;

    add_alias_failed()?;

    add_current_folder()?;
    add_current_folder_failed()?;

    list_aliasses_isempty()?;

    add_alias("testalias")?;

    list_aliasses_contains("testalias")?;

    add_alias("testalias2")?;

    list_aliasses_contains("testalias2")?;

    remove_alias()?;

    remove_alias_failed()?;

    list_aliasses_isempty()?;

    delete_project()?;

    delete_project()?;

    list_aliasses_isempty()?;

    fs::remove_file(TEST_DATABASE_FILE)?;
    Ok(())
}

#[cfg(unix)]
#[test]
fn integration_test_init_and_update() -> Result<(), Box<dyn std::error::Error>> {
    use gcd_cli::db::Database;

    fs::create_dir_all("./testdb/.gcd")?;
    fs::create_dir_all("./testdb/project/.git")?;
    Command::cargo_bin("./gcd-init")?
        .env("HOME", "./testdb")
        .assert()
        .success();

    let db = Database::new("./testdb/.gcd/gcd.db")?;

    assert_eq!(db.all()?.len(), 1);
    Command::cargo_bin("./gcd-mv")?
        .env("HOME", "./testdb")
        .arg("testdb/project")
        .arg("testdb/project2")
    .assert()
    .success();


    Command::cargo_bin("./gcd-update")?
        .env("HOME", "./testdb")
        .assert()
        .success();
    assert_eq!(db.all()?.len(), 2);

    Command::cargo_bin("./gcd-purge")?
        .env("HOME", "./testdb")
        .assert()
        .success();
    assert_eq!(db.all()?.len(), 1);

    fs::remove_dir_all("./testdb/.gcd")?;
    fs::remove_dir_all("./testdb/project")?;

    Ok(())
}