env-hooks 0.1.4

Shell integration for automatic environment management
Documentation
use std::env;
use std::os::unix::fs::PermissionsExt;
use std::{collections::HashSet, fs};

use env_hooks::{
    BashSource, EnvVars, EnvVarsState, get_env_vars_from_bash, get_env_vars_from_current_process,
    get_env_vars_reset, get_old_env_vars_to_be_updated, merge_delimited_env_var,
    remove_ignored_env_vars,
};

#[test]
fn get_old_env_vars_to_be_updated_finds_changed_vars() {
    let old_vars = EnvVars::from_iter([
        ("VAR1".to_string(), "old_value".to_string()),
        ("VAR2".to_string(), "unchanged".to_string()),
        ("VAR3".to_string(), "old".to_string()),
    ]);

    let new_vars = EnvVars::from_iter([
        ("VAR1".to_string(), "new_value".to_string()),
        ("VAR2".to_string(), "unchanged".to_string()),
        ("VAR3".to_string(), "old".to_string()),
    ]);

    let result = get_old_env_vars_to_be_updated(old_vars, &new_vars);

    assert_eq!(
        result,
        EnvVars::from_iter([("VAR1".to_string(), "old_value".to_string())])
    );
}

#[test]
fn get_old_env_vars_to_be_updated_ignores_new_vars() {
    let old_vars = EnvVars::from_iter([("VAR1".to_string(), "value1".to_string())]);

    let new_vars = EnvVars::from_iter([
        ("VAR1".to_string(), "value1".to_string()),
        ("VAR2".to_string(), "value2".to_string()),
    ]);

    let result = get_old_env_vars_to_be_updated(old_vars, &new_vars);

    assert!(result.is_empty());
}

#[test]
fn get_old_env_vars_to_be_updated_empty_old_vars() {
    let old_vars = EnvVars::new();
    let new_vars = EnvVars::new();

    let result = get_old_env_vars_to_be_updated(old_vars, &new_vars);

    assert!(result.is_empty());
}

#[test]
fn get_env_vars_reset_returns_state_to_old_env_vars() {
    let old_env_vars = EnvVars::from_iter([
        ("VAR1".to_string(), "old1".to_string()),
        ("VAR2".to_string(), "old2".to_string()),
    ]);

    let new_vars = HashSet::from_iter(["VAR1".to_string(), "VAR3".to_string()]);

    let result = get_env_vars_reset(old_env_vars, new_vars, "STATE_VAR".to_string());

    assert_eq!(
        result,
        EnvVarsState::from_iter([
            ("VAR1".to_string(), Some("old1".to_string())),
            ("VAR3".to_string(), None),
            ("STATE_VAR".to_string(), None),
        ])
    );
}

#[test]
fn get_env_vars_from_current_process_returns_current_env() {
    let result = get_env_vars_from_current_process();
    let path = env::var("PATH").ok();
    assert!(path.is_some());
    assert_eq!(result.get("PATH"), path.as_ref());
}

#[test]
fn merge_delimited_values_combines_paths_and_preserves_order_with_new_paths_in_front() {
    {
        let mut new_env_vars = EnvVars::new();
        merge_delimited_env_var("PATH", ':', ':', &EnvVars::new(), &mut new_env_vars);
        assert!(new_env_vars.is_empty());
    }

    let mut new_env_vars =
        EnvVars::from_iter([("PATH".to_string(), "/home/user/bin:/usr/bin".to_string())]);
    merge_delimited_env_var(
        "PATH",
        ':',
        ' ',
        &EnvVars::from_iter([("PATH".to_string(), "/usr/bin:/usr/local/bin".to_string())]),
        &mut new_env_vars,
    );

    assert_eq!(
        new_env_vars,
        EnvVars::from_iter([(
            "PATH".to_string(),
            "/home/user/bin /usr/bin /usr/local/bin".to_string()
        )])
    );
}

#[test]
fn env_vars_into_env_vars_state_conversion() {
    assert_eq!(
        EnvVarsState::from(EnvVars::from_iter([
            ("VAR1".to_string(), "value1".to_string()),
            ("VAR2".to_string(), "value2".to_string()),
        ])),
        EnvVarsState::from_iter([
            ("VAR1".to_string(), Some("value1".to_string())),
            ("VAR2".to_string(), Some("value2".to_string())),
        ])
    );
}

#[test]
fn test_getting_env_vars_from_bash() {
    let tempdir = tempfile::tempdir().unwrap();
    let bash_script_path = tempdir.path().join("my_bash_script.sh");
    let bash_path = env::var("NIX_BIN_BASH").unwrap_or_else(|_| String::from("/bin/bash"));
    fs::write(
        &bash_script_path,
        format!("#! {bash_path}\nexport TEST_VAR=true"),
    )
    .unwrap();
    fs::set_permissions(&bash_script_path, fs::Permissions::from_mode(0o755)).unwrap();

    let old_path = env::var("PATH").unwrap();

    let mut new_env_vars = get_env_vars_from_bash(
        BashSource::File(bash_script_path),
        Some(EnvVars::from_iter([(
            String::from("PATH"),
            old_path.clone(),
        )])),
    )
    .unwrap();
    remove_ignored_env_vars(&mut new_env_vars);

    assert_eq!(new_env_vars.get("PATH").unwrap(), &old_path);
    new_env_vars.shift_remove("PATH");

    assert_eq!(
        new_env_vars,
        EnvVars::from_iter([(String::from("TEST_VAR"), String::from("true"))])
    );
}