nu-protocol 0.113.0

Nushell's internal protocols, including its abstract syntax tree
Documentation
use nu_protocol::{ConfigError, Record, Type};
use nu_test_support::prelude::*;

const DEFAULT_FILES_DIR: &str = "crates/nu-utils/src/default_files";

#[track_caller]
fn config_error<const N: usize>(err: &ShellError) -> Result<&[ConfigError; N]> {
    match err {
        ShellError::InvalidConfig { errors } => match errors.as_slice().try_into() {
            Ok(errs) => Ok(errs),
            _ => panic!("expected {N} config error, got {}", errors.len()),
        },
        _ => Err(err.clone().into()),
    }
}

#[test]
fn config_is_mutable() -> Result {
    let mut tester = test();
    let () = tester.run("$env.config = { ls: { clickable_links: true } }")?;
    let () = tester.run("$env.config.ls.clickable_links = false")?;
    tester
        .run("$env.config.ls.clickable_links")
        .expect_value_eq(false)
}

#[test]
fn config_preserved_after_do() -> Result {
    let mut tester = test();
    let () = tester.run("$env.config = { ls: { clickable_links: true } }")?;
    let () = tester.run("do -i { $env.config.ls.clickable_links = false }")?;
    tester
        .run("$env.config.ls.clickable_links")
        .expect_value_eq(true)
}

#[test]
#[env(NU_TEST_LOCALE_OVERRIDE = "en_US.UTF-8")]
fn config_affected_when_mutated() -> Result {
    let mut tester = test();
    let () = tester.run("$env.config = { filesize: { unit: binary } }")?;
    let () = tester.run("$env.config = { filesize: { unit: metric } }")?;
    tester.run("20MB | into string").expect_value_eq("20.0 MB")
}

#[test]
#[env(NU_TEST_LOCALE_OVERRIDE = "en_US.UTF-8")]
fn config_affected_when_deep_mutated() -> Result {
    let mut tester = test().cwd(DEFAULT_FILES_DIR);
    let () = tester.run("source default_config.nu")?;
    let () = tester.run("$env.config.filesize.unit = 'binary'")?;
    tester
        .run("20MiB | into string")
        .expect_value_eq("20.0 MiB")
}

#[test]
fn config_add_unsupported_key() -> Result {
    let mut tester = test().cwd(DEFAULT_FILES_DIR);
    let () = tester.run("source default_config.nu")?;
    let shell_error = tester.run("$env.config.foo = 2").expect_shell_error()?;
    let [err] = config_error(&shell_error)?;

    match err {
        ConfigError::UnknownOption { path, .. } if path == "$env.config.foo" => Ok(()),
        _ => Err(shell_error.into()),
    }
}

#[test]
fn config_add_unsupported_type() -> Result {
    let mut tester = test().cwd(DEFAULT_FILES_DIR);
    let () = tester.run("source default_config.nu")?;
    let shell_error = tester.run("$env.config.ls = '' ").expect_shell_error()?;
    let [err] = config_error(&shell_error)?;

    match err {
        ConfigError::TypeMismatch {
            expected: Type::Record(_),
            actual: Type::String,
            ..
        } => Ok(()),
        _ => Err(shell_error.into()),
    }
}

#[test]
fn config_add_unsupported_value() -> Result {
    let mut tester = test().cwd(DEFAULT_FILES_DIR);
    let () = tester.run("source default_config.nu")?;
    let shell_error = tester
        .run("$env.config.history.file_format = ''")
        .expect_shell_error()?;
    let [err] = config_error(&shell_error)?;

    match err {
        ConfigError::InvalidValue { valid, actual, .. } => {
            #[cfg(feature = "sqlite")]
            assert_eq!(valid, "'sqlite' or 'plaintext'");
            #[cfg(not(feature = "sqlite"))]
            assert_eq!(valid, "'plaintext'");

            assert_eq!(actual, "''");
            Ok(())
        }
        _ => Err(shell_error.into()),
    }
}

#[test]
fn config_unsupported_key_reverted() -> Result {
    let mut tester = test().cwd(DEFAULT_FILES_DIR);
    let () = tester.run("source default_config.nu")?;
    let _ = tester.run("$env.config.foo = 1").expect_shell_error()?;
    tester.run("'foo' in $env.config").expect_value_eq(false)
}

#[test]
fn config_unsupported_type_reverted() -> Result {
    let mut tester = test().cwd(DEFAULT_FILES_DIR);
    let () = tester.run(" source default_config.nu")?;
    let _ = tester.run("$env.config.ls = ''").expect_shell_error()?;
    let _: Record = tester.run("$env.config.ls")?;
    Ok(())
}

#[test]
fn config_unsupported_value_reverted() -> Result {
    let mut tester = test().cwd(DEFAULT_FILES_DIR);
    let () = tester.run(" source default_config.nu")?;
    let () = tester.run("$env.config.history.file_format = 'plaintext'")?;
    let _ = tester
        .run("$env.config.history.file_format = ''")
        .expect_shell_error()?;
    tester
        .run("$env.config.history.file_format")
        .expect_value_eq("plaintext")
}