Restore nu_with_plugins test macro (#6065)

* Updated nu_with_plugins to handle new nushell

- Now it requires the plugin format and name to be passed in, because
  we can't really guess the format
- It calls `register` with format and plugin path
- It creates a temporary folder and in it an empty temporary plugin.nu
  so that the tests don't conflict with each other or with local copy of
  plugin.nu
- Instead of passing the commands via stdin it passes them via the new
  --commands command line argument

* Rename path to command for clarity

* Enable core_inc tests

Remove deprecated inc feature and replace with new plugin feature

* Update core_inc tests for new nu_with_plugins syntax

* Rework core_inc::can_only_apply_one

The new inc plugin doesn't error if passed more than one but instead
chooses the highest increment

* Gate all plugin tests behind feature = "plugin" instead of one by one

* Remove format!-like behavior from nu_with_plugins

nu_with_plugins had format!-like behavior where it would allow calls
such as this:
```rs
nu_with_plugins!(
  cwd: "dir/",
  "open {} | get {}",
  "Cargo.toml",
  "package.version"
)
```
And although nifty it seems to have never been used before and the same
can be achieved with a format! like so:
```rs
nu_with_plugins!(
  cwd: "dir/",
  format!("open {} | get {}", "Cargo.toml", "package.version")
)
```
So I am removing it to keep the complexity of the macro in check

* Add multi-plugin support to nu_with_plugins

Useful for testing interactions between plugins

* Alternative 1: run `cargo build` inside of tests

* Handle Windows by canonicalizing paths and add .exe

One VM install later and lots of learning about how command line
arguments work and here we are
This commit is contained in:
Mathspy 2022-07-22 00:14:37 -04:00 committed by GitHub
parent 0646f1118c
commit c66b97126f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 111 additions and 47 deletions

View file

@ -51,3 +51,47 @@
// }
// }
// }
use std::{
io::Read,
process::{Command, Stdio},
};
pub fn ensure_binary_present(package: &str) {
let cargo_path = env!("CARGO");
let mut arguments = vec!["build", "--package", package, "--quiet"];
let profile = std::env::var("NUSHELL_CARGO_TARGET");
if let Ok(profile) = &profile {
arguments.push("--profile");
arguments.push(profile);
}
let mut command = Command::new(cargo_path)
.args(arguments)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.expect("Failed to spawn cargo build command");
let stderr = command.stderr.take();
let success = command
.wait()
.expect("failed to wait cargo build command")
.success();
if let Some(mut stderr) = stderr {
let mut buffer = String::new();
stderr
.read_to_string(&mut buffer)
.expect("failed to read cargo build stderr");
if !buffer.is_empty() {
println!("=== cargo build stderr\n{}", buffer);
}
}
if !success {
panic!("cargo build failed");
}
}

View file

@ -102,37 +102,38 @@ macro_rules! nu {
}};
}
#[macro_export]
macro_rules! with_exe {
($name:literal) => {{
#[cfg(windows)]
{
concat!($name, ".exe")
}
#[cfg(not(windows))]
{
$name
}
}};
}
#[macro_export]
macro_rules! nu_with_plugins {
(cwd: $cwd:expr, $path:expr, $($part:expr),*) => {{
use $crate::fs::DisplayPath;
let path = format!($path, $(
$part.display_path()
),*);
nu_with_plugins!($cwd, &path)
(cwd: $cwd:expr, plugins: [$(($format:expr, $plugin_name:expr)),+$(,)?], $command:expr) => {{
nu_with_plugins!($cwd, [$(($format, $plugin_name)),+], $command)
}};
(cwd: $cwd:expr, plugin: ($format:expr, $plugin_name:expr), $command:expr) => {{
nu_with_plugins!($cwd, [($format, $plugin_name)], $command)
}};
(cwd: $cwd:expr, $path:expr) => {{
nu_with_plugins!($cwd, $path)
}};
($cwd:expr, $path:expr) => {{
($cwd:expr, [$(($format:expr, $plugin_name:expr)),+$(,)?], $command:expr) => {{
pub use std::error::Error;
pub use std::io::prelude::*;
pub use std::process::{Command, Stdio};
pub use $crate::NATIVE_PATH_ENV_VAR;
let commands = &*format!(
"
{}
exit",
$crate::fs::DisplayPath::display_path(&$path)
);
pub use tempfile::tempdir;
pub use $crate::{NATIVE_PATH_ENV_VAR, with_exe};
let test_bins = $crate::fs::binaries();
let test_bins = nu_path::canonicalize(&test_bins).unwrap_or_else(|e| {
let test_bins = nu_path::canonicalize_with(&test_bins, ".").unwrap_or_else(|e| {
panic!(
"Couldn't canonicalize dummy binaries path {}: {:?}",
test_bins.display(),
@ -140,21 +141,33 @@ macro_rules! nu_with_plugins {
)
});
let mut paths = $crate::shell_os_paths();
paths.insert(0, test_bins);
let temp = tempdir().expect("couldn't create a temporary directory");
let temp_plugin_file = temp.path().join("plugin.nu");
std::fs::File::create(&temp_plugin_file).expect("couldn't create temporary plugin file");
let paths_joined = match std::env::join_paths(paths) {
Ok(all) => all,
Err(_) => panic!("Couldn't join paths for PATH var."),
};
$($crate::commands::ensure_binary_present($plugin_name);)+
let registrations = format!(
concat!($(concat!("register -e ", $format, " {};")),+),
$(
nu_path::canonicalize_with(with_exe!($plugin_name), &test_bins)
.unwrap_or_else(|e| {
panic!("failed to canonicalize plugin {} path", $plugin_name)
})
.display()
),+
);
let commands = format!("{registrations}{}", $command);
let target_cwd = $crate::fs::in_directory(&$cwd);
let mut process = match Command::new($crate::fs::executable_path())
.env("PWD", &target_cwd) // setting PWD is enough to set cwd
.env(NATIVE_PATH_ENV_VAR, paths_joined)
.current_dir(&target_cwd)
.env("PWD", &target_cwd) // setting PWD is enough to set cwd
.arg("--commands")
.arg(commands)
.arg("--plugin-config")
.arg(temp_plugin_file)
.stdout(Stdio::piped())
.stdin(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
{
@ -162,13 +175,6 @@ macro_rules! nu_with_plugins {
Err(why) => panic!("Can't run test {}", why.to_string()),
};
let stdin = process.stdin.as_mut().expect("couldn't open stdin");
stdin
.write_all(commands.as_bytes())
.expect("couldn't write to stdin");
stdin.flush()?
let output = process
.wait_with_output()
.expect("couldn't read from stdout/stderr");
@ -176,9 +182,9 @@ macro_rules! nu_with_plugins {
let out = $crate::macros::read_std(&output.stdout);
let err = String::from_utf8_lossy(&output.stderr);
println!("=== stderr\n{}", err);
println!("=== stderr\n{}", err);
$crate::Outcome::new(out,err.into_owned())
$crate::Outcome::new(out, err.into_owned())
}};
}

View file

@ -5,6 +5,7 @@ mod nu_repl;
mod overlays;
mod parsing;
mod path;
#[cfg(feature = "plugin")]
mod plugins;
mod scope;
mod shell;

View file

@ -3,15 +3,23 @@ use nu_test_support::nu_with_plugins;
use nu_test_support::playground::Playground;
#[test]
fn can_only_apply_one() {
fn chooses_highest_increment_if_given_more_than_one() {
let actual = nu_with_plugins!(
cwd: "tests/fixtures/formats",
"open cargo_sample.toml | first 1 | inc package.version --major --minor"
plugin: ("json", "nu_plugin_inc"),
"open cargo_sample.toml | first 1 | inc package.version --major --minor | get package.version"
);
assert!(actual
.err
.contains("Usage: inc field [--major|--minor|--patch]"));
assert_eq!(actual.out, "1.0.0");
let actual = nu_with_plugins!(
cwd: "tests/fixtures/formats",
plugin: ("json", "nu_plugin_inc"),
// Regardless of order of arguments
"open cargo_sample.toml | first 1 | inc package.version --minor --major | get package.version"
);
assert_eq!(actual.out, "1.0.0");
}
#[test]
@ -27,6 +35,7 @@ fn by_one_with_field_passed() {
let actual = nu_with_plugins!(
cwd: dirs.test(),
plugin: ("json", "nu_plugin_inc"),
"open sample.toml | inc package.edition | get package.edition"
);
@ -47,6 +56,7 @@ fn by_one_with_no_field_passed() {
let actual = nu_with_plugins!(
cwd: dirs.test(),
plugin: ("json", "nu_plugin_inc"),
"open sample.toml | get package.contributors | inc"
);
@ -67,6 +77,7 @@ fn semversion_major_inc() {
let actual = nu_with_plugins!(
cwd: dirs.test(),
plugin: ("json", "nu_plugin_inc"),
"open sample.toml | inc package.version -M | get package.version"
);
@ -87,6 +98,7 @@ fn semversion_minor_inc() {
let actual = nu_with_plugins!(
cwd: dirs.test(),
plugin: ("json", "nu_plugin_inc"),
"open sample.toml | inc package.version --minor | get package.version"
);
@ -107,6 +119,7 @@ fn semversion_patch_inc() {
let actual = nu_with_plugins!(
cwd: dirs.test(),
plugin: ("json", "nu_plugin_inc"),
"open sample.toml | inc package.version --patch | get package.version"
);
@ -127,6 +140,7 @@ fn semversion_without_passing_field() {
let actual = nu_with_plugins!(
cwd: dirs.test(),
plugin: ("json", "nu_plugin_inc"),
"open sample.toml | get package.version | inc --patch"
);

View file

@ -1,2 +1 @@
#[cfg(features = "inc")]
mod core_inc;