From 6c958c34efeacb84a4802a290bd6b568cdd99a12 Mon Sep 17 00:00:00 2001 From: prsabahrami Date: Tue, 10 Sep 2024 10:33:14 -0400 Subject: [PATCH 1/6] Added tests on parser.rs --- crates/deno_task_shell/src/grammar.pest | 2 - crates/deno_task_shell/src/parser.rs | 368 +++++++++++++++++++++++- 2 files changed, 367 insertions(+), 3 deletions(-) diff --git a/crates/deno_task_shell/src/grammar.pest b/crates/deno_task_shell/src/grammar.pest index 8909557..c104886 100644 --- a/crates/deno_task_shell/src/grammar.pest +++ b/crates/deno_task_shell/src/grammar.pest @@ -85,8 +85,6 @@ DLESSDASH = { "<<-" } CLOBBER = { ">|" } AMPERSAND = { "&" } EXIT_STATUS = ${ "$?" } -TILDE = ${ "~" } - // Operators OPERATOR = _{ diff --git a/crates/deno_task_shell/src/parser.rs b/crates/deno_task_shell/src/parser.rs index 414b66a..07d8916 100644 --- a/crates/deno_task_shell/src/parser.rs +++ b/crates/deno_task_shell/src/parser.rs @@ -517,7 +517,7 @@ fn parse_shell_var(pair: Pair) -> Result { let value = inner .next() .ok_or_else(|| anyhow::anyhow!("Expected variable value"))?; - let value = parse_word(value)?; + let value = parse_assignment_value(value)?; Ok(Sequence::ShellVar(EnvVar { name, value })) } @@ -1046,7 +1046,373 @@ mod test { assert!(parse("echo \"foo\" > out.txt").is_ok()); } + #[test] + fn test_sequential_list() { + let parse_and_create = |input: &str| -> Result { + let pairs = ShellParser::parse(Rule::complete_command, input) + .map_err(|e| anyhow::Error::msg(e.to_string()))? + .next() + .unwrap(); + // println!("pairs: {:?}", pairs); + parse_complete_command(pairs) + }; + + // Test case 1 + let input = concat!( + "Name=Value OtherVar=Other command arg1 || command2 arg12 arg13 ; ", + "command3 && command4 & command5 ; export ENV6=5 ; ", + "ENV7=other && command8 || command9 ; ", + "cmd10 && (cmd11 || cmd12)" + ); + let result = parse_and_create(input).unwrap(); + let expected = SequentialList { + items: vec![ + SequentialListItem { + is_async: false, + sequence: Sequence::BooleanList(Box::new(BooleanList { + current: SimpleCommand { + env_vars: vec![ + EnvVar::new("Name".to_string(), Word::new_word("Value")), + EnvVar::new("OtherVar".to_string(), Word::new_word("Other")), + ], + args: vec![Word::new_word("command"), Word::new_word("arg1")], + } + .into(), + op: BooleanListOperator::Or, + next: SimpleCommand { + env_vars: vec![], + args: vec![ + Word::new_word("command2"), + Word::new_word("arg12"), + Word::new_word("arg13"), + ], + } + .into(), + })), + }, + SequentialListItem { + is_async: true, + sequence: Sequence::BooleanList(Box::new(BooleanList { + current: SimpleCommand { + env_vars: vec![], + args: vec![Word::new_word("command3")], + } + .into(), + op: BooleanListOperator::And, + next: SimpleCommand { + env_vars: vec![], + args: vec![Word::new_word("command4")], + } + .into(), + })), + }, + SequentialListItem { + is_async: false, + sequence: SimpleCommand { + env_vars: vec![], + args: vec![Word::new_word("command5")], + } + .into(), + }, + SequentialListItem { + is_async: false, + sequence: SimpleCommand { + env_vars: vec![], + args: vec![Word::new_word("export"), Word::new_word("ENV6=5")], + } + .into(), + }, + SequentialListItem { + is_async: false, + sequence: Sequence::BooleanList(Box::new(BooleanList { + current: Sequence::ShellVar(EnvVar::new( + "ENV7".to_string(), + Word::new_word("other"), + )), + op: BooleanListOperator::And, + next: Sequence::BooleanList(Box::new(BooleanList { + current: SimpleCommand { + env_vars: vec![], + args: vec![Word::new_word("command8")], + } + .into(), + op: BooleanListOperator::Or, + next: SimpleCommand { + env_vars: vec![], + args: vec![Word::new_word("command9")], + } + .into(), + })), + })), + }, + SequentialListItem { + is_async: false, + sequence: Sequence::BooleanList(Box::new(BooleanList { + current: SimpleCommand { + env_vars: vec![], + args: vec![Word::new_word("cmd10")], + } + .into(), + op: BooleanListOperator::And, + next: Command { + inner: CommandInner::Subshell(Box::new(SequentialList { + items: vec![SequentialListItem { + is_async: false, + sequence: Sequence::BooleanList(Box::new(BooleanList { + current: SimpleCommand { + env_vars: vec![], + args: vec![Word::new_word("cmd11")], + } + .into(), + op: BooleanListOperator::Or, + next: SimpleCommand { + env_vars: vec![], + args: vec![Word::new_word("cmd12")], + } + .into(), + })), + }], + })), + redirect: None, + } + .into(), + })), + }, + ], + }; + assert_eq!(result, expected); + + // Test case 2 + let input = "command1 ; command2 ; A='b' command3"; + let result = parse_and_create(input).unwrap(); + let expected = SequentialList { + items: vec![ + SequentialListItem { + is_async: false, + sequence: SimpleCommand { + env_vars: vec![], + args: vec![Word::new_word("command1")], + } + .into(), + }, + SequentialListItem { + is_async: false, + sequence: SimpleCommand { + env_vars: vec![], + args: vec![Word::new_word("command2")], + } + .into(), + }, + SequentialListItem { + is_async: false, + sequence: SimpleCommand { + env_vars: vec![EnvVar::new("A".to_string(), Word::new_string("b"))], + args: vec![Word::new_word("command3")], + } + .into(), + }, + ], + }; + assert_eq!(result, expected); + + // Test case 3 + let input = "test &&"; + assert!(parse_and_create(input).is_err()); + + // Test case 4 + let input = "command &"; + let result = parse_and_create(input).unwrap(); + let expected = SequentialList { + items: vec![SequentialListItem { + is_async: true, + sequence: SimpleCommand { + env_vars: vec![], + args: vec![Word::new_word("command")], + } + .into(), + }], + }; + assert_eq!(result, expected); + + // Test case 5 + let input = "test | other"; + let result = parse_and_create(input).unwrap(); + let expected = SequentialList { + items: vec![SequentialListItem { + is_async: false, + sequence: PipeSequence { + current: SimpleCommand { + env_vars: vec![], + args: vec![Word::new_word("test")], + } + .into(), + op: PipeSequenceOperator::Stdout, + next: SimpleCommand { + env_vars: vec![], + args: vec![Word::new_word("other")], + } + .into(), + } + .into(), + }], + }; + assert_eq!(result, expected); + + // Test case 6 + let input = "test |& other"; + let result = parse_and_create(input).unwrap(); + let expected = SequentialList { + items: vec![SequentialListItem { + is_async: false, + sequence: PipeSequence { + current: SimpleCommand { + env_vars: vec![], + args: vec![Word::new_word("test")], + } + .into(), + op: PipeSequenceOperator::StdoutStderr, + next: SimpleCommand { + env_vars: vec![], + args: vec![Word::new_word("other")], + } + .into(), + } + .into(), + }], + }; + assert_eq!(result, expected); + + // Test case 8 + let input = "echo $MY_ENV;"; + let result = parse_and_create(input).unwrap(); + let expected = SequentialList { + items: vec![SequentialListItem { + is_async: false, + sequence: SimpleCommand { + env_vars: vec![], + args: vec![ + Word::new_word("echo"), + Word(vec![WordPart::Variable("MY_ENV".to_string())]), + ], + } + .into(), + }], + }; + assert_eq!(result, expected); + + // Test case 9 + let input = "! cmd1 | cmd2 && cmd3"; + let result = parse_and_create(input).unwrap(); + let expected = SequentialList { + items: vec![SequentialListItem { + is_async: false, + sequence: Sequence::BooleanList(Box::new(BooleanList { + current: Pipeline { + negated: true, + inner: PipeSequence { + current: SimpleCommand { + args: vec![Word::new_word("cmd1")], + env_vars: vec![], + } + .into(), + op: PipeSequenceOperator::Stdout, + next: SimpleCommand { + args: vec![Word::new_word("cmd2")], + env_vars: vec![], + } + .into(), + } + .into(), + } + .into(), + op: BooleanListOperator::And, + next: SimpleCommand { + args: vec![Word::new_word("cmd3")], + env_vars: vec![], + } + .into(), + })), + }], + }; + assert_eq!(result, expected); + } + #[test] + fn test_env_var() { + let parse_and_create = |input: &str| -> Result { + let pairs = ShellParser::parse(Rule::ASSIGNMENT_WORD, input) + .map_err(|e| anyhow::anyhow!(e.to_string()))? + .next() + .unwrap(); + parse_env_var(pairs) + }; + + assert_eq!( + parse_and_create("Name=Value").unwrap(), + EnvVar { + name: "Name".to_string(), + value: Word::new_word("Value"), + } + ); + + assert_eq!( + parse_and_create("Name='quoted value'").unwrap(), + EnvVar { + name: "Name".to_string(), + value: Word::new_string("quoted value"), + } + ); + + assert_eq!( + parse_and_create("Name=\"double quoted value\"").unwrap(), + EnvVar { + name: "Name".to_string(), + value: Word::new_string("double quoted value"), + } + ); + + assert_eq!( + parse_and_create("Name=").unwrap(), + EnvVar { + name: "Name".to_string(), + value: Word(vec![]), + } + ); + + assert_eq!( + parse_and_create("Name=$(test)").unwrap(), + EnvVar { + name: "Name".to_string(), + value: Word(vec![WordPart::Command(SequentialList { + items: vec![SequentialListItem { + is_async: false, + sequence: SimpleCommand { + env_vars: vec![], + args: vec![Word::new_word("test")], + } + .into(), + }], + })]), + } + ); + + assert_eq!( + parse_and_create("Name=$(OTHER=5)").unwrap(), + EnvVar { + name: "Name".to_string(), + value: Word(vec![WordPart::Command(SequentialList { + items: vec![SequentialListItem { + is_async: false, + sequence: Sequence::ShellVar(EnvVar { + name: "OTHER".to_string(), + value: Word::new_word("5"), + }), + }], + })]), + } + ); + } + #[cfg(feature = "serialization")] #[test] fn serializes_command_to_json() { From 80867d2fd9b6c6b020fbd93209e8f23edc52d06a Mon Sep 17 00:00:00 2001 From: prsabahrami Date: Tue, 10 Sep 2024 10:58:16 -0400 Subject: [PATCH 2/6] Added tests on shell --- crates/deno_task_shell/src/grammar.pest | 2 +- crates/deno_task_shell/src/shell/test.rs | 113 ++++++++++++++++++ .../deno_task_shell/src/shell/test_builder.rs | 31 ++++- 3 files changed, 144 insertions(+), 2 deletions(-) diff --git a/crates/deno_task_shell/src/grammar.pest b/crates/deno_task_shell/src/grammar.pest index c104886..f9ed255 100644 --- a/crates/deno_task_shell/src/grammar.pest +++ b/crates/deno_task_shell/src/grammar.pest @@ -62,7 +62,7 @@ DOUBLE_QUOTED = @{ "\"" ~ QUOTED_PENDING_WORD ~ "\"" } SINGLE_QUOTED = @{ "'" ~ (!"'" ~ ANY)* ~ "'" } NAME = ${ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")* } -ASSIGNMENT_WORD = { NAME ~ "=" ~ ASSIGNMENT_VALUE? } +ASSIGNMENT_WORD = ${ NAME ~ "=" ~ ASSIGNMENT_VALUE? } ASSIGNMENT_VALUE = ${ ASSIGNMENT_TILDE_PREFIX ~ ((":" ~ ASSIGNMENT_TILDE_PREFIX) | (!":" ~ UNQUOTED_PENDING_WORD))* | diff --git a/crates/deno_task_shell/src/shell/test.rs b/crates/deno_task_shell/src/shell/test.rs index 43293d4..226e7b6 100644 --- a/crates/deno_task_shell/src/shell/test.rs +++ b/crates/deno_task_shell/src/shell/test.rs @@ -7,6 +7,119 @@ use super::types::ExecuteResult; const FOLDER_SEPARATOR: char = if cfg!(windows) { '\\' } else { '/' }; +#[tokio::test] +async fn commands() { + TestBuilder::new() + .command("echo 1") + .assert_stdout("1\n") + .run() + .await; + + TestBuilder::new() + .command("echo 1 2 3") + .assert_stdout("1 2 3\n") + .run() + .await; + + TestBuilder::new() + .command(r#"echo "1 2 3""#) + .assert_stdout("1 2 3\n") + .run() + .await; + + TestBuilder::new() + .command(r"echo 1 2\ \ \ 3") + .assert_stdout("1 2 3\n") + .run() + .await; + + TestBuilder::new() + .command(r#"echo "1 2\ \ \ 3""#) + .assert_stdout("1 2\\ \\ \\ 3\n") + .run() + .await; + + TestBuilder::new() + .command(r#"echo test$(echo "1 2")"#) + .assert_stdout("test1 2\n") + .run() + .await; + + TestBuilder::new() + .command(r#"TEST="1 2" ; echo $TEST"#) + .assert_stdout("1 2\n") + .run() + .await; + + TestBuilder::new() + .command( + r#"VAR=1 deno eval 'console.log(Deno.env.get("VAR"))' && echo $VAR"#, + ) + .assert_stdout("1\n\n") + .run() + .await; + + TestBuilder::new() + .command(r#"VAR=1 VAR2=2 deno eval 'console.log(Deno.env.get("VAR") + Deno.env.get("VAR2"))'"#) + .assert_stdout("12\n") + .run() + .await; + + TestBuilder::new() + .command( + r#"EMPTY= deno eval 'console.log(`EMPTY: ${Deno.env.get("EMPTY")}`)'"#, + ) + .assert_stdout("EMPTY: \n") + .run() + .await; + + TestBuilder::new() + .command(r#""echo" "1""#) + .assert_stdout("1\n") + .run() + .await; + + TestBuilder::new() + .command(r#""echo" "*""#) + .assert_stdout("*\n") + .run() + .await; + + TestBuilder::new() + .command("echo test-dashes") + .assert_stdout("test-dashes\n") + .run() + .await; + + TestBuilder::new() + .command("echo 'a/b'/c") + .assert_stdout("a/b/c\n") + .run() + .await; + + TestBuilder::new() + .command("echo 'a/b'ctest\"te st\"'asdf'") + .assert_stdout("a/bctestte stasdf\n") + .run() + .await; + + TestBuilder::new() + .command("echo --test=\"2\" --test='2' test\"TEST\" TEST'test'TEST 'test''test' test'test'\"test\" \"test\"\"test\"'test'") + .assert_stdout("--test=2 --test=2 testTEST TESTtestTEST testtest testtesttest testtesttest\n") + .run() + .await; + + TestBuilder::new() + .command("deno eval 'console.log(1)'") + .env_var("PATH", "") + .assert_stderr("deno: command not found\n") + .assert_exit_code(127) + .run() + .await; + + TestBuilder::new().command("unset").run().await; +} + #[tokio::test] async fn boolean_logic() { TestBuilder::new() diff --git a/crates/deno_task_shell/src/shell/test_builder.rs b/crates/deno_task_shell/src/shell/test_builder.rs index e3acb33..9dece43 100644 --- a/crates/deno_task_shell/src/shell/test_builder.rs +++ b/crates/deno_task_shell/src/shell/test_builder.rs @@ -1,5 +1,5 @@ // Copyright 2018-2024 the Deno authors. MIT license. - +use anyhow::Context; use futures::future::LocalBoxFuture; use pretty_assertions::assert_eq; use std::collections::HashMap; @@ -39,6 +39,7 @@ impl ShellCommand for FnShellCommand { enum TestAssertion { FileExists(String), FileNotExists(String), + FileTextEquals(String, String), } struct TempDir { @@ -132,6 +133,11 @@ impl TestBuilder { self } + pub fn env_var(&mut self, name: &str, value: &str) -> &mut Self { + self.env_vars.insert(name.to_string(), value.to_string()); + self + } + pub fn custom_command( &mut self, name: &str, @@ -143,6 +149,19 @@ impl TestBuilder { self } + pub fn assert_file_equals( + &mut self, + path: &str, + file_text: &str, + ) -> &mut Self { + self.ensure_temp_dir(); + self.assertions.push(TestAssertion::FileTextEquals( + path.to_string(), + file_text.to_string(), + )); + self + } + pub fn file(&mut self, path: &str, text: &str) -> &mut Self { let temp_dir = self.get_temp_dir(); fs::write(temp_dir.cwd.join(path), text).unwrap(); @@ -243,6 +262,16 @@ impl TestBuilder { path, ) } + TestAssertion::FileTextEquals(path, text) => { + let actual_text = std::fs::read_to_string(cwd.join(path)) + .with_context(|| format!("Error reading {path}")) + .unwrap(); + assert_eq!( + &actual_text, text, + "\n\nFailed for: {}\nPath: {}", + self.command, path, + ) + } } } } From 705a95d9d925448f58110fef7695de49649c54c1 Mon Sep 17 00:00:00 2001 From: prsabahrami Date: Tue, 10 Sep 2024 11:00:19 -0400 Subject: [PATCH 3/6] run fmt --- crates/deno_task_shell/src/parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/deno_task_shell/src/parser.rs b/crates/deno_task_shell/src/parser.rs index 07d8916..87c778f 100644 --- a/crates/deno_task_shell/src/parser.rs +++ b/crates/deno_task_shell/src/parser.rs @@ -1412,7 +1412,7 @@ mod test { } ); } - + #[cfg(feature = "serialization")] #[test] fn serializes_command_to_json() { From 851099573bf16d3f6291fb3c923e85f2702e4e0e Mon Sep 17 00:00:00 2001 From: prsabahrami Date: Tue, 10 Sep 2024 14:20:32 -0400 Subject: [PATCH 4/6] Fixes --- crates/deno_task_shell/src/shell/test.rs | 70 +++++++++++++++++++ .../deno_task_shell/src/shell/test_builder.rs | 26 +++---- 2 files changed, 83 insertions(+), 13 deletions(-) diff --git a/crates/deno_task_shell/src/shell/test.rs b/crates/deno_task_shell/src/shell/test.rs index 226e7b6..90eae50 100644 --- a/crates/deno_task_shell/src/shell/test.rs +++ b/crates/deno_task_shell/src/shell/test.rs @@ -236,6 +236,76 @@ async fn sequential_lists() { .run() .await; } +#[tokio::test] +async fn pipeline() { + TestBuilder::new() + .command(r#"echo 1 | deno eval 'await Deno.stdin.readable.pipeTo(Deno.stdout.writable)'"#) + .assert_stdout("1\n") + .run() + .await; + + TestBuilder::new() + .command(r#"echo 1 | echo 2 && echo 3"#) + .assert_stdout("2\n3\n") + .run() + .await; + + TestBuilder::new() + .command(r#"echo $(sleep 0.1 && echo 2 & echo 1) | deno eval 'await Deno.stdin.readable.pipeTo(Deno.stdout.writable)'"#) + .assert_stdout("1 2\n") + .run() + .await; + + TestBuilder::new() + .command(r#"echo 2 | echo 1 | deno eval 'await Deno.stdin.readable.pipeTo(Deno.stdout.writable)'"#) + .assert_stdout("1\n") + .run() + .await; + + TestBuilder::new() + .command(r#"deno eval 'console.log(1); console.error(2);' | deno eval 'await Deno.stdin.readable.pipeTo(Deno.stdout.writable)'"#) + .assert_stdout("1\n") + .assert_stderr("2\n") + .run() + .await; + + // stdout and stderr pipeline + + TestBuilder::new() + .command(r#"deno eval 'console.log(1); console.error(2);' |& deno eval 'await Deno.stdin.readable.pipeTo(Deno.stdout.writable)'"#) + .assert_stdout("1\n2\n") + .run() + .await; + + TestBuilder::new() + // add bit of a delay while outputting stdout so that it doesn't race with stderr + .command(r#"deno eval 'console.log(1); console.error(2);' | deno eval 'setTimeout(async () => { await Deno.stdin.readable.pipeTo(Deno.stderr.writable) }, 10)' |& deno eval 'await Deno.stdin.readable.pipeTo(Deno.stderr.writable)'"#) + // still outputs 2 because the first command didn't pipe stderr + .assert_stderr("2\n1\n") + .run() + .await; + + // |& pipeline should still pipe stdout + TestBuilder::new() + .command(r#"echo 1 |& deno eval 'await Deno.stdin.readable.pipeTo(Deno.stdout.writable)'"#) + .assert_stdout("1\n") + .run() + .await; + + // pipeline with redirect + TestBuilder::new() + .command(r#"echo 1 | deno eval 'await Deno.stdin.readable.pipeTo(Deno.stdout.writable)' > output.txt"#) + .assert_file_equals("output.txt", "1\n") + .run() + .await; + + // pipeline with stderr redirect + TestBuilder::new() + .command(r#"echo 1 | deno eval 'await Deno.stdin.readable.pipeTo(Deno.stderr.writable)' 2> output.txt"#) + .assert_file_equals("output.txt", "1\n") + .run() + .await; +} #[tokio::test] async fn redirects_input() { diff --git a/crates/deno_task_shell/src/shell/test_builder.rs b/crates/deno_task_shell/src/shell/test_builder.rs index 9dece43..387cc26 100644 --- a/crates/deno_task_shell/src/shell/test_builder.rs +++ b/crates/deno_task_shell/src/shell/test_builder.rs @@ -149,19 +149,6 @@ impl TestBuilder { self } - pub fn assert_file_equals( - &mut self, - path: &str, - file_text: &str, - ) -> &mut Self { - self.ensure_temp_dir(); - self.assertions.push(TestAssertion::FileTextEquals( - path.to_string(), - file_text.to_string(), - )); - self - } - pub fn file(&mut self, path: &str, text: &str) -> &mut Self { let temp_dir = self.get_temp_dir(); fs::write(temp_dir.cwd.join(path), text).unwrap(); @@ -199,6 +186,19 @@ impl TestBuilder { self } + pub fn assert_file_equals( + &mut self, + path: &str, + file_text: &str, + ) -> &mut Self { + self.ensure_temp_dir(); + self.assertions.push(TestAssertion::FileTextEquals( + path.to_string(), + file_text.to_string(), + )); + self + } + pub async fn run(&mut self) { let list = parse(&self.command).unwrap(); let cwd = if let Some(temp_dir) = &self.temp_dir { From 4a42c8501fe713e009566b5d2894a3937d0dc2a6 Mon Sep 17 00:00:00 2001 From: prsabahrami Date: Tue, 10 Sep 2024 17:49:52 -0400 Subject: [PATCH 5/6] Remove deno files --- crates/deno_task_shell/src/shell/test.rs | 100 +---------------------- 1 file changed, 1 insertion(+), 99 deletions(-) diff --git a/crates/deno_task_shell/src/shell/test.rs b/crates/deno_task_shell/src/shell/test.rs index 90eae50..c8605f3 100644 --- a/crates/deno_task_shell/src/shell/test.rs +++ b/crates/deno_task_shell/src/shell/test.rs @@ -51,28 +51,6 @@ async fn commands() { .run() .await; - TestBuilder::new() - .command( - r#"VAR=1 deno eval 'console.log(Deno.env.get("VAR"))' && echo $VAR"#, - ) - .assert_stdout("1\n\n") - .run() - .await; - - TestBuilder::new() - .command(r#"VAR=1 VAR2=2 deno eval 'console.log(Deno.env.get("VAR") + Deno.env.get("VAR2"))'"#) - .assert_stdout("12\n") - .run() - .await; - - TestBuilder::new() - .command( - r#"EMPTY= deno eval 'console.log(`EMPTY: ${Deno.env.get("EMPTY")}`)'"#, - ) - .assert_stdout("EMPTY: \n") - .run() - .await; - TestBuilder::new() .command(r#""echo" "1""#) .assert_stdout("1\n") @@ -109,14 +87,6 @@ async fn commands() { .run() .await; - TestBuilder::new() - .command("deno eval 'console.log(1)'") - .env_var("PATH", "") - .assert_stderr("deno: command not found\n") - .assert_exit_code(127) - .run() - .await; - TestBuilder::new().command("unset").run().await; } @@ -238,12 +208,6 @@ async fn sequential_lists() { } #[tokio::test] async fn pipeline() { - TestBuilder::new() - .command(r#"echo 1 | deno eval 'await Deno.stdin.readable.pipeTo(Deno.stdout.writable)'"#) - .assert_stdout("1\n") - .run() - .await; - TestBuilder::new() .command(r#"echo 1 | echo 2 && echo 3"#) .assert_stdout("2\n3\n") @@ -251,57 +215,8 @@ async fn pipeline() { .await; TestBuilder::new() - .command(r#"echo $(sleep 0.1 && echo 2 & echo 1) | deno eval 'await Deno.stdin.readable.pipeTo(Deno.stdout.writable)'"#) - .assert_stdout("1 2\n") - .run() - .await; - - TestBuilder::new() - .command(r#"echo 2 | echo 1 | deno eval 'await Deno.stdin.readable.pipeTo(Deno.stdout.writable)'"#) - .assert_stdout("1\n") - .run() - .await; - - TestBuilder::new() - .command(r#"deno eval 'console.log(1); console.error(2);' | deno eval 'await Deno.stdin.readable.pipeTo(Deno.stdout.writable)'"#) + .command(r#"echo 1 | tee output.txt"#) .assert_stdout("1\n") - .assert_stderr("2\n") - .run() - .await; - - // stdout and stderr pipeline - - TestBuilder::new() - .command(r#"deno eval 'console.log(1); console.error(2);' |& deno eval 'await Deno.stdin.readable.pipeTo(Deno.stdout.writable)'"#) - .assert_stdout("1\n2\n") - .run() - .await; - - TestBuilder::new() - // add bit of a delay while outputting stdout so that it doesn't race with stderr - .command(r#"deno eval 'console.log(1); console.error(2);' | deno eval 'setTimeout(async () => { await Deno.stdin.readable.pipeTo(Deno.stderr.writable) }, 10)' |& deno eval 'await Deno.stdin.readable.pipeTo(Deno.stderr.writable)'"#) - // still outputs 2 because the first command didn't pipe stderr - .assert_stderr("2\n1\n") - .run() - .await; - - // |& pipeline should still pipe stdout - TestBuilder::new() - .command(r#"echo 1 |& deno eval 'await Deno.stdin.readable.pipeTo(Deno.stdout.writable)'"#) - .assert_stdout("1\n") - .run() - .await; - - // pipeline with redirect - TestBuilder::new() - .command(r#"echo 1 | deno eval 'await Deno.stdin.readable.pipeTo(Deno.stdout.writable)' > output.txt"#) - .assert_file_equals("output.txt", "1\n") - .run() - .await; - - // pipeline with stderr redirect - TestBuilder::new() - .command(r#"echo 1 | deno eval 'await Deno.stdin.readable.pipeTo(Deno.stderr.writable)' 2> output.txt"#) .assert_file_equals("output.txt", "1\n") .run() .await; @@ -678,19 +593,6 @@ async fn rm() { #[tokio::test] async fn windows_resolve_command() { // not cross platform, but still allow this - TestBuilder::new() - .command("deno.exe eval 'console.log(1)'") - .assert_stdout("1\n") - .run() - .await; - - TestBuilder::new() - .command("deno eval 'console.log(1)'") - // handle trailing semi-colon - .env_var("PATHEXT", ".EXE;") - .assert_stdout("1\n") - .run() - .await; } #[tokio::test] From 8ec5549bf72ad0b1ba6dd528fb25f0c9f4eb1943 Mon Sep 17 00:00:00 2001 From: prsabahrami Date: Tue, 10 Sep 2024 17:53:27 -0400 Subject: [PATCH 6/6] Added test for env_var --- crates/deno_task_shell/src/shell/test.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/crates/deno_task_shell/src/shell/test.rs b/crates/deno_task_shell/src/shell/test.rs index c8605f3..1e639ed 100644 --- a/crates/deno_task_shell/src/shell/test.rs +++ b/crates/deno_task_shell/src/shell/test.rs @@ -87,6 +87,14 @@ async fn commands() { .run() .await; + TestBuilder::new() + .command("deno eval 'console.log(1)'") + .env_var("PATH", "") + .assert_stderr("deno: command not found\n") + .assert_exit_code(127) + .run() + .await; + TestBuilder::new().command("unset").run().await; }