nu-command 0.112.2

Nushell's built-in commands
Documentation
use nu_test_support::{
    fs::Stub::{FileWithContent, FileWithContentToBeTrimmed},
    prelude::*,
};
use rstest::rstest;

#[test]
fn use_module_file_within_block() -> Result {
    Playground::setup("use_test_1", |dirs, playground| {
        let file = dirs.test().join("spam.nu");

        playground.with_files(&[FileWithContent(
            file.as_os_str().to_str().unwrap(),
            r#"
                export def foo [] {
                    echo "hello world"
                }
            "#,
        )]);

        let code = "
            def bar [] {
                use spam.nu foo;
                foo
            };
            bar
        ";

        test()
            .cwd(dirs.test())
            .run(code)
            .expect_value_eq("hello world")
    })
}

#[test]
fn use_keeps_doc_comments() -> Result {
    Playground::setup("use_doc_comments", |dirs, playground| {
        let file = dirs.test().join("spam.nu");

        playground.with_files(&[FileWithContent(
            file.as_os_str().to_str().unwrap(),
            r#"
                # this is my foo command
                export def foo [
                    x:string # this is an x parameter
                ] {
                    echo "hello world"
                }
            "#,
        )]);

        let code = "
            use spam.nu foo;
            help foo
        ";

        let output: String = test().cwd(dirs.test()).run(code)?;
        assert_contains("this is my foo command", &output);
        assert_contains("this is an x parameter", &output);
        Ok(())
    })
}

#[test]
fn use_eval_export_env() -> Result {
    Playground::setup("use_eval_export_env", |dirs, playground| {
        playground.with_files(&[FileWithContentToBeTrimmed(
            "spam.nu",
            "
                export-env { $env.FOO = 'foo' }
            ",
        )]);

        let mut tester = test().cwd(dirs.test());
        let () = tester.run("use spam.nu")?;
        tester.run("$env.FOO").expect_value_eq("foo")
    })
}

#[test]
fn use_eval_export_env_hide() -> Result {
    Playground::setup("use_eval_export_env", |dirs, playground| {
        playground.with_files(&[FileWithContentToBeTrimmed(
            "spam.nu",
            "
                export-env { hide-env FOO }
            ",
        )]);

        let mut tester = test().cwd(dirs.test());
        let () = tester.run("$env.FOO = 'foo'")?;
        let () = tester.run("use spam.nu")?;

        let err = tester.run("$env.FOO").expect_shell_error()?;
        match err {
            ShellError::CantFindColumn { col_name, .. } => {
                assert_eq!(col_name, "FOO");
                Ok(())
            }
            err => Err(err.into()),
        }
    })
}

#[test]
fn use_do_cd() -> Result {
    Playground::setup("use_do_cd", |dirs, playground| {
        playground
            .mkdir("test1/test2")
            .with_files(&[FileWithContentToBeTrimmed(
                "test1/test2/spam.nu",
                "
                    export-env { cd test1/test2 }
                ",
            )]);

        let mut tester = test().cwd(dirs.test());
        let () = tester.run("use test1/test2/spam.nu")?;
        tester
            .run("$env.PWD | path basename")
            .expect_value_eq("test2")
    })
}

#[test]
fn use_do_cd_file_relative() -> Result {
    Playground::setup("use_do_cd_file_relative", |dirs, playground| {
        playground
            .mkdir("test1/test2")
            .with_files(&[FileWithContentToBeTrimmed(
                "test1/test2/spam.nu",
                "
                    export-env { cd ($env.FILE_PWD | path join '..') }
                ",
            )]);

        let mut tester = test().cwd(dirs.test());
        let () = tester.run("use test1/test2/spam.nu")?;
        tester
            .run("$env.PWD | path basename")
            .expect_value_eq("test1")
    })
}

#[test]
fn use_dont_cd_overlay() -> Result {
    Playground::setup("use_dont_cd_overlay", |dirs, playground| {
        playground
            .mkdir("test1/test2")
            .with_files(&[FileWithContentToBeTrimmed(
                "test1/test2/spam.nu",
                "
                    export-env {
                        overlay new spam
                        cd test1/test2
                        overlay hide spam
                    }
                ",
            )]);

        let mut tester = test().cwd(dirs.test());
        let () = tester.run("use test1/test2/spam.nu")?;
        tester
            .run("$env.PWD | path basename")
            .expect_value_eq("use_dont_cd_overlay")
    })
}

#[test]
fn use_export_env_combined() -> Result {
    Playground::setup("use_is_scoped", |dirs, playground| {
        playground.with_files(&[FileWithContentToBeTrimmed(
            "spam.nu",
            "
                def foo [] { 'foo' }
                alias bar = foo
                export-env { $env.FOO = (bar) }
            ",
        )]);

        let mut tester = test().cwd(dirs.test());
        let () = tester.run("use spam.nu")?;
        tester.run("$env.FOO").expect_value_eq("foo")
    })
}

#[test]
fn use_module_creates_accurate_did_you_mean_1() -> Result {
    let code = r#"
        module spam {
            export def foo [] {
                "foo"
            }
        }
        
        use spam
        foo
    "#;

    let err = test().run(code).expect_shell_error()?;
    match err {
        ShellError::ExternalCommand { help, .. } => {
            assert_eq!(help, "Did you mean `spam foo`?");
            Ok(())
        }
        err => Err(err.into()),
    }
}

#[test]
fn use_module_creates_accurate_did_you_mean_2() -> Result {
    let code = r#"
        module spam {
            export def foo [] {
                "foo"
            }
        }
        
        foo
    "#;

    let err = test().run(code).expect_shell_error()?;
    match err {
        ShellError::ExternalCommand { help, .. } => {
            assert_contains("A command with that name exists in module `spam`.", help);
            Ok(())
        }
        err => Err(err.into()),
    }
}

#[rstest]
#[case("use spam")]
#[case("use spam main")]
#[case("use spam [ main ]")]
#[case("use spam *")]
fn use_main(#[case] use_module: &str) -> Result {
    let mut tester = test();
    let () = tester.run(r#"module spam { export def main [] { "spam" } }"#)?;
    let () = tester.run(use_module)?;
    tester.run("spam").expect_value_eq("spam")
}

#[test]
fn use_main_def_env() -> Result {
    let mut tester = test();
    let () = tester.run(r#"module spam { export def --env main [] { $env.SPAM = "spam" } }"#)?;
    let () = tester.run("use spam")?;
    let () = tester.run("spam")?;
    tester.run("$env.SPAM").expect_value_eq("spam")
}

#[test]
fn use_main_def_known_external() -> Result {
    let mut tester = test().inherit_rust_toolchain_env();
    let () = tester.run("module cargo { export extern main [] }")?;
    let () = tester.run("use cargo")?;
    let outcome: String = tester.run("cargo --version")?;
    assert_contains("cargo", outcome);
    Ok(())
}

#[test]
fn use_main_not_exported() -> Result {
    let mut tester = test();
    let () = tester.run(r#"module unique-module-name { def main [] { "hi" } }"#)?;
    let () = tester.run("use unique-module-name")?;
    let err = tester.run("unique-module-name").expect_shell_error()?;
    assert!(matches!(err, ShellError::ExternalCommand { .. }));
    Ok(())
}

#[test]
fn use_sub_subname_error_if_not_from_submodule() -> Result {
    let code = "
        module spam {
            export def foo [] {}
            export def bar [] {}
        }

        use spam foo bar
    ";

    let err = test().run(code).expect_parse_error()?;
    match err {
        ParseError::WrongImportPattern(msg, ..) => {
            assert_contains("try `use <module> [<name1>, <name2>]`", msg);
            Ok(())
        }
        err => Err(err.into()),
    }
}

#[test]
fn can_use_sub_subname_from_submodule() -> Result {
    let code = r#"
        module spam {
            export module foo {
                export def bar [] {
                    "bar"
                }
            }
        }

        use spam foo bar
        bar
    "#;

    test().run(code).expect_value_eq("bar")
}

#[test]
fn test_use_with_printing_file_pwd() -> Result {
    Playground::setup("use_with_printing_file_pwd", |dirs, playground| {
        let file = dirs.test().join("mod.nu");
        playground.with_files(&[FileWithContent(
            file.as_os_str().to_str().unwrap(),
            "
                export-env {
                    $env.CAPTURED_FILE_PWD = $env.FILE_PWD
                }
            ",
        )]);

        test()
            .cwd(dirs.test())
            .run("use .; $env.CAPTURED_FILE_PWD")
            .expect_value_eq(dirs.test().to_string_lossy())
    })
}

#[test]
fn test_use_with_printing_current_file() -> Result {
    Playground::setup("use_with_printing_current_file", |dirs, playground| {
        let file = dirs.test().join("mod.nu");
        playground.with_files(&[FileWithContent(
            file.as_os_str().to_str().unwrap(),
            "
                export-env {
                    $env.CAPTURED_CURRENT_FILE = $env.CURRENT_FILE
                }
            ",
        )]);

        test()
            .cwd(dirs.test())
            .run("use .; $env.CAPTURED_CURRENT_FILE")
            .expect_value_eq(dirs.test().join("mod.nu").to_string_lossy())
    })
}

#[test]
fn report_errors_in_export_env() -> Result {
    let code = r#"
        module spam {
            export-env { error make -u {msg: "reported"} }
        }
        
        use spam
    "#;

    let err = test().run(code).expect_shell_error()?;
    assert_contains("reported", err.to_string());
    Ok(())
}