forked from extern/nushell
Groundwork for coverage with Nu internals. (#1205)
This commit is contained in:
parent
5fd3191d91
commit
d3dae05714
@ -42,16 +42,16 @@ steps:
|
|||||||
echo "##vso[task.prependpath]$HOME/.cargo/bin"
|
echo "##vso[task.prependpath]$HOME/.cargo/bin"
|
||||||
rustup component add rustfmt --toolchain "stable"
|
rustup component add rustfmt --toolchain "stable"
|
||||||
displayName: Install Rust
|
displayName: Install Rust
|
||||||
- bash: RUSTFLAGS="-D warnings" cargo test --all --features=stable
|
- bash: RUSTFLAGS="-D warnings" cargo test --all --features=stable,nu-dummies
|
||||||
condition: eq(variables['style'], 'unflagged')
|
condition: eq(variables['style'], 'unflagged')
|
||||||
displayName: Run tests
|
displayName: Run tests
|
||||||
- bash: RUSTFLAGS="-D warnings" cargo clippy --all --features=stable -- -D clippy::result_unwrap_used -D clippy::option_unwrap_used
|
- bash: RUSTFLAGS="-D warnings" cargo clippy --all --features=stable,nu-dummies -- -D clippy::result_unwrap_used -D clippy::option_unwrap_used
|
||||||
condition: eq(variables['style'], 'unflagged')
|
condition: eq(variables['style'], 'unflagged')
|
||||||
displayName: Check clippy lints
|
displayName: Check clippy lints
|
||||||
- bash: NUSHELL_ENABLE_ALL_FLAGS=1 RUSTFLAGS="-D warnings" cargo test --all --features=stable
|
- bash: NUSHELL_ENABLE_ALL_FLAGS=1 RUSTFLAGS="-D warnings" cargo test --all --features=stable,nu-dummies
|
||||||
condition: eq(variables['style'], 'canary')
|
condition: eq(variables['style'], 'canary')
|
||||||
displayName: Run tests
|
displayName: Run tests
|
||||||
- bash: NUSHELL_ENABLE_ALL_FLAGS=1 RUSTFLAGS="-D warnings" cargo clippy --all --features=stable -- -D clippy::result_unwrap_used -D clippy::option_unwrap_used
|
- bash: NUSHELL_ENABLE_ALL_FLAGS=1 RUSTFLAGS="-D warnings" cargo clippy --all --features=stable,nu-dummies -- -D clippy::result_unwrap_used -D clippy::option_unwrap_used
|
||||||
condition: eq(variables['style'], 'canary')
|
condition: eq(variables['style'], 'canary')
|
||||||
displayName: Check clippy lints
|
displayName: Check clippy lints
|
||||||
- bash: cargo fmt --all -- --check
|
- bash: cargo fmt --all -- --check
|
||||||
|
17
Cargo.toml
17
Cargo.toml
@ -142,6 +142,8 @@ users = "0.9"
|
|||||||
default = ["sys", "ps", "textview", "inc", "str"]
|
default = ["sys", "ps", "textview", "inc", "str"]
|
||||||
stable = ["sys", "ps", "textview", "inc", "str", "starship-prompt", "binaryview", "match", "tree", "average", "sum", "post", "fetch", "clipboard"]
|
stable = ["sys", "ps", "textview", "inc", "str", "starship-prompt", "binaryview", "match", "tree", "average", "sum", "post", "fetch", "clipboard"]
|
||||||
|
|
||||||
|
nu-dummies = []
|
||||||
|
|
||||||
# Default
|
# Default
|
||||||
sys = ["heim", "battery"]
|
sys = ["heim", "battery"]
|
||||||
ps = ["heim", "futures-timer"]
|
ps = ["heim", "futures-timer"]
|
||||||
@ -178,6 +180,21 @@ name = "nu"
|
|||||||
doctest = false
|
doctest = false
|
||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "fail"
|
||||||
|
path = "crates/nu-test-support/src/bin/fail.rs"
|
||||||
|
required-features = ["nu-dummies"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "chop"
|
||||||
|
path = "crates/nu-test-support/src/bin/chop.rs"
|
||||||
|
required-features = ["nu-dummies"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "cococo"
|
||||||
|
path = "crates/nu-test-support/src/bin/cococo.rs"
|
||||||
|
required-features = ["nu-dummies"]
|
||||||
|
|
||||||
# Core plugins that ship with `cargo install nu` by default
|
# Core plugins that ship with `cargo install nu` by default
|
||||||
# Currently, Cargo limits us to installing only one binary
|
# Currently, Cargo limits us to installing only one binary
|
||||||
# unless we use [[bin]], so we use this as a workaround
|
# unless we use [[bin]], so we use this as a workaround
|
||||||
|
22
crates/nu-test-support/src/bin/chop.rs
Normal file
22
crates/nu-test-support/src/bin/chop.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
use std::io::{self, BufRead};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let stdin = io::stdin();
|
||||||
|
|
||||||
|
let mut input = stdin.lock().lines();
|
||||||
|
|
||||||
|
if let Some(Ok(given)) = input.next() {
|
||||||
|
if !given.is_empty() {
|
||||||
|
println!("{}", chop(&given));
|
||||||
|
std::process::exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::process::exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn chop(word: &str) -> &str {
|
||||||
|
let to = word.len() - 1;
|
||||||
|
|
||||||
|
&word[..to]
|
||||||
|
}
|
17
crates/nu-test-support/src/bin/cococo.rs
Normal file
17
crates/nu-test-support/src/bin/cococo.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
fn main() {
|
||||||
|
let args: Vec<String> = std::env::args().collect();
|
||||||
|
|
||||||
|
if args.len() > 1 {
|
||||||
|
// Write back out all the arguments passed
|
||||||
|
// if given at least 1 instead of chickens
|
||||||
|
// speaking co co co.
|
||||||
|
let mut arguments = args.iter();
|
||||||
|
arguments.next();
|
||||||
|
|
||||||
|
for arg in arguments {
|
||||||
|
println!("{}", &arg);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("cococo");
|
||||||
|
}
|
||||||
|
}
|
3
crates/nu-test-support/src/bin/fail.rs
Normal file
3
crates/nu-test-support/src/bin/fail.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fn main() {
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
@ -220,11 +220,16 @@ pub fn delete_directory_at(full_path: &str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn executable_path() -> PathBuf {
|
pub fn executable_path() -> PathBuf {
|
||||||
let mut buf = PathBuf::new();
|
let mut path = binaries();
|
||||||
buf.push("target");
|
path.push("nu");
|
||||||
buf.push("debug");
|
path
|
||||||
buf.push("nu");
|
}
|
||||||
buf
|
|
||||||
|
pub fn binaries() -> PathBuf {
|
||||||
|
let mut path = PathBuf::new();
|
||||||
|
path.push("target");
|
||||||
|
path.push("debug");
|
||||||
|
path
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn in_directory(str: impl AsRef<Path>) -> String {
|
pub fn in_directory(str: impl AsRef<Path>) -> String {
|
||||||
|
@ -13,7 +13,7 @@ pub fn pipeline(commands: &str) -> String {
|
|||||||
.to_string()
|
.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(tests)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::pipeline;
|
use super::pipeline;
|
||||||
|
|
||||||
|
@ -159,6 +159,17 @@ async fn run_with_iterator_arg(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn argument_is_quoted(argument: &str) -> bool {
|
||||||
|
(argument.starts_with('"') && argument.ends_with('"')
|
||||||
|
|| (argument.starts_with('\'') && argument.ends_with('\'')))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_quotes(argument: &str) -> &str {
|
||||||
|
let size = argument.len();
|
||||||
|
|
||||||
|
&argument[1..size - 1]
|
||||||
|
}
|
||||||
|
|
||||||
async fn run_with_stdin(
|
async fn run_with_stdin(
|
||||||
command: ExternalCommand,
|
command: ExternalCommand,
|
||||||
context: &mut Context,
|
context: &mut Context,
|
||||||
@ -169,19 +180,17 @@ async fn run_with_stdin(
|
|||||||
let home_dir = dirs::home_dir();
|
let home_dir = dirs::home_dir();
|
||||||
|
|
||||||
let mut process = Exec::cmd(&command.name);
|
let mut process = Exec::cmd(&command.name);
|
||||||
|
|
||||||
for arg in command.args.iter() {
|
for arg in command.args.iter() {
|
||||||
// Let's also replace ~ as we shell out
|
// Let's also replace ~ as we shell out
|
||||||
let arg = shellexpand::tilde_with_context(arg.deref(), || home_dir.as_ref());
|
let arg = shellexpand::tilde_with_context(arg.deref(), || home_dir.as_ref());
|
||||||
|
|
||||||
// Strip quotes from a quoted string
|
// Strip quotes from a quoted string
|
||||||
if arg.len() > 1
|
process = if arg.len() > 1 && (argument_is_quoted(&arg)) {
|
||||||
&& ((arg.starts_with('"') && arg.ends_with('"'))
|
process.arg(remove_quotes(&arg))
|
||||||
|| (arg.starts_with('\'') && arg.ends_with('\'')))
|
|
||||||
{
|
|
||||||
process = process.arg(arg.chars().skip(1).take(arg.len() - 2).collect::<String>());
|
|
||||||
} else {
|
} else {
|
||||||
process = process.arg(arg.as_ref());
|
process.arg(arg.as_ref())
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
process = process.cwd(context.shell_manager.path()?);
|
process = process.cwd(context.shell_manager.path()?);
|
||||||
@ -315,3 +324,103 @@ async fn run_with_stdin(
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::{argument_is_quoted, remove_quotes, run_external_command, Context, OutputStream};
|
||||||
|
use futures::executor::block_on;
|
||||||
|
use futures::stream::TryStreamExt;
|
||||||
|
use nu_errors::ShellError;
|
||||||
|
use nu_parser::commands::classified::external::{ExternalArgs, ExternalCommand};
|
||||||
|
use nu_protocol::{UntaggedValue, Value};
|
||||||
|
use nu_source::{Span, SpannedItem, Tag};
|
||||||
|
|
||||||
|
async fn read(mut stream: OutputStream) -> Option<Value> {
|
||||||
|
match stream.try_next().await {
|
||||||
|
Ok(val) => {
|
||||||
|
if let Some(val) = val {
|
||||||
|
val.raw_value()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn external(name: &str) -> ExternalCommand {
|
||||||
|
let mut path = nu_test_support::fs::binaries();
|
||||||
|
path.push(name);
|
||||||
|
|
||||||
|
let name = path.to_string_lossy().to_string().spanned(Span::unknown());
|
||||||
|
|
||||||
|
ExternalCommand {
|
||||||
|
name: name.to_string(),
|
||||||
|
name_tag: Tag {
|
||||||
|
anchor: None,
|
||||||
|
span: name.span,
|
||||||
|
},
|
||||||
|
args: ExternalArgs {
|
||||||
|
list: vec![],
|
||||||
|
span: name.span,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn non_existent_run() -> Result<(), ShellError> {
|
||||||
|
let cmd = external("i_dont_exist.exe");
|
||||||
|
|
||||||
|
let mut ctx = Context::basic().expect("There was a problem creating a basic context.");
|
||||||
|
|
||||||
|
assert!(run_external_command(cmd, &mut ctx, None, false)
|
||||||
|
.await
|
||||||
|
.is_err());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn failure_run() -> Result<(), ShellError> {
|
||||||
|
let cmd = external("fail");
|
||||||
|
|
||||||
|
let mut ctx = Context::basic().expect("There was a problem creating a basic context.");
|
||||||
|
let stream = run_external_command(cmd, &mut ctx, None, false)
|
||||||
|
.await?
|
||||||
|
.expect("There was a problem running the external command.");
|
||||||
|
|
||||||
|
match read(stream.into()).await {
|
||||||
|
Some(Value {
|
||||||
|
value: UntaggedValue::Error(_),
|
||||||
|
..
|
||||||
|
}) => {}
|
||||||
|
None | _ => panic!("Command didn't fail."),
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn identifies_command_failed() -> Result<(), ShellError> {
|
||||||
|
block_on(failure_run())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn identifies_command_not_found() -> Result<(), ShellError> {
|
||||||
|
block_on(non_existent_run())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn checks_quotes_from_argument_to_be_passed_in() {
|
||||||
|
assert_eq!(argument_is_quoted("'andrés"), false);
|
||||||
|
assert_eq!(argument_is_quoted("andrés'"), false);
|
||||||
|
assert_eq!(argument_is_quoted(r#""andrés"#), false);
|
||||||
|
assert_eq!(argument_is_quoted(r#"andrés""#), false);
|
||||||
|
assert_eq!(argument_is_quoted("'andrés'"), true);
|
||||||
|
assert_eq!(argument_is_quoted(r#""andrés""#), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn strips_quotes_from_argument_to_be_passed_in() {
|
||||||
|
assert_eq!(remove_quotes(r#"'andrés'"#), "andrés");
|
||||||
|
assert_eq!(remove_quotes(r#""andrés""#), "andrés");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user