mirror of
https://github.com/nushell/nushell
synced 2024-12-26 21:13:19 +00:00
Groundwork for coverage with Nu internals. (#1205)
This commit is contained in:
parent
5fd3191d91
commit
d3dae05714
8 changed files with 190 additions and 17 deletions
|
@ -42,16 +42,16 @@ steps:
|
|||
echo "##vso[task.prependpath]$HOME/.cargo/bin"
|
||||
rustup component add rustfmt --toolchain "stable"
|
||||
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')
|
||||
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')
|
||||
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')
|
||||
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')
|
||||
displayName: Check clippy lints
|
||||
- bash: cargo fmt --all -- --check
|
||||
|
|
17
Cargo.toml
17
Cargo.toml
|
@ -142,6 +142,8 @@ users = "0.9"
|
|||
default = ["sys", "ps", "textview", "inc", "str"]
|
||||
stable = ["sys", "ps", "textview", "inc", "str", "starship-prompt", "binaryview", "match", "tree", "average", "sum", "post", "fetch", "clipboard"]
|
||||
|
||||
nu-dummies = []
|
||||
|
||||
# Default
|
||||
sys = ["heim", "battery"]
|
||||
ps = ["heim", "futures-timer"]
|
||||
|
@ -178,6 +180,21 @@ name = "nu"
|
|||
doctest = false
|
||||
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
|
||||
# Currently, Cargo limits us to installing only one binary
|
||||
# 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 {
|
||||
let mut buf = PathBuf::new();
|
||||
buf.push("target");
|
||||
buf.push("debug");
|
||||
buf.push("nu");
|
||||
buf
|
||||
let mut path = binaries();
|
||||
path.push("nu");
|
||||
path
|
||||
}
|
||||
|
||||
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 {
|
||||
|
|
|
@ -13,7 +13,7 @@ pub fn pipeline(commands: &str) -> String {
|
|||
.to_string()
|
||||
}
|
||||
|
||||
#[cfg(tests)]
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
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(
|
||||
command: ExternalCommand,
|
||||
context: &mut Context,
|
||||
|
@ -169,19 +180,17 @@ async fn run_with_stdin(
|
|||
let home_dir = dirs::home_dir();
|
||||
|
||||
let mut process = Exec::cmd(&command.name);
|
||||
|
||||
for arg in command.args.iter() {
|
||||
// Let's also replace ~ as we shell out
|
||||
let arg = shellexpand::tilde_with_context(arg.deref(), || home_dir.as_ref());
|
||||
|
||||
// Strip quotes from a quoted string
|
||||
if arg.len() > 1
|
||||
&& ((arg.starts_with('"') && arg.ends_with('"'))
|
||||
|| (arg.starts_with('\'') && arg.ends_with('\'')))
|
||||
{
|
||||
process = process.arg(arg.chars().skip(1).take(arg.len() - 2).collect::<String>());
|
||||
process = if arg.len() > 1 && (argument_is_quoted(&arg)) {
|
||||
process.arg(remove_quotes(&arg))
|
||||
} else {
|
||||
process = process.arg(arg.as_ref());
|
||||
}
|
||||
process.arg(arg.as_ref())
|
||||
};
|
||||
}
|
||||
|
||||
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 a new issue