pxh 0.9.24

pxh is a fast, cross-shell history mining tool with interactive fuzzy search, secret scanning, and bidirectional sync across machines. It indexes bash and zsh history in SQLite with rich metadata for powerful recall.
Documentation
use assert_cmd::Command;
use tempfile::TempDir;

#[test]
fn test_ssh_sync_command_help() {
    let mut cmd = Command::new(assert_cmd::cargo::cargo_bin!("pxh"));

    cmd.arg("sync")
        .arg("--help")
        .assert()
        .success()
        .stdout(predicates::str::contains("--remote"))
        .stdout(predicates::str::contains("--send-only"))
        .stdout(predicates::str::contains("--receive-only"))
        .stdout(predicates::str::contains("--remote-db"))
        .stdout(predicates::str::contains("--remote-pxh"))
        .stdout(predicates::str::contains("--ssh-cmd"));
}

#[test]
fn test_ssh_sync_send_only() {
    let temp_dir = TempDir::new().unwrap();
    let db_path = temp_dir.path().join("test.db");

    let mut cmd = Command::new(assert_cmd::cargo::cargo_bin!("pxh"));

    cmd.arg("--db")
        .arg(&db_path)
        .arg("sync")
        .arg("--remote")
        .arg("nonexistent-host")
        .arg("--send-only")
        .assert()
        .failure()
        .stderr(predicates::str::contains("Could not resolve hostname"));
}

#[test]
fn test_ssh_sync_receive_only() {
    let temp_dir = TempDir::new().unwrap();
    let db_path = temp_dir.path().join("test.db");

    let mut cmd = Command::new(assert_cmd::cargo::cargo_bin!("pxh"));

    cmd.arg("--db")
        .arg(&db_path)
        .arg("sync")
        .arg("--remote")
        .arg("nonexistent-host")
        .arg("--receive-only")
        .assert()
        .failure()
        .stderr(predicates::str::contains("Could not resolve hostname"));
}

#[test]
fn test_ssh_sync_bidirectional() {
    let temp_dir = TempDir::new().unwrap();
    let db_path = temp_dir.path().join("test.db");

    let mut cmd = Command::new(assert_cmd::cargo::cargo_bin!("pxh"));

    cmd.arg("--db")
        .arg(&db_path)
        .arg("sync")
        .arg("--remote")
        .arg("nonexistent-host")
        .assert()
        .failure()
        .stderr(predicates::str::contains("Could not resolve hostname"));
}

#[test]
fn test_directory_sync() {
    let temp_dir = TempDir::new().unwrap();
    let db_path = temp_dir.path().join("test.db");
    let sync_dir = temp_dir.path().join("sync");

    let mut cmd = Command::new(assert_cmd::cargo::cargo_bin!("pxh"));

    cmd.arg("--db").arg(&db_path).arg("sync").arg(&sync_dir).assert().success();
}

#[test]
fn test_sync_without_path_or_remote() {
    let temp_dir = TempDir::new().unwrap();
    let db_path = temp_dir.path().join("test.db");

    let mut cmd = Command::new(assert_cmd::cargo::cargo_bin!("pxh"));

    cmd.arg("--db")
        .arg(&db_path)
        .arg("sync")
        .assert()
        .failure()
        .stderr(predicates::str::contains("Directory path is required for directory-based sync"));
}

#[test]
fn test_send_only_without_remote() {
    let temp_dir = TempDir::new().unwrap();
    let db_path = temp_dir.path().join("test.db");

    let mut cmd = Command::new(assert_cmd::cargo::cargo_bin!("pxh"));

    cmd.arg("--db").arg(&db_path).arg("sync").arg("--send-only").assert().failure().stderr(
        predicates::str::contains(
            "--send-only and --receive-only flags require --remote or --stdin-stdout to be specified",
        ),
    );
}

#[test]
fn test_receive_only_without_remote() {
    let temp_dir = TempDir::new().unwrap();
    let db_path = temp_dir.path().join("test.db");

    let mut cmd = Command::new(assert_cmd::cargo::cargo_bin!("pxh"));

    cmd.arg("--db").arg(&db_path).arg("sync").arg("--receive-only").assert().failure().stderr(
        predicates::str::contains(
            "--send-only and --receive-only flags require --remote or --stdin-stdout to be specified",
        ),
    );
}

#[test]
fn test_remote_with_directory() {
    let temp_dir = TempDir::new().unwrap();
    let db_path = temp_dir.path().join("test.db");
    let sync_dir = temp_dir.path().join("sync");

    let mut cmd = Command::new(assert_cmd::cargo::cargo_bin!("pxh"));

    cmd.arg("--db")
        .arg(&db_path)
        .arg("sync")
        .arg("--remote")
        .arg("localhost")
        .arg(&sync_dir)
        .assert()
        .failure()
        .stderr(predicates::str::contains("Cannot specify both --remote and a directory path"));
}