From d6f4189c7b5ff74c762d969a6a65b68795caba7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20=C5=BD=C3=A1dn=C3=ADk?= Date: Fri, 29 Jul 2022 23:42:00 +0300 Subject: [PATCH] Fix file lookup in parser keywords; Refactor nu_repl (#6185) * Fix file lookup in parser keywords * Make nu_repl a testbin; Fix wrong cwd test error --- crates/nu-parser/src/parse_keywords.rs | 32 +++--- crates/nu-protocol/src/config.rs | 6 +- crates/nu-test-support/src/lib.rs | 19 ++++ src/main.rs | 1 + src/test_bins.rs | 128 ++++++++++++++++++++++++ tests/hooks/mod.rs | 56 +++++------ tests/main.rs | 1 - tests/nu_repl/mod.rs | 130 ------------------------- tests/overlays/mod.rs | 83 ++++++++-------- tests/shell/mod.rs | 116 +++++++++++++++++++++- 10 files changed, 353 insertions(+), 219 deletions(-) delete mode 100644 tests/nu_repl/mod.rs diff --git a/crates/nu-parser/src/parse_keywords.rs b/crates/nu-parser/src/parse_keywords.rs index 8fd3cf16ff..2d940b5b85 100644 --- a/crates/nu-parser/src/parse_keywords.rs +++ b/crates/nu-parser/src/parse_keywords.rs @@ -2834,25 +2834,29 @@ pub fn parse_register( /// This helper function is used to find files during parsing /// -/// Checks whether the file is: -/// 1. relative to the directory of the file currently being parsed -/// 2. relative to the current working directory -/// 3. within one of the NU_LIB_DIRS entries +/// First, the actual current working directory is selected as +/// a) the directory of a file currently being parsed +/// b) current working directory (PWD) /// -/// Always returns absolute path +/// Then, if the file is not found in the actual cwd, NU_LIB_DIRS is checked. +/// If there is a relative path in NU_LIB_DIRS, it is assumed to be relative to the actual cwd +/// determined in the first step. +/// +/// Always returns an absolute path fn find_in_dirs( filename: &str, working_set: &StateWorkingSet, cwd: &str, dirs_env: &str, ) -> Option { - if let Some(currently_parsed_cwd) = &working_set.currently_parsed_cwd { - if let Ok(p) = canonicalize_with(filename, currently_parsed_cwd) { - Some(p) - } else { - None - } - } else if let Ok(p) = canonicalize_with(filename, cwd) { + // Choose whether to use file-relative or PWD-relative path + let actual_cwd = if let Some(currently_parsed_cwd) = &working_set.currently_parsed_cwd { + currently_parsed_cwd.as_path() + } else { + Path::new(cwd) + }; + + if let Ok(p) = canonicalize_with(filename, actual_cwd) { Some(p) } else { let path = Path::new(filename); @@ -2862,8 +2866,8 @@ fn find_in_dirs( if let Ok(dirs) = lib_dirs.as_list() { for lib_dir in dirs { if let Ok(dir) = lib_dir.as_path() { - if let Ok(dir_abs) = canonicalize_with(&dir, cwd) { - // make sure the dir is absolute path + // make sure the dir is absolute path + if let Ok(dir_abs) = canonicalize_with(&dir, actual_cwd) { if let Ok(path) = canonicalize_with(filename, dir_abs) { return Some(path); } diff --git a/crates/nu-protocol/src/config.rs b/crates/nu-protocol/src/config.rs index 8c39460048..7493a5532a 100644 --- a/crates/nu-protocol/src/config.rs +++ b/crates/nu-protocol/src/config.rs @@ -199,7 +199,7 @@ impl Value { if let Ok(map) = create_map(value, &config) { config.color_config = map; } else { - eprintln!("$config.color_config is not a record") + eprintln!("$env.config.color_config is not a record") } } "use_grid_icons" => { @@ -403,7 +403,7 @@ impl Value { } } } else { - eprintln!("$config is not a record"); + eprintln!("$env.config is not a record"); } Ok(config) @@ -412,7 +412,7 @@ impl Value { fn try_parse_trim_strategy(value: &Value, config: &Config) -> Result { let map = create_map(value, config).map_err(|e| { - eprintln!("$config.table_trim is not a record"); + eprintln!("$env.config.table_trim is not a record"); e })?; diff --git a/crates/nu-test-support/src/lib.rs b/crates/nu-test-support/src/lib.rs index 7f297123d0..78ff10b326 100644 --- a/crates/nu-test-support/src/lib.rs +++ b/crates/nu-test-support/src/lib.rs @@ -35,6 +35,25 @@ pub fn pipeline(commands: &str) -> String { .to_string() } +pub fn nu_repl_code(source_lines: &[&str]) -> String { + let mut out = String::from("nu --testbin=nu_repl [ "); + + for line in source_lines.iter() { + // convert each "line" to really be a single line to prevent nu! macro joining the newlines + // with ';' + let line = pipeline(line); + + out.push('`'); + out.push_str(&line); + out.push('`'); + out.push(' '); + } + + out.push(']'); + + out +} + pub fn shell_os_paths() -> Vec { let mut original_paths = vec![]; diff --git a/src/main.rs b/src/main.rs index a7be597d9e..ba2c41128d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -177,6 +177,7 @@ fn main() -> Result<()> { "nonu" => test_bins::nonu(), "chop" => test_bins::chop(), "repeater" => test_bins::repeater(), + "nu_repl" => test_bins::nu_repl(), _ => std::process::exit(1), } std::process::exit(0) diff --git a/src/test_bins.rs b/src/test_bins.rs index bdd0ac4d43..66249f9e7b 100644 --- a/src/test_bins.rs +++ b/src/test_bins.rs @@ -1,5 +1,13 @@ use std::io::{self, BufRead, Write}; +use nu_cli::{eval_env_change_hook, eval_hook}; +use nu_command::create_default_context; +use nu_engine::eval_block; +use nu_parser::parse; +use nu_protocol::engine::{EngineState, Stack, StateWorkingSet}; +use nu_protocol::{CliError, PipelineData, Span, Value}; +// use nu_test_support::fs::in_directory; + /// Echo's value of env keys from args /// Example: nu --testbin env_echo FOO BAR /// If it it's not present echo's nothing @@ -112,6 +120,126 @@ pub fn chop() { std::process::exit(0); } +fn outcome_err( + engine_state: &EngineState, + error: &(dyn miette::Diagnostic + Send + Sync + 'static), +) -> ! { + let working_set = StateWorkingSet::new(engine_state); + + eprintln!("Error: {:?}", CliError(error, &working_set)); + + std::process::exit(1); +} + +fn outcome_ok(msg: String) -> ! { + println!("{}", msg); + + std::process::exit(0); +} + +pub fn nu_repl() { + //cwd: &str, source_lines: &[&str]) { + let cwd = std::env::current_dir().expect("Could not get current working directory."); + let source_lines = args(); + + let mut engine_state = create_default_context(); + let mut stack = Stack::new(); + + stack.add_env_var( + "PWD".to_string(), + Value::String { + val: cwd.to_string_lossy().to_string(), + span: Span::test_data(), + }, + ); + + let mut last_output = String::new(); + + for (i, line) in source_lines.iter().enumerate() { + let cwd = match nu_engine::env::current_dir(&engine_state, &stack) { + Ok(d) => d, + Err(err) => { + outcome_err(&engine_state, &err); + } + }; + + // Before doing anything, merge the environment from the previous REPL iteration into the + // permanent state. + if let Err(err) = engine_state.merge_env(&mut stack, &cwd) { + outcome_err(&engine_state, &err); + } + + // Check for pre_prompt hook + let config = engine_state.get_config(); + if let Some(hook) = config.hooks.pre_prompt.clone() { + if let Err(err) = eval_hook(&mut engine_state, &mut stack, vec![], &hook) { + outcome_err(&engine_state, &err); + } + } + + // Check for env change hook + let config = engine_state.get_config(); + if let Err(err) = eval_env_change_hook( + config.hooks.env_change.clone(), + &mut engine_state, + &mut stack, + ) { + outcome_err(&engine_state, &err); + } + + // Check for pre_execution hook + let config = engine_state.get_config(); + if let Some(hook) = config.hooks.pre_execution.clone() { + if let Err(err) = eval_hook(&mut engine_state, &mut stack, vec![], &hook) { + outcome_err(&engine_state, &err); + } + } + + // Eval the REPL line + let (block, delta) = { + let mut working_set = StateWorkingSet::new(&engine_state); + let (block, err) = parse( + &mut working_set, + Some(&format!("line{}", i)), + line.as_bytes(), + false, + &[], + ); + + if let Some(err) = err { + outcome_err(&engine_state, &err); + } + (block, working_set.render()) + }; + + if let Err(err) = engine_state.merge_delta(delta) { + outcome_err(&engine_state, &err); + } + + let input = PipelineData::new(Span::test_data()); + let config = engine_state.get_config(); + + match eval_block(&engine_state, &mut stack, &block, input, false, false) { + Ok(pipeline_data) => match pipeline_data.collect_string("", config) { + Ok(s) => last_output = s, + Err(err) => outcome_err(&engine_state, &err), + }, + Err(err) => outcome_err(&engine_state, &err), + } + + if let Some(cwd) = stack.get_env_var(&engine_state, "PWD") { + let path = match cwd.as_string() { + Ok(p) => p, + Err(err) => outcome_err(&engine_state, &err), + }; + let _ = std::env::set_current_dir(path); + engine_state.add_env_var("PWD".into(), cwd); + } + } + + outcome_ok(last_output) +} + fn did_chop_arguments() -> bool { let args: Vec = args(); diff --git a/tests/hooks/mod.rs b/tests/hooks/mod.rs index 4e05b799ac..c8f98b8dc3 100644 --- a/tests/hooks/mod.rs +++ b/tests/hooks/mod.rs @@ -1,4 +1,4 @@ -use super::nu_repl::nu_repl; +use nu_test_support::{nu, nu_repl_code}; fn env_change_hook_code_list(name: &str, code_list: &[&str]) -> String { let mut list = String::new(); @@ -115,7 +115,7 @@ fn env_change_define_command() { "foo", ]; - let actual_repl = nu_repl("tests/hooks", inp); + let actual_repl = nu!(cwd: "tests/hooks", nu_repl_code(inp)); assert_eq!(actual_repl.err, ""); assert_eq!(actual_repl.out, "got foo!"); @@ -129,7 +129,7 @@ fn env_change_define_variable() { "$x", ]; - let actual_repl = nu_repl("tests/hooks", inp); + let actual_repl = nu!(cwd: "tests/hooks", nu_repl_code(inp)); assert_eq!(actual_repl.err, ""); assert_eq!(actual_repl.out, "spam"); @@ -143,7 +143,7 @@ fn env_change_define_env_var() { "$env.SPAM", ]; - let actual_repl = nu_repl("tests/hooks", inp); + let actual_repl = nu!(cwd: "tests/hooks", nu_repl_code(inp)); assert_eq!(actual_repl.err, ""); assert_eq!(actual_repl.out, "spam"); @@ -157,7 +157,7 @@ fn env_change_define_alias() { "spam", ]; - let actual_repl = nu_repl("tests/hooks", inp); + let actual_repl = nu!(cwd: "tests/hooks", nu_repl_code(inp)); assert_eq!(actual_repl.err, ""); assert_eq!(actual_repl.out, "spam"); @@ -171,7 +171,7 @@ fn env_change_simple_block_preserve_env_var() { "$env.SPAM", ]; - let actual_repl = nu_repl("tests/hooks", inp); + let actual_repl = nu!(cwd: "tests/hooks", nu_repl_code(inp)); assert_eq!(actual_repl.err, ""); assert_eq!(actual_repl.out, "spam"); @@ -191,7 +191,7 @@ fn env_change_simple_block_list_shadow_env_var() { "$env.SPAM", ]; - let actual_repl = nu_repl("tests/hooks", inp); + let actual_repl = nu!(cwd: "tests/hooks", nu_repl_code(inp)); assert_eq!(actual_repl.err, ""); assert_eq!(actual_repl.out, "spam"); @@ -205,7 +205,7 @@ fn env_change_block_preserve_env_var() { "$env.SPAM", ]; - let actual_repl = nu_repl("tests/hooks", inp); + let actual_repl = nu!(cwd: "tests/hooks", nu_repl_code(inp)); assert_eq!(actual_repl.err, ""); assert_eq!(actual_repl.out, "spam"); @@ -218,7 +218,7 @@ fn pre_prompt_define_command() { "foo", ]; - let actual_repl = nu_repl("tests/hooks", inp); + let actual_repl = nu!(cwd: "tests/hooks", nu_repl_code(inp)); assert_eq!(actual_repl.err, ""); assert_eq!(actual_repl.out, "got foo!"); @@ -231,7 +231,7 @@ fn pre_prompt_simple_block_preserve_env_var() { "$env.SPAM", ]; - let actual_repl = nu_repl("tests/hooks", inp); + let actual_repl = nu!(cwd: "tests/hooks", nu_repl_code(inp)); assert_eq!(actual_repl.err, ""); assert_eq!(actual_repl.out, "spam"); @@ -249,7 +249,7 @@ fn pre_prompt_simple_block_list_shadow_env_var() { "$env.SPAM", ]; - let actual_repl = nu_repl("tests/hooks", inp); + let actual_repl = nu!(cwd: "tests/hooks", nu_repl_code(inp)); assert_eq!(actual_repl.err, ""); assert_eq!(actual_repl.out, "spam"); @@ -262,7 +262,7 @@ fn pre_prompt_block_preserve_env_var() { "$env.SPAM", ]; - let actual_repl = nu_repl("tests/hooks", inp); + let actual_repl = nu!(cwd: "tests/hooks", nu_repl_code(inp)); assert_eq!(actual_repl.err, ""); assert_eq!(actual_repl.out, "spam"); @@ -275,7 +275,7 @@ fn pre_execution_define_command() { "foo", ]; - let actual_repl = nu_repl("tests/hooks", inp); + let actual_repl = nu!(cwd: "tests/hooks", nu_repl_code(inp)); assert_eq!(actual_repl.err, ""); assert_eq!(actual_repl.out, "got foo!"); @@ -288,7 +288,7 @@ fn pre_execution_simple_block_preserve_env_var() { "$env.SPAM", ]; - let actual_repl = nu_repl("tests/hooks", inp); + let actual_repl = nu!(cwd: "tests/hooks", nu_repl_code(inp)); assert_eq!(actual_repl.err, ""); assert_eq!(actual_repl.out, "spam"); @@ -306,7 +306,7 @@ fn pre_execution_simple_block_list_shadow_env_var() { "$env.SPAM", ]; - let actual_repl = nu_repl("tests/hooks", inp); + let actual_repl = nu!(cwd: "tests/hooks", nu_repl_code(inp)); assert_eq!(actual_repl.err, ""); assert_eq!(actual_repl.out, "spam"); @@ -319,7 +319,7 @@ fn pre_execution_block_preserve_env_var() { "$env.SPAM", ]; - let actual_repl = nu_repl("tests/hooks", inp); + let actual_repl = nu!(cwd: "tests/hooks", nu_repl_code(inp)); assert_eq!(actual_repl.err, ""); assert_eq!(actual_repl.out, "spam"); @@ -339,7 +339,7 @@ fn env_change_shadow_command() { "foo", ]; - let actual_repl = nu_repl("tests/hooks", inp); + let actual_repl = nu!(cwd: "tests/hooks", nu_repl_code(inp)); assert_eq!(actual_repl.err, ""); assert_eq!(actual_repl.out, "got foo!"); @@ -353,7 +353,7 @@ fn env_change_block_dont_preserve_command() { "foo", ]; - let actual_repl = nu_repl("tests/hooks", inp); + let actual_repl = nu!(cwd: "tests/hooks", nu_repl_code(inp)); #[cfg(windows)] assert!(actual_repl.out != "foo"); @@ -373,7 +373,7 @@ fn env_change_block_condition_pwd() { "$env.SPAM", ]; - let actual_repl = nu_repl("tests/hooks", inp); + let actual_repl = nu!(cwd: "tests/hooks", nu_repl_code(inp)); assert_eq!(actual_repl.err, ""); assert_eq!(actual_repl.out, "spam"); @@ -393,7 +393,7 @@ fn env_change_block_condition_correct_args() { "$env.SPAM", ]; - let actual_repl = nu_repl("tests/hooks", inp); + let actual_repl = nu!(cwd: "tests/hooks", nu_repl_code(inp)); assert_eq!(actual_repl.err, ""); assert_eq!(actual_repl.out, "true"); @@ -407,7 +407,7 @@ fn env_change_dont_panic_with_many_args() { "", ]; - let actual_repl = nu_repl("tests/hooks", inp); + let actual_repl = nu!(cwd: "tests/hooks", nu_repl_code(inp)); assert!(actual_repl.err.contains("IncompatibleParametersSingle")); assert_eq!(actual_repl.out, ""); @@ -427,7 +427,7 @@ fn err_hook_wrong_env_type_1() { "", ]; - let actual_repl = nu_repl("tests/hooks", inp); + let actual_repl = nu!(cwd: "tests/hooks", nu_repl_code(inp)); assert!(actual_repl.err.contains("UnsupportedConfigValue")); assert_eq!(actual_repl.out, ""); @@ -444,7 +444,7 @@ fn err_hook_wrong_env_type_2() { "", ]; - let actual_repl = nu_repl("tests/hooks", inp); + let actual_repl = nu!(cwd: "tests/hooks", nu_repl_code(inp)); assert!(actual_repl.err.contains("TypeMismatch")); assert_eq!(actual_repl.out, ""); @@ -466,7 +466,7 @@ fn err_hook_wrong_env_type_3() { "", ]; - let actual_repl = nu_repl("tests/hooks", inp); + let actual_repl = nu!(cwd: "tests/hooks", nu_repl_code(inp)); assert!(actual_repl.err.contains("UnsupportedConfigValue")); assert_eq!(actual_repl.out, ""); @@ -489,7 +489,7 @@ fn err_hook_non_boolean_condition_output() { "", ]; - let actual_repl = nu_repl("tests/hooks", inp); + let actual_repl = nu!(cwd: "tests/hooks", nu_repl_code(inp)); assert!(actual_repl.err.contains("UnsupportedConfigValue")); assert_eq!(actual_repl.out, ""); @@ -512,7 +512,7 @@ fn err_hook_non_condition_not_a_block() { "", ]; - let actual_repl = nu_repl("tests/hooks", inp); + let actual_repl = nu!(cwd: "tests/hooks", nu_repl_code(inp)); assert!(actual_repl.err.contains("UnsupportedConfigValue")); assert_eq!(actual_repl.out, ""); @@ -534,7 +534,7 @@ fn err_hook_parse_error() { "", ]; - let actual_repl = nu_repl("tests/hooks", inp); + let actual_repl = nu!(cwd: "tests/hooks", nu_repl_code(inp)); assert!(actual_repl.err.contains("UnsupportedConfigValue")); assert_eq!(actual_repl.out, ""); @@ -544,7 +544,7 @@ fn err_hook_parse_error() { fn err_hook_dont_allow_string() { let inp = &[&pre_prompt_hook(r#"'def foo [] { "got foo!" }'"#), "foo"]; - let actual_repl = nu_repl("tests/hooks", inp); + let actual_repl = nu!(cwd: "tests/hooks", nu_repl_code(inp)); assert!(actual_repl.out.is_empty()); assert!(actual_repl.err.contains("UnsupportedConfigValue")); diff --git a/tests/main.rs b/tests/main.rs index a74971e0ad..161292bd9a 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -2,7 +2,6 @@ extern crate nu_test_support; mod hooks; mod modules; -mod nu_repl; mod overlays; mod parsing; mod path; diff --git a/tests/nu_repl/mod.rs b/tests/nu_repl/mod.rs deleted file mode 100644 index 586c073e94..0000000000 --- a/tests/nu_repl/mod.rs +++ /dev/null @@ -1,130 +0,0 @@ -use nu_cli::{eval_env_change_hook, eval_hook}; -use nu_command::create_default_context; -use nu_engine::eval_block; -use nu_parser::parse; -use nu_protocol::engine::{EngineState, Stack, StateWorkingSet}; -use nu_protocol::{CliError, PipelineData, Span, Value}; -use nu_test_support::fs::in_directory; -use nu_test_support::Outcome; - -fn outcome_err( - engine_state: &EngineState, - error: &(dyn miette::Diagnostic + Send + Sync + 'static), -) -> Outcome { - let working_set = StateWorkingSet::new(engine_state); - - eprintln!("Error: {:?}", CliError(error, &working_set)); - - Outcome { - out: String::new(), - err: format!("{:?}", error), - } -} - -fn outcome_ok(msg: String) -> Outcome { - Outcome { - out: msg, - err: String::new(), - } -} - -pub fn nu_repl(cwd: &str, source_lines: &[&str]) -> Outcome { - let cwd = in_directory(cwd); - - let mut engine_state = create_default_context(); - let mut stack = Stack::new(); - - stack.add_env_var( - "PWD".to_string(), - Value::String { - val: cwd.to_string(), - span: Span::test_data(), - }, - ); - - let mut last_output = String::new(); - - for (i, line) in source_lines.iter().enumerate() { - let cwd = match nu_engine::env::current_dir(&engine_state, &stack) { - Ok(d) => d, - Err(err) => { - return outcome_err(&engine_state, &err); - } - }; - - // Before doing anything, merge the environment from the previous REPL iteration into the - // permanent state. - if let Err(err) = engine_state.merge_env(&mut stack, &cwd) { - return outcome_err(&engine_state, &err); - } - - // Check for pre_prompt hook - let config = engine_state.get_config(); - if let Some(hook) = config.hooks.pre_prompt.clone() { - if let Err(err) = eval_hook(&mut engine_state, &mut stack, vec![], &hook) { - return outcome_err(&engine_state, &err); - } - } - - // Check for env change hook - let config = engine_state.get_config(); - if let Err(err) = eval_env_change_hook( - config.hooks.env_change.clone(), - &mut engine_state, - &mut stack, - ) { - return outcome_err(&engine_state, &err); - } - - // Check for pre_execution hook - let config = engine_state.get_config(); - if let Some(hook) = config.hooks.pre_execution.clone() { - if let Err(err) = eval_hook(&mut engine_state, &mut stack, vec![], &hook) { - return outcome_err(&engine_state, &err); - } - } - - // Eval the REPL line - let (block, delta) = { - let mut working_set = StateWorkingSet::new(&engine_state); - let (block, err) = parse( - &mut working_set, - Some(&format!("line{}", i)), - line.as_bytes(), - false, - &[], - ); - - if let Some(err) = err { - return outcome_err(&engine_state, &err); - } - (block, working_set.render()) - }; - - if let Err(err) = engine_state.merge_delta(delta) { - return outcome_err(&engine_state, &err); - } - - let input = PipelineData::new(Span::test_data()); - let config = engine_state.get_config(); - - match eval_block(&engine_state, &mut stack, &block, input, false, false) { - Ok(pipeline_data) => match pipeline_data.collect_string("", config) { - Ok(s) => last_output = s, - Err(err) => return outcome_err(&engine_state, &err), - }, - Err(err) => return outcome_err(&engine_state, &err), - } - - if let Some(cwd) = stack.get_env_var(&engine_state, "PWD") { - let path = match cwd.as_string() { - Ok(p) => p, - Err(err) => return outcome_err(&engine_state, &err), - }; - let _ = std::env::set_current_dir(path); - engine_state.add_env_var("PWD".into(), cwd); - } - } - - outcome_ok(last_output) -} diff --git a/tests/overlays/mod.rs b/tests/overlays/mod.rs index 91ad5ef667..5e666b5c94 100644 --- a/tests/overlays/mod.rs +++ b/tests/overlays/mod.rs @@ -1,5 +1,4 @@ -use super::nu_repl::nu_repl; -use nu_test_support::{nu, pipeline}; +use nu_test_support::{nu, nu_repl_code, pipeline}; #[test] fn add_overlay() { @@ -10,7 +9,7 @@ fn add_overlay() { ]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert_eq!(actual.out, "foo"); assert_eq!(actual_repl.out, "foo"); @@ -25,7 +24,7 @@ fn add_overlay_env() { ]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert_eq!(actual.out, "foo"); assert_eq!(actual_repl.out, "foo"); @@ -36,7 +35,7 @@ fn add_overlay_from_file_decl() { let inp = &[r#"overlay add samples/spam.nu"#, r#"foo"#]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert_eq!(actual.out, "foo"); assert_eq!(actual_repl.out, "foo"); @@ -47,7 +46,7 @@ fn add_overlay_from_file_decl() { fn add_overlay_from_file_decl_cd() { let inp = &[r#"cd samples"#, r#"overlay add spam.nu"#, r#"foo"#]; - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert_eq!(actual_repl.out, "foo"); } @@ -57,7 +56,7 @@ fn add_overlay_from_file_alias() { let inp = &[r#"overlay add samples/spam.nu"#, r#"bar"#]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert_eq!(actual.out, "bar"); assert_eq!(actual_repl.out, "bar"); @@ -68,7 +67,7 @@ fn add_overlay_from_file_env() { let inp = &[r#"overlay add samples/spam.nu"#, r#"$env.BAZ"#]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert_eq!(actual.out, "baz"); assert_eq!(actual_repl.out, "baz"); @@ -83,7 +82,7 @@ fn add_overlay_scoped() { ]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert!(!actual.err.is_empty()); #[cfg(windows)] @@ -103,7 +102,7 @@ fn update_overlay_from_module() { ]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert_eq!(actual.out, "bar"); assert_eq!(actual_repl.out, "bar"); @@ -120,7 +119,7 @@ fn update_overlay_from_module_env() { ]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert_eq!(actual.out, "bar"); assert_eq!(actual_repl.out, "bar"); @@ -136,7 +135,7 @@ fn remove_overlay() { ]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert!(!actual.err.is_empty()); #[cfg(windows)] @@ -155,7 +154,7 @@ fn remove_last_overlay() { ]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert!(!actual.err.is_empty()); #[cfg(windows)] @@ -174,7 +173,7 @@ fn remove_overlay_scoped() { ]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert_eq!(actual.out, "foo"); assert_eq!(actual_repl.out, "foo"); @@ -190,7 +189,7 @@ fn remove_overlay_env() { ]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert!(actual.err.contains("did you mean")); assert!(actual_repl.err.contains("DidYouMean")); @@ -206,7 +205,7 @@ fn remove_overlay_scoped_env() { ]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert_eq!(actual.out, "foo"); assert_eq!(actual_repl.out, "foo"); @@ -217,7 +216,7 @@ fn list_default_overlay() { let inp = &[r#"overlay list | last"#]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert_eq!(actual.out, "zero"); assert_eq!(actual_repl.out, "zero"); @@ -232,7 +231,7 @@ fn list_last_overlay() { ]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert_eq!(actual.out, "spam"); assert_eq!(actual_repl.out, "spam"); @@ -247,7 +246,7 @@ fn list_overlay_scoped() { ]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert_eq!(actual.out, "spam"); assert_eq!(actual_repl.out, "spam"); @@ -263,7 +262,7 @@ fn remove_overlay_discard_decl() { ]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert!(!actual.err.is_empty()); #[cfg(windows)] @@ -282,7 +281,7 @@ fn remove_overlay_discard_alias() { ]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert!(!actual.err.is_empty()); #[cfg(windows)] @@ -295,13 +294,13 @@ fn remove_overlay_discard_alias() { fn remove_overlay_discard_env() { let inp = &[ r#"overlay add samples/spam.nu"#, - r#"let-env BAGR = "bagr""#, + r#"let-env BAGR = `bagr`"#, r#"overlay remove spam"#, r#"$env.BAGR"#, ]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert!(actual.err.contains("did you mean")); assert!(actual_repl.err.contains("DidYouMean")); @@ -317,7 +316,7 @@ fn remove_overlay_keep_decl() { ]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert!(actual.out.contains("bagr")); assert!(actual_repl.out.contains("bagr")); @@ -327,13 +326,13 @@ fn remove_overlay_keep_decl() { fn remove_overlay_keep_alias() { let inp = &[ r#"overlay add samples/spam.nu"#, - r#"alias bagr = "bagr""#, + r#"alias bagr = `bagr`"#, r#"overlay remove --keep-custom spam"#, r#"bagr"#, ]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert!(actual.out.contains("bagr")); assert!(actual_repl.out.contains("bagr")); @@ -343,13 +342,13 @@ fn remove_overlay_keep_alias() { fn remove_overlay_keep_env() { let inp = &[ r#"overlay add samples/spam.nu"#, - r#"let-env BAGR = "bagr""#, + r#"let-env BAGR = `bagr`"#, r#"overlay remove --keep-custom spam"#, r#"$env.BAGR"#, ]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert!(actual.out.contains("bagr")); assert!(actual_repl.out.contains("bagr")); @@ -365,7 +364,7 @@ fn remove_overlay_keep_discard_overwritten_decl() { ]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert!(!actual.err.is_empty()); #[cfg(windows)] @@ -378,13 +377,13 @@ fn remove_overlay_keep_discard_overwritten_decl() { fn remove_overlay_keep_discard_overwritten_alias() { let inp = &[ r#"overlay add samples/spam.nu"#, - r#"alias bar = 'baz'"#, + r#"alias bar = `baz`"#, r#"overlay remove --keep-custom spam"#, r#"bar"#, ]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert!(!actual.err.is_empty()); #[cfg(windows)] @@ -397,13 +396,13 @@ fn remove_overlay_keep_discard_overwritten_alias() { fn remove_overlay_keep_discard_overwritten_env() { let inp = &[ r#"overlay add samples/spam.nu"#, - r#"let-env BAZ = "bagr""#, + r#"let-env BAZ = `bagr`"#, r#"overlay remove --keep-custom spam"#, r#"$env.BAZ"#, ]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert!(actual.err.contains("did you mean")); assert!(actual_repl.err.contains("DidYouMean")); @@ -421,7 +420,7 @@ fn remove_overlay_keep_decl_in_latest_overlay() { ]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert!(actual.out.contains("bagr")); assert!(actual_repl.out.contains("bagr")); @@ -431,7 +430,7 @@ fn remove_overlay_keep_decl_in_latest_overlay() { fn remove_overlay_keep_alias_in_latest_overlay() { let inp = &[ r#"overlay add samples/spam.nu"#, - r#"alias bagr = 'bagr'"#, + r#"alias bagr = `bagr`"#, r#"module eggs { }"#, r#"overlay add eggs"#, r#"overlay remove --keep-custom spam"#, @@ -439,7 +438,7 @@ fn remove_overlay_keep_alias_in_latest_overlay() { ]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert!(actual.out.contains("bagr")); assert!(actual_repl.out.contains("bagr")); @@ -449,7 +448,7 @@ fn remove_overlay_keep_alias_in_latest_overlay() { fn remove_overlay_keep_env_in_latest_overlay() { let inp = &[ r#"overlay add samples/spam.nu"#, - r#"let-env BAGR = "bagr""#, + r#"let-env BAGR = `bagr`"#, r#"module eggs { }"#, r#"overlay add eggs"#, r#"overlay remove --keep-custom spam"#, @@ -457,7 +456,7 @@ fn remove_overlay_keep_env_in_latest_overlay() { ]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert!(actual.out.contains("bagr")); assert!(actual_repl.out.contains("bagr")); @@ -474,7 +473,7 @@ fn preserve_overrides() { ]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert_eq!(actual.out, "new-foo"); assert_eq!(actual_repl.out, "new-foo"); @@ -491,7 +490,7 @@ fn reset_overrides() { ]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert_eq!(actual.out, "foo"); assert_eq!(actual_repl.out, "foo"); @@ -502,7 +501,7 @@ fn overlay_new() { let inp = &[r#"overlay new spam"#, r#"overlay list | last"#]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert_eq!(actual.out, "spam"); assert_eq!(actual_repl.out, "spam"); @@ -518,7 +517,7 @@ fn overlay_keep_pwd() { ]; let actual = nu!(cwd: "tests/overlays", pipeline(&inp.join("; "))); - let actual_repl = nu_repl("tests/overlays", inp); + let actual_repl = nu!(cwd: "tests/overlays", nu_repl_code(inp)); assert_eq!(actual.out, "samples"); assert_eq!(actual_repl.out, "samples"); diff --git a/tests/shell/mod.rs b/tests/shell/mod.rs index d4122fadf7..5b30142119 100644 --- a/tests/shell/mod.rs +++ b/tests/shell/mod.rs @@ -1,4 +1,6 @@ -use nu_test_support::{nu, pipeline}; +use nu_test_support::fs::Stub::FileWithContentToBeTrimmed; +use nu_test_support::playground::Playground; +use nu_test_support::{nu, nu_repl_code, pipeline}; #[cfg(feature = "which-support")] mod environment; @@ -56,3 +58,115 @@ fn do_not_panic_if_broken_pipe() { assert!(child_output.stderr.is_empty()); } + +#[test] +fn nu_lib_dirs_repl() { + Playground::setup("nu_lib_dirs_repl", |dirs, sandbox| { + sandbox + .mkdir("scripts") + .with_files(vec![FileWithContentToBeTrimmed( + "scripts/foo.nu", + r#" + let-env FOO = "foo" + "#, + )]); + + let inp_lines = &[ + r#"let-env NU_LIB_DIRS = [ ('scripts' | path expand) ]"#, + r#"source foo.nu"#, + r#"$env.FOO"#, + ]; + + let actual_repl = nu!(cwd: dirs.test(), nu_repl_code(inp_lines)); + + assert!(actual_repl.err.is_empty()); + assert_eq!(actual_repl.out, "foo"); + }) +} + +#[test] +fn nu_lib_dirs_script() { + Playground::setup("nu_lib_dirs_script", |dirs, sandbox| { + sandbox + .mkdir("scripts") + .with_files(vec![FileWithContentToBeTrimmed( + "scripts/foo.nu", + r#" + let-env FOO = "foo" + "#, + )]) + .with_files(vec![FileWithContentToBeTrimmed( + "main.nu", + r#" + source foo.nu + "#, + )]); + + let inp_lines = &[ + r#"let-env NU_LIB_DIRS = [ ('scripts' | path expand) ]"#, + r#"source main.nu"#, + r#"$env.FOO"#, + ]; + + let actual_repl = nu!(cwd: dirs.test(), nu_repl_code(inp_lines)); + + assert!(actual_repl.err.is_empty()); + assert_eq!(actual_repl.out, "foo"); + }) +} + +#[test] +fn nu_lib_dirs_relative_repl() { + Playground::setup("nu_lib_dirs_relative_repl", |dirs, sandbox| { + sandbox + .mkdir("scripts") + .with_files(vec![FileWithContentToBeTrimmed( + "scripts/foo.nu", + r#" + let-env FOO = "foo" + "#, + )]); + + let inp_lines = &[ + r#"let-env NU_LIB_DIRS = [ 'scripts' ]"#, + r#"source foo.nu"#, + r#"$env.FOO"#, + ]; + + let actual_repl = nu!(cwd: dirs.test(), nu_repl_code(inp_lines)); + + assert!(actual_repl.err.is_empty()); + assert_eq!(actual_repl.out, "foo"); + }) +} + +#[test] +fn nu_lib_dirs_relative_script() { + Playground::setup("nu_lib_dirs_relative_script", |dirs, sandbox| { + sandbox + .mkdir("scripts") + .with_files(vec![FileWithContentToBeTrimmed( + "scripts/main.nu", + r#" + source ../foo.nu + "#, + )]) + .with_files(vec![FileWithContentToBeTrimmed( + "foo.nu", + r#" + let-env FOO = "foo" + "#, + )]); + + let inp_lines = &[ + r#"let-env NU_LIB_DIRS = [ 'scripts' ]"#, + r#"source scripts/main.nu"#, + r#"$env.FOO"#, + ]; + + let actual_repl = nu!(cwd: dirs.test(), nu_repl_code(inp_lines)); + + assert!(actual_repl.err.is_empty()); + assert_eq!(actual_repl.out, "foo"); + }) +}