nushell/tests/hooks/mod.rs
Ian Manske cd00a489af
Fix hooks on 0.92.0 (#12383)
# Description
Fixes #12382, where overlay changes from hooks were not preserved into
the global state. This was due to creating child stacks for hooks, when
the global stack should have been used instead.
2024-04-04 09:25:54 +02:00

567 lines
12 KiB
Rust

use nu_test_support::{nu, nu_repl_code};
use pretty_assertions::assert_eq;
fn env_change_hook_code_list(name: &str, code_list: &[&str]) -> String {
let mut list = String::new();
for code in code_list.iter() {
list.push_str("{ code: ");
list.push_str(code);
list.push_str(" }\n");
}
format!(
"$env.config = {{
hooks: {{
env_change: {{
{name} : [
{list}
]
}}
}}
}}"
)
}
fn env_change_hook(name: &str, code: &str) -> String {
format!(
"$env.config = {{
hooks: {{
env_change: {{
{name} : {code}
}}
}}
}}"
)
}
fn env_change_hook_code(name: &str, code: &str) -> String {
format!(
"$env.config = {{
hooks: {{
env_change: {{
{name} : {{
code: {code}
}}
}}
}}
}}"
)
}
fn env_change_hook_code_condition(name: &str, condition: &str, code: &str) -> String {
format!(
"$env.config = {{
hooks: {{
env_change: {{
{name} : {{
condition: {condition}
code: {code}
}}
}}
}}
}}"
)
}
fn pre_prompt_hook(code: &str) -> String {
format!(
"$env.config = {{
hooks: {{
pre_prompt: {code}
}}
}}"
)
}
fn pre_prompt_hook_code(code: &str) -> String {
format!(
"$env.config = {{
hooks: {{
pre_prompt: {{
code: {code}
}}
}}
}}"
)
}
fn pre_execution_hook(code: &str) -> String {
format!(
"$env.config = {{
hooks: {{
pre_execution: {code}
}}
}}"
)
}
fn pre_execution_hook_code(code: &str) -> String {
format!(
"$env.config = {{
hooks: {{
pre_execution: {{
code: {code}
}}
}}
}}"
)
}
#[test]
fn env_change_define_command() {
let inp = &[
&env_change_hook_code("FOO", r#"'def foo [] { "got foo!" }'"#),
"$env.FOO = 1",
"foo",
];
let actual_repl = nu!(nu_repl_code(inp));
assert_eq!(actual_repl.err, "");
assert_eq!(actual_repl.out, "got foo!");
}
#[test]
fn env_change_define_variable() {
let inp = &[
&env_change_hook_code("FOO", r#"'let x = "spam"'"#),
"$env.FOO = 1",
"$x",
];
let actual_repl = nu!(nu_repl_code(inp));
assert_eq!(actual_repl.err, "");
assert_eq!(actual_repl.out, "spam");
}
#[test]
fn env_change_define_env_var() {
let inp = &[
&env_change_hook_code("FOO", r#"'$env.SPAM = "spam"'"#),
"$env.FOO = 1",
"$env.SPAM",
];
let actual_repl = nu!(nu_repl_code(inp));
assert_eq!(actual_repl.err, "");
assert_eq!(actual_repl.out, "spam");
}
#[test]
fn env_change_define_alias() {
let inp = &[
&env_change_hook_code("FOO", r#"'alias spam = echo "spam"'"#),
"$env.FOO = 1",
"spam",
];
let actual_repl = nu!(nu_repl_code(inp));
assert_eq!(actual_repl.err, "");
assert_eq!(actual_repl.out, "spam");
}
#[test]
fn env_change_simple_block_preserve_env_var() {
let inp = &[
&env_change_hook("FOO", r#"{|| $env.SPAM = "spam" }"#),
"$env.FOO = 1",
"$env.SPAM",
];
let actual_repl = nu!(nu_repl_code(inp));
assert_eq!(actual_repl.err, "");
assert_eq!(actual_repl.out, "spam");
}
#[test]
fn env_change_simple_block_list_shadow_env_var() {
let inp = &[
&env_change_hook(
"FOO",
r#"[
{|| $env.SPAM = "foo" }
{|| $env.SPAM = "spam" }
]"#,
),
"$env.FOO = 1",
"$env.SPAM",
];
let actual_repl = nu!(nu_repl_code(inp));
assert_eq!(actual_repl.err, "");
assert_eq!(actual_repl.out, "spam");
}
#[test]
fn env_change_block_preserve_env_var() {
let inp = &[
&env_change_hook_code("FOO", r#"{|| $env.SPAM = "spam" }"#),
"$env.FOO = 1",
"$env.SPAM",
];
let actual_repl = nu!(nu_repl_code(inp));
assert_eq!(actual_repl.err, "");
assert_eq!(actual_repl.out, "spam");
}
#[test]
fn pre_prompt_define_command() {
let inp = &[
&pre_prompt_hook_code(r#"'def foo [] { "got foo!" }'"#),
"foo",
];
let actual_repl = nu!(nu_repl_code(inp));
assert_eq!(actual_repl.err, "");
assert_eq!(actual_repl.out, "got foo!");
}
#[test]
fn pre_prompt_simple_block_preserve_env_var() {
let inp = &[&pre_prompt_hook(r#"{|| $env.SPAM = "spam" }"#), "$env.SPAM"];
let actual_repl = nu!(nu_repl_code(inp));
assert_eq!(actual_repl.err, "");
assert_eq!(actual_repl.out, "spam");
}
#[test]
fn pre_prompt_simple_block_list_shadow_env_var() {
let inp = &[
&pre_prompt_hook(
r#"[
{|| $env.SPAM = "foo" }
{|| $env.SPAM = "spam" }
]"#,
),
"$env.SPAM",
];
let actual_repl = nu!(nu_repl_code(inp));
assert_eq!(actual_repl.err, "");
assert_eq!(actual_repl.out, "spam");
}
#[test]
fn pre_prompt_block_preserve_env_var() {
let inp = &[
&pre_prompt_hook_code(r#"{|| $env.SPAM = "spam" }"#),
"$env.SPAM",
];
let actual_repl = nu!(nu_repl_code(inp));
assert_eq!(actual_repl.err, "");
assert_eq!(actual_repl.out, "spam");
}
#[test]
fn pre_execution_define_command() {
let inp = &[
&pre_execution_hook_code(r#"'def foo [] { "got foo!" }'"#),
"foo",
];
let actual_repl = nu!(nu_repl_code(inp));
assert_eq!(actual_repl.err, "");
assert_eq!(actual_repl.out, "got foo!");
}
#[test]
fn pre_execution_simple_block_preserve_env_var() {
let inp = &[
&pre_execution_hook(r#"{|| $env.SPAM = "spam" }"#),
"$env.SPAM",
];
let actual_repl = nu!(nu_repl_code(inp));
assert_eq!(actual_repl.err, "");
assert_eq!(actual_repl.out, "spam");
}
#[test]
fn pre_execution_simple_block_list_shadow_env_var() {
let inp = &[
&pre_execution_hook(
r#"[
{|| $env.SPAM = "foo" }
{|| $env.SPAM = "spam" }
]"#,
),
"$env.SPAM",
];
let actual_repl = nu!(nu_repl_code(inp));
assert_eq!(actual_repl.err, "");
assert_eq!(actual_repl.out, "spam");
}
#[test]
fn pre_execution_block_preserve_env_var() {
let inp = &[
&pre_execution_hook_code(r#"{|| $env.SPAM = "spam" }"#),
"$env.SPAM",
];
let actual_repl = nu!(nu_repl_code(inp));
assert_eq!(actual_repl.err, "");
assert_eq!(actual_repl.out, "spam");
}
#[test]
fn pre_execution_commandline() {
let inp = &[
&pre_execution_hook_code("{|| $env.repl_commandline = (commandline) }"),
"$env.repl_commandline",
];
let actual_repl = nu!(nu_repl_code(inp));
assert_eq!(actual_repl.err, "");
assert_eq!(actual_repl.out, "$env.repl_commandline");
}
#[test]
fn env_change_shadow_command() {
let inp = &[
&env_change_hook_code_list(
"FOO",
&[
r#"'def foo [] { "got spam!" }'"#,
r#"'def foo [] { "got foo!" }'"#,
],
),
"$env.FOO = 1",
"foo",
];
let actual_repl = nu!(nu_repl_code(inp));
assert_eq!(actual_repl.err, "");
assert_eq!(actual_repl.out, "got foo!");
}
#[test]
fn env_change_block_dont_preserve_command() {
let inp = &[
&env_change_hook_code("FOO", r#"{|| def foo [] { "foo" } }"#),
"$env.FOO = 1",
"foo",
];
let actual_repl = nu!(nu_repl_code(inp));
#[cfg(windows)]
assert_ne!(actual_repl.out, "foo");
#[cfg(not(windows))]
assert!(actual_repl.err.contains("external_command"));
}
#[test]
fn env_change_block_condition_pwd() {
let inp = &[
&env_change_hook_code_condition(
"PWD",
"{|before, after| ($after | path basename) == samples }",
"'source-env .nu-env'",
),
"cd samples",
"$env.SPAM",
];
let actual_repl = nu!(cwd: "tests/hooks", nu_repl_code(inp));
assert_eq!(actual_repl.err, "");
assert_eq!(actual_repl.out, "spam");
}
#[test]
fn env_change_block_condition_correct_args() {
let inp = &[
"$env.FOO = 1",
&env_change_hook_code_condition(
"FOO",
"{|before, after| $before == 1 and $after == 2}",
"{|before, after| $env.SPAM = ($before == 1 and $after == 2) }",
),
"",
"$env.FOO = 2",
"$env.SPAM",
];
let actual_repl = nu!(nu_repl_code(inp));
assert_eq!(actual_repl.err, "");
assert_eq!(actual_repl.out, "true");
}
#[test]
fn env_change_dont_panic_with_many_args() {
let inp = &[
&env_change_hook_code("FOO", "{ |a, b, c| $env.SPAM = 'spam' }"),
"$env.FOO = 1",
"",
];
let actual_repl = nu!(nu_repl_code(inp));
assert!(actual_repl.err.contains("incompatible_parameters"));
assert_eq!(actual_repl.out, "");
}
#[test]
fn err_hook_wrong_env_type_1() {
let inp = &[
"$env.config = {
hooks: {
env_change: {
FOO : 1
}
}
}",
"$env.FOO = 1",
"",
];
let actual_repl = nu!(nu_repl_code(inp));
dbg!(&actual_repl.err);
assert!(actual_repl.err.contains("unsupported_config_value"));
assert_eq!(actual_repl.out, "");
}
#[test]
fn err_hook_wrong_env_type_2() {
let inp = &[
r#"$env.config = {
hooks: {
env_change: "print spam"
}
}"#,
"",
];
let actual_repl = nu!(nu_repl_code(inp));
assert!(actual_repl.err.contains("type_mismatch"));
assert_eq!(actual_repl.out, "");
}
#[test]
fn err_hook_wrong_env_type_3() {
let inp = &[
"$env.config = {
hooks: {
env_change: {
FOO : {
code: 1
}
}
}
}",
"$env.FOO = 1",
"",
];
let actual_repl = nu!(nu_repl_code(inp));
assert!(actual_repl.err.contains("unsupported_config_value"));
assert_eq!(actual_repl.out, "");
}
#[test]
fn err_hook_non_boolean_condition_output() {
let inp = &[
r#"$env.config = {
hooks: {
env_change: {
FOO : {
condition: {|| "foo" }
code: "print spam"
}
}
}
}"#,
"$env.FOO = 1",
"",
];
let actual_repl = nu!(nu_repl_code(inp));
assert!(actual_repl.err.contains("unsupported_config_value"));
assert_eq!(actual_repl.out, "");
}
#[test]
fn err_hook_non_condition_not_a_block() {
let inp = &[
r#"$env.config = {
hooks: {
env_change: {
FOO : {
condition: "foo"
code: "print spam"
}
}
}
}"#,
"$env.FOO = 1",
"",
];
let actual_repl = nu!(nu_repl_code(inp));
assert!(actual_repl.err.contains("unsupported_config_value"));
assert_eq!(actual_repl.out, "");
}
#[test]
fn err_hook_parse_error() {
let inp = &[
r#"$env.config = {
hooks: {
env_change: {
FOO : {
code: "def foo { 'foo' }"
}
}
}
}"#,
"$env.FOO = 1",
"",
];
let actual_repl = nu!(nu_repl_code(inp));
assert!(actual_repl.err.contains("unsupported_config_value"));
assert_eq!(actual_repl.out, "");
}
#[test]
fn env_change_overlay() {
let inp = &[
"module test { export-env { $env.BAR = 2 } }",
&env_change_hook_code("FOO", "'overlay use test'"),
"$env.FOO = 1",
"$env.BAR",
];
let actual_repl = nu!(nu_repl_code(inp));
assert_eq!(actual_repl.out, "2");
}