nushell/crates/nu-command/tests/commands/let_.rs
Wind 58c6fea60b
Support redirect stderr and stdout+stderr with a pipe (#11708)
# Description
Close: #9673
Close: #8277
Close: #10944

This pr introduces the following syntax:
1. `e>|`, pipe stderr to next command. Example: `$env.FOO=bar nu
--testbin echo_env_stderr FOO e>| str length`
2. `o+e>|` and `e+o>|`, pipe both stdout and stderr to next command,
example: `$env.FOO=bar nu --testbin echo_env_mixed out-err FOO FOO e+o>|
str length`

Note: it only works for external commands. ~There is no different for
internal commands, that is, the following three commands do the same
things:~ Edit: it raises errors if we want to pipes for internal
commands
``` 
❯ ls e>| str length
Error:   × `e>|` only works with external streams
   ╭─[entry #1:1:1]
 1 │ ls e>| str length
   ·    ─┬─
   ·     ╰── `e>|` only works on external streams
   ╰────

❯ ls e+o>| str length
Error:   × `o+e>|` only works with external streams
   ╭─[entry #2:1:1]
 1 │ ls e+o>| str length
   ·    ──┬──
   ·      ╰── `o+e>|` only works on external streams
   ╰────
```

This can help us to avoid some strange issues like the following:

`$env.FOO=bar (nu --testbin echo_env_stderr FOO) e>| str length`

Which is hard to understand and hard to explain to users.

# User-Facing Changes
Nan

# Tests + Formatting
To be done

# After Submitting
Maybe update documentation about these syntax.
2024-02-09 01:30:46 +08:00

92 lines
2.1 KiB
Rust

use nu_test_support::nu;
#[test]
fn let_name_builtin_var() {
let actual = nu!("let in = 3");
assert!(actual
.err
.contains("'in' is the name of a builtin Nushell variable"));
}
#[test]
fn let_doesnt_mutate() {
let actual = nu!("let i = 3; $i = 4");
assert!(actual.err.contains("immutable"));
}
#[test]
fn let_takes_pipeline() {
let actual = nu!(r#"let x = "hello world" | str length; print $x"#);
assert_eq!(actual.out, "11");
}
#[test]
fn let_pipeline_allows_in() {
let actual =
nu!(r#"def foo [] { let x = $in | str length; print ($x + 10) }; "hello world" | foo"#);
assert_eq!(actual.out, "21");
}
#[test]
fn mut_takes_pipeline() {
let actual = nu!(r#"mut x = "hello world" | str length; print $x"#);
assert_eq!(actual.out, "11");
}
#[test]
fn mut_pipeline_allows_in() {
let actual =
nu!(r#"def foo [] { mut x = $in | str length; print ($x + 10) }; "hello world" | foo"#);
assert_eq!(actual.out, "21");
}
#[test]
fn let_pipeline_redirects_internals() {
let actual = nu!(r#"let x = echo 'bar'; $x | str length"#);
assert_eq!(actual.out, "3");
}
#[test]
fn let_pipeline_redirects_externals() {
let actual = nu!(r#"let x = nu --testbin cococo 'bar'; $x | str length"#);
assert_eq!(actual.out, "3");
}
#[test]
fn let_err_pipeline_redirects_externals() {
let actual = nu!(
r#"let x = with-env [FOO "foo"] {nu --testbin echo_env_stderr FOO e>| str length}; $x"#
);
// have an extra \n, so length is 4.
assert_eq!(actual.out, "4");
}
#[test]
fn let_outerr_pipeline_redirects_externals() {
let actual = nu!(
r#"let x = with-env [FOO "foo"] {nu --testbin echo_env_stderr FOO o+e>| str length}; $x"#
);
// have an extra \n, so length is 4.
assert_eq!(actual.out, "4");
}
#[ignore]
#[test]
fn let_with_external_failed() {
// FIXME: this test hasn't run successfully for a long time. We should
// bring it back to life at some point.
let actual = nu!(r#"let x = nu --testbin outcome_err "aa"; echo fail"#);
assert!(!actual.out.contains("fail"));
}