use expect_test::{expect, Expect}; use oyster_parser::ast; use oyster_runtime::Shell; use crate::collect_output; // TODO: test signal return codes fn check(ast: &ast::Code, expect: Expect) { let actual = collect_output(|| { let mut shell = Shell::new().unwrap(); shell.run(ast).unwrap(); }); expect.assert_debug_eq(&actual); } #[test] fn simple_command() { let ast = { use oyster_parser::ast::*; Code(vec![Statement::Pipeline(Pipeline(vec![Command( vec![ Word(vec![WordPart::Text("echo")]), Word(vec![WordPart::Text("hi")]), ], Redirect::None, )]))]) }; check( &ast, expect![[r#" "hi\r\n" "#]], ); } #[test] fn pipeline() { let ast = { use oyster_parser::ast::*; Code(vec![Statement::Pipeline(Pipeline(vec![ Command( vec![ Word(vec![WordPart::Text("echo")]), Word(vec![WordPart::Text("hi")]), ], Redirect::Stdout, ), Command( vec![ Word(vec![WordPart::Text("wc")]), Word(vec![WordPart::Text("-c")]), ], Redirect::None, ), ]))]) }; check( &ast, expect![[r#" "3\r\n" "#]], ); } #[test] fn command_not_found() { let ast = { use oyster_parser::ast::*; Code(vec![Statement::Pipeline(Pipeline(vec![Command( vec![Word(vec![WordPart::Text("this_command_doesnt_exist")])], Redirect::None, )]))]) }; // XXX: this relies on the command actually not existing, as unsetting PATH is rather complex let mut shell = Shell::new().unwrap(); let actual = shell.run(&ast); let expect = expect![[r#" Err( CommandNotFound( "this_command_doesnt_exist", ), ) "#]]; expect.assert_debug_eq(&actual); } #[test] fn permission_denied() { let ast = { use oyster_parser::ast::*; Code(vec![Statement::Pipeline(Pipeline(vec![Command( vec![Word(vec![WordPart::Text("/")])], Redirect::None, )]))]) }; let mut shell = Shell::new().unwrap(); let actual = shell.run(&ast); let expect = expect![[r#" Err( PermissionDenied( "/", ), ) "#]]; expect.assert_debug_eq(&actual); } #[test] fn multipart_word() { let ast = { use oyster_parser::ast::*; Code(vec![Statement::Pipeline(Pipeline(vec![Command( vec![ Word(vec![WordPart::Text("ec"), WordPart::Text("ho")]), Word(vec![WordPart::Text("hel"), WordPart::Text("lo")]), ], Redirect::None, )]))]) }; check( &ast, expect![[r#" "hello\r\n" "#]], ); } #[test] fn command_substitution() { let ast = { use oyster_parser::ast::*; Code(vec![Statement::Pipeline(Pipeline(vec![Command( vec![ Word(vec![WordPart::Text("echo")]), Word(vec![WordPart::CommandSubstitution(Code(vec![ Statement::Pipeline(Pipeline(vec![Command( vec![ Word(vec![WordPart::Text("echo")]), Word(vec![WordPart::Text("hello")]), ], Redirect::None, )])), ]))]), ], Redirect::None, )]))]) }; check( &ast, expect![[r#" "hello\r\n" "#]], ); }