// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. use std::fs::File; use std::process::Command; use test_util as util; use test_util::TempDir; use util::assert_contains; use util::env_vars_for_npm_tests; use util::TestContextBuilder; #[test] fn compile() { let dir = TempDir::new(); let exe = if cfg!(windows) { dir.path().join("welcome.exe") } else { dir.path().join("welcome") }; // try this twice to ensure it works with the cache for _ in 0..2 { let output = util::deno_cmd_with_deno_dir(&dir) .current_dir(util::root_path()) .arg("compile") .arg("--unstable") .arg("--output") .arg(&exe) .arg("./test_util/std/examples/welcome.ts") .stdout(std::process::Stdio::piped()) .spawn() .unwrap() .wait_with_output() .unwrap(); assert!(output.status.success()); let output = Command::new(&exe) .stdout(std::process::Stdio::piped()) .spawn() .unwrap() .wait_with_output() .unwrap(); assert!(output.status.success()); assert_eq!(output.stdout, "Welcome to Deno!\n".as_bytes()); } } #[test] fn standalone_args() { let dir = TempDir::new(); let exe = if cfg!(windows) { dir.path().join("args.exe") } else { dir.path().join("args") }; let output = util::deno_cmd() .current_dir(util::testdata_path()) .arg("compile") .arg("--unstable") .arg("--output") .arg(&exe) .arg("./compile/args.ts") .arg("a") .arg("b") .stdout(std::process::Stdio::piped()) .spawn() .unwrap() .wait_with_output() .unwrap(); assert!(output.status.success()); let output = Command::new(exe) .arg("foo") .arg("--bar") .arg("--unstable") .stdout(std::process::Stdio::piped()) .spawn() .unwrap() .wait_with_output() .unwrap(); assert!(output.status.success()); assert_eq!(output.stdout, b"a\nb\nfoo\n--bar\n--unstable\n"); } #[test] fn standalone_error() { let dir = TempDir::new(); let exe = if cfg!(windows) { dir.path().join("error.exe") } else { dir.path().join("error") }; let testdata_path = util::testdata_path(); let output = util::deno_cmd() .current_dir(&testdata_path) .arg("compile") .arg("--unstable") .arg("--output") .arg(&exe) .arg("./compile/standalone_error.ts") .stdout(std::process::Stdio::piped()) .spawn() .unwrap() .wait_with_output() .unwrap(); assert!(output.status.success()); let output = Command::new(exe) .env("NO_COLOR", "1") .stdout(std::process::Stdio::piped()) .stderr(std::process::Stdio::piped()) .spawn() .unwrap() .wait_with_output() .unwrap(); assert!(!output.status.success()); assert_eq!(output.stdout, b""); let stderr = String::from_utf8(output.stderr).unwrap(); let stderr = util::strip_ansi_codes(&stderr).to_string(); // On Windows, we cannot assert the file path (because '\'). // Instead we just check for relevant output. assert_contains!(stderr, "error: Uncaught Error: boom!"); assert_contains!(stderr, "throw new Error(\"boom!\");"); assert_contains!(stderr, "\n at boom (file://"); assert_contains!(stderr, "standalone_error.ts:2:11"); assert_contains!(stderr, "at foo (file://"); assert_contains!(stderr, "standalone_error.ts:5:5"); assert_contains!(stderr, "standalone_error.ts:7:1"); } #[test] fn standalone_error_module_with_imports() { let dir = TempDir::new(); let exe = if cfg!(windows) { dir.path().join("error.exe") } else { dir.path().join("error") }; let testdata_path = util::testdata_path(); let output = util::deno_cmd() .current_dir(&testdata_path) .arg("compile") .arg("--unstable") .arg("--output") .arg(&exe) .arg("./compile/standalone_error_module_with_imports_1.ts") .stdout(std::process::Stdio::piped()) .spawn() .unwrap() .wait_with_output() .unwrap(); assert!(output.status.success()); let output = Command::new(exe) .env("NO_COLOR", "1") .stdout(std::process::Stdio::piped()) .stderr(std::process::Stdio::piped()) .spawn() .unwrap() .wait_with_output() .unwrap(); assert!(!output.status.success()); assert_eq!(output.stdout, b"hello\n"); let stderr = String::from_utf8(output.stderr).unwrap(); let stderr = util::strip_ansi_codes(&stderr).to_string(); // On Windows, we cannot assert the file path (because '\'). // Instead we just check for relevant output. assert_contains!(stderr, "error: Uncaught Error: boom!"); assert_contains!(stderr, "throw new Error(\"boom!\");"); assert_contains!(stderr, "\n at file://"); assert_contains!(stderr, "standalone_error_module_with_imports_2.ts:2:7"); } #[test] fn standalone_load_datauri() { let dir = TempDir::new(); let exe = if cfg!(windows) { dir.path().join("load_datauri.exe") } else { dir.path().join("load_datauri") }; let output = util::deno_cmd() .current_dir(util::testdata_path()) .arg("compile") .arg("--unstable") .arg("--output") .arg(&exe) .arg("./compile/standalone_import_datauri.ts") .stdout(std::process::Stdio::piped()) .spawn() .unwrap() .wait_with_output() .unwrap(); assert!(output.status.success()); let output = Command::new(exe) .stdout(std::process::Stdio::piped()) .stderr(std::process::Stdio::piped()) .spawn() .unwrap() .wait_with_output() .unwrap(); assert!(output.status.success()); assert_eq!(output.stdout, b"Hello Deno!\n"); } // https://github.com/denoland/deno/issues/13704 #[test] fn standalone_follow_redirects() { let dir = TempDir::new(); let exe = if cfg!(windows) { dir.path().join("follow_redirects.exe") } else { dir.path().join("follow_redirects") }; let output = util::deno_cmd() .current_dir(util::testdata_path()) .arg("compile") .arg("--unstable") .arg("--output") .arg(&exe) .arg("./compile/standalone_follow_redirects.ts") .stdout(std::process::Stdio::piped()) .spawn() .unwrap() .wait_with_output() .unwrap(); assert!(output.status.success()); let output = Command::new(exe) .stdout(std::process::Stdio::piped()) .stderr(std::process::Stdio::piped()) .spawn() .unwrap() .wait_with_output() .unwrap(); assert!(output.status.success()); assert_eq!(output.stdout, b"Hello\n"); } #[test] fn compile_with_file_exists_error() { let dir = TempDir::new(); let output_path = if cfg!(windows) { dir.path().join(r"args\") } else { dir.path().join("args/") }; let file_path = dir.path().join("args"); File::create(&file_path).unwrap(); let output = util::deno_cmd() .current_dir(util::testdata_path()) .arg("compile") .arg("--unstable") .arg("--output") .arg(&output_path) .arg("./compile/args.ts") .stderr(std::process::Stdio::piped()) .spawn() .unwrap() .wait_with_output() .unwrap(); assert!(!output.status.success()); let expected_stderr = format!( concat!( "Could not compile to file '{}' because its parent directory ", "is an existing file. You can use the `--output ` flag to ", "provide an alternative name.\n", ), file_path.display(), ); let stderr = String::from_utf8(output.stderr).unwrap(); assert_contains!(stderr, &expected_stderr); } #[test] fn compile_with_directory_exists_error() { let dir = TempDir::new(); let exe = if cfg!(windows) { dir.path().join("args.exe") } else { dir.path().join("args") }; std::fs::create_dir(&exe).unwrap(); let output = util::deno_cmd() .current_dir(util::testdata_path()) .arg("compile") .arg("--unstable") .arg("--output") .arg(&exe) .arg("./compile/args.ts") .stderr(std::process::Stdio::piped()) .spawn() .unwrap() .wait_with_output() .unwrap(); assert!(!output.status.success()); let expected_stderr = format!( concat!( "Could not compile to file '{}' because a directory exists with ", "the same name. You can use the `--output ` flag to ", "provide an alternative name." ), exe.display() ); let stderr = String::from_utf8(output.stderr).unwrap(); assert_contains!(stderr, &expected_stderr); } #[test] fn compile_with_conflict_file_exists_error() { let dir = TempDir::new(); let exe = if cfg!(windows) { dir.path().join("args.exe") } else { dir.path().join("args") }; std::fs::write(&exe, b"SHOULD NOT BE OVERWRITTEN").unwrap(); let output = util::deno_cmd() .current_dir(util::testdata_path()) .arg("compile") .arg("--unstable") .arg("--output") .arg(&exe) .arg("./compile/args.ts") .stderr(std::process::Stdio::piped()) .spawn() .unwrap() .wait_with_output() .unwrap(); assert!(!output.status.success()); let expected_stderr = format!( concat!( "Could not compile to file '{}' because the file already exists ", "and cannot be overwritten. Please delete the existing file or ", "use the `--output { input_specifier: &'a str, output_file: &'a str, node_modules_dir: bool, input_name: Option<&'a str>, expected_name: &'a str, run_args: Vec<&'a str>, } fn run_npm_bin_compile_test(opts: RunNpmBinCompileOptions) { let context = TestContextBuilder::for_npm() .use_sync_npm_download() .use_temp_cwd() .build(); let temp_dir = context.temp_dir(); let testdata_path = context.testdata_path(); let main_specifier = if opts.input_specifier.starts_with("npm:") { opts.input_specifier.to_string() } else { testdata_path .join(opts.input_specifier) .to_string_lossy() .to_string() }; let mut args = vec![ "compile".to_string(), "-A".to_string(), "--unstable".to_string(), ]; if opts.node_modules_dir { args.push("--node-modules-dir".to_string()); } if let Some(bin_name) = opts.input_name { args.push("--output".to_string()); args.push(bin_name.to_string()); } args.push(main_specifier); // compile let output = context.new_command().args_vec(args).run(); output.assert_exit_code(0); output.skip_output_check(); // run let binary_path = if cfg!(windows) { temp_dir.path().join(format!("{}.exe", opts.expected_name)) } else { temp_dir.path().join(opts.expected_name) }; let output = context .new_command() .command_name(binary_path.to_string_lossy()) .args_vec(opts.run_args) .run(); output.assert_matches_file(opts.output_file); }