Merged tests to produce a single binary (#12826)

This PR should close #7147 

# Description
Merged src/tests into /tests to produce a single binary.

![image](https://github.com/nushell/nushell/assets/94604837/84726469-d447-4619-b6d1-2d1415d0f42e)

# User-Facing Changes
No user facing changes

# Tests + Formatting
Moved tests. Tollkit check pr pass.

# After Submitting

---------

Co-authored-by: Ian Manske <ian.manske@pm.me>
This commit is contained in:
francesco-gaglione
2024-05-13 15:37:53 +02:00
committed by GitHub
parent c70c43aae9
commit c4dca5fe03
31 changed files with 53 additions and 59 deletions

View File

@ -7,8 +7,6 @@ mod signals;
#[cfg(unix)]
mod terminal;
mod test_bins;
#[cfg(test)]
mod tests;
#[cfg(feature = "mimalloc")]
#[global_allocator]

View File

@ -1,191 +0,0 @@
mod test_bits;
mod test_cell_path;
mod test_commandline;
mod test_conditionals;
mod test_config;
mod test_config_path;
mod test_converters;
mod test_custom_commands;
mod test_engine;
mod test_env;
mod test_help;
mod test_hiding;
mod test_ide;
mod test_iteration;
mod test_known_external;
mod test_math;
mod test_modules;
mod test_parser;
mod test_ranges;
mod test_regex;
mod test_signatures;
mod test_spread;
mod test_stdlib;
mod test_strings;
mod test_table_operations;
mod test_type_check;
use assert_cmd::prelude::*;
use pretty_assertions::assert_eq;
use std::collections::HashMap;
use std::io::Write;
use std::process::Command;
use tempfile::NamedTempFile;
pub type TestResult = Result<(), Box<dyn std::error::Error>>;
pub fn run_test_with_env(input: &str, expected: &str, env: &HashMap<&str, &str>) -> TestResult {
let mut file = NamedTempFile::new()?;
let name = file.path();
let mut cmd = Command::cargo_bin("nu")?;
cmd.arg("--no-config-file");
cmd.arg(name).envs(env);
writeln!(file, "{input}")?;
run_cmd_and_assert(cmd, expected)
}
#[cfg(test)]
pub fn run_test(input: &str, expected: &str) -> TestResult {
let mut file = NamedTempFile::new()?;
let name = file.path();
let mut cmd = Command::cargo_bin("nu")?;
cmd.arg("--no-std-lib");
cmd.arg("--no-config-file");
cmd.arg(name);
cmd.env(
"PWD",
std::env::current_dir().expect("Can't get current dir"),
);
writeln!(file, "{input}")?;
run_cmd_and_assert(cmd, expected)
}
#[cfg(test)]
pub fn run_test_std(input: &str, expected: &str) -> TestResult {
let mut file = NamedTempFile::new()?;
let name = file.path();
let mut cmd = Command::cargo_bin("nu")?;
cmd.arg("--no-config-file");
cmd.arg(name);
cmd.env(
"PWD",
std::env::current_dir().expect("Can't get current dir"),
);
writeln!(file, "{input}")?;
run_cmd_and_assert(cmd, expected)
}
#[cfg(test)]
fn run_cmd_and_assert(mut cmd: Command, expected: &str) -> TestResult {
let output = cmd.output()?;
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
println!("stdout: {stdout}");
println!("stderr: {stderr}");
assert!(output.status.success());
assert_eq!(stdout.trim(), expected);
Ok(())
}
#[cfg(test)]
pub fn run_test_contains(input: &str, expected: &str) -> TestResult {
let mut file = NamedTempFile::new()?;
let name = file.path();
let mut cmd = Command::cargo_bin("nu")?;
cmd.arg("--no-std-lib");
cmd.arg("--no-config-file");
cmd.arg(name);
writeln!(file, "{input}")?;
let output = cmd.output()?;
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
println!("stdout: {stdout}");
println!("stderr: {stderr}");
println!("Expected output to contain: {expected}");
assert!(output.status.success());
assert!(stdout.contains(expected));
Ok(())
}
#[cfg(test)]
pub fn test_ide_contains(input: &str, ide_commands: &[&str], expected: &str) -> TestResult {
let mut file = NamedTempFile::new()?;
let name = file.path();
let mut cmd = Command::cargo_bin("nu")?;
cmd.arg("--no-std-lib");
cmd.arg("--no-config-file");
for ide_command in ide_commands {
cmd.arg(ide_command);
}
cmd.arg(name);
writeln!(file, "{input}")?;
let output = cmd.output()?;
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
println!("stdout: {stdout}");
println!("stderr: {stderr}");
println!("Expected output to contain: {expected}");
assert!(output.status.success());
assert!(stdout.contains(expected));
Ok(())
}
#[cfg(test)]
pub fn fail_test(input: &str, expected: &str) -> TestResult {
let mut file = NamedTempFile::new()?;
let name = file.path();
let mut cmd = Command::cargo_bin("nu")?;
cmd.arg("--no-std-lib");
cmd.arg("--no-config-file");
cmd.arg(name);
cmd.env(
"PWD",
std::env::current_dir().expect("Can't get current dir"),
);
writeln!(file, "{input}")?;
let output = cmd.output()?;
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
println!("stdout: {stdout}");
println!("stderr: {stderr}");
println!("Expected error to contain: {expected}");
assert!(!stderr.is_empty() && stderr.contains(expected));
Ok(())
}

View File

@ -1,124 +0,0 @@
use crate::tests::{run_test, TestResult};
#[test]
fn bits_and() -> TestResult {
run_test("2 | bits and 4", "0")
}
#[test]
fn bits_and_negative() -> TestResult {
run_test("-3 | bits and 5", "5")
}
#[test]
fn bits_and_list() -> TestResult {
run_test("[1 2 3 8 9 10] | bits and 2 | str join '.'", "0.2.2.0.0.2")
}
#[test]
fn bits_or() -> TestResult {
run_test("2 | bits or 3", "3")
}
#[test]
fn bits_or_negative() -> TestResult {
run_test("-3 | bits or 5", "-3")
}
#[test]
fn bits_or_list() -> TestResult {
run_test(
"[1 2 3 8 9 10] | bits or 2 | str join '.'",
"3.2.3.10.11.10",
)
}
#[test]
fn bits_xor() -> TestResult {
run_test("2 | bits xor 3", "1")
}
#[test]
fn bits_xor_negative() -> TestResult {
run_test("-3 | bits xor 5", "-8")
}
#[test]
fn bits_xor_list() -> TestResult {
run_test(
"[1 2 3 8 9 10] | bits xor 2 | into string | str join '.'",
"3.0.1.10.11.8",
)
}
#[test]
fn bits_shift_left() -> TestResult {
run_test("2 | bits shl 3", "16")
}
#[test]
fn bits_shift_left_negative() -> TestResult {
run_test("-3 | bits shl 5", "-96")
}
#[test]
fn bits_shift_left_list() -> TestResult {
run_test(
"[1 2 7 32 9 10] | bits shl 3 | str join '.'",
"8.16.56.0.72.80",
)
}
#[test]
fn bits_shift_right() -> TestResult {
run_test("8 | bits shr 2", "2")
}
#[test]
fn bits_shift_right_negative() -> TestResult {
run_test("-32 | bits shr 2", "-8")
}
#[test]
fn bits_shift_right_list() -> TestResult {
run_test(
"[12 98 7 64 900 10] | bits shr 3 | str join '.'",
"1.12.0.8.112.1",
)
}
#[test]
fn bits_rotate_left() -> TestResult {
run_test("2 | bits rol 3", "16")
}
#[test]
fn bits_rotate_left_negative() -> TestResult {
run_test("-3 | bits rol 5", "-65")
}
#[test]
fn bits_rotate_left_list() -> TestResult {
run_test(
"[1 2 7 32 9 10] | bits rol 3 | str join '.'",
"8.16.56.1.72.80",
)
}
#[test]
fn bits_rotate_right() -> TestResult {
run_test("2 | bits ror 62", "8")
}
#[test]
fn bits_rotate_right_negative() -> TestResult {
run_test("-3 | bits ror 60", "-33")
}
#[test]
fn bits_rotate_right_list() -> TestResult {
run_test(
"[1 2 7 32 23 10] | bits ror 60 | str join '.'",
"16.32.112.2.113.160",
)
}

View File

@ -1,156 +0,0 @@
use crate::tests::{fail_test, run_test, TestResult};
// Tests for null / null / Value::Nothing
#[test]
fn nothing_fails_string() -> TestResult {
fail_test("let nil = null; $nil.foo", "doesn't support cell paths")
}
#[test]
fn nothing_fails_int() -> TestResult {
fail_test("let nil = null; $nil.3", "doesn't support cell paths")
}
// Tests for records
#[test]
fn record_single_field_success() -> TestResult {
run_test("{foo: 'bar'}.foo == 'bar'", "true")
}
#[test]
fn record_single_field_optional_success() -> TestResult {
run_test("{foo: 'bar'}.foo? == 'bar'", "true")
}
#[test]
fn get_works_with_cell_path_success() -> TestResult {
run_test("{foo: 'bar'} | get foo?", "bar")
}
#[test]
fn get_works_with_cell_path_missing_data() -> TestResult {
run_test("{foo: 'bar'} | get foobar? | to nuon", "null")
}
#[test]
fn record_single_field_failure() -> TestResult {
fail_test("{foo: 'bar'}.foobar", "")
}
#[test]
fn record_int_failure() -> TestResult {
fail_test("{foo: 'bar'}.3", "")
}
#[test]
fn record_single_field_optional() -> TestResult {
run_test("{foo: 'bar'}.foobar? | to nuon", "null")
}
#[test]
fn record_single_field_optional_short_circuits() -> TestResult {
// Check that we return null as soon as the `.foobar?` access
// fails instead of erroring on the `.baz` access
run_test("{foo: 'bar'}.foobar?.baz | to nuon", "null")
}
#[test]
fn record_multiple_optional_fields() -> TestResult {
run_test("{foo: 'bar'}.foobar?.baz? | to nuon", "null")
}
#[test]
fn nested_record_field_success() -> TestResult {
run_test("{foo: {bar: 'baz'} }.foo.bar == 'baz'", "true")
}
#[test]
fn nested_record_field_failure() -> TestResult {
fail_test("{foo: {bar: 'baz'} }.foo.asdf", "")
}
#[test]
fn nested_record_field_optional() -> TestResult {
run_test("{foo: {bar: 'baz'} }.foo.asdf? | to nuon", "null")
}
#[test]
fn record_with_nested_list_success() -> TestResult {
run_test("{foo: [{bar: 'baz'}]}.foo.0.bar == 'baz'", "true")
}
#[test]
fn record_with_nested_list_int_failure() -> TestResult {
fail_test("{foo: [{bar: 'baz'}]}.foo.3.bar", "")
}
#[test]
fn record_with_nested_list_column_failure() -> TestResult {
fail_test("{foo: [{bar: 'baz'}]}.foo.0.asdf", "")
}
// Tests for lists
#[test]
fn list_single_field_success() -> TestResult {
run_test("[{foo: 'bar'}].foo.0 == 'bar'", "true")?;
// test field access both ways
run_test("[{foo: 'bar'}].0.foo == 'bar'", "true")
}
#[test]
fn list_single_field_failure() -> TestResult {
fail_test("[{foo: 'bar'}].asdf", "")
}
// Test the scenario where the requested column is not present in all rows
#[test]
fn jagged_list_access_fails() -> TestResult {
fail_test("[{foo: 'bar'}, {}].foo", "cannot find column")?;
fail_test("[{}, {foo: 'bar'}].foo", "cannot find column")
}
#[test]
fn jagged_list_optional_access_succeeds() -> TestResult {
run_test("[{foo: 'bar'}, {}].foo?.0", "bar")?;
run_test("[{foo: 'bar'}, {}].foo?.1 | to nuon", "null")?;
run_test("[{}, {foo: 'bar'}].foo?.0 | to nuon", "null")?;
run_test("[{}, {foo: 'bar'}].foo?.1", "bar")
}
// test that accessing a nonexistent row fails
#[test]
fn list_row_access_failure() -> TestResult {
fail_test("[{foo: 'bar'}, {foo: 'baz'}].2", "")
}
#[test]
fn list_row_optional_access_succeeds() -> TestResult {
run_test("[{foo: 'bar'}, {foo: 'baz'}].2? | to nuon", "null")?;
run_test("[{foo: 'bar'}, {foo: 'baz'}].3? | to nuon", "null")
}
// regression test for an old bug
#[test]
fn do_not_delve_too_deep_in_nested_lists() -> TestResult {
fail_test("[[{foo: bar}]].foo", "cannot find column")
}
#[test]
fn cell_path_literals() -> TestResult {
run_test("let cell_path = $.a.b; {a: {b: 3}} | get $cell_path", "3")
}
// Test whether cell path access short-circuits properly
#[test]
fn deeply_nested_cell_path_short_circuits() -> TestResult {
run_test(
"{foo: [{bar: 'baz'}]}.foo.3?.bar.asdfdafg.234.foobar | to nuon",
"null",
)
}
#[test]
fn cell_path_type() -> TestResult {
run_test("$.a.b | describe", "cell-path")
}

View File

@ -1,142 +0,0 @@
use crate::tests::{fail_test, run_test, TestResult};
#[test]
fn commandline_test_get_empty() -> TestResult {
run_test("commandline", "")
}
#[test]
fn commandline_test_append() -> TestResult {
run_test(
"commandline edit --replace '0👩👩2'\n\
commandline set-cursor 2\n\
commandline edit --append 'ab'\n\
print (commandline)\n\
commandline get-cursor",
"0👩👩2ab\n\
2",
)
}
#[test]
fn commandline_test_insert() -> TestResult {
run_test(
"commandline edit --replace '0👩👩2'\n\
commandline set-cursor 2\n\
commandline edit --insert 'ab'\n\
print (commandline)\n\
commandline get-cursor",
"0👩👩ab2\n\
4",
)
}
#[test]
fn commandline_test_replace() -> TestResult {
run_test(
"commandline edit --replace '0👩👩2'\n\
commandline edit --replace 'ab'\n\
print (commandline)\n\
commandline get-cursor",
"ab\n\
2",
)
}
#[test]
fn commandline_test_cursor() -> TestResult {
run_test(
"commandline edit --replace '0👩👩2'\n\
commandline set-cursor 1\n\
commandline edit --insert 'x'\n\
commandline",
"0x👩👩2",
)?;
run_test(
"commandline edit --replace '0👩👩2'\n\
commandline set-cursor 2\n\
commandline edit --insert 'x'\n\
commandline",
"0👩👩x2",
)
}
#[test]
fn commandline_test_cursor_show_pos_begin() -> TestResult {
run_test(
"commandline edit --replace '0👩👩'\n\
commandline set-cursor 0\n\
commandline get-cursor",
"0",
)
}
#[test]
fn commandline_test_cursor_show_pos_end() -> TestResult {
run_test(
"commandline edit --replace '0👩👩'\n\
commandline set-cursor 2\n\
commandline get-cursor",
"2",
)
}
#[test]
fn commandline_test_cursor_show_pos_mid() -> TestResult {
run_test(
"commandline edit --replace '0👩👩2'\n\
commandline set-cursor 1\n\
commandline get-cursor",
"1",
)?;
run_test(
"commandline edit --replace '0👩👩2'\n\
commandline set-cursor 2\n\
commandline get-cursor",
"2",
)
}
#[test]
fn commandline_test_cursor_too_small() -> TestResult {
run_test(
"commandline edit --replace '123456'\n\
commandline set-cursor -1\n\
commandline edit --insert '0'\n\
commandline",
"0123456",
)
}
#[test]
fn commandline_test_cursor_too_large() -> TestResult {
run_test(
"commandline edit --replace '123456'\n\
commandline set-cursor 10\n\
commandline edit --insert '0'\n\
commandline",
"1234560",
)
}
#[test]
fn commandline_test_cursor_invalid() -> TestResult {
fail_test(
"commandline edit --replace '123456'\n\
commandline set-cursor 'abc'",
"expected int",
)
}
#[test]
fn commandline_test_cursor_end() -> TestResult {
run_test(
"commandline edit --insert '🤔🤔'; commandline set-cursor --end; commandline get-cursor",
"2", // 2 graphemes
)
}
#[test]
fn commandline_test_cursor_type() -> TestResult {
run_test("commandline get-cursor | describe", "int")
}

View File

@ -1,77 +0,0 @@
use crate::tests::{run_test, TestResult};
#[test]
fn if_test1() -> TestResult {
run_test("if true { 10 } else { 20 } ", "10")
}
#[test]
fn if_test2() -> TestResult {
run_test("if false { 10 } else { 20 } ", "20")
}
#[test]
fn simple_if() -> TestResult {
run_test("if true { 10 } ", "10")
}
#[test]
fn simple_if2() -> TestResult {
run_test("if false { 10 } ", "")
}
#[test]
fn if_cond() -> TestResult {
run_test("if 2 < 3 { 3 } ", "3")
}
#[test]
fn if_cond2() -> TestResult {
run_test("if 2 > 3 { 3 } ", "")
}
#[test]
fn if_cond3() -> TestResult {
run_test("if 2 < 3 { 5 } else { 4 } ", "5")
}
#[test]
fn if_cond4() -> TestResult {
run_test("if 2 > 3 { 5 } else { 4 } ", "4")
}
#[test]
fn if_elseif1() -> TestResult {
run_test("if 2 > 3 { 5 } else if 6 < 7 { 4 } ", "4")
}
#[test]
fn if_elseif2() -> TestResult {
run_test("if 2 < 3 { 5 } else if 6 < 7 { 4 } else { 8 } ", "5")
}
#[test]
fn if_elseif3() -> TestResult {
run_test("if 2 > 3 { 5 } else if 6 > 7 { 4 } else { 8 } ", "8")
}
#[test]
fn if_elseif4() -> TestResult {
run_test("if 2 > 3 { 5 } else if 6 < 7 { 4 } else { 8 } ", "4")
}
#[test]
fn mutation_in_else() -> TestResult {
run_test(
"mut x = 100; if 2 > 3 { $x = 200 } else { $x = 300 }; $x ",
"300",
)
}
#[test]
fn mutation_in_else2() -> TestResult {
run_test(
"mut x = 100; if 2 > 3 { $x = 200 } else if true { $x = 400 } else { $x = 300 }; $x ",
"400",
)
}

View File

@ -1,171 +0,0 @@
use super::{fail_test, run_test, run_test_std};
use crate::tests::TestResult;
#[test]
fn mutate_nu_config() -> TestResult {
run_test_std(
r#"$env.config.footer_mode = 30; $env.config.footer_mode"#,
"30",
)
}
#[test]
fn mutate_nu_config_nested_ls() -> TestResult {
run_test_std(
r#"$env.config.ls.clickable_links = false; $env.config.ls.clickable_links"#,
"false",
)
}
#[test]
fn mutate_nu_config_nested_table() -> TestResult {
run_test_std(
r#"
$env.config.table.trim.methodology = wrapping
$env.config.table.trim.wrapping_try_keep_words = false
$env.config.table.trim.wrapping_try_keep_words
"#,
"false",
)
}
#[test]
fn mutate_nu_config_nested_menu() -> TestResult {
run_test_std(
r#"
$env.config.menus = [
{
name: menu
only_buffer_difference: true
marker: "M "
type: {}
style: {}
}
];
$env.config.menus.0.type.columns = 3;
$env.config.menus.0.type.columns
"#,
"3",
)
}
#[test]
fn mutate_nu_config_nested_keybindings() -> TestResult {
run_test_std(
r#"
$env.config.keybindings = [
{
name: completion_previous
modifier: shift
keycode: backtab
mode: [ vi_normal, vi_insert ]
event: { send: menuprevious }
}
];
$env.config.keybindings.0.keycode = 'char_x';
$env.config.keybindings.0.keycode
"#,
"char_x",
)
}
#[test]
fn mutate_nu_config_nested_color_nested() -> TestResult {
run_test_std(
r#"$env.config.color_config.shape_flag = 'cyan'; $env.config.color_config.shape_flag"#,
"cyan",
)
}
#[test]
fn mutate_nu_config_nested_completion() -> TestResult {
run_test_std(
r#"$env.config.completions.external.enable = false; $env.config.completions.external.enable"#,
"false",
)
}
#[test]
fn mutate_nu_config_nested_history() -> TestResult {
run_test_std(
r#"$env.config.history.max_size = 100; $env.config.history.max_size"#,
"100",
)
}
#[test]
fn mutate_nu_config_nested_filesize() -> TestResult {
run_test_std(
r#"$env.config.filesize.format = 'kb'; $env.config.filesize.format"#,
"kb",
)
}
#[test]
fn mutate_nu_config_plugin() -> TestResult {
run_test_std(
r#"
$env.config.plugins = {
config: {
key1: value
key2: other
}
};
$env.config.plugins.config.key1 = 'updated'
$env.config.plugins.config.key1
"#,
"updated",
)
}
#[test]
fn reject_nu_config_plugin_non_record() -> TestResult {
fail_test(r#"$env.config.plugins = 5"#, "should be a record")
}
#[test]
fn mutate_nu_config_plugin_gc_default_enabled() -> TestResult {
run_test(
r#"
$env.config.plugin_gc.default.enabled = false
$env.config.plugin_gc.default.enabled
"#,
"false",
)
}
#[test]
fn mutate_nu_config_plugin_gc_default_stop_after() -> TestResult {
run_test(
r#"
$env.config.plugin_gc.default.stop_after = 20sec
$env.config.plugin_gc.default.stop_after
"#,
"20sec",
)
}
#[test]
fn mutate_nu_config_plugin_gc_default_stop_after_negative() -> TestResult {
fail_test(
r#"
$env.config.plugin_gc.default.stop_after = -1sec
$env.config.plugin_gc.default.stop_after
"#,
"must not be negative",
)
}
#[test]
fn mutate_nu_config_plugin_gc_plugins() -> TestResult {
run_test(
r#"
$env.config.plugin_gc.plugins.inc = {
enabled: true
stop_after: 0sec
}
$env.config.plugin_gc.plugins.inc.stop_after
"#,
"0sec",
)
}

View File

@ -1,287 +0,0 @@
use nu_path::canonicalize_with;
use nu_test_support::nu;
use nu_test_support::playground::{Executable, Playground};
use pretty_assertions::assert_eq;
use std::fs::{self, File};
use std::path::{Path, PathBuf};
#[cfg(not(target_os = "windows"))]
fn adjust_canonicalization<P: AsRef<Path>>(p: P) -> String {
p.as_ref().display().to_string()
}
#[cfg(target_os = "windows")]
fn adjust_canonicalization<P: AsRef<Path>>(p: P) -> String {
const VERBATIM_PREFIX: &str = r"\\?\";
let p = p.as_ref().display().to_string();
if let Some(stripped) = p.strip_prefix(VERBATIM_PREFIX) {
stripped.to_string()
} else {
p
}
}
/// Make the config directory a symlink that points to a temporary folder, and also makes
/// the nushell directory inside a symlink.
/// Returns the path to the `nushell` config folder inside, via the symlink.
fn setup_fake_config(playground: &mut Playground) -> PathBuf {
let config_dir = "config_real";
let config_link = "config_link";
let nushell_real = "nushell_real";
let nushell_config_dir = Path::new(config_dir).join("nushell").display().to_string();
playground.mkdir(nushell_real);
playground.mkdir(config_dir);
playground.symlink(nushell_real, &nushell_config_dir);
playground.symlink(config_dir, config_link);
playground.with_env(
"XDG_CONFIG_HOME",
&playground.cwd().join(config_link).display().to_string(),
);
let path = Path::new(config_link).join("nushell");
canonicalize_with(&path, playground.cwd()).unwrap_or(path)
}
fn run(playground: &mut Playground, command: &str) -> String {
let result = playground.pipeline(command).execute().map_err(|e| {
let outcome = e.output.map(|outcome| {
format!(
"out: '{}', err: '{}'",
String::from_utf8_lossy(&outcome.out),
String::from_utf8_lossy(&outcome.err)
)
});
format!(
"desc: {}, exit: {:?}, outcome: {}",
e.desc,
e.exit,
outcome.unwrap_or("empty".to_owned())
)
});
String::from_utf8_lossy(&result.unwrap().out)
.trim()
.to_string()
}
#[cfg(not(windows))]
fn run_interactive_stderr(xdg_config_home: impl AsRef<Path>) -> String {
let child_output = std::process::Command::new("sh")
.arg("-c")
.arg(format!(
"{:?} -i -c 'echo $nu.is-interactive'",
nu_test_support::fs::executable_path()
))
.env("XDG_CONFIG_HOME", adjust_canonicalization(xdg_config_home))
.output()
.expect("Should have outputted");
return String::from_utf8_lossy(&child_output.stderr)
.trim()
.to_string();
}
fn test_config_path_helper(playground: &mut Playground, config_dir_nushell: PathBuf) {
// Create the config dir folder structure if it does not already exist
if !config_dir_nushell.exists() {
let _ = fs::create_dir_all(&config_dir_nushell);
}
let config_dir_nushell =
std::fs::canonicalize(&config_dir_nushell).expect("canonicalize config dir failed");
let actual = run(playground, "$nu.default-config-dir");
assert_eq!(actual, adjust_canonicalization(&config_dir_nushell));
let config_path = config_dir_nushell.join("config.nu");
// We use canonicalize here in case the config or env is symlinked since $nu.config-path is returning the canonicalized path in #8653
let canon_config_path =
adjust_canonicalization(std::fs::canonicalize(&config_path).unwrap_or(config_path));
let actual = run(playground, "$nu.config-path");
assert_eq!(actual, canon_config_path);
let env_path = config_dir_nushell.join("env.nu");
let canon_env_path =
adjust_canonicalization(std::fs::canonicalize(&env_path).unwrap_or(env_path));
let actual = run(playground, "$nu.env-path");
assert_eq!(actual, canon_env_path);
let history_path = config_dir_nushell.join("history.txt");
let canon_history_path =
adjust_canonicalization(std::fs::canonicalize(&history_path).unwrap_or(history_path));
let actual = run(playground, "$nu.history-path");
assert_eq!(actual, canon_history_path);
let login_path = config_dir_nushell.join("login.nu");
let canon_login_path =
adjust_canonicalization(std::fs::canonicalize(&login_path).unwrap_or(login_path));
let actual = run(playground, "$nu.loginshell-path");
assert_eq!(actual, canon_login_path);
#[cfg(feature = "plugin")]
{
let plugin_path = config_dir_nushell.join("plugin.msgpackz");
let canon_plugin_path =
adjust_canonicalization(std::fs::canonicalize(&plugin_path).unwrap_or(plugin_path));
let actual = run(playground, "$nu.plugin-path");
assert_eq!(actual, canon_plugin_path);
}
}
#[test]
fn test_default_config_path() {
Playground::setup("default_config_path", |_, playground| {
let config_dir = nu_path::config_dir().expect("Could not get config directory");
test_config_path_helper(playground, config_dir.join("nushell"));
});
}
/// Make the config folder a symlink to a temporary folder without any config files
/// and see if the config files' paths are properly canonicalized
#[test]
fn test_default_symlinked_config_path_empty() {
Playground::setup("symlinked_empty_config_dir", |_, playground| {
let config_dir_nushell = setup_fake_config(playground);
test_config_path_helper(playground, config_dir_nushell);
});
}
/// Like [`test_default_symlinked_config_path_empty`], but fill the temporary folder
/// with broken symlinks and see if they're properly canonicalized
#[test]
fn test_default_symlink_config_path_broken_symlink_config_files() {
Playground::setup(
"symlinked_cfg_dir_with_symlinked_cfg_files_broken",
|_, playground| {
let fake_config_dir_nushell = setup_fake_config(playground);
let fake_dir = PathBuf::from("fake");
playground.mkdir(&fake_dir.display().to_string());
for config_file in [
"config.nu",
"env.nu",
"history.txt",
"history.sqlite3",
"login.nu",
"plugin.msgpackz",
] {
let fake_file = fake_dir.join(config_file);
File::create(playground.cwd().join(&fake_file)).unwrap();
playground.symlink(&fake_file, fake_config_dir_nushell.join(config_file));
}
// Windows doesn't allow creating a symlink without the file existing,
// so we first create original files for the symlinks, then delete them
// to break the symlinks
std::fs::remove_dir_all(playground.cwd().join(&fake_dir)).unwrap();
test_config_path_helper(playground, fake_config_dir_nushell);
},
);
}
/// Like [`test_default_symlinked_config_path_empty`], but fill the temporary folder
/// with working symlinks to empty files and see if they're properly canonicalized
#[test]
fn test_default_config_path_symlinked_config_files() {
Playground::setup(
"symlinked_cfg_dir_with_symlinked_cfg_files",
|_, playground| {
let fake_config_dir_nushell = setup_fake_config(playground);
for config_file in [
"config.nu",
"env.nu",
"history.txt",
"history.sqlite3",
"login.nu",
"plugin.msgpackz",
] {
let empty_file = playground.cwd().join(format!("empty-{config_file}"));
File::create(&empty_file).unwrap();
playground.symlink(empty_file, fake_config_dir_nushell.join(config_file));
}
test_config_path_helper(playground, fake_config_dir_nushell);
},
);
}
#[test]
fn test_alternate_config_path() {
let config_file = "crates/nu-utils/src/sample_config/default_config.nu";
let env_file = "crates/nu-utils/src/sample_config/default_env.nu";
let cwd = std::env::current_dir().expect("Could not get current working directory");
let config_path =
nu_path::canonicalize_with(config_file, &cwd).expect("Could not get config path");
let actual = nu!(
cwd: &cwd,
format!("nu --config {config_path:?} -c '$nu.config-path'")
);
assert_eq!(actual.out, config_path.to_string_lossy().to_string());
let env_path = nu_path::canonicalize_with(env_file, &cwd).expect("Could not get env path");
let actual = nu!(
cwd: &cwd,
format!("nu --env-config {env_path:?} -c '$nu.env-path'")
);
assert_eq!(actual.out, env_path.to_string_lossy().to_string());
}
#[test]
fn test_xdg_config_empty() {
Playground::setup("xdg_config_empty", |_, playground| {
playground.with_env("XDG_CONFIG_HOME", "");
let actual = run(playground, "$nu.default-config-dir");
let expected = dirs_next::config_dir().unwrap().join("nushell");
assert_eq!(
actual,
adjust_canonicalization(expected.canonicalize().unwrap_or(expected))
);
});
}
#[test]
fn test_xdg_config_bad() {
Playground::setup("xdg_config_bad", |_, playground| {
let xdg_config_home = r#"mn2''6t\/k*((*&^//k//: "#;
playground.with_env("XDG_CONFIG_HOME", xdg_config_home);
let actual = run(playground, "$nu.default-config-dir");
let expected = dirs_next::config_dir().unwrap().join("nushell");
assert_eq!(
actual,
adjust_canonicalization(expected.canonicalize().unwrap_or(expected))
);
#[cfg(not(windows))]
{
let stderr = run_interactive_stderr(xdg_config_home);
assert!(
stderr.contains("xdg_config_home_invalid"),
"stderr was {}",
stderr
);
}
});
}
/// Shouldn't complain if XDG_CONFIG_HOME is a symlink
#[test]
#[cfg(not(windows))]
fn test_xdg_config_symlink() {
Playground::setup("xdg_config_symlink", |_, playground| {
let config_link = "config_link";
playground.symlink("real", config_link);
let stderr = run_interactive_stderr(playground.cwd().join(config_link));
assert!(
!stderr.contains("xdg_config_home_invalid"),
"stderr was {}",
stderr
);
});
}

View File

@ -1,55 +0,0 @@
use crate::tests::{run_test, TestResult};
#[test]
fn from_json_1() -> TestResult {
run_test(r#"('{"name": "Fred"}' | from json).name"#, "Fred")
}
#[test]
fn from_json_2() -> TestResult {
run_test(
r#"('{"name": "Fred"}
{"name": "Sally"}' | from json -o).name.1"#,
"Sally",
)
}
#[test]
fn to_json_raw_flag_1() -> TestResult {
run_test(
"[[a b]; [jim susie] [3 4]] | to json -r",
r#"[{"a":"jim","b":"susie"},{"a":3,"b":4}]"#,
)
}
#[test]
fn to_json_raw_flag_2() -> TestResult {
run_test(
"[[\"a b\" c]; [jim susie] [3 4]] | to json -r",
r#"[{"a b":"jim","c":"susie"},{"a b":3,"c":4}]"#,
)
}
#[test]
fn to_json_raw_flag_3() -> TestResult {
run_test(
"[[\"a b\" \"c d\"]; [\"jim smith\" \"susie roberts\"] [3 4]] | to json -r",
r#"[{"a b":"jim smith","c d":"susie roberts"},{"a b":3,"c d":4}]"#,
)
}
#[test]
fn to_json_escaped() -> TestResult {
run_test(
r#"{foo: {bar: '[{"a":"b","c": 2}]'}} | to json --raw"#,
r#"{"foo":{"bar":"[{\"a\":\"b\",\"c\": 2}]"}}"#,
)
}
#[test]
fn to_json_raw_backslash_in_quotes() -> TestResult {
run_test(
r#"{a: '\', b: 'some text'} | to json -r"#,
r#"{"a":"\\","b":"some text"}"#,
)
}

View File

@ -1,276 +0,0 @@
use crate::tests::{fail_test, run_test, run_test_contains, TestResult};
use nu_test_support::nu;
use pretty_assertions::assert_eq;
#[test]
fn no_scope_leak1() -> TestResult {
fail_test(
"if false { let $x = 10 } else { let $x = 20 }; $x",
"Variable not found",
)
}
#[test]
fn no_scope_leak2() -> TestResult {
fail_test(
"def foo [] { $x }; def bar [] { let $x = 10; foo }; bar",
"Variable not found",
)
}
#[test]
fn no_scope_leak3() -> TestResult {
run_test(
"def foo [$x] { $x }; def bar [] { let $x = 10; foo 20}; bar",
"20",
)
}
#[test]
fn no_scope_leak4() -> TestResult {
run_test(
"def foo [$x] { $x }; def bar [] { let $x = 10; (foo 20) + $x}; bar",
"30",
)
}
#[test]
fn custom_rest_var() -> TestResult {
run_test("def foo [...x] { $x.0 + $x.1 }; foo 10 80", "90")
}
#[test]
fn def_twice_should_fail() -> TestResult {
fail_test(
r#"def foo [] { "foo" }; def foo [] { "bar" }"#,
"defined more than once",
)
}
#[test]
fn missing_parameters() -> TestResult {
fail_test(r#"def foo {}"#, "Missing required positional")
}
#[test]
fn flag_param_value() -> TestResult {
run_test(
r#"def foo [--bob: int] { $bob + 100 }; foo --bob 55"#,
"155",
)
}
#[test]
fn do_rest_args() -> TestResult {
run_test(r#"(do { |...rest| $rest } 1 2).1 + 10"#, "12")
}
#[test]
fn custom_switch1() -> TestResult {
run_test(
r#"def florb [ --dry-run ] { if ($dry_run) { "foo" } else { "bar" } }; florb --dry-run"#,
"foo",
)
}
#[test]
fn custom_flag_with_type_checking() -> TestResult {
fail_test(
r#"def florb [--dry-run: int] { $dry_run }; let y = "3"; florb --dry-run=$y"#,
"type_mismatch",
)
}
#[test]
fn custom_switch2() -> TestResult {
run_test(
r#"def florb [ --dry-run ] { if ($dry_run) { "foo" } else { "bar" } }; florb"#,
"bar",
)
}
#[test]
fn custom_switch3() -> TestResult {
run_test(
r#"def florb [ --dry-run ] { $dry_run }; florb --dry-run=false"#,
"false",
)
}
#[test]
fn custom_switch4() -> TestResult {
run_test(
r#"def florb [ --dry-run ] { $dry_run }; florb --dry-run=true"#,
"true",
)
}
#[test]
fn custom_switch5() -> TestResult {
run_test(r#"def florb [ --dry-run ] { $dry_run }; florb"#, "false")
}
#[test]
fn custom_switch6() -> TestResult {
run_test(
r#"def florb [ --dry-run ] { $dry_run }; florb --dry-run"#,
"true",
)
}
#[test]
fn custom_flag1() -> TestResult {
run_test(
r#"def florb [
--age: int = 0
--name = "foobar"
] {
($age | into string) + $name
}
florb"#,
"0foobar",
)
}
#[test]
fn custom_flag2() -> TestResult {
run_test(
r#"def florb [
--age: int
--name = "foobar"
] {
($age | into string) + $name
}
florb --age 3"#,
"3foobar",
)
}
#[test]
fn deprecated_boolean_flag() {
let actual = nu!(r#"def florb [--dry-run: bool, --another-flag] { "aaa" }; florb"#);
assert!(actual.err.contains("not allowed"));
}
#[test]
fn simple_var_closing() -> TestResult {
run_test("let $x = 10; def foo [] { $x }; foo", "10")
}
#[test]
fn predecl_check() -> TestResult {
run_test("def bob [] { sam }; def sam [] { 3 }; bob", "3")
}
#[test]
fn def_with_no_dollar() -> TestResult {
run_test("def bob [x] { $x + 3 }; bob 4", "7")
}
#[test]
fn allow_missing_optional_params() -> TestResult {
run_test(
"def foo [x?:int] { if $x != null { $x + 10 } else { 5 } }; foo",
"5",
)
}
#[test]
fn help_present_in_def() -> TestResult {
run_test_contains(
"def foo [] {}; help foo;",
"Display the help message for this command",
)
}
#[test]
fn help_not_present_in_extern() -> TestResult {
run_test(
"module test {export extern \"git fetch\" []}; use test `git fetch`; help git fetch | ansi strip",
"Usage:\n > git fetch",
)
}
#[test]
fn override_table() -> TestResult {
run_test(r#"def table [-e] { "hi" }; table"#, "hi")
}
#[test]
fn override_table_eval_file() {
let actual = nu!(r#"def table [-e] { "hi" }; table"#);
assert_eq!(actual.out, "hi");
}
// This test is disabled on Windows because they cause a stack overflow in CI (but not locally!).
// For reasons we don't understand, the Windows CI runners are prone to stack overflow.
// TODO: investigate so we can enable on Windows
#[cfg(not(target_os = "windows"))]
#[test]
fn infinite_recursion_does_not_panic() {
let actual = nu!(r#"
def bang [] { bang }; bang
"#);
assert!(actual.err.contains("Recursion limit (50) reached"));
}
// This test is disabled on Windows because they cause a stack overflow in CI (but not locally!).
// For reasons we don't understand, the Windows CI runners are prone to stack overflow.
// TODO: investigate so we can enable on Windows
#[cfg(not(target_os = "windows"))]
#[test]
fn infinite_mutual_recursion_does_not_panic() {
let actual = nu!(r#"
def bang [] { def boom [] { bang }; boom }; bang
"#);
assert!(actual.err.contains("Recursion limit (50) reached"));
}
#[test]
fn type_check_for_during_eval() -> TestResult {
fail_test(
r#"def spam [foo: string] { $foo | describe }; def outer [--foo: string] { spam $foo }; outer"#,
"can't convert nothing to string",
)
}
#[test]
fn type_check_for_during_eval2() -> TestResult {
fail_test(
r#"def spam [foo: string] { $foo | describe }; def outer [--foo: any] { spam $foo }; outer"#,
"can't convert nothing to string",
)
}
#[test]
fn empty_list_matches_list_type() -> TestResult {
let _ = run_test(
r#"def spam [foo: list<int>] { echo $foo }; spam [] | length"#,
"0",
);
run_test(
r#"def spam [foo: list<string>] { echo $foo }; spam [] | length"#,
"0",
)
}
#[test]
fn path_argument_dont_auto_expand_if_single_quoted() -> TestResult {
run_test("def spam [foo: path] { echo $foo }; spam '~/aa'", "~/aa")
}
#[test]
fn path_argument_dont_auto_expand_if_double_quoted() -> TestResult {
run_test(r#"def spam [foo: path] { echo $foo }; spam "~/aa""#, "~/aa")
}
#[test]
fn dont_allow_implicit_casting_between_glob_and_string() -> TestResult {
let _ = fail_test(
r#"def spam [foo: string] { echo $foo }; let f: glob = 'aa'; spam $f"#,
"expected string",
);
fail_test(
r#"def spam [foo: glob] { echo $foo }; let f = 'aa'; spam $f"#,
"can't convert",
)
}

View File

@ -1,441 +0,0 @@
use crate::tests::{fail_test, run_test, TestResult};
use rstest::rstest;
#[test]
fn concrete_variable_assignment() -> TestResult {
run_test(
"let x = (1..100 | each { |y| $y + 100 }); let y = ($x | length); $x | length",
"100",
)
}
#[test]
fn proper_shadow() -> TestResult {
run_test("let x = 10; let x = $x + 9; $x", "19")
}
#[test]
fn in_variable_1() -> TestResult {
run_test(r#"[3] | if $in.0 > 4 { "yay!" } else { "boo" }"#, "boo")
}
#[test]
fn in_variable_2() -> TestResult {
run_test(r#"3 | if $in > 2 { "yay!" } else { "boo" }"#, "yay!")
}
#[test]
fn in_variable_3() -> TestResult {
run_test(r#"3 | if $in > 4 { "yay!" } else { $in }"#, "3")
}
#[test]
fn in_variable_4() -> TestResult {
run_test(r#"3 | do { $in }"#, "3")
}
#[test]
fn in_variable_5() -> TestResult {
run_test(r#"3 | if $in > 2 { $in - 10 } else { $in * 10 }"#, "-7")
}
#[test]
fn in_variable_6() -> TestResult {
run_test(r#"3 | if $in > 6 { $in - 10 } else { $in * 10 }"#, "30")
}
#[test]
fn in_and_if_else() -> TestResult {
run_test(
r#"[1, 2, 3] | if false {} else if true { $in | length }"#,
"3",
)
}
#[test]
fn help_works_with_missing_requirements() -> TestResult {
let expected_length = "70";
run_test(r#"each --help | lines | length"#, expected_length)
}
#[test]
fn scope_variable() -> TestResult {
run_test(
r#"let x = 3; scope variables | where name == "$x" | get type.0"#,
"int",
)
}
#[rstest]
#[case("a", "<> nothing")]
#[case("b", "<1.23> float")]
#[case("flag1", "<> nothing")]
#[case("flag2", "<4.56> float")]
fn scope_command_defaults(#[case] var: &str, #[case] exp_result: &str) -> TestResult {
run_test(
&format!(
r#"def t1 [a:int b?:float=1.23 --flag1:string --flag2:float=4.56] {{ true }};
let rslt = (scope commands | where name == 't1' | get signatures.0.any | where parameter_name == '{var}' | get parameter_default.0);
$"<($rslt)> ($rslt | describe)""#
),
exp_result,
)
}
#[test]
fn earlier_errors() -> TestResult {
fail_test(
r#"[1, "bob"] | each { |it| $it + 3 } | each { |it| $it / $it } | table"#,
"int",
)
}
#[test]
fn missing_flags_are_nothing() -> TestResult {
run_test(
r#"def foo [--aaa(-a): int, --bbb(-b): int] { (if $aaa == null { 10 } else { $aaa }) + (if $bbb == null { 100 } else { $bbb }) }; foo"#,
"110",
)
}
#[test]
fn missing_flags_are_nothing2() -> TestResult {
run_test(
r#"def foo [--aaa(-a): int, --bbb(-b): int] { (if $aaa == null { 10 } else { $aaa }) + (if $bbb == null { 100 } else { $bbb }) }; foo -a 90"#,
"190",
)
}
#[test]
fn missing_flags_are_nothing3() -> TestResult {
run_test(
r#"def foo [--aaa(-a): int, --bbb(-b): int] { (if $aaa == null { 10 } else { $aaa }) + (if $bbb == null { 100 } else { $bbb }) }; foo -b 45"#,
"55",
)
}
#[test]
fn missing_flags_are_nothing4() -> TestResult {
run_test(
r#"def foo [--aaa(-a): int, --bbb(-b): int] { (if $aaa == null { 10 } else { $aaa }) + (if $bbb == null { 100 } else { $bbb }) }; foo -a 3 -b 10000"#,
"10003",
)
}
#[test]
fn proper_variable_captures() -> TestResult {
run_test(
r#"def foo [x] { let y = 100; { || $y + $x } }; do (foo 23)"#,
"123",
)
}
#[test]
fn proper_variable_captures_with_calls() -> TestResult {
run_test(
r#"def foo [] { let y = 60; def bar [] { $y }; {|| bar } }; do (foo)"#,
"60",
)
}
#[test]
fn proper_variable_captures_with_nesting() -> TestResult {
run_test(
r#"def foo [x] { let z = 100; def bar [y] { $y - $x + $z } ; { |z| bar $z } }; do (foo 11) 13"#,
"102",
)
}
#[test]
fn divide_duration() -> TestResult {
run_test(r#"4ms / 4ms"#, "1")
}
#[test]
fn divide_filesize() -> TestResult {
run_test(r#"4mb / 4mb"#, "1")
}
#[test]
fn date_comparison() -> TestResult {
run_test(r#"(date now) < ((date now) + 2min)"#, "true")
}
#[test]
fn let_sees_input() -> TestResult {
run_test(
r#"def c [] { let x = (str length); $x }; "hello world" | c"#,
"11",
)
}
#[test]
fn let_sees_in_variable() -> TestResult {
run_test(
r#"def c [] { let x = $in.name; $x | str length }; {name: bob, size: 100 } | c"#,
"3",
)
}
#[test]
fn let_sees_in_variable2() -> TestResult {
run_test(
r#"def c [] { let x = ($in | str length); $x }; 'bob' | c"#,
"3",
)
}
#[test]
fn def_env() -> TestResult {
run_test(
r#"def --env bob [] { $env.BAR = "BAZ" }; bob; $env.BAR"#,
"BAZ",
)
}
#[test]
fn not_def_env() -> TestResult {
fail_test(r#"def bob [] { $env.BAR = "BAZ" }; bob; $env.BAR"#, "")
}
#[test]
fn def_env_hiding_something() -> TestResult {
fail_test(
r#"$env.FOO = "foo"; def --env bob [] { hide-env FOO }; bob; $env.FOO"#,
"",
)
}
#[test]
fn def_env_then_hide() -> TestResult {
fail_test(
r#"def --env bob [] { $env.BOB = "bob" }; def --env un-bob [] { hide-env BOB }; bob; un-bob; $env.BOB"#,
"",
)
}
#[test]
fn export_def_env() -> TestResult {
run_test(
r#"module foo { export def --env bob [] { $env.BAR = "BAZ" } }; use foo bob; bob; $env.BAR"#,
"BAZ",
)
}
#[test]
fn dynamic_load_env() -> TestResult {
run_test(r#"let x = "FOO"; load-env {$x: "BAZ"}; $env.FOO"#, "BAZ")
}
#[test]
fn reduce_spans() -> TestResult {
fail_test(
r#"let x = ([1, 2, 3] | reduce --fold 0 { $it.item + 2 * $it.acc }); error make {msg: "oh that hurts", label: {text: "right here", start: (metadata $x).span.start, end: (metadata $x).span.end } }"#,
"right here",
)
}
#[test]
fn with_env_shorthand_nested_quotes() -> TestResult {
run_test(
r#"FOO='-arg "hello world"' echo $env | get FOO"#,
"-arg \"hello world\"",
)
}
#[test]
fn test_redirection_stderr() -> TestResult {
// try a nonsense binary
run_test(r#"do -i { asdjw4j5cnaabw44rd }; echo done"#, "done")
}
#[test]
fn datetime_literal() -> TestResult {
run_test(r#"(date now) - 2019-08-23 > 1hr"#, "true")
}
#[test]
fn shortcircuiting_and() -> TestResult {
run_test(r#"false and (5 / 0; false)"#, "false")
}
#[test]
fn shortcircuiting_or() -> TestResult {
run_test(r#"true or (5 / 0; false)"#, "true")
}
#[test]
fn nonshortcircuiting_xor() -> TestResult {
run_test(r#"true xor (print "hello"; false) | ignore"#, "hello")
}
#[test]
fn open_ended_range() -> TestResult {
run_test(r#"1.. | first 100000 | length"#, "100000")
}
#[test]
fn default_value1() -> TestResult {
run_test(r#"def foo [x = 3] { $x }; foo"#, "3")
}
#[test]
fn default_value2() -> TestResult {
run_test(r#"def foo [x: int = 3] { $x }; foo"#, "3")
}
#[test]
fn default_value3() -> TestResult {
run_test(r#"def foo [--x = 3] { $x }; foo"#, "3")
}
#[test]
fn default_value4() -> TestResult {
run_test(r#"def foo [--x: int = 3] { $x }; foo"#, "3")
}
#[test]
fn default_value5() -> TestResult {
run_test(r#"def foo [x = 3] { $x }; foo 10"#, "10")
}
#[test]
fn default_value6() -> TestResult {
run_test(r#"def foo [x: int = 3] { $x }; foo 10"#, "10")
}
#[test]
fn default_value7() -> TestResult {
run_test(r#"def foo [--x = 3] { $x }; foo --x 10"#, "10")
}
#[test]
fn default_value8() -> TestResult {
run_test(r#"def foo [--x: int = 3] { $x }; foo --x 10"#, "10")
}
#[test]
fn default_value9() -> TestResult {
fail_test(r#"def foo [--x = 3] { $x }; foo --x a"#, "expected int")
}
#[test]
fn default_value10() -> TestResult {
fail_test(r#"def foo [x = 3] { $x }; foo a"#, "expected int")
}
#[test]
fn default_value11() -> TestResult {
fail_test(
r#"def foo [x = 3, y] { $x }; foo a"#,
"after optional parameter",
)
}
#[test]
fn default_value12() -> TestResult {
fail_test(
r#"def foo [--x:int = "a"] { $x }"#,
"expected default value to be `int`",
)
}
#[test]
fn default_value_constant1() -> TestResult {
run_test(r#"def foo [x = "foo"] { $x }; foo"#, "foo")
}
#[test]
fn default_value_constant2() -> TestResult {
run_test(r#"def foo [secs = 1sec] { $secs }; foo"#, "1sec")
}
#[test]
fn default_value_constant3() -> TestResult {
run_test(r#"def foo [x = ("foo" | str length)] { $x }; foo"#, "3")
}
#[test]
fn default_value_not_constant2() -> TestResult {
fail_test(
r#"def foo [x = (loop { break })] { $x }; foo"#,
"expected a constant",
)
}
#[test]
fn loose_each() -> TestResult {
run_test(
r#"[[1, 2, 3], [4, 5, 6]] | each {|| $in.1 } | math sum"#,
"7",
)
}
#[test]
fn in_means_input() -> TestResult {
run_test(r#"def shl [] { $in * 2 }; 2 | shl"#, "4")
}
#[test]
fn in_iteration() -> TestResult {
run_test(
r#"[3, 4, 5] | each {|| echo $"hi ($in)" } | str join"#,
"hi 3hi 4hi 5",
)
}
#[test]
fn reusable_in() -> TestResult {
run_test(
r#"[1, 2, 3, 4] | take (($in | length) - 1) | math sum"#,
"6",
)
}
#[test]
fn better_operator_spans() -> TestResult {
run_test(
r#"metadata ({foo: 10} | (20 - $in.foo)) | get span | $in.start < $in.end"#,
"true",
)
}
#[test]
fn range_right_exclusive() -> TestResult {
run_test(r#"[1, 4, 5, 8, 9] | range 1..<3 | math sum"#, "9")
}
/// Issue #7872
#[test]
fn assignment_to_in_var_no_panic() -> TestResult {
fail_test(r#"$in = 3"#, "needs to be a mutable variable")
}
#[test]
fn assignment_to_env_no_panic() -> TestResult {
fail_test(r#"$env = 3"#, "cannot_replace_env")
}
#[test]
fn short_flags() -> TestResult {
run_test(
r#"def foobar [-a: int, -b: string, -c: string] { echo $'($a) ($c) ($b)' }; foobar -b "balh balh" -a 1543 -c "FALSE123""#,
"1543 FALSE123 balh balh",
)
}
#[test]
fn short_flags_1() -> TestResult {
run_test(
r#"def foobar [-a: string, -b: string, -s: int] { if ( $s == 0 ) { echo $'($b)($a)' }}; foobar -a test -b case -s 0 "#,
"casetest",
)
}
#[test]
fn short_flags_2() -> TestResult {
run_test(
r#"def foobar [-a: int, -b: string, -c: int] { $a + $c };foobar -b "balh balh" -a 10 -c 1 "#,
"11",
)
}

View File

@ -1,29 +0,0 @@
use crate::tests::{fail_test, run_test, TestResult};
use nu_test_support::nu;
#[test]
fn shorthand_env_1() -> TestResult {
run_test(r#"FOO=BAZ $env.FOO"#, "BAZ")
}
#[test]
fn shorthand_env_2() -> TestResult {
fail_test(r#"FOO=BAZ FOO=MOO $env.FOO"#, "defined_twice")
}
#[test]
fn shorthand_env_3() -> TestResult {
run_test(r#"FOO=BAZ BAR=MOO $env.FOO"#, "BAZ")
}
#[test]
fn default_nu_lib_dirs_type() {
let actual = nu!("$env.NU_LIB_DIRS | describe");
assert_eq!(actual.out, "list<string>");
}
#[test]
fn default_nu_plugin_dirs_type() {
let actual = nu!("$env.NU_PLUGIN_DIRS | describe");
assert_eq!(actual.out, "list<string>");
}

View File

@ -1,27 +0,0 @@
use crate::tests::{run_test, TestResult};
use rstest::rstest;
#[rstest]
// avoid feeding strings containing parens to regex. Does not end well.
#[case(": arga help")]
#[case("argb help")]
#[case("optional, default: 20")]
#[case("- f1 switch")]
#[case("- f2 named no default")]
#[case("- f3 named default 3")]
#[case("default: 33")]
#[case("--help - Display the help message")]
fn can_get_help(#[case] exp_result: &str) -> TestResult {
run_test(
&format!(
r#"def t [a:string, # arga help
b:int=20, # argb help
--f1, # f1 switch help
--f2:string, # f2 named no default
--f3:int=33 # f3 named default 3
] {{ true }};
help t | ansi strip | find `{exp_result}` | get 0 | str replace --all --regex '^(.*({exp_result}).*)$' '$2'"#,
),
exp_result,
)
}

View File

@ -1,407 +0,0 @@
use crate::tests::{fail_test, run_test, TestResult};
// TODO: Test the use/hide tests also as separate lines in REPL (i.e., with merging the delta in between)
#[test]
fn hides_def() -> TestResult {
fail_test(
r#"def myfoosymbol [] { "myfoosymbol" }; hide myfoosymbol; myfoosymbol"#,
"external_command",
)
}
#[test]
fn hides_alias() -> TestResult {
fail_test(
r#"alias myfoosymbol = echo "myfoosymbol"; hide myfoosymbol; myfoosymbol"#,
"external_command",
)
}
#[test]
fn hides_env() -> TestResult {
fail_test(
r#"$env.myfoosymbol = "myfoosymbol"; hide-env myfoosymbol; $env.myfoosymbol"#,
"",
)
}
#[test]
fn hides_def_then_redefines() -> TestResult {
// this one should fail because of predecl -- cannot have more defs with the same name in a
// block
fail_test(
r#"def myfoosymbol [] { "myfoosymbol" }; hide myfoosymbol; def myfoosymbol [] { "bar" }; myfoosymbol"#,
"defined more than once",
)
}
#[ignore = "TODO: We'd need to make predecls work with hiding as well"]
#[test]
fn hides_alias_then_redefines() -> TestResult {
run_test(
r#"alias myfoosymbol = echo "myfoosymbol"; hide myfoosymbol; alias myfoosymbol = echo "myfoosymbol"; myfoosymbol"#,
"myfoosymbol",
)
}
#[test]
fn hides_env_then_redefines() -> TestResult {
run_test(
r#"$env.myfoosymbol = "myfoosymbol"; hide-env myfoosymbol; $env.myfoosymbol = "bar"; $env.myfoosymbol"#,
"bar",
)
}
#[test]
fn hides_def_in_scope_1() -> TestResult {
fail_test(
r#"def myfoosymbol [] { "myfoosymbol" }; do { hide myfoosymbol; myfoosymbol }"#,
"external_command",
)
}
#[test]
fn hides_def_in_scope_2() -> TestResult {
run_test(
r#"def myfoosymbol [] { "myfoosymbol" }; do { def myfoosymbol [] { "bar" }; hide myfoosymbol; myfoosymbol }"#,
"myfoosymbol",
)
}
#[test]
fn hides_def_in_scope_3() -> TestResult {
fail_test(
r#"def myfoosymbol [] { "myfoosymbol" }; do { hide myfoosymbol; def myfoosymbol [] { "bar" }; hide myfoosymbol; myfoosymbol }"#,
"external_command",
)
}
#[test]
fn hides_def_in_scope_4() -> TestResult {
fail_test(
r#"def myfoosymbol [] { "myfoosymbol" }; do { def myfoosymbol [] { "bar" }; hide myfoosymbol; hide myfoosymbol; myfoosymbol }"#,
"external_command",
)
}
#[test]
fn hides_alias_in_scope_1() -> TestResult {
fail_test(
r#"alias myfoosymbol = echo "myfoosymbol"; do { hide myfoosymbol; myfoosymbol }"#,
"external_command",
)
}
#[test]
fn hides_alias_in_scope_2() -> TestResult {
run_test(
r#"alias myfoosymbol = echo "myfoosymbol"; do { alias myfoosymbol = echo "bar"; hide myfoosymbol; myfoosymbol }"#,
"myfoosymbol",
)
}
#[test]
fn hides_alias_in_scope_3() -> TestResult {
fail_test(
r#"alias myfoosymbol = echo "myfoosymbol"; do { hide myfoosymbol; alias myfoosymbol = echo "bar"; hide myfoosymbol; myfoosymbol }"#,
"external_command",
)
}
#[test]
fn hides_alias_in_scope_4() -> TestResult {
fail_test(
r#"alias myfoosymbol = echo "myfoosymbol"; do { alias myfoosymbol = echo "bar"; hide myfoosymbol; hide myfoosymbol; myfoosymbol }"#,
"external_command",
)
}
#[test]
fn hides_env_in_scope_1() -> TestResult {
fail_test(
r#"$env.myfoosymbol = "myfoosymbol"; do { hide-env myfoosymbol; $env.myfoosymbol }"#,
"not_found",
)
}
#[test]
fn hides_env_in_scope_2() -> TestResult {
run_test(
r#"$env.myfoosymbol = "myfoosymbol"; do { $env.myfoosymbol = "bar"; hide-env myfoosymbol; $env.myfoosymbol }"#,
"myfoosymbol",
)
}
#[test]
fn hides_env_in_scope_3() -> TestResult {
fail_test(
r#"$env.myfoosymbol = "myfoosymbol"; do { hide-env myfoosymbol; $env.myfoosymbol = "bar"; hide-env myfoosymbol; $env.myfoosymbol }"#,
"",
)
}
#[test]
fn hides_env_in_scope_4() -> TestResult {
fail_test(
r#"$env.myfoosymbol = "myfoosymbol"; do { $env.myfoosymbol = "bar"; hide-env myfoosymbol; hide-env myfoosymbol; $env.myfoosymbol }"#,
"",
)
}
#[test]
#[ignore]
fn hide_def_twice_not_allowed() -> TestResult {
fail_test(
r#"def myfoosymbol [] { "myfoosymbol" }; hide myfoosymbol; hide myfoosymbol"#,
"did not find",
)
}
#[test]
#[ignore]
fn hide_alias_twice_not_allowed() -> TestResult {
fail_test(
r#"alias myfoosymbol = echo "myfoosymbol"; hide myfoosymbol; hide myfoosymbol"#,
"did not find",
)
}
#[test]
fn hide_env_twice_not_allowed() -> TestResult {
fail_test(
r#"$env.myfoosymbol = "myfoosymbol"; hide-env myfoosymbol; hide-env myfoosymbol"#,
"",
)
}
#[test]
fn hide_env_twice_allowed() -> TestResult {
fail_test(
r#"$env.myfoosymbol = "myfoosymbol"; hide-env myfoosymbol; hide-env -i myfoosymbol; $env.myfoosymbol"#,
"",
)
}
#[test]
fn hides_def_runs_env() -> TestResult {
run_test(
r#"$env.myfoosymbol = "bar"; def myfoosymbol [] { "myfoosymbol" }; hide myfoosymbol; $env.myfoosymbol"#,
"bar",
)
}
#[test]
fn hides_def_import_1() -> TestResult {
fail_test(
r#"module myspammodule { export def myfoosymbol [] { "myfoosymbol" } }; use myspammodule; hide myspammodule myfoosymbol; myspammodule myfoosymbol"#,
"external_command",
)
}
#[test]
fn hides_def_import_2() -> TestResult {
fail_test(
r#"module myspammodule { export def myfoosymbol [] { "myfoosymbol" } }; use myspammodule; hide myspammodule; myspammodule myfoosymbol"#,
"external_command",
)
}
#[test]
fn hides_def_import_3() -> TestResult {
fail_test(
r#"module myspammodule { export def myfoosymbol [] { "myfoosymbol" } }; use myspammodule; hide myspammodule [myfoosymbol]; myspammodule myfoosymbol"#,
"external_command",
)
}
#[test]
fn hides_def_import_4() -> TestResult {
fail_test(
r#"module myspammodule { export def myfoosymbol [] { "myfoosymbol" } }; use myspammodule myfoosymbol; hide myfoosymbol; myfoosymbol"#,
"external_command",
)
}
#[test]
fn hides_def_import_5() -> TestResult {
fail_test(
r#"module myspammodule { export def myfoosymbol [] { "myfoosymbol" } }; use myspammodule *; hide myfoosymbol; myfoosymbol"#,
"external_command",
)
}
#[test]
fn hides_def_import_6() -> TestResult {
fail_test(
r#"module myspammodule { export def myfoosymbol [] { "myfoosymbol" } }; use myspammodule *; hide myspammodule *; myfoosymbol"#,
"external_command",
)
}
#[test]
fn hides_def_import_then_reimports() -> TestResult {
run_test(
r#"module myspammodule { export def myfoosymbol [] { "myfoosymbol" } }; use myspammodule myfoosymbol; hide myfoosymbol; use myspammodule myfoosymbol; myfoosymbol"#,
"myfoosymbol",
)
}
#[test]
fn hides_alias_import_1() -> TestResult {
fail_test(
r#"module myspammodule { export alias myfoosymbol = echo "myfoosymbol" }; use myspammodule; hide myspammodule myfoosymbol; myspammodule myfoosymbol"#,
"external_command",
)
}
#[test]
fn hides_alias_import_2() -> TestResult {
fail_test(
r#"module myspammodule { export alias myfoosymbol = echo "myfoosymbol" }; use myspammodule; hide myspammodule; myspammodule myfoosymbol"#,
"external_command",
)
}
#[test]
fn hides_alias_import_3() -> TestResult {
fail_test(
r#"module myspammodule { export alias myfoosymbol = echo "myfoosymbol" }; use myspammodule; hide myspammodule [myfoosymbol]; myspammodule myfoosymbol"#,
"external_command",
)
}
#[test]
fn hides_alias_import_4() -> TestResult {
fail_test(
r#"module myspammodule { export alias myfoosymbol = echo "myfoosymbol" }; use myspammodule myfoosymbol; hide myfoosymbol; myfoosymbol"#,
"external_command",
)
}
#[test]
fn hides_alias_import_5() -> TestResult {
fail_test(
r#"module myspammodule { export alias myfoosymbol = echo "myfoosymbol" }; use myspammodule *; hide myfoosymbol; myfoosymbol"#,
"external_command",
)
}
#[test]
fn hides_alias_import_6() -> TestResult {
fail_test(
r#"module myspammodule { export alias myfoosymbol = echo "myfoosymbol" }; use myspammodule *; hide myspammodule *; myfoosymbol"#,
"external_command",
)
}
#[test]
fn hides_alias_import_then_reimports() -> TestResult {
run_test(
r#"module myspammodule { export alias myfoosymbol = echo "myfoosymbol" }; use myspammodule myfoosymbol; hide myfoosymbol; use myspammodule myfoosymbol; myfoosymbol"#,
"myfoosymbol",
)
}
#[test]
fn hides_env_import_1() -> TestResult {
fail_test(
r#"module myspammodule { export-env { $env.myfoosymbol = "myfoosymbol" } }; use myspammodule; hide-env myfoosymbol; $env.myfoosymbol"#,
"",
)
}
#[test]
fn hides_def_runs_env_import() -> TestResult {
run_test(
r#"module myspammodule { export-env { $env.myfoosymbol = "myfoosymbol" }; export def myfoosymbol [] { "bar" } }; use myspammodule myfoosymbol; hide myfoosymbol; $env.myfoosymbol"#,
"myfoosymbol",
)
}
#[test]
fn hides_def_and_env_import_1() -> TestResult {
fail_test(
r#"module myspammodule { export-env { $env.myfoosymbol = "myfoosymbol" }; export def myfoosymbol [] { "bar" } }; use myspammodule myfoosymbol; hide myfoosymbol; hide-env myfoosymbol; $env.myfoosymbol"#,
"",
)
}
#[test]
fn use_def_import_after_hide() -> TestResult {
run_test(
r#"module myspammodule { export def myfoosymbol [] { "myfoosymbol" } }; use myspammodule myfoosymbol; hide myfoosymbol; use myspammodule myfoosymbol; myfoosymbol"#,
"myfoosymbol",
)
}
#[test]
fn use_env_import_after_hide() -> TestResult {
run_test(
r#"module myspammodule { export-env { $env.myfoosymbol = "myfoosymbol" } }; use myspammodule; hide-env myfoosymbol; use myspammodule; $env.myfoosymbol"#,
"myfoosymbol",
)
}
#[test]
fn hide_shadowed_decl() -> TestResult {
run_test(
r#"module myspammodule { export def myfoosymbol [] { "bar" } }; def myfoosymbol [] { "myfoosymbol" }; do { use myspammodule myfoosymbol; hide myfoosymbol; myfoosymbol }"#,
"myfoosymbol",
)
}
#[test]
fn hide_shadowed_env() -> TestResult {
run_test(
r#"module myspammodule { export-env { $env.myfoosymbol = "bar" } }; $env.myfoosymbol = "myfoosymbol"; do { use myspammodule; hide-env myfoosymbol; $env.myfoosymbol }"#,
"myfoosymbol",
)
}
#[test]
fn hides_all_decls_within_scope() -> TestResult {
fail_test(
r#"module myspammodule { export def myfoosymbol [] { "bar" } }; def myfoosymbol [] { "myfoosymbol" }; use myspammodule myfoosymbol; hide myfoosymbol; myfoosymbol"#,
"external_command",
)
}
#[test]
fn hides_all_envs_within_scope() -> TestResult {
fail_test(
r#"module myspammodule { export-env { $env.myfoosymbol = "bar" } }; $env.myfoosymbol = "myfoosymbol"; use myspammodule; hide-env myfoosymbol; $env.myfoosymbol"#,
"",
)
}
#[test]
fn hides_main_import_1() -> TestResult {
fail_test(
r#"module myspammodule { export def main [] { "myfoosymbol" } }; use myspammodule; hide myspammodule; myspammodule"#,
"external_command",
)
}
#[test]
fn hides_main_import_2() -> TestResult {
fail_test(
r#"module myspammodule { export def main [] { "myfoosymbol" } }; use myspammodule; hide myspammodule main; myspammodule"#,
"external_command",
)
}
#[test]
fn hides_main_import_3() -> TestResult {
fail_test(
r#"module myspammodule { export def main [] { "myfoosymbol" } }; use myspammodule; hide myspammodule [ main ]; myspammodule"#,
"external_command",
)
}
#[test]
fn hides_main_import_4() -> TestResult {
fail_test(
r#"module myspammodule { export def main [] { "myfoosymbol" } }; use myspammodule; hide myspammodule *; myspammodule"#,
"external_command",
)
}

View File

@ -1,10 +0,0 @@
use crate::tests::{test_ide_contains, TestResult};
#[test]
fn parser_recovers() -> TestResult {
test_ide_contains(
"3 + \"bob\"\nlet x = \"fred\"\n",
&["--ide-check 5"],
"\"typename\":\"string\"",
)
}

View File

@ -1,41 +0,0 @@
use crate::tests::{run_test, TestResult};
#[test]
fn better_block_types() -> TestResult {
run_test(
r#"([1, 2, 3] | enumerate | each { |e| $"($e.index) is ($e.item)" }).1"#,
"1 is 2",
)
}
#[test]
fn row_iteration() -> TestResult {
run_test(
"[[name, size]; [tj, 100], [rl, 200]] | each { |it| $it.size * 8 } | get 1",
"1600",
)
}
#[test]
fn row_condition1() -> TestResult {
run_test(
"([[name, size]; [a, 1], [b, 2], [c, 3]] | where size < 3).name | get 1",
"b",
)
}
#[test]
fn row_condition2() -> TestResult {
run_test(
"[[name, size]; [a, 1], [b, 2], [c, 3]] | where $it.size > 2 | length",
"1",
)
}
#[test]
fn par_each() -> TestResult {
run_test(
r#"1..10 | enumerate | par-each { |it| ([[index, item]; [$it.index, ($it.item > 5)]]).0 } | where index == 4 | get item.0"#,
"false",
)
}

View File

@ -1,140 +0,0 @@
use std::process::Command;
use crate::tests::{fail_test, run_test, run_test_contains, TestResult};
// cargo version prints a string of the form:
// cargo 1.60.0 (d1fd9fe2c 2022-03-01)
#[test]
fn known_external_runs() -> TestResult {
run_test_contains(r#"extern "cargo version" []; cargo version"#, "cargo")
}
#[test]
fn known_external_unknown_flag() -> TestResult {
run_test_contains(r#"extern "cargo" []; cargo --version"#, "cargo")
}
/// GitHub issues #5179, #4618
#[test]
fn known_external_alias() -> TestResult {
run_test_contains(
r#"extern "cargo version" []; alias cv = cargo version; cv"#,
"cargo",
)
}
/// GitHub issues #5179, #4618
#[test]
fn known_external_subcommand_alias() -> TestResult {
run_test_contains(
r#"extern "cargo version" []; alias c = cargo; c version"#,
"cargo",
)
}
#[test]
fn known_external_complex_unknown_args() -> TestResult {
run_test_contains(
"extern echo []; echo foo -b -as -9 --abc -- -Dxmy=AKOO - bar",
"foo -b -as -9 --abc -- -Dxmy=AKOO - bar",
)
}
#[test]
fn known_external_from_module() -> TestResult {
run_test_contains(
r#"module spam {
export extern echo []
}
use spam echo
echo foo -b -as -9 --abc -- -Dxmy=AKOO - bar
"#,
"foo -b -as -9 --abc -- -Dxmy=AKOO - bar",
)
}
#[test]
fn known_external_short_flag_batch_arg_allowed() -> TestResult {
run_test_contains("extern echo [-a, -b: int]; echo -ab 10", "-b 10")
}
#[test]
fn known_external_short_flag_batch_arg_disallowed() -> TestResult {
fail_test(
"extern echo [-a: int, -b]; echo -ab 10",
"last flag can take args",
)
}
#[test]
fn known_external_short_flag_batch_multiple_args() -> TestResult {
fail_test(
"extern echo [-a: int, -b: int]; echo -ab 10 20",
"last flag can take args",
)
}
#[test]
fn known_external_missing_positional() -> TestResult {
fail_test("extern echo [a]; echo", "missing_positional")
}
#[test]
fn known_external_type_mismatch() -> TestResult {
fail_test("extern echo [a: int]; echo 1.234", "mismatch")
}
#[test]
fn known_external_missing_flag_param() -> TestResult {
fail_test(
"extern echo [--foo: string]; echo --foo",
"missing_flag_param",
)
}
#[test]
fn known_external_misc_values() -> TestResult {
run_test(
r#"
let x = 'abc'
extern echo [...args]
echo $x ...[ a b c ]
"#,
"abc a b c",
)
}
/// GitHub issue #7822
#[test]
fn known_external_subcommand_from_module() -> TestResult {
let output = Command::new("cargo").arg("check").arg("-h").output()?;
run_test(
r#"
module cargo {
export extern check []
};
use cargo;
cargo check -h
"#,
String::from_utf8(output.stdout)?.trim(),
)
}
/// GitHub issue #7822
#[test]
fn known_external_aliased_subcommand_from_module() -> TestResult {
let output = Command::new("cargo").arg("check").arg("-h").output()?;
run_test(
r#"
module cargo {
export extern check []
};
use cargo;
alias cc = cargo check;
cc -h
"#,
String::from_utf8(output.stdout)?.trim(),
)
}

View File

@ -1,208 +0,0 @@
use crate::tests::{fail_test, run_test, TestResult};
#[test]
fn add_simple() -> TestResult {
run_test("3 + 4", "7")
}
#[test]
fn add_simple2() -> TestResult {
run_test("3 + 4 + 9", "16")
}
#[test]
fn broken_math() -> TestResult {
fail_test("3 + ", "incomplete")
}
#[test]
fn modulo1() -> TestResult {
run_test("5 mod 2", "1")
}
#[test]
fn modulo2() -> TestResult {
run_test("5.25 mod 2", "1.25")
}
#[test]
fn bit_shr() -> TestResult {
run_test("16 bit-shr 1", "8")
}
#[test]
fn bit_shl() -> TestResult {
run_test("5 bit-shl 1", "10")
}
#[test]
fn bit_shl_add() -> TestResult {
run_test("2 bit-shl 1 + 2", "16")
}
#[test]
fn sub_bit_shr() -> TestResult {
run_test("10 - 2 bit-shr 2", "2")
}
#[test]
fn and() -> TestResult {
run_test("true and false", "false")
}
#[test]
fn or() -> TestResult {
run_test("true or false", "true")
}
#[test]
fn xor_1() -> TestResult {
run_test("false xor true", "true")
}
#[test]
fn xor_2() -> TestResult {
run_test("true xor true", "false")
}
#[test]
fn bit_xor() -> TestResult {
run_test("4 bit-xor 4", "0")
}
#[test]
fn bit_xor_add() -> TestResult {
run_test("4 bit-xor 2 + 2", "0")
}
#[test]
fn bit_and() -> TestResult {
run_test("2 bit-and 4", "0")
}
#[test]
fn bit_or() -> TestResult {
run_test("2 bit-or 4", "6")
}
#[test]
fn bit_and_or() -> TestResult {
run_test("2 bit-or 4 bit-and 1 + 2", "2")
}
#[test]
fn pow() -> TestResult {
run_test("3 ** 3", "27")
}
#[test]
fn contains() -> TestResult {
run_test("'testme' =~ 'test'", "true")
}
#[test]
fn not_contains() -> TestResult {
run_test("'testme' !~ 'test'", "false")
}
#[test]
fn not_precedence() -> TestResult {
run_test("not false and false", "false")
}
#[test]
fn not_precedence2() -> TestResult {
run_test("(not false) and false", "false")
}
#[test]
fn not_precedence3() -> TestResult {
run_test("not not true and true", "true")
}
#[test]
fn not_precedence4() -> TestResult {
run_test("not not true and not not true", "true")
}
#[test]
fn floating_add() -> TestResult {
run_test("10.1 + 0.8", "10.9")
}
#[test]
fn precedence_of_or_groups() -> TestResult {
run_test(r#"4 mod 3 == 0 or 5 mod 5 == 0"#, "true")
}
#[test]
fn test_filesize_op() -> TestResult {
run_test("-5kb + 4.5kb", "-500 B")
}
#[test]
fn test_duration_op() -> TestResult {
run_test("4min + 20sec", "4min 20sec").unwrap();
run_test("42sec * 2", "1min 24sec").unwrap();
run_test("(3min + 14sec) / 2", "1min 37sec").unwrap();
run_test("(4min + 20sec) mod 69sec", "53sec")
}
#[test]
fn lt() -> TestResult {
run_test("1 < 3", "true").unwrap();
run_test("3 < 3", "false").unwrap();
run_test("3 < 1", "false")
}
// Comparison operators return null if 1 side or both side is null.
// The motivation for this behaviour: JT asked the C# devs and they said this is
// the behaviour they would choose if they were starting from scratch.
#[test]
fn lt_null() -> TestResult {
run_test("3 < null | to nuon", "null").unwrap();
run_test("null < 3 | to nuon", "null").unwrap();
run_test("null < null | to nuon", "null")
}
#[test]
fn lte() -> TestResult {
run_test("1 <= 3", "true").unwrap();
run_test("3 <= 3", "true").unwrap();
run_test("3 <= 1", "false")
}
#[test]
fn lte_null() -> TestResult {
run_test("3 <= null | to nuon", "null").unwrap();
run_test("null <= 3 | to nuon", "null").unwrap();
run_test("null <= null | to nuon", "null")
}
#[test]
fn gt() -> TestResult {
run_test("1 > 3", "false").unwrap();
run_test("3 > 3", "false").unwrap();
run_test("3 > 1", "true")
}
#[test]
fn gt_null() -> TestResult {
run_test("3 > null | to nuon", "null").unwrap();
run_test("null > 3 | to nuon", "null").unwrap();
run_test("null > null | to nuon", "null")
}
#[test]
fn gte() -> TestResult {
run_test("1 >= 3", "false").unwrap();
run_test("3 >= 3", "true").unwrap();
run_test("3 >= 1", "true")
}
#[test]
fn gte_null() -> TestResult {
run_test("3 >= null | to nuon", "null").unwrap();
run_test("null >= 3 | to nuon", "null").unwrap();
run_test("null >= null | to nuon", "null")
}

View File

@ -1,157 +0,0 @@
use crate::tests::{fail_test, run_test, TestResult};
#[test]
fn module_def_imports_1() -> TestResult {
run_test(
r#"module foo { export def a [] { 1 }; def b [] { 2 } }; use foo; foo a"#,
"1",
)
}
#[test]
fn module_def_imports_2() -> TestResult {
run_test(
r#"module foo { export def a [] { 1 }; def b [] { 2 } }; use foo a; a"#,
"1",
)
}
#[test]
fn module_def_imports_3() -> TestResult {
run_test(
r#"module foo { export def a [] { 1 }; export def b [] { 2 } }; use foo *; b"#,
"2",
)
}
#[test]
fn module_def_imports_4() -> TestResult {
fail_test(
r#"module foo { export def a [] { 1 }; export def b [] { 2 } }; use foo c"#,
"not find import",
)
}
#[test]
fn module_def_imports_5() -> TestResult {
run_test(
r#"module foo { export def a [] { 1 }; def b [] { '2' }; export def c [] { '3' } }; use foo [a, c]; c"#,
"3",
)
}
#[test]
fn module_env_imports_1() -> TestResult {
run_test(
r#"module foo { export-env { $env.a = '1' } }; use foo; $env.a"#,
"1",
)
}
#[test]
fn module_env_imports_2() -> TestResult {
run_test(
r#"module foo { export-env { $env.a = '1'; $env.b = '2' } }; use foo; $env.b"#,
"2",
)
}
#[test]
fn module_env_imports_3() -> TestResult {
run_test(
r#"module foo { export-env { $env.a = '1' }; export-env { $env.b = '2' }; export-env {$env.c = '3'} }; use foo; $env.c"#,
"3",
)
}
#[test]
fn module_def_and_env_imports_1() -> TestResult {
run_test(
r#"module spam { export-env { $env.foo = "foo" }; export def foo [] { "bar" } }; use spam; $env.foo"#,
"foo",
)
}
#[test]
fn module_def_and_env_imports_2() -> TestResult {
run_test(
r#"module spam { export-env { $env.foo = "foo" }; export def foo [] { "bar" } }; use spam foo; foo"#,
"bar",
)
}
#[test]
fn module_def_import_uses_internal_command() -> TestResult {
run_test(
r#"module foo { def b [] { 2 }; export def a [] { b } }; use foo; foo a"#,
"2",
)
}
#[test]
fn module_env_import_uses_internal_command() -> TestResult {
run_test(
r#"module foo { def b [] { "2" }; export-env { $env.a = (b) } }; use foo; $env.a"#,
"2",
)
}
#[test]
fn multi_word_imports() -> TestResult {
run_test(
r#"module spam { export def "foo bar" [] { 10 } }; use spam "foo bar"; foo bar"#,
"10",
)
}
#[test]
fn export_alias() -> TestResult {
run_test(
r#"module foo { export alias hi = echo hello }; use foo hi; hi"#,
"hello",
)
}
#[test]
fn export_consts() -> TestResult {
run_test(
r#"module spam { export const b = 3; }; use spam b; $b"#,
"3",
)
}
#[test]
fn func_use_consts() -> TestResult {
run_test(
r#"module spam { const b = 3; export def c [] { $b } }; use spam; spam c"#,
"3",
)
}
#[test]
fn export_module_which_defined_const() -> TestResult {
run_test(
r#"module spam { export const b = 3; export const c = 4 }; use spam; $spam.b + $spam.c"#,
"7",
)
}
#[test]
fn cannot_export_private_const() -> TestResult {
fail_test(
r#"module spam { const b = 3; export const c = 4 }; use spam; $spam.b + $spam.c"#,
"cannot find column 'b'",
)
}
#[test]
fn test_lexical_binding() -> TestResult {
run_test(
r#"module spam { const b = 3; export def c [] { $b } }; use spam c; const b = 4; c"#,
"3",
)?;
run_test(
r#"const b = 4; module spam { const b = 3; export def c [] { $b } }; use spam; spam c"#,
"3",
)
}

View File

@ -1,892 +0,0 @@
use crate::tests::{fail_test, run_test, run_test_with_env, TestResult};
use nu_test_support::{nu, nu_repl_code};
use std::collections::HashMap;
use super::run_test_contains;
#[test]
fn env_shorthand() -> TestResult {
run_test("FOO=BAR if false { 3 } else { 4 }", "4")
}
#[test]
fn subcommand() -> TestResult {
run_test("def foo [] {}; def \"foo bar\" [] {3}; foo bar", "3")
}
#[test]
fn alias_1() -> TestResult {
run_test("def foo [$x] { $x + 10 }; alias f = foo; f 100", "110")
}
#[test]
fn ints_with_underscores() -> TestResult {
run_test("1_0000_0000_0000 + 10", "1000000000010")
}
#[test]
fn floats_with_underscores() -> TestResult {
run_test("3.1415_9265_3589_793 * 2", "6.283185307179586")
}
#[test]
fn bin_ints_with_underscores() -> TestResult {
run_test("0b_10100_11101_10010", "21426")
}
#[test]
fn oct_ints_with_underscores() -> TestResult {
run_test("0o2443_6442_7652_0044", "90422533333028")
}
#[test]
fn hex_ints_with_underscores() -> TestResult {
run_test("0x68__9d__6a", "6856042")
}
#[test]
fn alias_2() -> TestResult {
run_test(
"def foo [$x $y] { $x + $y + 10 }; alias f = foo 33; f 100",
"143",
)
}
#[test]
fn alias_2_multi_word() -> TestResult {
run_test(
r#"def "foo bar" [$x $y] { $x + $y + 10 }; alias f = foo bar 33; f 100"#,
"143",
)
}
#[ignore = "TODO: Allow alias to alias existing command with the same name"]
#[test]
fn alias_recursion() -> TestResult {
run_test_contains(r#"alias ls = ls -a; ls"#, " ")
}
#[test]
fn block_param1() -> TestResult {
run_test("[3] | each { |it| $it + 10 } | get 0", "13")
}
#[test]
fn block_param2() -> TestResult {
run_test("[3] | each { |y| $y + 10 } | get 0", "13")
}
#[test]
fn block_param3_list_iteration() -> TestResult {
run_test("[1,2,3] | each { |it| $it + 10 } | get 1", "12")
}
#[test]
fn block_param4_list_iteration() -> TestResult {
run_test("[1,2,3] | each { |y| $y + 10 } | get 2", "13")
}
#[test]
fn range_iteration1() -> TestResult {
run_test("1..4 | each { |y| $y + 10 } | get 0", "11")
}
#[test]
fn range_iteration2() -> TestResult {
run_test("4..1 | each { |y| $y + 100 } | get 3", "101")
}
#[test]
fn simple_value_iteration() -> TestResult {
run_test("4 | each { |it| $it + 10 }", "14")
}
#[test]
fn comment_multiline() -> TestResult {
run_test(
r#"def foo [] {
let x = 1 + 2 # comment
let y = 3 + 4 # another comment
$x + $y
}; foo"#,
"10",
)
}
#[test]
fn comment_skipping_1() -> TestResult {
run_test(
r#"let x = {
y: 20
# foo
}; $x.y"#,
"20",
)
}
#[test]
fn comment_skipping_2() -> TestResult {
run_test(
r#"let x = {
y: 20
# foo
z: 40
}; $x.z"#,
"40",
)
}
#[test]
fn comment_skipping_in_pipeline_1() -> TestResult {
run_test(
r#"[1,2,3] | #comment
each { |$it| $it + 2 } | # foo
math sum #bar"#,
"12",
)
}
#[test]
fn comment_skipping_in_pipeline_2() -> TestResult {
run_test(
r#"[1,2,3] #comment
| #comment2
each { |$it| $it + 2 } #foo
| # bar
math sum #baz"#,
"12",
)
}
#[test]
fn comment_skipping_in_pipeline_3() -> TestResult {
run_test(
r#"[1,2,3] | #comment
#comment2
each { |$it| $it + 2 } #foo
| # bar
#baz
math sum #foobar"#,
"12",
)
}
#[test]
fn bad_var_name() -> TestResult {
fail_test(r#"let $"foo bar" = 4"#, "can't contain")
}
#[test]
fn bad_var_name2() -> TestResult {
fail_test(r#"let $foo-bar = 4"#, "valid variable")
}
#[test]
fn assignment_with_no_var() -> TestResult {
let cases = [
"let = if $",
"mut = if $",
"const = if $",
"let = 'foo' | $in; $x | describe",
"mut = 'foo' | $in; $x | describe",
];
let expected = "valid variable";
for case in cases {
fail_test(case, expected)?;
}
Ok(())
}
#[test]
fn long_flag() -> TestResult {
run_test(
r#"([a, b, c] | enumerate | each --keep-empty { |e| if $e.index != 1 { 100 }}).1 | to nuon"#,
"null",
)
}
#[test]
fn for_in_missing_var_name() -> TestResult {
fail_test("for in", "missing")
}
#[test]
fn multiline_pipe_in_block() -> TestResult {
run_test(
r#"do {
echo hello |
str length
}"#,
"5",
)
}
#[test]
fn bad_short_flag() -> TestResult {
fail_test(r#"def foo3 [-l?:int] { $l }"#, "short flag")
}
#[test]
fn quotes_with_equals() -> TestResult {
run_test(
r#"let query_prefix = "https://api.github.com/search/issues?q=repo:nushell/"; $query_prefix"#,
"https://api.github.com/search/issues?q=repo:nushell/",
)
}
#[test]
fn string_interp_with_equals() -> TestResult {
run_test(
r#"let query_prefix = $"https://api.github.com/search/issues?q=repo:nushell/"; $query_prefix"#,
"https://api.github.com/search/issues?q=repo:nushell/",
)
}
#[test]
fn recursive_parse() -> TestResult {
run_test(r#"def c [] { c }; echo done"#, "done")
}
#[test]
fn commands_have_usage() -> TestResult {
run_test_contains(
r#"
# This is a test
#
# To see if I have cool usage
def foo [] {}
help foo"#,
"cool usage",
)
}
#[test]
fn equals_separates_long_flag() -> TestResult {
run_test(
r#"'nushell' | fill --alignment right --width=10 --character='-'"#,
"---nushell",
)
}
#[test]
fn assign_expressions() -> TestResult {
let env = HashMap::from([("VENV_OLD_PATH", "Foobar"), ("Path", "Quux")]);
run_test_with_env(
r#"$env.Path = (if ($env | columns | "VENV_OLD_PATH" in $in) { $env.VENV_OLD_PATH } else { $env.Path }); echo $env.Path"#,
"Foobar",
&env,
)
}
#[test]
fn string_interpolation_paren_test() -> TestResult {
run_test(r#"$"('(')(')')""#, "()")
}
#[test]
fn string_interpolation_paren_test2() -> TestResult {
run_test(r#"$"('(')test(')')""#, "(test)")
}
#[test]
fn string_interpolation_paren_test3() -> TestResult {
run_test(r#"$"('(')("test")test(')')""#, "(testtest)")
}
#[test]
fn string_interpolation_escaping() -> TestResult {
run_test(r#"$"hello\nworld" | lines | length"#, "2")
}
#[test]
fn capture_multiple_commands() -> TestResult {
run_test(
r#"
let CONST_A = 'Hello'
def 'say-hi' [] {
echo (call-me)
}
def 'call-me' [] {
echo $CONST_A
}
[(say-hi) (call-me)] | str join
"#,
"HelloHello",
)
}
#[test]
fn capture_multiple_commands2() -> TestResult {
run_test(
r#"
let CONST_A = 'Hello'
def 'call-me' [] {
echo $CONST_A
}
def 'say-hi' [] {
echo (call-me)
}
[(say-hi) (call-me)] | str join
"#,
"HelloHello",
)
}
#[test]
fn capture_multiple_commands3() -> TestResult {
run_test(
r#"
let CONST_A = 'Hello'
def 'say-hi' [] {
echo (call-me)
}
def 'call-me' [] {
echo $CONST_A
}
[(call-me) (say-hi)] | str join
"#,
"HelloHello",
)
}
#[test]
fn capture_multiple_commands4() -> TestResult {
run_test(
r#"
let CONST_A = 'Hello'
def 'call-me' [] {
echo $CONST_A
}
def 'say-hi' [] {
echo (call-me)
}
[(call-me) (say-hi)] | str join
"#,
"HelloHello",
)
}
#[test]
fn capture_row_condition() -> TestResult {
run_test(
r#"let name = "foo"; [foo] | where $'($name)' =~ $it | str join"#,
"foo",
)
}
#[test]
fn starts_with_operator_succeeds() -> TestResult {
run_test(
r#"[Moe Larry Curly] | where $it starts-with L | str join"#,
"Larry",
)
}
#[test]
fn ends_with_operator_succeeds() -> TestResult {
run_test(
r#"[Moe Larry Curly] | where $it ends-with ly | str join"#,
"Curly",
)
}
#[test]
fn proper_missing_param() -> TestResult {
fail_test(r#"def foo [x y z w] { }; foo a b c"#, "missing w")
}
#[test]
fn block_arity_check1() -> TestResult {
fail_test(r#"ls | each { |x, y| 1}"#, "expected 1 closure parameter")
}
// deprecating former support for escapes like `/uNNNN`, dropping test.
#[test]
fn string_escape_unicode_extended() -> TestResult {
run_test(r#""\u{015B}\u{1f10b}""#, "ś🄋")
}
#[test]
fn string_escape_interpolation() -> TestResult {
run_test(r#"$"\u{015B}(char hamburger)abc""#, "ś≡abc")
}
#[test]
fn string_escape_interpolation2() -> TestResult {
run_test(r#"$"2 + 2 is \(2 + 2)""#, "2 + 2 is (2 + 2)")
}
#[test]
fn proper_rest_types() -> TestResult {
run_test(
r#"def foo [--verbose(-v), # my test flag
...rest: int # my rest comment
] { if $verbose { print "verbose!" } else { print "not verbose!" } }; foo"#,
"not verbose!",
)
}
#[test]
fn single_value_row_condition() -> TestResult {
run_test(
r#"[[a, b]; [true, false], [true, true]] | where a | length"#,
"2",
)
}
#[test]
fn performance_nested_lists() -> TestResult {
// Parser used to be exponential on deeply nested lists
// TODO: Add a timeout
fail_test(r#"[[[[[[[[[[[[[[[[[[[[[[[[[[[["#, "Unexpected end of code")
}
#[test]
fn unary_not_1() -> TestResult {
run_test(r#"not false"#, "true")
}
#[test]
fn unary_not_2() -> TestResult {
run_test(r#"not (false)"#, "true")
}
#[test]
fn unary_not_3() -> TestResult {
run_test(r#"(not false)"#, "true")
}
#[test]
fn unary_not_4() -> TestResult {
run_test(r#"if not false { "hello" } else { "world" }"#, "hello")
}
#[test]
fn unary_not_5() -> TestResult {
run_test(
r#"if not not not not false { "hello" } else { "world" }"#,
"world",
)
}
#[test]
fn unary_not_6() -> TestResult {
run_test(
r#"[[name, present]; [abc, true], [def, false]] | where not present | get name.0"#,
"def",
)
}
#[test]
fn comment_in_multiple_pipelines() -> TestResult {
run_test(
r#"[[name, present]; [abc, true], [def, false]]
# | where not present
| get name.0"#,
"abc",
)
}
#[test]
fn date_literal() -> TestResult {
run_test(r#"2022-09-10 | date to-record | get day"#, "10")
}
#[test]
fn and_and_or() -> TestResult {
run_test(r#"true and false or true"#, "true")
}
#[test]
fn and_and_xor() -> TestResult {
// Assumes the precedence NOT > AND > XOR > OR
run_test(r#"true and true xor true and false"#, "true")
}
#[test]
fn or_and_xor() -> TestResult {
// Assumes the precedence NOT > AND > XOR > OR
run_test(r#"true or false xor true or false"#, "true")
}
#[test]
fn unbalanced_delimiter() -> TestResult {
fail_test(r#"{a:{b:5}}}"#, "unbalanced { and }")
}
#[test]
fn unbalanced_delimiter2() -> TestResult {
fail_test(r#"{}#.}"#, "unbalanced { and }")
}
#[test]
fn unbalanced_delimiter3() -> TestResult {
fail_test(r#"{"#, "Unexpected end of code")
}
#[test]
fn unbalanced_delimiter4() -> TestResult {
fail_test(r#"}"#, "unbalanced { and }")
}
#[test]
fn unbalanced_parens1() -> TestResult {
fail_test(r#")"#, "unbalanced ( and )")
}
#[test]
fn unbalanced_parens2() -> TestResult {
fail_test(r#"("("))"#, "unbalanced ( and )")
}
#[test]
fn register_with_string_literal() -> TestResult {
fail_test(r#"register 'nu-plugin-math'"#, "File not found")
}
#[test]
fn register_with_string_constant() -> TestResult {
let input = "\
const file = 'nu-plugin-math'
register $file
";
// should not fail with `not a constant`
fail_test(input, "File not found")
}
#[test]
fn register_with_string_variable() -> TestResult {
let input = "\
let file = 'nu-plugin-math'
register $file
";
fail_test(input, "Value is not a parse-time constant")
}
#[test]
fn register_with_non_string_constant() -> TestResult {
let input = "\
const file = 6
register $file
";
fail_test(input, "expected string, found int")
}
#[test]
fn plugin_use_with_string_literal() -> TestResult {
fail_test(
r#"plugin use 'nu-plugin-math'"#,
"Plugin registry file not set",
)
}
#[test]
fn plugin_use_with_string_constant() -> TestResult {
let input = "\
const file = 'nu-plugin-math'
plugin use $file
";
// should not fail with `not a constant`
fail_test(input, "Plugin registry file not set")
}
#[test]
fn plugin_use_with_string_variable() -> TestResult {
let input = "\
let file = 'nu-plugin-math'
plugin use $file
";
fail_test(input, "Value is not a parse-time constant")
}
#[test]
fn plugin_use_with_non_string_constant() -> TestResult {
let input = "\
const file = 6
plugin use $file
";
fail_test(input, "expected string, found int")
}
#[test]
fn extern_errors_with_no_space_between_params_and_name_1() -> TestResult {
fail_test("extern cmd[]", "expected space")
}
#[test]
fn extern_errors_with_no_space_between_params_and_name_2() -> TestResult {
fail_test("extern cmd(--flag)", "expected space")
}
#[test]
fn duration_with_underscores_1() -> TestResult {
run_test("420_min", "7hr")
}
#[test]
fn duration_with_underscores_2() -> TestResult {
run_test("1_000_000sec", "1wk 4day 13hr 46min 40sec")
}
#[test]
fn duration_with_underscores_3() -> TestResult {
fail_test("1_000_d_ay", "executable was not found")
}
#[test]
fn duration_with_faulty_number() -> TestResult {
fail_test("sleep 4-ms", "duration value must be a number")
}
#[test]
fn filesize_with_underscores_1() -> TestResult {
run_test("420_mb", "400.5 MiB")
}
#[test]
fn filesize_with_underscores_2() -> TestResult {
run_test("1_000_000B", "976.6 KiB")
}
#[test]
fn filesize_with_underscores_3() -> TestResult {
fail_test("42m_b", "executable was not found")
}
#[test]
fn filesize_is_not_hex() -> TestResult {
run_test("0x42b", "1067")
}
#[test]
fn let_variable_type_mismatch() -> TestResult {
fail_test(r#"let x: int = "foo""#, "expected int, found string")
}
#[test]
fn let_variable_disallows_completer() -> TestResult {
fail_test(
r#"let x: int@completer = 42"#,
"Unexpected custom completer",
)
}
#[test]
fn def_with_input_output() -> TestResult {
run_test(r#"def foo []: nothing -> int { 3 }; foo"#, "3")
}
#[test]
fn def_with_input_output_with_line_breaks() -> TestResult {
run_test(
r#"def foo []: [
nothing -> int
] { 3 }; foo"#,
"3",
)
}
#[test]
fn def_with_multi_input_output_with_line_breaks() -> TestResult {
run_test(
r#"def foo []: [
nothing -> int
string -> int
] { 3 }; foo"#,
"3",
)
}
#[test]
fn def_with_multi_input_output_without_commas() -> TestResult {
run_test(
r#"def foo []: [nothing -> int string -> int] { 3 }; foo"#,
"3",
)
}
#[test]
fn def_with_multi_input_output_called_with_first_sig() -> TestResult {
run_test(
r#"def foo []: [int -> int, string -> int] { 3 }; 10 | foo"#,
"3",
)
}
#[test]
fn def_with_multi_input_output_called_with_second_sig() -> TestResult {
run_test(
r#"def foo []: [int -> int, string -> int] { 3 }; "bob" | foo"#,
"3",
)
}
#[test]
fn def_with_input_output_mismatch_1() -> TestResult {
fail_test(
r#"def foo []: [int -> int, string -> int] { 3 }; foo"#,
"command doesn't support",
)
}
#[test]
fn def_with_input_output_mismatch_2() -> TestResult {
fail_test(
r#"def foo []: [int -> int, string -> int] { 3 }; {x: 2} | foo"#,
"command doesn't support",
)
}
#[test]
fn def_with_input_output_broken_1() -> TestResult {
fail_test(r#"def foo []: int { 3 }"#, "expected arrow")
}
#[test]
fn def_with_input_output_broken_2() -> TestResult {
fail_test(r#"def foo []: int -> { 3 }"#, "expected type")
}
#[test]
fn def_with_input_output_broken_3() -> TestResult {
fail_test(
r#"def foo []: int -> int@completer {}"#,
"Unexpected custom completer",
)
}
#[test]
fn def_with_input_output_broken_4() -> TestResult {
fail_test(
r#"def foo []: int -> list<int@completer> {}"#,
"Unexpected custom completer",
)
}
#[test]
fn def_with_in_var_let_1() -> TestResult {
run_test(
r#"def foo []: [int -> int, string -> int] { let x = $in; if ($x | describe) == "int" { 3 } else { 4 } }; "100" | foo"#,
"4",
)
}
#[test]
fn def_with_in_var_let_2() -> TestResult {
run_test(
r#"def foo []: [int -> int, string -> int] { let x = $in; if ($x | describe) == "int" { 3 } else { 4 } }; 100 | foo"#,
"3",
)
}
#[test]
fn def_with_in_var_mut_1() -> TestResult {
run_test(
r#"def foo []: [int -> int, string -> int] { mut x = $in; if ($x | describe) == "int" { 3 } else { 4 } }; "100" | foo"#,
"4",
)
}
#[test]
fn def_with_in_var_mut_2() -> TestResult {
run_test(
r#"def foo []: [int -> int, string -> int] { mut x = $in; if ($x | describe) == "int" { 3 } else { 4 } }; 100 | foo"#,
"3",
)
}
#[test]
fn properly_nest_captures() -> TestResult {
run_test(r#"do { let b = 3; def c [] { $b }; c }"#, "3")
}
#[test]
fn properly_nest_captures_call_first() -> TestResult {
run_test(r#"do { let b = 3; c; def c [] { $b }; c }"#, "3")
}
#[test]
fn properly_typecheck_rest_param() -> TestResult {
run_test(
r#"def foo [...rest: string] { $rest | length }; foo "a" "b" "c""#,
"3",
)
}
#[test]
fn implied_collect_has_compatible_type() -> TestResult {
run_test(r#"let idx = 3 | $in; $idx < 1"#, "false")
}
#[test]
fn record_expected_colon() -> TestResult {
fail_test(r#"{ a: 2 b }"#, "expected ':'")?;
fail_test(r#"{ a: 2 b 3 }"#, "expected ':'")
}
#[test]
fn record_missing_value() -> TestResult {
fail_test(r#"{ a: 2 b: }"#, "expected value for record field")
}
#[test]
fn def_requires_body_closure() -> TestResult {
fail_test("def a [] (echo 4)", "expected definition body closure")
}
#[test]
fn not_panic_with_recursive_call() {
let result = nu!(nu_repl_code(&[
"def px [] { if true { 3 } else { px } }",
"let x = 1",
"$x | px",
]));
assert_eq!(result.out, "3");
let result = nu!(nu_repl_code(&[
"def px [n=0] { let l = $in; if $n == 0 { return false } else { $l | px ($n - 1) } }",
"let x = 1",
"$x | px"
]));
assert_eq!(result.out, "false");
let result = nu!(nu_repl_code(&[
"def px [n=0] { let l = $in; if $n == 0 { return false } else { $l | px ($n - 1) } }",
"let x = 1",
"def foo [] { $x }",
"foo | px"
]));
assert_eq!(result.out, "false");
let result = nu!(nu_repl_code(&[
"def px [n=0] { let l = $in; if $n == 0 { return false } else { $l | px ($n - 1) } }",
"let x = 1",
"do {|| $x } | px"
]));
assert_eq!(result.out, "false");
let result = nu!(
cwd: "tests/parsing/samples",
"nu recursive_func_with_alias.nu"
);
assert!(result.status.success());
}

View File

@ -1,36 +0,0 @@
use crate::tests::{fail_test, run_test, TestResult};
#[test]
fn int_in_inc_range() -> TestResult {
run_test(r#"1 in -4..9.42"#, "true")
}
#[test]
fn int_in_dec_range() -> TestResult {
run_test(r#"1 in 9.42..-4"#, "true")
}
#[test]
fn int_in_exclusive_range() -> TestResult {
run_test(r#"3 in 0..<3"#, "false")
}
#[test]
fn non_number_in_range() -> TestResult {
fail_test(r#"'a' in 1..3"#, "subset comparison is not supported")
}
#[test]
fn float_not_in_inc_range() -> TestResult {
run_test(r#"1.4 not-in 2..9.42"#, "true")
}
#[test]
fn range_and_reduction() -> TestResult {
run_test(r#"1..6..36 | math sum"#, "148")
}
#[test]
fn zip_ranges() -> TestResult {
run_test(r#"1..3 | zip 4..6 | get 2.1"#, "6")
}

View File

@ -1,82 +0,0 @@
use crate::tests::{fail_test, run_test, TestResult};
#[test]
fn contains() -> TestResult {
run_test(r#"'foobarbaz' =~ bar"#, "true")
}
#[test]
fn contains_case_insensitive() -> TestResult {
run_test(r#"'foobarbaz' =~ '(?i)BaR'"#, "true")
}
#[test]
fn not_contains() -> TestResult {
run_test(r#"'foobarbaz' !~ asdf"#, "true")
}
#[test]
fn match_full_line() -> TestResult {
run_test(r#"'foobarbaz' =~ '^foobarbaz$'"#, "true")
}
#[test]
fn not_match_full_line() -> TestResult {
run_test(r#"'foobarbaz' !~ '^foobarbaz$'"#, "false")
}
#[test]
fn starts_with() -> TestResult {
run_test(r#"'foobarbaz' =~ '^foo'"#, "true")
}
#[test]
fn not_starts_with() -> TestResult {
run_test(r#"'foobarbaz' !~ '^foo'"#, "false")
}
#[test]
fn ends_with() -> TestResult {
run_test(r#"'foobarbaz' =~ 'baz$'"#, "true")
}
#[test]
fn not_ends_with() -> TestResult {
run_test(r#"'foobarbaz' !~ 'baz$'"#, "false")
}
#[test]
fn where_works() -> TestResult {
run_test(
r#"[{name: somefile.txt} {name: anotherfile.csv }] | where name =~ ^s | get name.0"#,
"somefile.txt",
)
}
#[test]
fn where_not_works() -> TestResult {
run_test(
r#"[{name: somefile.txt} {name: anotherfile.csv }] | where name !~ ^s | get name.0"#,
"anotherfile.csv",
)
}
#[test]
fn invalid_regex_fails() -> TestResult {
fail_test(r#"'foo' =~ '['"#, "Invalid character class")
}
#[test]
fn invalid_not_regex_fails() -> TestResult {
fail_test(r#"'foo' !~ '['"#, "Invalid character class")
}
#[test]
fn regex_on_int_fails() -> TestResult {
fail_test(r#"33 =~ foo"#, "is not supported")
}
#[test]
fn not_regex_on_int_fails() -> TestResult {
fail_test(r#"33 !~ foo"#, "is not supported")
}

View File

@ -1,377 +0,0 @@
use crate::tests::{fail_test, run_test, TestResult};
#[test]
fn list_annotations() -> TestResult {
let input = "def run [list: list<int>] {$list | length}; run [2 5 4]";
let expected = "3";
run_test(input, expected)
}
#[test]
fn list_annotations_unknown_prefix() -> TestResult {
let input = "def run [list: listint>] {$list | length}; run [2 5 4]";
let expected = "unknown type";
fail_test(input, expected)
}
#[test]
fn list_annotations_empty_1() -> TestResult {
let input = "def run [list: list] {$list | length}; run [2 5 4]";
let expected = "3";
run_test(input, expected)
}
#[test]
fn list_annotations_empty_2() -> TestResult {
let input = "def run [list: list<>] {$list | length}; run [2 5 4]";
let expected = "3";
run_test(input, expected)
}
#[test]
fn list_annotations_empty_3() -> TestResult {
let input = "def run [list: list< >] {$list | length}; run [2 5 4]";
let expected = "3";
run_test(input, expected)
}
#[test]
fn list_annotations_empty_4() -> TestResult {
let input = "def run [list: list<\n>] {$list | length}; run [2 5 4]";
let expected = "3";
run_test(input, expected)
}
#[test]
fn list_annotations_nested() -> TestResult {
let input = "def run [list: list<list<float>>] {$list | length}; run [ [2.0] [5.0] [4.0]]";
let expected = "3";
run_test(input, expected)
}
#[test]
fn list_annotations_unknown_inner_type() -> TestResult {
let input = "def run [list: list<str>] {$list | length}; run ['nushell' 'nunu' 'nana']";
let expected = "unknown type";
fail_test(input, expected)
}
#[test]
fn list_annotations_nested_unknown_inner() -> TestResult {
let input = "def run [list: list<list<str>>] {$list | length}; run [ [nushell] [nunu] [nana]]";
let expected = "unknown type";
fail_test(input, expected)
}
#[test]
fn list_annotations_unterminated() -> TestResult {
let input = "def run [list: list<string] {$list | length}; run [nu she ll]";
let expected = "expected closing >";
fail_test(input, expected)
}
#[test]
fn list_annotations_nested_unterminated() -> TestResult {
let input = "def run [list: list<list<>] {$list | length}; run [2 5 4]";
let expected = "expected closing >";
fail_test(input, expected)
}
#[test]
fn list_annotations_space_within_1() -> TestResult {
let input = "def run [list: list< range>] {$list | length}; run [2..32 5..<64 4..128]";
let expected = "3";
run_test(input, expected)
}
#[test]
fn list_annotations_space_within_2() -> TestResult {
let input = "def run [list: list<number >] {$list | length}; run [2 5 4]";
let expected = "3";
run_test(input, expected)
}
#[test]
fn list_annotations_space_within_3() -> TestResult {
let input = "def run [list: list< int >] {$list | length}; run [2 5 4]";
let expected = "3";
run_test(input, expected)
}
#[test]
fn list_annotations_space_before() -> TestResult {
let input = "def run [list: list <int>] {$list | length}; run [2 5 4]";
let expected = "expected valid variable name for this parameter";
fail_test(input, expected)
}
#[test]
fn list_annotations_unknown_separators() -> TestResult {
let input = "def run [list: list<int, string>] {$list | length}; run [2 5 4]";
let expected = "unknown type";
fail_test(input, expected)
}
#[test]
fn list_annotations_with_default_val_1() -> TestResult {
let input = "def run [list: list<int> = [2 5 4]] {$list | length}; run";
let expected = "3";
run_test(input, expected)
}
#[test]
fn list_annotations_with_default_val_2() -> TestResult {
let input = "def run [list: list<string> = [2 5 4]] {$list | length}; run";
let expected = "Default value wrong type";
fail_test(input, expected)
}
#[test]
fn list_annotations_with_extra_characters() -> TestResult {
let input = "def run [list: list<int>extra] {$list | length}; run [1 2 3]";
let expected = "Extra characters in the parameter name";
fail_test(input, expected)
}
#[test]
fn record_annotations_none() -> TestResult {
let input = "def run [rec: record] { $rec }; run {} | describe";
let expected = "record";
run_test(input, expected)
}
#[test]
fn record_annotations() -> TestResult {
let input = "def run [rec: record<age: int>] { $rec }; run {age: 3} | describe";
let expected = "record<age: int>";
run_test(input, expected)
}
#[test]
fn record_annotations_two_types() -> TestResult {
let input = "def run [rec: record<name: string age: int>] { $rec }; run {name: nushell age: 3} | describe";
let expected = "record<name: string, age: int>";
run_test(input, expected)
}
#[test]
fn record_annotations_two_types_comma_sep() -> TestResult {
let input = "def run [rec: record<name: string, age: int>] { $rec }; run {name: nushell age: 3} | describe";
let expected = "record<name: string, age: int>";
run_test(input, expected)
}
#[test]
fn record_annotations_key_with_no_type() -> TestResult {
let input = "def run [rec: record<name>] { $rec }; run {name: nushell} | describe";
let expected = "record<name: string>";
run_test(input, expected)
}
#[test]
fn record_annotations_two_types_one_with_no_type() -> TestResult {
let input =
"def run [rec: record<name: string, age>] { $rec }; run {name: nushell age: 3} | describe";
let expected = "record<name: string, age: int>";
run_test(input, expected)
}
#[test]
fn record_annotations_two_types_both_with_no_types() -> TestResult {
let input = "def run [rec: record<name age>] { $rec }; run {name: nushell age: 3} | describe";
let expected = "record<name: string, age: int>";
run_test(input, expected)
}
#[test]
fn record_annotations_nested() -> TestResult {
let input = "def run [
err: record<
msg: string,
label: record<
text: string
start: int,
end: int,
>>
] {
$err
}; run {
msg: 'error message'
label: {
text: 'here is the error'
start: 0
end: 69
}
} | describe";
let expected = "record<msg: string, label: record<text: string, start: int, end: int>>";
run_test(input, expected)
}
#[test]
fn record_annotations_type_inference_1() -> TestResult {
let input = "def run [rec: record<age: any>] { $rec }; run {age: 2wk} | describe";
let expected = "record<age: duration>";
run_test(input, expected)
}
#[test]
fn record_annotations_type_inference_2() -> TestResult {
let input = "def run [rec: record<size>] { $rec }; run {size: 2mb} | describe";
let expected = "record<size: filesize>";
run_test(input, expected)
}
#[test]
fn record_annotations_not_terminated() -> TestResult {
let input = "def run [rec: record<age: int] { $rec }";
let expected = "expected closing >";
fail_test(input, expected)
}
#[test]
fn record_annotations_not_terminated_inner() -> TestResult {
let input = "def run [rec: record<name: string, repos: list<string>] { $rec }";
let expected = "expected closing >";
fail_test(input, expected)
}
#[test]
fn record_annotations_no_type_after_colon() -> TestResult {
let input = "def run [rec: record<name: >] { $rec }";
let expected = "type after colon";
fail_test(input, expected)
}
#[test]
fn record_annotations_type_mismatch_key() -> TestResult {
let input = "def run [rec: record<name: string>] { $rec }; run {nme: nushell}";
let expected = "expected record<name: string>, found record<nme: string>";
fail_test(input, expected)
}
#[test]
fn record_annotations_type_mismatch_shape() -> TestResult {
let input = "def run [rec: record<age: int>] { $rec }; run {age: 2wk}";
let expected = "expected record<age: int>, found record<age: duration>";
fail_test(input, expected)
}
#[test]
fn record_annotations_with_extra_characters() -> TestResult {
let input = "def run [list: record<int>extra] {$list | length}; run [1 2 3]";
let expected = "Extra characters in the parameter name";
fail_test(input, expected)
}
#[test]
fn table_annotations_none() -> TestResult {
let input = "def run [t: table] { $t }; run [[]; []] | describe";
let expected = "table";
run_test(input, expected)
}
#[test]
fn table_annotations() -> TestResult {
let input = "def run [t: table<age: int>] { $t }; run [[age]; [3]] | describe";
let expected = "table<age: int>";
run_test(input, expected)
}
#[test]
fn table_annotations_two_types() -> TestResult {
let input = "\
def run [t: table<name: string age: int>] { $t };
run [[name, age]; [nushell, 3]] | describe";
let expected = "table<name: string, age: int>";
run_test(input, expected)
}
#[test]
fn table_annotations_two_types_comma_sep() -> TestResult {
let input = "\
def run [t: table<name: string, age: int>] { $t };
run [[name, age]; [nushell, 3]] | describe";
let expected = "table<name: string, age: int>";
run_test(input, expected)
}
#[test]
fn table_annotations_key_with_no_type() -> TestResult {
let input = "def run [t: table<name>] { $t }; run [[name]; [nushell]] | describe";
let expected = "table<name: string>";
run_test(input, expected)
}
#[test]
fn table_annotations_two_types_one_with_no_type() -> TestResult {
let input = "\
def run [t: table<name: string, age>] { $t };
run [[name, age]; [nushell, 3]] | describe";
let expected = "table<name: string, age: int>";
run_test(input, expected)
}
#[test]
fn table_annotations_two_types_both_with_no_types() -> TestResult {
let input = "\
def run [t: table<name, age>] { $t };
run [[name, age]; [nushell, 3]] | describe";
let expected = "table<name: string, age: int>";
run_test(input, expected)
}
#[test]
fn table_annotations_type_inference_1() -> TestResult {
let input = "def run [t: table<age: any>] { $t }; run [[age]; [2wk]] | describe";
let expected = "table<age: duration>";
run_test(input, expected)
}
#[test]
fn table_annotations_type_inference_2() -> TestResult {
let input = "def run [t: table<size>] { $t }; run [[size]; [2mb]] | describe";
let expected = "table<size: filesize>";
run_test(input, expected)
}
#[test]
fn table_annotations_not_terminated() -> TestResult {
let input = "def run [t: table<age: int] { $t }";
let expected = "expected closing >";
fail_test(input, expected)
}
#[test]
fn table_annotations_not_terminated_inner() -> TestResult {
let input = "def run [t: table<name: string, repos: list<string>] { $t }";
let expected = "expected closing >";
fail_test(input, expected)
}
#[test]
fn table_annotations_no_type_after_colon() -> TestResult {
let input = "def run [t: table<name: >] { $t }";
let expected = "type after colon";
fail_test(input, expected)
}
#[test]
fn table_annotations_type_mismatch_column() -> TestResult {
let input = "def run [t: table<name: string>] { $t }; run [[nme]; [nushell]]";
let expected = "expected table<name: string>, found table<nme: string>";
fail_test(input, expected)
}
#[test]
fn table_annotations_type_mismatch_shape() -> TestResult {
let input = "def run [t: table<age: int>] { $t }; run [[age]; [2wk]]";
let expected = "expected table<age: int>, found table<age: duration>";
fail_test(input, expected)
}
#[test]
fn table_annotations_with_extra_characters() -> TestResult {
let input = "def run [t: table<int>extra] {$t | length}; run [[int]; [8]]";
let expected = "Extra characters in the parameter name";
fail_test(input, expected)
}

View File

@ -1,202 +0,0 @@
use crate::tests::{fail_test, run_test, TestResult};
use nu_test_support::nu;
#[test]
fn spread_in_list() -> TestResult {
run_test(r#"[...[]] | to nuon"#, "[]").unwrap();
run_test(
r#"[1 2 ...[[3] {x: 1}] 5] | to nuon"#,
"[1, 2, [3], {x: 1}, 5]",
)
.unwrap();
run_test(
r#"[...("foo" | split chars) 10] | to nuon"#,
"[f, o, o, 10]",
)
.unwrap();
run_test(
r#"let l = [1, 2, [3]]; [...$l $l] | to nuon"#,
"[1, 2, [3], [1, 2, [3]]]",
)
.unwrap();
run_test(
r#"[ ...[ ...[ ...[ a ] b ] c ] d ] | to nuon"#,
"[a, b, c, d]",
)
}
#[test]
fn not_spread() -> TestResult {
run_test(r#"def ... [x] { $x }; ... ..."#, "...").unwrap();
run_test(
r#"let a = 4; [... $a ... [1] ... (5) ...bare ...] | to nuon"#,
"[..., 4, ..., [1], ..., 5, ...bare, ...]",
)
}
#[test]
fn bad_spread_on_non_list() -> TestResult {
fail_test(r#"let x = 5; [...$x]"#, "cannot spread").unwrap();
fail_test(r#"[...({ x: 1 })]"#, "cannot spread")
}
#[test]
fn spread_type_list() -> TestResult {
run_test(
r#"def f [a: list<int>] { $a | describe }; f [1 ...[]]"#,
"list<int>",
)
.unwrap();
run_test(
r#"def f [a: list<int>] { $a | describe }; f [1 ...[2]]"#,
"list<int>",
)
.unwrap();
fail_test(
r#"def f [a: list<int>] { }; f ["foo" ...[4 5 6]]"#,
"expected int",
)
.unwrap();
fail_test(
r#"def f [a: list<int>] { }; f [1 2 ...["misfit"] 4]"#,
"expected int",
)
}
#[test]
fn spread_in_record() -> TestResult {
run_test(r#"{...{...{...{}}}} | to nuon"#, "{}").unwrap();
run_test(
r#"{foo: bar ...{a: {x: 1}} b: 3} | to nuon"#,
"{foo: bar, a: {x: 1}, b: 3}",
)
}
#[test]
fn duplicate_cols() -> TestResult {
fail_test(r#"{a: 1, ...{a: 3}}"#, "column used twice").unwrap();
fail_test(r#"{...{a: 4, x: 3}, x: 1}"#, "column used twice").unwrap();
fail_test(r#"{...{a: 0, x: 2}, ...{x: 5}}"#, "column used twice")
}
#[test]
fn bad_spread_on_non_record() -> TestResult {
fail_test(r#"let x = 5; { ...$x }"#, "cannot spread").unwrap();
fail_test(r#"{...([1, 2])}"#, "cannot spread")
}
#[test]
fn spread_type_record() -> TestResult {
run_test(
r#"def f [a: record<x: int>] { $a.x }; f { ...{x: 0} }"#,
"0",
)
.unwrap();
fail_test(
r#"def f [a: record<x: int>] {}; f { ...{x: "not an int"} }"#,
"type_mismatch",
)
}
#[test]
fn spread_external_args() {
assert_eq!(
nu!(r#"nu --testbin cococo ...[1 "foo"] 2 ...[3 "bar"]"#).out,
"1 foo 2 3 bar",
);
// exec doesn't have rest parameters but allows unknown arguments
assert_eq!(
nu!(r#"exec nu --testbin cococo "foo" ...[5 6]"#).out,
"foo 5 6"
);
}
#[test]
fn spread_internal_args() -> TestResult {
run_test(
r#"
let list = ["foo" 4]
def f [a b c? d? ...x] { [$a $b $c $d $x] | to nuon }
f 1 2 ...[5 6] 7 ...$list"#,
"[1, 2, null, null, [5, 6, 7, foo, 4]]",
)
.unwrap();
run_test(
r#"
def f [a b c? d? ...x] { [$a $b $c $d $x] | to nuon }
f 1 2 3 ...[5 6]"#,
"[1, 2, 3, null, [5, 6]]",
)
.unwrap();
run_test(
r#"
def f [--flag: int ...x] { [$flag $x] | to nuon }
f 2 ...[foo] 4 --flag 5 6 ...[7 8]"#,
"[5, [2, foo, 4, 6, 7, 8]]",
)
.unwrap();
run_test(
r#"
def f [a b? --flag: int ...x] { [$a $b $flag $x] | to nuon }
f 1 ...[foo] 4 --flag 5 6 ...[7 8]"#,
"[1, null, 5, [foo, 4, 6, 7, 8]]",
)
}
#[test]
fn bad_spread_internal_args() -> TestResult {
fail_test(
r#"
def f [a b c? d? ...x] { echo $a $b $c $d $x }
f 1 ...[5 6]"#,
"Missing required positional argument",
)
.unwrap();
fail_test(
r#"
def f [a b?] { echo a b c d }
f ...[5 6]"#,
"unexpected spread argument",
)
}
#[test]
fn spread_non_list_args() {
fail_test(r#"echo ...(1)"#, "cannot spread value").unwrap();
assert!(nu!(r#"nu --testbin cococo ...(1)"#)
.err
.contains("cannot spread value"));
}
#[test]
fn spread_args_type() -> TestResult {
fail_test(r#"def f [...x: int] {}; f ...["abc"]"#, "expected int")
}
#[test]
fn explain_spread_args() -> TestResult {
run_test(
r#"(explain { || echo ...[1 2] }).cmd_args.0 | select arg_type name type | to nuon"#,
r#"[[arg_type, name, type]; [spread, "[1 2]", list<int>]]"#,
)
}
#[test]
fn disallow_implicit_spread_for_externals() -> TestResult {
fail_test(
r#"nu --testbin cococo [1 2]"#,
"Lists are not automatically spread",
)
}
#[test]
fn respect_shape() -> TestResult {
fail_test(
"def foo [...rest] { ...$rest }; foo bar baz",
"executable was not found",
)
.unwrap();
fail_test("module foo { ...$bar }", "expected_keyword").unwrap();
run_test(r#"def "...$foo" [] {2}; do { ...$foo }"#, "2").unwrap();
run_test(r#"match "...$foo" { ...$foo => 5 }"#, "5")
}

View File

@ -1,21 +0,0 @@
use crate::tests::{fail_test, run_test_std, TestResult};
#[test]
fn library_loaded() -> TestResult {
run_test_std("scope modules | where name == 'std' | length", "1")
}
#[test]
fn prelude_loaded() -> TestResult {
run_test_std("shells | length", "1")
}
#[test]
fn not_loaded() -> TestResult {
fail_test("log info", "")
}
#[test]
fn use_command() -> TestResult {
run_test_std("use std assert; assert true; print 'it works'", "it works")
}

View File

@ -1,159 +0,0 @@
use crate::tests::{fail_test, run_test, TestResult};
#[test]
fn cjk_in_substrings() -> TestResult {
run_test(
r#"let s = '[Rust 程序设计语言](title-page.md)'; let start = ($s | str index-of '('); let end = ($s | str index-of ')'); $s | str substring ($start + 1)..($end)"#,
"title-page.md",
)
}
#[test]
fn string_not_in_string() -> TestResult {
run_test(r#"'d' not-in 'abc'"#, "true")
}
#[test]
fn string_in_string() -> TestResult {
run_test(r#"'z' in 'abc'"#, "false")
}
#[test]
fn non_string_in_string() -> TestResult {
fail_test(r#"42 in 'abc'"#, "is not supported")
}
#[test]
fn string_in_record() -> TestResult {
run_test(r#""a" in ('{ "a": 13, "b": 14 }' | from json)"#, "true")
}
#[test]
fn non_string_in_record() -> TestResult {
fail_test(
r#"4 in ('{ "a": 13, "b": 14 }' | from json)"#,
"mismatch during operation",
)
}
#[test]
fn string_in_valuestream() -> TestResult {
run_test(
r#"
'Hello' in ("Hello
World" | lines)"#,
"true",
)
}
#[test]
fn single_tick_interpolation() -> TestResult {
run_test(r#"$'(3 + 4)'"#, "7")
}
#[test]
fn detect_newlines() -> TestResult {
run_test("'hello\r\nworld' | lines | get 0 | str length", "5")
}
#[test]
fn case_insensitive_sort() -> TestResult {
run_test(
r#"[a, B, d, C, f] | sort -i | to json --raw"#,
"[\"a\",\"B\",\"C\",\"d\",\"f\"]",
)
}
#[test]
fn case_insensitive_sort_columns() -> TestResult {
run_test(
r#"[[version, package]; ["two", "Abc"], ["three", "abc"], ["four", "abc"]] | sort-by -i package version | to json --raw"#,
r#"[{"version":"four","package":"abc"},{"version":"three","package":"abc"},{"version":"two","package":"Abc"}]"#,
)
}
#[test]
fn raw_string() -> TestResult {
run_test(r#"r#'abcde""fghi"''''jkl'#"#, r#"abcde""fghi"''''jkl"#)?;
run_test(r#"r##'abcde""fghi"''''#jkl'##"#, r#"abcde""fghi"''''#jkl"#)?;
run_test(
r#"r###'abcde""fghi"'''##'#jkl'###"#,
r#"abcde""fghi"'''##'#jkl"#,
)?;
run_test("r#''#", "")?;
run_test(
r#"r#'a string with sharp inside # and ends with #'#"#,
"a string with sharp inside # and ends with #",
)
}
#[test]
fn raw_string_inside_parentheses() -> TestResult {
let (left, right) = ('(', ')');
run_test(
&format!(r#"{left}r#'abcde""fghi"''''jkl'#{right}"#),
r#"abcde""fghi"''''jkl"#,
)?;
run_test(
&format!(r#"{left}r##'abcde""fghi"''''#jkl'##{right}"#),
r#"abcde""fghi"''''#jkl"#,
)?;
run_test(
&format!(r#"{left}r###'abcde""fghi"'''##'#jkl'###{right}"#),
r#"abcde""fghi"'''##'#jkl"#,
)?;
run_test(&format!("{left}r#''#{right}"), "")?;
run_test(
&format!(r#"{left}r#'a string with sharp inside # and ends with #'#{right}"#),
"a string with sharp inside # and ends with #",
)
}
#[test]
fn raw_string_inside_list() -> TestResult {
let (left, right) = ('[', ']');
run_test(
&format!(r#"{left}r#'abcde""fghi"''''jkl'#{right} | get 0"#),
r#"abcde""fghi"''''jkl"#,
)?;
run_test(
&format!(r#"{left}r##'abcde""fghi"''''#jkl'##{right} | get 0"#),
r#"abcde""fghi"''''#jkl"#,
)?;
run_test(
&format!(r#"{left}r###'abcde""fghi"'''##'#jkl'###{right} | get 0"#),
r#"abcde""fghi"'''##'#jkl"#,
)?;
run_test(&format!("{left}r#''#{right} | get 0"), "")?;
run_test(
&format!(r#"{left}r#'a string with sharp inside # and ends with #'#{right} | get 0"#),
"a string with sharp inside # and ends with #",
)
}
#[test]
fn raw_string_inside_closure() -> TestResult {
let (left, right) = ('{', '}');
run_test(
&format!(r#"do {left}r#'abcde""fghi"''''jkl'#{right}"#),
r#"abcde""fghi"''''jkl"#,
)?;
run_test(
&format!(r#"do {left}r##'abcde""fghi"''''#jkl'##{right}"#),
r#"abcde""fghi"''''#jkl"#,
)?;
run_test(
&format!(r#"do {left}r###'abcde""fghi"'''##'#jkl'###{right}"#),
r#"abcde""fghi"'''##'#jkl"#,
)?;
run_test(&format!("do {left}r#''#{right}"), "")?;
run_test(
&format!(r#"do {left}r#'a string with sharp inside # and ends with #'#{right}"#),
"a string with sharp inside # and ends with #",
)
}
#[test]
fn incomplete_raw_string() -> TestResult {
fail_test("r#abc", "expected '")
}

View File

@ -1,313 +0,0 @@
use crate::tests::{fail_test, run_test, TestResult};
#[test]
fn illegal_column_duplication() -> TestResult {
fail_test("[[lang, lang]; [nu, 100]]", "column_defined_twice")
}
#[test]
fn cell_path_subexpr1() -> TestResult {
run_test("([[lang, gems]; [nu, 100]]).lang | get 0", "nu")
}
#[test]
fn cell_path_subexpr2() -> TestResult {
run_test("([[lang, gems]; [nu, 100]]).lang.0", "nu")
}
#[test]
fn cell_path_var1() -> TestResult {
run_test("let x = [[lang, gems]; [nu, 100]]; $x.lang | get 0", "nu")
}
#[test]
fn cell_path_var2() -> TestResult {
run_test("let x = [[lang, gems]; [nu, 100]]; $x.lang.0", "nu")
}
#[test]
fn flatten_simple_list() -> TestResult {
run_test(
"[[N, u, s, h, e, l, l]] | flatten | str join (char nl)",
"N\nu\ns\nh\ne\nl\nl",
)
}
#[test]
fn flatten_get_simple_list() -> TestResult {
run_test("[[N, u, s, h, e, l, l]] | flatten | get 0", "N")
}
#[test]
fn flatten_table_get() -> TestResult {
run_test(
"[[origin, people]; [Ecuador, ([[name, meal]; ['Andres', 'arepa']])]] | flatten --all | get meal.0",
"arepa",
)
}
#[test]
fn flatten_table_column_get_last() -> TestResult {
run_test(
"[[origin, crate, versions]; [World, ([[name]; ['nu-cli']]), ['0.21', '0.22']]] | flatten versions --all | last | get versions",
"0.22",
)
}
#[test]
fn flatten_should_just_flatten_one_level() -> TestResult {
run_test(
"[[origin, crate, versions]; [World, ([[name]; ['nu-cli']]), ['0.21', '0.22']]] | flatten crate | get crate.name.0",
"nu-cli"
)
}
#[test]
fn flatten_nest_table_when_all_provided() -> TestResult {
run_test(
"[[origin, crate, versions]; [World, ([[name]; ['nu-cli']]), ['0.21', '0.22']]] | flatten crate --all | get name.0",
"nu-cli"
)
}
#[test]
fn get_table_columns_1() -> TestResult {
run_test(
"[[name, age, grade]; [paul,21,a]] | columns | first",
"name",
)
}
#[test]
fn get_table_columns_2() -> TestResult {
run_test("[[name, age, grade]; [paul,21,a]] | columns | get 1", "age")
}
#[test]
fn flatten_should_flatten_inner_table() -> TestResult {
run_test(
"[[[name, value]; [abc, 123]]] | flatten --all | get value.0",
"123",
)
}
#[test]
fn command_filter_reject_1() -> TestResult {
run_test(
"[[lang, gems]; [nu, 100]] | reject gems | to json",
r#"[
{
"lang": "nu"
}
]"#,
)
}
#[test]
fn command_filter_reject_2() -> TestResult {
run_test(
"[[lang, gems, grade]; [nu, 100, a]] | reject gems grade | to json",
r#"[
{
"lang": "nu"
}
]"#,
)
}
#[test]
fn command_filter_reject_3() -> TestResult {
run_test(
"[[lang, gems, grade]; [nu, 100, a]] | reject grade gems | to json",
r#"[
{
"lang": "nu"
}
]"#,
)
}
#[test]
#[rustfmt::skip]
fn command_filter_reject_4() -> TestResult {
run_test(
"[[lang, gems, grade]; [nu, 100, a]] | reject gems | to json -r",
r#"[{"lang":"nu","grade":"a"}]"#,
)
}
#[test]
fn command_drop_column_1() -> TestResult {
run_test(
"[[lang, gems, grade]; [nu, 100, a]] | drop column 2 | to json",
r#"[
{
"lang": "nu"
}
]"#,
)
}
#[test]
fn record_1() -> TestResult {
run_test(r#"{'a': 'b'} | get a"#, "b")
}
#[test]
fn record_2() -> TestResult {
run_test(r#"{'b': 'c'}.b"#, "c")
}
#[test]
fn where_on_ranges() -> TestResult {
run_test(r#"1..10 | where $it > 8 | math sum"#, "19")
}
#[test]
fn index_on_list() -> TestResult {
run_test(r#"[1, 2, 3].1"#, "2")
}
#[test]
fn update_cell_path_1() -> TestResult {
run_test(
r#"[[name, size]; [a, 1.1]] | into int size | get size.0"#,
"1",
)
}
#[test]
fn missing_column_errors() -> TestResult {
fail_test(
r#"[ { name: ABC, size: 20 }, { name: HIJ } ].size.1 == null"#,
"cannot find column",
)
}
#[test]
fn missing_optional_column_fills_in_nothing() -> TestResult {
// The empty value will be replaced with null because of the ?
run_test(
r#"[ { name: ABC, size: 20 }, { name: HIJ } ].size?.1 == null"#,
"true",
)
}
#[test]
fn missing_required_row_fails() -> TestResult {
// .3 will fail if there is no 3rd row
fail_test(
r#"[ { name: ABC, size: 20 }, { name: HIJ } ].3"#,
"", // we just care if it errors
)
}
#[test]
fn missing_optional_row_fills_in_nothing() -> TestResult {
// ?.3 will return null if there is no 3rd row
run_test(
r#"[ { name: ABC, size: 20 }, { name: HIJ } ].3? == null"#,
"true",
)
}
#[test]
fn string_cell_path() -> TestResult {
run_test(
r#"let x = "name"; [["name", "score"]; [a, b], [c, d]] | get $x | get 1"#,
"c",
)
}
#[test]
fn split_row() -> TestResult {
run_test(r#""hello world" | split row " " | get 1"#, "world")
}
#[test]
fn split_column() -> TestResult {
run_test(
r#""hello world" | split column " " | get "column1".0"#,
"hello",
)
}
#[test]
fn wrap() -> TestResult {
run_test(r#"([1, 2, 3] | wrap foo).foo.1"#, "2")
}
#[test]
fn get() -> TestResult {
run_test(
r#"[[name, grade]; [Alice, A], [Betty, B]] | get grade.1"#,
"B",
)
}
#[test]
fn select_1() -> TestResult {
run_test(
r#"([[name, age]; [a, 1], [b, 2]]) | select name | get 1 | get name"#,
"b",
)
}
#[test]
fn select_2() -> TestResult {
run_test(
r#"[[name, age]; [a, 1] [b, 2]] | get 1 | select age | get age"#,
"2",
)
}
#[test]
fn update_will_insert() -> TestResult {
run_test(r#"{} | upsert a b | get a"#, "b")
}
#[test]
fn length_for_columns() -> TestResult {
run_test(
r#"[[name,age,grade]; [bill,20,a] [a b c]] | columns | length"#,
"3",
)
}
#[test]
fn length_for_rows() -> TestResult {
run_test(r#"[[name,age,grade]; [bill,20,a] [a b c]] | length"#, "2")
}
#[test]
fn length_defaulted_columns() -> TestResult {
run_test(
r#"[[name, age]; [test, 10]] | default 11 age | get 0 | columns | length"#,
"2",
)
}
#[test]
fn nullify_errors() -> TestResult {
run_test("([{a:1} {a:2} {a:3}] | get foo? | length) == 3", "true")?;
run_test(
"([{a:1} {a:2} {a:3}] | get foo? | to nuon) == '[null, null, null]'",
"true",
)
}
#[test]
fn nullify_holes() -> TestResult {
run_test(
"([{a:1} {b:2} {a:3}] | get a? | to nuon) == '[1, null, 3]'",
"true",
)
}
#[test]
fn get_insensitive() -> TestResult {
run_test(
r#"[[name, age]; [a, 1] [b, 2]] | get NAmE | select 0 | get 0"#,
"a",
)
}

View File

@ -1,131 +0,0 @@
use crate::tests::{fail_test, run_test, TestResult};
#[test]
fn chained_operator_typecheck() -> TestResult {
run_test("1 != 2 and 3 != 4 and 5 != 6", "true")
}
#[test]
fn type_in_list_of_this_type() -> TestResult {
run_test(r#"42 in [41 42 43]"#, "true")
}
#[test]
fn type_in_list_of_non_this_type() -> TestResult {
fail_test(r#"'hello' in [41 42 43]"#, "is not supported")
}
#[test]
fn number_int() -> TestResult {
run_test(r#"def foo [x:number] { $x }; foo 1"#, "1")
}
#[test]
fn int_record_mismatch() -> TestResult {
fail_test(r#"def foo [x:int] { $x }; foo {}"#, "expected int")
}
#[test]
fn number_float() -> TestResult {
run_test(r#"def foo [x:number] { $x }; foo 1.4"#, "1.4")
}
#[test]
fn date_minus_duration() -> TestResult {
let input = "2023-04-22 - 2day | format date %Y-%m-%d";
let expected = "2023-04-20";
run_test(input, expected)
}
#[test]
fn date_plus_duration() -> TestResult {
let input = "2023-04-18 + 2day | format date %Y-%m-%d";
let expected = "2023-04-20";
run_test(input, expected)
}
#[test]
fn block_not_first_class_def() -> TestResult {
fail_test(
"def foo [x: block] { do $x }",
"Blocks are not support as first-class values",
)
}
#[test]
fn block_not_first_class_let() -> TestResult {
fail_test(
"let x: block = { 3 }",
"Blocks are not support as first-class values",
)
}
#[test]
fn record_subtyping() -> TestResult {
run_test(
"def test [rec: record<name: string, age: int>] { $rec | describe };
test { age: 4, name: 'John' }",
"record<age: int, name: string>",
)
}
#[test]
fn record_subtyping_2() -> TestResult {
run_test(
"def test [rec: record<name: string, age: int>] { $rec | describe };
test { age: 4, name: 'John', height: '5-9' }",
"record<age: int, name: string, height: string>",
)
}
#[test]
fn record_subtyping_3() -> TestResult {
fail_test(
"def test [rec: record<name: string, age: int>] { $rec | describe };
test { name: 'Nu' }",
"expected",
)
}
#[test]
fn record_subtyping_allows_general_record() -> TestResult {
run_test(
"def test []: record<name: string, age: int> -> string { $in; echo 'success' };
def underspecified []: nothing -> record {{name:'Douglas', age:42}};
underspecified | test",
"success",
)
}
#[test]
fn record_subtyping_allows_record_after_general_command() -> TestResult {
run_test(
"def test []: record<name: string, age: int> -> string { $in; echo 'success' };
{name:'Douglas', surname:'Adams', age:42} | select name age | test",
"success",
)
}
#[test]
fn record_subtyping_allows_general_inner() -> TestResult {
run_test(
"def merge_records [other: record<bar: int>]: record<foo: string> -> record<foo: string, bar: int> { merge $other }",
"",
)
}
#[test]
fn record_subtyping_works() -> TestResult {
run_test(
r#"def merge_records [other: record<bar: int>] { "" }; merge_records {"bar": 3, "foo": 4}"#,
"",
)
}
#[test]
fn transpose_into_load_env() -> TestResult {
run_test(
"[[col1, col2]; [a, 10], [b, 20]] | transpose --ignore-titles -r -d | load-env; $env.a",
"10",
)
}