From acf13a6fcff8bfcb10045d449d0b000328fed621 Mon Sep 17 00:00:00 2001 From: Jason Gedge Date: Mon, 18 May 2020 08:56:01 -0400 Subject: [PATCH] Add (near) automatic testing for command examples (#1777) --- crates/nu-cli/src/cli.rs | 4 +- crates/nu-cli/src/commands.rs | 1 + crates/nu-cli/src/commands/alias.rs | 18 +- crates/nu-cli/src/commands/append.rs | 24 ++- crates/nu-cli/src/commands/autoview.rs | 18 +- crates/nu-cli/src/commands/cal.rs | 18 +- crates/nu-cli/src/commands/calc.rs | 17 +- crates/nu-cli/src/commands/cd.rs | 20 +- crates/nu-cli/src/commands/clear.rs | 22 ++- crates/nu-cli/src/commands/clip.rs | 209 ++++++++++---------- crates/nu-cli/src/commands/command.rs | 5 +- crates/nu-cli/src/commands/compact.rs | 34 +++- crates/nu-cli/src/commands/config.rs | 23 ++- crates/nu-cli/src/commands/count.rs | 21 +- crates/nu-cli/src/commands/cp.rs | 18 +- crates/nu-cli/src/commands/date.rs | 18 +- crates/nu-cli/src/commands/debug.rs | 12 ++ crates/nu-cli/src/commands/default.rs | 17 +- crates/nu-cli/src/commands/drop.rs | 23 ++- crates/nu-cli/src/commands/du.rs | 19 +- crates/nu-cli/src/commands/each.rs | 39 +++- crates/nu-cli/src/commands/echo.rs | 18 +- crates/nu-cli/src/commands/enter.rs | 18 +- crates/nu-cli/src/commands/evaluate_by.rs | 12 ++ crates/nu-cli/src/commands/exit.rs | 18 +- crates/nu-cli/src/commands/first.rs | 23 ++- crates/nu-cli/src/commands/format.rs | 17 +- crates/nu-cli/src/commands/from.rs | 12 ++ crates/nu-cli/src/commands/from_bson.rs | 17 +- crates/nu-cli/src/commands/from_csv.rs | 19 +- crates/nu-cli/src/commands/from_eml.rs | 12 ++ crates/nu-cli/src/commands/from_ics.rs | 12 ++ crates/nu-cli/src/commands/from_ini.rs | 12 ++ crates/nu-cli/src/commands/from_json.rs | 12 ++ crates/nu-cli/src/commands/from_ods.rs | 12 ++ crates/nu-cli/src/commands/from_sqlite.rs | 12 ++ crates/nu-cli/src/commands/from_ssv.rs | 8 + crates/nu-cli/src/commands/from_toml.rs | 12 ++ crates/nu-cli/src/commands/from_tsv.rs | 12 ++ crates/nu-cli/src/commands/from_url.rs | 12 ++ crates/nu-cli/src/commands/from_vcf.rs | 12 ++ crates/nu-cli/src/commands/from_xlsx.rs | 12 ++ crates/nu-cli/src/commands/from_xml.rs | 8 + crates/nu-cli/src/commands/from_yaml.rs | 12 ++ crates/nu-cli/src/commands/get.rs | 18 +- crates/nu-cli/src/commands/group_by.rs | 46 ++++- crates/nu-cli/src/commands/group_by_date.rs | 19 +- crates/nu-cli/src/commands/headers.rs | 19 +- crates/nu-cli/src/commands/help.rs | 12 ++ crates/nu-cli/src/commands/histogram.rs | 21 +- crates/nu-cli/src/commands/history.rs | 12 ++ crates/nu-cli/src/commands/insert.rs | 12 ++ crates/nu-cli/src/commands/is_empty.rs | 12 ++ crates/nu-cli/src/commands/keep.rs | 29 ++- crates/nu-cli/src/commands/keep_until.rs | 12 ++ crates/nu-cli/src/commands/keep_while.rs | 12 ++ crates/nu-cli/src/commands/kill.rs | 18 +- crates/nu-cli/src/commands/last.rs | 28 ++- crates/nu-cli/src/commands/lines.rs | 21 +- crates/nu-cli/src/commands/ls.rs | 19 +- crates/nu-cli/src/commands/map_max_by.rs | 12 ++ crates/nu-cli/src/commands/merge.rs | 17 +- crates/nu-cli/src/commands/mkdir.rs | 17 +- crates/nu-cli/src/commands/mv.rs | 19 +- crates/nu-cli/src/commands/next.rs | 12 ++ crates/nu-cli/src/commands/nth.rs | 20 +- crates/nu-cli/src/commands/open.rs | 12 ++ crates/nu-cli/src/commands/pivot.rs | 12 ++ crates/nu-cli/src/commands/prepend.rs | 24 ++- crates/nu-cli/src/commands/prev.rs | 12 ++ crates/nu-cli/src/commands/pwd.rs | 17 +- crates/nu-cli/src/commands/range.rs | 12 ++ crates/nu-cli/src/commands/reduce_by.rs | 12 ++ crates/nu-cli/src/commands/reject.rs | 12 ++ crates/nu-cli/src/commands/rename.rs | 22 ++- crates/nu-cli/src/commands/reverse.rs | 29 ++- crates/nu-cli/src/commands/rm.rs | 18 +- crates/nu-cli/src/commands/save.rs | 12 ++ crates/nu-cli/src/commands/select.rs | 18 +- crates/nu-cli/src/commands/shells.rs | 12 ++ crates/nu-cli/src/commands/shuffle.rs | 12 ++ crates/nu-cli/src/commands/size.rs | 24 ++- crates/nu-cli/src/commands/skip.rs | 24 ++- crates/nu-cli/src/commands/skip_until.rs | 12 ++ crates/nu-cli/src/commands/skip_while.rs | 12 ++ crates/nu-cli/src/commands/sort_by.rs | 28 ++- crates/nu-cli/src/commands/split_by.rs | 8 + crates/nu-cli/src/commands/split_column.rs | 12 ++ crates/nu-cli/src/commands/split_row.rs | 12 ++ crates/nu-cli/src/commands/sum.rs | 20 +- crates/nu-cli/src/commands/t_sort_by.rs | 12 ++ crates/nu-cli/src/commands/table.rs | 12 ++ crates/nu-cli/src/commands/tags.rs | 12 ++ crates/nu-cli/src/commands/to.rs | 12 ++ crates/nu-cli/src/commands/to_bson.rs | 12 ++ crates/nu-cli/src/commands/to_csv.rs | 12 ++ crates/nu-cli/src/commands/to_html.rs | 12 ++ crates/nu-cli/src/commands/to_json.rs | 24 ++- crates/nu-cli/src/commands/to_md.rs | 12 ++ crates/nu-cli/src/commands/to_sqlite.rs | 12 ++ crates/nu-cli/src/commands/to_toml.rs | 12 ++ crates/nu-cli/src/commands/to_tsv.rs | 12 ++ crates/nu-cli/src/commands/to_url.rs | 12 ++ crates/nu-cli/src/commands/to_yaml.rs | 12 ++ crates/nu-cli/src/commands/touch.rs | 12 ++ crates/nu-cli/src/commands/trim.rs | 12 ++ crates/nu-cli/src/commands/uniq.rs | 12 ++ crates/nu-cli/src/commands/update.rs | 12 ++ crates/nu-cli/src/commands/version.rs | 12 ++ crates/nu-cli/src/commands/what.rs | 12 ++ crates/nu-cli/src/commands/where_.rs | 12 ++ crates/nu-cli/src/commands/which_.rs | 12 ++ crates/nu-cli/src/commands/with_env.rs | 19 +- crates/nu-cli/src/commands/wrap.rs | 52 ++++- crates/nu-cli/src/examples.rs | 89 +++++++++ crates/nu-cli/src/lib.rs | 3 + crates/nu-cli/tests/main.rs | 1 + crates/nu-protocol/src/value.rs | 74 ++++--- crates/nu-protocol/src/value/primitive.rs | 14 ++ 119 files changed, 1935 insertions(+), 282 deletions(-) create mode 100644 crates/nu-cli/src/examples.rs diff --git a/crates/nu-cli/src/cli.rs b/crates/nu-cli/src/cli.rs index dfcfb294f0..3bd190eba4 100644 --- a/crates/nu-cli/src/cli.rs +++ b/crates/nu-cli/src/cli.rs @@ -376,9 +376,7 @@ pub fn create_default_context( #[cfg(feature = "clipboard")] { - context.add_commands(vec![whole_stream_command( - crate::commands::clip::clipboard::Clip, - )]); + context.add_commands(vec![whole_stream_command(crate::commands::clip::Clip)]); } } diff --git a/crates/nu-cli/src/commands.rs b/crates/nu-cli/src/commands.rs index 465e7e835f..4d37e38b0e 100644 --- a/crates/nu-cli/src/commands.rs +++ b/crates/nu-cli/src/commands.rs @@ -12,6 +12,7 @@ pub(crate) mod cal; pub(crate) mod calc; pub(crate) mod cd; pub(crate) mod classified; +#[cfg(feature = "clipboard")] pub(crate) mod clip; pub(crate) mod command; pub(crate) mod compact; diff --git a/crates/nu-cli/src/commands/alias.rs b/crates/nu-cli/src/commands/alias.rs index 389643c583..bdff7c77b3 100644 --- a/crates/nu-cli/src/commands/alias.rs +++ b/crates/nu-cli/src/commands/alias.rs @@ -43,15 +43,17 @@ impl WholeStreamCommand for Alias { alias(args, registry) } - fn examples(&self) -> &[Example] { - &[ + fn examples(&self) -> Vec { + vec![ Example { description: "An alias without parameters", example: "alias say-hi [] { echo 'Hello!' }", + result: None, }, Example { description: "An alias with a single parameter", example: "alias l [x] { ls $x }", + result: None, }, ] } @@ -74,3 +76,15 @@ pub fn alias(args: CommandArgs, registry: &CommandRegistry) -> Result &[Example] { - &[Example { + fn examples(&self) -> Vec { + vec![Example { description: "Add something to the end of a list or table", example: "echo [1 2 3] | append 4", + result: Some(vec![ + UntaggedValue::int(1).into(), + UntaggedValue::int(2).into(), + UntaggedValue::int(3).into(), + UntaggedValue::int(4).into(), + ]), }] } } @@ -58,3 +64,15 @@ fn append(args: CommandArgs, registry: &CommandRegistry) -> Result &[Example] { - &[ + fn examples(&self) -> Vec { + vec![ Example { description: "Automatically view the results", example: "ls | autoview", + result: None, }, Example { description: "Autoview is also implied. The above can be written as", example: "ls", + result: None, }, ] } @@ -336,3 +338,15 @@ fn create_default_command_args(context: &RunnableContextWithoutInput) -> RawComm }, } } + +#[cfg(test)] +mod tests { + use super::Autoview; + + #[test] + fn examples_work_as_expected() { + use crate::examples::test as test_examples; + + test_examples(Autoview {}) + } +} diff --git a/crates/nu-cli/src/commands/cal.rs b/crates/nu-cli/src/commands/cal.rs index d9130809d0..af9d8469b8 100644 --- a/crates/nu-cli/src/commands/cal.rs +++ b/crates/nu-cli/src/commands/cal.rs @@ -44,15 +44,17 @@ impl WholeStreamCommand for Cal { cal(args, registry) } - fn examples(&self) -> &[Example] { - &[ + fn examples(&self) -> Vec { + vec![ Example { description: "This month's calendar", example: "cal", + result: None, }, Example { description: "The calendar for all of 2012", example: "cal --full-year 2012", + result: None, }, ] } @@ -340,3 +342,15 @@ fn add_month_to_table( Ok(()) } + +#[cfg(test)] +mod tests { + use super::Cal; + + #[test] + fn examples_work_as_expected() { + use crate::examples::test as test_examples; + + test_examples(Cal {}) + } +} diff --git a/crates/nu-cli/src/commands/calc.rs b/crates/nu-cli/src/commands/calc.rs index c213594916..e20f331c41 100644 --- a/crates/nu-cli/src/commands/calc.rs +++ b/crates/nu-cli/src/commands/calc.rs @@ -22,10 +22,11 @@ impl WholeStreamCommand for Calc { calc(args, registry) } - fn examples(&self) -> &[Example] { - &[Example { + fn examples(&self) -> Vec { + vec![Example { description: "Calculate math in the pipeline", example: "echo '10 / 4' | calc", + result: Some(vec![UntaggedValue::decimal(2.5).into()]), }] } } @@ -70,3 +71,15 @@ pub fn parse(math_expression: &str, tag: impl Into) -> Result Err(error.to_string()), } } + +#[cfg(test)] +mod tests { + use super::Calc; + + #[test] + fn examples_work_as_expected() { + use crate::examples::test as test_examples; + + test_examples(Calc {}) + } +} diff --git a/crates/nu-cli/src/commands/cd.rs b/crates/nu-cli/src/commands/cd.rs index 1dd35d0dda..1c0f2bddf5 100644 --- a/crates/nu-cli/src/commands/cd.rs +++ b/crates/nu-cli/src/commands/cd.rs @@ -39,23 +39,27 @@ impl WholeStreamCommand for Cd { cd(args, registry) } - fn examples(&self) -> &[Example] { - &[ + fn examples(&self) -> Vec { + vec![ Example { description: "Change to a new directory called 'dirname'", example: "cd dirname", + result: None, }, Example { description: "Change to your home directory", example: "cd", + result: None, }, Example { description: "Change to your home directory (alternate version)", example: "cd ~", + result: None, }, Example { description: "Change to the previous directory", example: "cd -", + result: None, }, ] } @@ -76,3 +80,15 @@ fn cd(args: CommandArgs, registry: &CommandRegistry) -> Result &str { "clear" } + fn signature(&self) -> Signature { Signature::build("clear") } + fn usage(&self) -> &str { "clears the terminal" } + fn run( &self, args: CommandArgs, @@ -23,13 +26,16 @@ impl WholeStreamCommand for Clear { ) -> Result { clear(args, registry) } - fn examples(&self) -> &[Example] { - &[Example { + + fn examples(&self) -> Vec { + vec![Example { description: "Clear the screen", example: "clear", + result: None, }] } } + fn clear(_args: CommandArgs, _registry: &CommandRegistry) -> Result { if cfg!(windows) { Command::new("cmd") @@ -44,3 +50,15 @@ fn clear(_args: CommandArgs, _registry: &CommandRegistry) -> Result &str { - "clip" - } - - fn signature(&self) -> Signature { - Signature::build("clip") - } - - fn usage(&self) -> &str { - "Copy the contents of the pipeline to the copy/paste buffer" - } - - fn run( - &self, - args: CommandArgs, - registry: &CommandRegistry, - ) -> Result { - clip(args, registry) - } - - fn examples(&self) -> &[Example] { - &[Example { - description: "Save text to the clipboard", - example: "echo 'secret value' | clip", - }] - } +impl WholeStreamCommand for Clip { + fn name(&self) -> &str { + "clip" } - pub fn clip( + fn signature(&self) -> Signature { + Signature::build("clip") + } + + fn usage(&self) -> &str { + "Copy the contents of the pipeline to the copy/paste buffer" + } + + fn run( + &self, args: CommandArgs, - _registry: &CommandRegistry, + registry: &CommandRegistry, ) -> Result { - let stream = async_stream! { - let mut input = args.input; - let name = args.call_info.name_tag.clone(); - let values: Vec = input.collect().await; - - let mut clip_stream = inner_clip(values, name).await; - while let Some(value) = clip_stream.next().await { - yield value; - } - }; - - let stream: BoxStream<'static, ReturnValue> = stream.boxed(); - - Ok(OutputStream::from(stream)) + clip(args, registry) } - async fn inner_clip(input: Vec, name: Tag) -> OutputStream { - if let Ok(clip_context) = ClipboardProvider::new() { - let mut clip_context: ClipboardContext = clip_context; - let mut new_copy_data = String::new(); - - if !input.is_empty() { - let mut first = true; - for i in input.iter() { - if !first { - new_copy_data.push_str("\n"); - } else { - first = false; - } - - let string: String = match i.as_string() { - Ok(string) => string.to_string(), - Err(_) => { - return OutputStream::one(Err(ShellError::labeled_error( - "Given non-string data", - "expected strings from pipeline", - name, - ))) - } - }; - - new_copy_data.push_str(&string); - } - } - - match clip_context.set_contents(new_copy_data) { - Ok(_) => {} - Err(_) => { - return OutputStream::one(Err(ShellError::labeled_error( - "Could not set contents of clipboard", - "could not set contents of clipboard", - name, - ))); - } - } - - OutputStream::empty() - } else { - OutputStream::one(Err(ShellError::labeled_error( - "Could not open clipboard", - "could not open clipboard", - name, - ))) - } + fn examples(&self) -> Vec { + vec![Example { + description: "Save text to the clipboard", + example: "echo 'secret value' | clip", + result: None, + }] + } +} + +pub fn clip(args: CommandArgs, _registry: &CommandRegistry) -> Result { + let stream = async_stream! { + let mut input = args.input; + let name = args.call_info.name_tag.clone(); + let values: Vec = input.collect().await; + + let mut clip_stream = inner_clip(values, name).await; + while let Some(value) = clip_stream.next().await { + yield value; + } + }; + + let stream: BoxStream<'static, ReturnValue> = stream.boxed(); + + Ok(OutputStream::from(stream)) +} + +async fn inner_clip(input: Vec, name: Tag) -> OutputStream { + if let Ok(clip_context) = ClipboardProvider::new() { + let mut clip_context: ClipboardContext = clip_context; + let mut new_copy_data = String::new(); + + if !input.is_empty() { + let mut first = true; + for i in input.iter() { + if !first { + new_copy_data.push_str("\n"); + } else { + first = false; + } + + let string: String = match i.as_string() { + Ok(string) => string.to_string(), + Err(_) => { + return OutputStream::one(Err(ShellError::labeled_error( + "Given non-string data", + "expected strings from pipeline", + name, + ))) + } + }; + + new_copy_data.push_str(&string); + } + } + + match clip_context.set_contents(new_copy_data) { + Ok(_) => {} + Err(_) => { + return OutputStream::one(Err(ShellError::labeled_error( + "Could not set contents of clipboard", + "could not set contents of clipboard", + name, + ))); + } + } + + OutputStream::empty() + } else { + OutputStream::one(Err(ShellError::labeled_error( + "Could not open clipboard", + "could not open clipboard", + name, + ))) + } +} + +#[cfg(test)] +mod tests { + use super::Clip; + + #[test] + fn examples_work_as_expected() { + use crate::examples::test as test_examples; + + test_examples(Clip {}) } } diff --git a/crates/nu-cli/src/commands/command.rs b/crates/nu-cli/src/commands/command.rs index 25d75a0843..e7f1a1ffeb 100644 --- a/crates/nu-cli/src/commands/command.rs +++ b/crates/nu-cli/src/commands/command.rs @@ -272,6 +272,7 @@ impl EvaluatedCommandArgs { pub struct Example { pub example: &'static str, pub description: &'static str, + pub result: Option>, } pub trait WholeStreamCommand: Send + Sync { @@ -293,8 +294,8 @@ pub trait WholeStreamCommand: Send + Sync { false } - fn examples(&self) -> &[Example] { - &[] + fn examples(&self) -> Vec { + Vec::new() } } diff --git a/crates/nu-cli/src/commands/compact.rs b/crates/nu-cli/src/commands/compact.rs index fb2902239b..8d6ebcac24 100644 --- a/crates/nu-cli/src/commands/compact.rs +++ b/crates/nu-cli/src/commands/compact.rs @@ -34,11 +34,23 @@ impl WholeStreamCommand for Compact { compact(args, registry) } - fn examples(&self) -> &[Example] { - &[Example { - description: "Remove all directory entries, except those with a 'target'", - example: "ls -af | compact target", - }] + fn examples(&self) -> Vec { + vec![ + Example { + description: "Filter out all null entries in a list", + example: "echo [1 2 $null 3 $null $null] | compact target", + result: Some(vec![ + UntaggedValue::int(1).into(), + UntaggedValue::int(2).into(), + UntaggedValue::int(3).into(), + ]), + }, + Example { + description: "Filter out all directory entries having no 'target'", + example: "ls -af | compact target", + result: None, + }, + ] } } @@ -68,3 +80,15 @@ pub fn compact(args: CommandArgs, registry: &CommandRegistry) -> Result &[Example] { - &[ + fn examples(&self) -> Vec { + vec![ Example { description: "See all config values", example: "config", + result: None, }, Example { description: "Set completion_mode to circular", example: "config --set [completion_mode circular]", + result: None, }, Example { description: "Store the contents of the pipeline as a path", example: "echo ['/usr/bin' '/bin'] | config --set_into path", + result: None, }, Example { description: "Get the current startup commands", example: "config --get startup", + result: None, }, Example { description: "Remove the startup commands", example: "config --remove startup", + result: None, }, Example { description: "Clear the config (be careful!)", example: "config --clear", + result: None, }, Example { description: "Get the path to the current config file", example: "config --path", + result: None, }, ] } @@ -220,3 +227,15 @@ pub fn config(args: CommandArgs, registry: &CommandRegistry) -> Result &[Example] { - &[Example { - description: "Count the number of files/directories in the current directory", - example: "ls | count", + fn examples(&self) -> Vec { + vec![Example { + description: "Count the number of entries in a list", + example: "echo [1 2 3 4 5] | count", + result: Some(vec![UntaggedValue::int(5).into()]), }] } } @@ -46,3 +47,15 @@ pub fn count(args: CommandArgs, _registry: &CommandRegistry) -> Result &[Example] { - &[ + fn examples(&self) -> Vec { + vec![ Example { description: "Copy myfile to dir_b", example: "cp myfile dir_b", + result: None, }, Example { description: "Recursively copy dir_a to dir_b", example: "cp -r dir_a dir_b", + result: None, }, ] } @@ -72,3 +74,15 @@ pub fn cp(args: CommandArgs, registry: &CommandRegistry) -> Result &[Example] { - &[ + fn examples(&self) -> Vec { + vec![ Example { description: "Get the current local time and date", example: "date", + result: None, }, Example { description: "Get the current UTC time and date", example: "date --utc", + result: None, }, ] } @@ -108,3 +110,15 @@ pub fn date(args: CommandArgs, registry: &CommandRegistry) -> Result Result &[Example] { - &[Example { + fn examples(&self) -> Vec { + vec![Example { description: "Give a default 'target' to all file entries", example: "ls -af | default target 'nothing'", + result: None, }] } } @@ -76,3 +77,15 @@ fn default(args: CommandArgs, registry: &CommandRegistry) -> Result &[Example] { - &[ + fn examples(&self) -> Vec { + vec![ Example { description: "Remove the last item of a list/table", example: "echo [1 2 3] | drop", + result: Some(vec![ + UntaggedValue::int(1).into(), + UntaggedValue::int(2).into(), + ]), }, Example { description: "Remove the last 2 items of a list/table", example: "echo [1 2 3] | drop 2", + result: Some(vec![UntaggedValue::int(1).into()]), }, ] } @@ -73,3 +78,15 @@ fn drop(args: CommandArgs, registry: &CommandRegistry) -> Result &[Example] { - &[Example { + fn examples(&self) -> Vec { + vec![Example { description: "Disk usage of the current directory", - example: "du *", + example: "du", + result: None, }] } } @@ -404,3 +405,15 @@ impl From for Value { UntaggedValue::row(r).retag(&f.tag) } } + +#[cfg(test)] +mod tests { + use super::Du; + + #[test] + fn examples_work_as_expected() { + use crate::examples::test as test_examples; + + test_examples(Du {}) + } +} diff --git a/crates/nu-cli/src/commands/each.rs b/crates/nu-cli/src/commands/each.rs index 57e78f1eee..542ec5ad7c 100644 --- a/crates/nu-cli/src/commands/each.rs +++ b/crates/nu-cli/src/commands/each.rs @@ -7,7 +7,7 @@ use futures::stream::once; use nu_errors::ShellError; use nu_protocol::{ hir::Block, hir::Expression, hir::SpannedExpression, hir::Synthetic, ReturnSuccess, Signature, - SyntaxShape, + SyntaxShape, UntaggedValue, }; pub struct Each; @@ -42,11 +42,26 @@ impl WholeStreamCommand for Each { each(args, registry) } - fn examples(&self) -> &[Example] { - &[Example { - description: "Print the name of each file", - example: "ls | each { echo $it.name }", - }] + fn examples(&self) -> Vec { + vec![ + Example { + description: "Echo the square of each integer", + example: "echo [1 2 3] | each { echo $(= $it * $it) }", + result: Some(vec![ + UntaggedValue::int(1).into(), + UntaggedValue::int(4).into(), + UntaggedValue::int(9).into(), + ]), + }, + Example { + description: "Echo the sum of each row", + example: "echo [[1 2] [3 4]] | each { echo $it | sum }", + result: Some(vec![ + UntaggedValue::int(3).into(), + UntaggedValue::int(7).into(), + ]), + }, + ] } } @@ -104,3 +119,15 @@ fn each(raw_args: CommandArgs, registry: &CommandRegistry) -> Result &[Example] { - &[ + fn examples(&self) -> Vec { + vec![ Example { description: "Put a hello message in the pipeline", example: "echo 'hello'", + result: Some(vec![Value::from("hello")]), }, Example { description: "Print the value of the special '$nu' variable", example: "echo $nu", + result: None, }, ] } @@ -76,3 +78,15 @@ fn echo(args: CommandArgs, registry: &CommandRegistry) -> Result &[Example] { - &[ + fn examples(&self) -> Vec { + vec![ Example { description: "Enter a path as a new shell", example: "enter ../projectB", + result: None, }, Example { description: "Enter a file as a new shell", example: "enter package.json", + result: None, }, ] } @@ -165,3 +167,15 @@ fn enter(raw_args: CommandArgs, registry: &CommandRegistry) -> Result &[Example] { - &[ + fn examples(&self) -> Vec { + vec![ Example { description: "Exit the current shell", example: "exit", + result: None, }, Example { description: "Exit all shells (exiting Nu)", example: "exit --now", + result: None, }, ] } @@ -55,3 +57,15 @@ pub fn exit(args: CommandArgs, registry: &CommandRegistry) -> Result &[Example] { - &[ + fn examples(&self) -> Vec { + vec![ Example { description: "Return the first item of a list/table", example: "echo [1 2 3] | first", + result: Some(vec![UntaggedValue::int(1).into()]), }, Example { description: "Return the first 2 items of a list/table", example: "echo [1 2 3] | first 2", + result: Some(vec![ + UntaggedValue::int(1).into(), + UntaggedValue::int(2).into(), + ]), }, ] } @@ -73,3 +78,15 @@ fn first(args: CommandArgs, registry: &CommandRegistry) -> Result &[Example] { - &[Example { + fn examples(&self) -> Vec { + vec![Example { description: "Print filenames with their sizes", example: "ls | format '{name}: {size}'", + result: None, }] } } @@ -172,3 +173,15 @@ fn to_column_path( .into_value(&tag), ) } + +#[cfg(test)] +mod tests { + use super::Format; + + #[test] + fn examples_work_as_expected() { + use crate::examples::test as test_examples; + + test_examples(Format {}) + } +} diff --git a/crates/nu-cli/src/commands/from.rs b/crates/nu-cli/src/commands/from.rs index e5302fb6aa..a141baf488 100644 --- a/crates/nu-cli/src/commands/from.rs +++ b/crates/nu-cli/src/commands/from.rs @@ -34,3 +34,15 @@ impl WholeStreamCommand for From { Ok(stream.to_output_stream()) } } + +#[cfg(test)] +mod tests { + use super::From; + + #[test] + fn examples_work_as_expected() { + use crate::examples::test as test_examples; + + test_examples(From {}) + } +} diff --git a/crates/nu-cli/src/commands/from_bson.rs b/crates/nu-cli/src/commands/from_bson.rs index 5097541d43..ac81f21ebd 100644 --- a/crates/nu-cli/src/commands/from_bson.rs +++ b/crates/nu-cli/src/commands/from_bson.rs @@ -29,10 +29,11 @@ impl WholeStreamCommand for FromBSON { from_bson(args, registry) } - fn examples(&self) -> &[Example] { - &[Example { + fn examples(&self) -> Vec { + vec![Example { description: "Convert bson data to a table", example: "open file.bin | from bson", + result: None, }] } } @@ -231,3 +232,15 @@ fn from_bson(args: CommandArgs, registry: &CommandRegistry) -> Result &[Example] { - &[ + fn examples(&self) -> Vec { + vec![ Example { description: "Convert comma-separated data to a table", example: "open data.txt | from csv", + result: None, }, Example { description: "Convert comma-separated data to a table, ignoring headers", example: "open data.txt | from csv --headerless", + result: None, }, Example { description: "Convert semicolon-separated data to a table", example: "open data.txt | from csv --separator ';'", + result: None, }, ] } @@ -100,3 +103,15 @@ fn from_csv(args: CommandArgs, registry: &CommandRegistry) -> Result Result)>, tag: Tag) -> Value { row.into_value() } + +#[cfg(test)] +mod tests { + use super::FromIcs; + + #[test] + fn examples_work_as_expected() { + use crate::examples::test as test_examples; + + test_examples(FromIcs {}) + } +} diff --git a/crates/nu-cli/src/commands/from_ini.rs b/crates/nu-cli/src/commands/from_ini.rs index ff9aec2699..a870e053bb 100644 --- a/crates/nu-cli/src/commands/from_ini.rs +++ b/crates/nu-cli/src/commands/from_ini.rs @@ -94,3 +94,15 @@ fn from_ini(args: CommandArgs, registry: &CommandRegistry) -> Result Result Result Result Result Result)>, tag: Tag) -> Value { row.into_value() } + +#[cfg(test)] +mod tests { + use super::FromVcf; + + #[test] + fn examples_work_as_expected() { + use crate::examples::test as test_examples; + + test_examples(FromVcf {}) + } +} diff --git a/crates/nu-cli/src/commands/from_xlsx.rs b/crates/nu-cli/src/commands/from_xlsx.rs index 9c82cbe050..c57600838c 100644 --- a/crates/nu-cli/src/commands/from_xlsx.rs +++ b/crates/nu-cli/src/commands/from_xlsx.rs @@ -92,3 +92,15 @@ fn from_xlsx(args: CommandArgs, registry: &CommandRegistry) -> Result Result &[Example] { - &[ + fn examples(&self) -> Vec { + vec![ Example { description: "Extract the name of files as a list", example: "ls | get name", + result: None, }, Example { description: "Extract the cpu list from the sys information", example: "sys | get cpu", + result: None, }, ] } @@ -240,3 +242,15 @@ pub fn get(args: CommandArgs, registry: &CommandRegistry) -> Result &[Example] { - &[Example { - description: "Group files by type", - example: "ls | group-by type", - }] + fn examples(&self) -> Vec { + vec![ + Example { + description: "Group items by type", + example: r#"ls | group-by type"#, + result: None, + }, + Example { + description: "Group items by their value", + example: "echo [1 3 1 3 2 1 1] | group-by", + result: Some(vec![UntaggedValue::row(indexmap! { + "1".to_string() => UntaggedValue::Table(vec![ + UntaggedValue::int(1).into(), + UntaggedValue::int(1).into(), + UntaggedValue::int(1).into(), + UntaggedValue::int(1).into(), + ]).into(), + + "3".to_string() => UntaggedValue::Table(vec![ + UntaggedValue::int(3).into(), + UntaggedValue::int(3).into(), + ]).into(), + + "2".to_string() => UntaggedValue::Table(vec![ + UntaggedValue::int(2).into(), + ]).into(), + }) + .into()]), + }, + ] } } @@ -185,4 +211,12 @@ mod tests { Ok(()) } + + #[test] + fn examples_work_as_expected() { + use super::GroupBy; + use crate::examples::test as test_examples; + + test_examples(GroupBy {}) + } } diff --git a/crates/nu-cli/src/commands/group_by_date.rs b/crates/nu-cli/src/commands/group_by_date.rs index ec84441bbe..e7b7e4e5e0 100644 --- a/crates/nu-cli/src/commands/group_by_date.rs +++ b/crates/nu-cli/src/commands/group_by_date.rs @@ -44,10 +44,11 @@ impl WholeStreamCommand for GroupByDate { group_by_date(args, registry) } - fn examples(&self) -> &[Example] { - &[Example { + fn examples(&self) -> Vec { + vec![Example { description: "Group files by type", - example: "ls | group-by date --fmt '%d/%m/%Y'", + example: "ls | group-by date --format '%d/%m/%Y'", + result: None, }] } } @@ -101,3 +102,15 @@ pub fn group_by_date( Ok(stream.to_output_stream()) } + +#[cfg(test)] +mod tests { + use super::GroupByDate; + + #[test] + fn examples_work_as_expected() { + use crate::examples::test as test_examples; + + test_examples(GroupByDate {}) + } +} diff --git a/crates/nu-cli/src/commands/headers.rs b/crates/nu-cli/src/commands/headers.rs index cb56a3baa6..c9c50440c2 100644 --- a/crates/nu-cli/src/commands/headers.rs +++ b/crates/nu-cli/src/commands/headers.rs @@ -30,10 +30,11 @@ impl WholeStreamCommand for Headers { headers(args, registry) } - fn examples(&self) -> &[Example] { - &[Example { + fn examples(&self) -> Vec { + vec![Example { description: "Create headers for a raw string", - example: "echo \"a b c|1 2 3\" | split-row \"|\" | split-column \" \" | headers", + example: r#"echo "a b c|1 2 3" | split-row "|" | split-column " " | headers"#, + result: None, }] } } @@ -84,3 +85,15 @@ pub fn headers(args: CommandArgs, _registry: &CommandRegistry) -> Result Str long_desc } + +#[cfg(test)] +mod tests { + use super::Help; + + #[test] + fn examples_work_as_expected() { + use crate::examples::test as test_examples; + + test_examples(Help {}) + } +} diff --git a/crates/nu-cli/src/commands/histogram.rs b/crates/nu-cli/src/commands/histogram.rs index 361ff5dde8..291d7e1878 100644 --- a/crates/nu-cli/src/commands/histogram.rs +++ b/crates/nu-cli/src/commands/histogram.rs @@ -47,20 +47,23 @@ impl WholeStreamCommand for Histogram { histogram(args, registry) } - fn examples(&self) -> &[Example] { - &[ + fn examples(&self) -> Vec { + vec![ Example { description: "Get a histogram for the types of files", example: "ls | histogram type", + result: None, }, Example { description: "Get a histogram for the types of files, with frequency column named count", example: "ls | histogram type count", + result: None, }, Example { description: "Get a histogram for a list of numbers", - example: "echo [1 2 3 1 2 3 1 1 1 1 3 2 1 1 3] | wrap | histogram Column", + example: "echo [1 2 3 1 1 1 2 2 1 1] | histogram", + result: None, }, ] } @@ -179,3 +182,15 @@ fn percentages(values: &Value, max: Value, tag: impl Into) -> Result Result Result Result &[Example] { - &[ + fn examples(&self) -> Vec { + vec![ Example { description: "Keep the first row", - example: "ls | keep", + example: "echo [1 2 3] | keep", + result: Some(vec![UntaggedValue::int(1).into()]), }, Example { description: "Keep the first four rows", - example: "ls | keep 4", + example: "echo [1 2 3 4 5] | keep 4", + result: Some(vec![ + UntaggedValue::int(1).into(), + UntaggedValue::int(2).into(), + UntaggedValue::int(3).into(), + UntaggedValue::int(4).into(), + ]), }, ] } @@ -73,3 +80,15 @@ fn keep(args: CommandArgs, registry: &CommandRegistry) -> Result &[Example] { - &[ + fn examples(&self) -> Vec { + vec![ Example { description: "Kill the pid using the most memory", example: "ps | sort-by mem | last | kill $it.pid", + result: None, }, Example { description: "Force kill a given pid", example: "kill --force 12345", + result: None, }, ] } @@ -117,3 +119,15 @@ fn kill(args: CommandArgs, registry: &CommandRegistry) -> Result &[Example] { - &[ + fn examples(&self) -> Vec { + vec![ Example { description: "Get the last row", - example: "ls | last", + example: "echo [1 2 3] | last", + result: Some(vec![Value::from(UntaggedValue::from(BigInt::from(3)))]), }, Example { description: "Get the last three rows", - example: "ls | last 3", + example: "echo [1 2 3 4 5] | last 3", + result: Some(vec![ + UntaggedValue::int(3).into(), + UntaggedValue::int(4).into(), + UntaggedValue::int(5).into(), + ]), }, ] } @@ -74,3 +80,15 @@ fn last(args: CommandArgs, registry: &CommandRegistry) -> Result &[Example] { - &[Example { - description: "Split output from an external command into lines", - example: "^ls -l | lines", + fn examples(&self) -> Vec { + vec![Example { + description: "Split multi-line string into lines", + example: r#"^echo "two\nlines" | lines"#, + result: None, }] } } @@ -121,3 +122,15 @@ fn lines(args: CommandArgs, registry: &CommandRegistry) -> Result &[Example] { - &[ + fn examples(&self) -> Vec { + vec![ Example { description: "List all files in the current directory", example: "ls", + result: None, }, Example { description: "List all files in a subdirectory", example: "ls subdir", + result: None, }, Example { description: "List all rust files", example: "ls *.rs", + result: None, }, ] } @@ -101,3 +104,15 @@ fn ls(args: CommandArgs, registry: &CommandRegistry) -> Result &[Example] { - &[Example { + fn examples(&self) -> Vec { + vec![Example { description: "Merge a 1-based index column with some ls output", example: "ls | select name | keep 3 | merge { echo [1 2 3] | wrap index }", + result: None, }] } } @@ -97,3 +98,15 @@ fn merge(raw_args: CommandArgs, registry: &CommandRegistry) -> Result &[Example] { - &[Example { + fn examples(&self) -> Vec { + vec![Example { description: "Make a directory named foo", example: "mkdir foo", + result: None, }] } } @@ -57,3 +58,15 @@ fn mkdir(args: CommandArgs, registry: &CommandRegistry) -> Result &[Example] { - &[ + fn examples(&self) -> Vec { + vec![ Example { description: "Rename a file", example: "mv before.txt after.txt", + result: None, }, Example { description: "Move a file into a directory", example: "mv test.txt my/subdirectory", + result: None, }, Example { description: "Move many files into a directory", example: "mv *.txt my/subdirectory", + result: None, }, ] } @@ -78,3 +81,15 @@ fn mv(args: CommandArgs, registry: &CommandRegistry) -> Result Result { Ok(vec![Ok(ReturnSuccess::Action(CommandAction::NextShell))].into()) } + +#[cfg(test)] +mod tests { + use super::Next; + + #[test] + fn examples_work_as_expected() { + use crate::examples::test as test_examples; + + test_examples(Next {}) + } +} diff --git a/crates/nu-cli/src/commands/nth.rs b/crates/nu-cli/src/commands/nth.rs index 5606f1ce1f..d090115a8e 100644 --- a/crates/nu-cli/src/commands/nth.rs +++ b/crates/nu-cli/src/commands/nth.rs @@ -2,7 +2,7 @@ use crate::commands::WholeStreamCommand; use crate::context::CommandRegistry; use crate::prelude::*; use nu_errors::ShellError; -use nu_protocol::{ReturnSuccess, Signature, SyntaxShape}; +use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, Value}; use nu_source::Tagged; #[derive(Deserialize)] @@ -40,15 +40,17 @@ impl WholeStreamCommand for Nth { nth(args, registry) } - fn examples(&self) -> &[Example] { - &[ + fn examples(&self) -> Vec { + vec![ Example { description: "Get the second row", example: "echo [first second third] | nth 1", + result: Some(vec![Value::from("second")]), }, Example { description: "Get the first and third rows", example: "echo [first second third] | nth 0 2", + result: Some(vec![Value::from("first"), Value::from("third")]), }, ] } @@ -79,3 +81,15 @@ fn nth(args: CommandArgs, registry: &CommandRegistry) -> Result Option> { Some(result) } } + +#[cfg(test)] +mod tests { + use super::Open; + + #[test] + fn examples_work_as_expected() { + use crate::examples::test as test_examples; + + test_examples(Open {}) + } +} diff --git a/crates/nu-cli/src/commands/pivot.rs b/crates/nu-cli/src/commands/pivot.rs index 894971e648..9764abc126 100644 --- a/crates/nu-cli/src/commands/pivot.rs +++ b/crates/nu-cli/src/commands/pivot.rs @@ -137,3 +137,15 @@ pub fn pivot(args: CommandArgs, registry: &CommandRegistry) -> Result &[Example] { - &[Example { + fn examples(&self) -> Vec { + vec![Example { description: "Add something to the beginning of a list or table", example: "echo [2 3 4] | prepend 1", + result: Some(vec![ + UntaggedValue::int(1).into(), + UntaggedValue::int(2).into(), + UntaggedValue::int(3).into(), + UntaggedValue::int(4).into(), + ]), }] } } @@ -58,3 +64,15 @@ fn prepend(args: CommandArgs, registry: &CommandRegistry) -> Result Result { Ok(vec![Ok(ReturnSuccess::Action(CommandAction::PreviousShell))].into()) } + +#[cfg(test)] +mod tests { + use super::Previous; + + #[test] + fn examples_work_as_expected() { + use crate::examples::test as test_examples; + + test_examples(Previous {}) + } +} diff --git a/crates/nu-cli/src/commands/pwd.rs b/crates/nu-cli/src/commands/pwd.rs index 77c646d23d..5444f592f8 100644 --- a/crates/nu-cli/src/commands/pwd.rs +++ b/crates/nu-cli/src/commands/pwd.rs @@ -26,10 +26,11 @@ impl WholeStreamCommand for Pwd { pwd(args, registry) } - fn examples(&self) -> &[Example] { - &[Example { + fn examples(&self) -> Vec { + vec![Example { description: "Print the current working directory", example: "pwd", + result: None, }] } } @@ -49,3 +50,15 @@ pub fn pwd(args: CommandArgs, registry: &CommandRegistry) -> Result Result Result &[Example] { - &[ + fn examples(&self) -> Vec { + vec![ Example { description: "Rename a column", - example: "ls | rename my_name", + example: r#"echo "{a: 1, b: 2, c: 3}" | from json | rename my_column"#, + result: None, }, Example { description: "Rename many columns", - example: "echo \"{a: 1, b: 2, c: 3}\" | from json | rename spam eggs cars", + example: r#"echo "{a: 1, b: 2, c: 3}" | from json | rename spam eggs cars"#, + result: None, }, ] } @@ -100,3 +102,15 @@ pub fn rename(args: CommandArgs, registry: &CommandRegistry) -> Result &[Example] { - &[Example { - description: "Sort files in descending file size", - example: "ls | sort-by size | reverse", + fn examples(&self) -> Vec { + vec![Example { + description: "Sort list of numbers in descending file size", + example: "echo [3 1 2 19 0] | reverse", + result: Some(vec![ + UntaggedValue::int(0).into(), + UntaggedValue::int(19).into(), + UntaggedValue::int(2).into(), + UntaggedValue::int(1).into(), + UntaggedValue::int(3).into(), + ]), }] } } @@ -49,3 +56,15 @@ fn reverse(args: CommandArgs, registry: &CommandRegistry) -> Result &[Example] { - &[ + fn examples(&self) -> Vec { + vec![ Example { description: "Delete a file", example: "rm file.txt", + result: None, }, Example { description: "Move a file to the system trash", example: "rm --trash file.txt", + result: None, }, ] } @@ -72,3 +74,15 @@ fn rm(args: CommandArgs, registry: &CommandRegistry) -> Result String { save_data } + +#[cfg(test)] +mod tests { + use super::Save; + + #[test] + fn examples_work_as_expected() { + use crate::examples::test as test_examples; + + test_examples(Save {}) + } +} diff --git a/crates/nu-cli/src/commands/select.rs b/crates/nu-cli/src/commands/select.rs index 18dd180608..29fa7ee2e3 100644 --- a/crates/nu-cli/src/commands/select.rs +++ b/crates/nu-cli/src/commands/select.rs @@ -40,15 +40,17 @@ impl WholeStreamCommand for Select { select(args, registry) } - fn examples(&self) -> &[Example] { - &[ + fn examples(&self) -> Vec { + vec![ Example { description: "Select just the name column", example: "ls | select name", + result: None, }, Example { description: "Select the name and size columns", example: "ls | select name size", + result: None, }, ] } @@ -172,3 +174,15 @@ fn select(args: CommandArgs, registry: &CommandRegistry) -> Result Result Result &[Example] { - &[Example { + fn examples(&self) -> Vec { + vec![Example { description: "Count the number of words in a string", example: r#"echo "There are seven words in this sentence" | size"#, + result: Some(vec![UntaggedValue::row(indexmap! { + "lines".to_string() => UntaggedValue::int(0).into(), + "words".to_string() => UntaggedValue::int(7).into(), + "chars".to_string() => UntaggedValue::int(38).into(), + "max length".to_string() => UntaggedValue::int(38).into(), + }) + .into()]), }] } } @@ -91,3 +99,15 @@ fn count(contents: &str, tag: impl Into) -> Value { dict.into_value() } + +#[cfg(test)] +mod tests { + use super::Size; + + #[test] + fn examples_work_as_expected() { + use crate::examples::test as test_examples; + + test_examples(Size {}) + } +} diff --git a/crates/nu-cli/src/commands/skip.rs b/crates/nu-cli/src/commands/skip.rs index 22018181c7..713b5ad0ae 100644 --- a/crates/nu-cli/src/commands/skip.rs +++ b/crates/nu-cli/src/commands/skip.rs @@ -2,7 +2,7 @@ use crate::commands::WholeStreamCommand; use crate::context::CommandRegistry; use crate::prelude::*; use nu_errors::ShellError; -use nu_protocol::{ReturnSuccess, Signature, SyntaxShape}; +use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue}; use nu_source::Tagged; pub struct Skip; @@ -33,10 +33,14 @@ impl WholeStreamCommand for Skip { skip(args, registry) } - fn examples(&self) -> &[Example] { - &[Example { + fn examples(&self) -> Vec { + vec![Example { description: "Skip the first 5 rows", - example: "ls | skip 5", + example: "echo [1 2 3 4 5 6 7] | skip 5", + result: Some(vec![ + UntaggedValue::int(6).into(), + UntaggedValue::int(7).into(), + ]), }] } } @@ -63,3 +67,15 @@ fn skip(args: CommandArgs, registry: &CommandRegistry) -> Result &[Example] { - &[ + fn examples(&self) -> Vec { + vec![ + Example { + description: "Sort list by increasing value", + example: "echo [4 2 3 1] | sort-by", + result: Some(vec![ + UntaggedValue::int(1).into(), + UntaggedValue::int(2).into(), + UntaggedValue::int(3).into(), + UntaggedValue::int(4).into(), + ]), + }, Example { description: "Sort output by increasing file size", example: "ls | sort-by size", + result: None, }, Example { description: "Sort output by type, and then by file size for each type", example: "ls | sort-by type size", + result: None, }, ] } @@ -81,3 +93,15 @@ fn sort_by(args: CommandArgs, registry: &CommandRegistry) -> Result Result Result &[Example] { - &[ + fn examples(&self) -> Vec { + vec![ Example { description: "Sum a list of numbers", example: "echo [1 2 3] | sum", + result: Some(vec![UntaggedValue::int(6).into()]), }, Example { description: "Get the disk usage for the current directory", example: "ls --all --du | get size | sum", + result: None, }, ] } @@ -65,3 +67,15 @@ fn sum(RunnableContext { mut input, .. }: RunnableContext) -> Result Result Result Result Result Result Result &[Example] { - &[ + fn examples(&self) -> Vec { + vec![ Example { description: "Outputs an unformatted JSON string representing the contents of this table", - example: "to json", + example: "echo [1 2 3] | to json", + result: Some(vec![Value::from("[1,2,3]")]), }, Example { description: - "Outputs a formatted JSON string representing the contents of this table with an indentation setting of 4 spaces", - example: "to json --pretty 4", + "Outputs a formatted JSON string representing the contents of this table with an indentation setting of 2 spaces", + example: "echo [1 2 3] | to json --pretty 2", + result: Some(vec![Value::from("[\n 1,\n 2,\n 3\n]")]), }, ] } @@ -233,3 +235,15 @@ fn to_json(args: CommandArgs, registry: &CommandRegistry) -> Result Result Result Result Result Result Result Result Result Result Result Result Result Result &[Example] { - &[Example { + fn examples(&self) -> Vec { + vec![Example { description: "Set the MYENV environment variable", example: r#"with-env [MYENV "my env value"] { echo $nu.env.MYENV }"#, + result: Some(vec![Value::from("my env value")]), }] } } @@ -89,3 +90,15 @@ fn with_env(raw_args: CommandArgs, registry: &CommandRegistry) -> Result &[Example] { - &[ + fn examples(&self) -> Vec { + vec![ Example { description: "Wrap a list into a table with the default column name", example: "echo [1 2 3] | wrap", + result: Some(vec![ + UntaggedValue::row(indexmap! { + DEFAULT_COLUMN_NAME.to_string() => UntaggedValue::int(1).into(), + }) + .into(), + UntaggedValue::row(indexmap! { + DEFAULT_COLUMN_NAME.to_string() => UntaggedValue::int(2).into(), + }) + .into(), + UntaggedValue::row(indexmap! { + DEFAULT_COLUMN_NAME.to_string() => UntaggedValue::int(3).into(), + }) + .into(), + ]), }, Example { description: "Wrap a list into a table with a given column name", example: "echo [1 2 3] | wrap MyColumn", + result: Some(vec![ + UntaggedValue::row(indexmap! { + "MyColumn".to_string() => UntaggedValue::int(1).into(), + }) + .into(), + UntaggedValue::row(indexmap! { + "MyColumn".to_string() => UntaggedValue::int(2).into(), + }) + .into(), + UntaggedValue::row(indexmap! { + "MyColumn".to_string() => UntaggedValue::int(3).into(), + }) + .into(), + ]), }, ] } @@ -76,7 +106,7 @@ fn wrap(args: CommandArgs, registry: &CommandRegistry) -> Result key.item.clone(), - None => "Column".into(), + None => DEFAULT_COLUMN_NAME.to_string(), }, value, ); @@ -92,7 +122,7 @@ fn wrap(args: CommandArgs, registry: &CommandRegistry) -> Result key.item.clone(), - None => "Column".into(), + None => DEFAULT_COLUMN_NAME.to_string(), }, UntaggedValue::table(&result_table).into_value(Tag::unknown()), ); @@ -112,3 +142,15 @@ fn wrap(args: CommandArgs, registry: &CommandRegistry) -> Result Result { + let line = if line.ends_with('\n') { + &line[..line.len() - 1] + } else { + line + }; + + let lite_result = nu_parser::lite_parse(&line, 0)?; + + // TODO ensure the command whose examples we're testing is actually in the pipeline + let mut classified_block = nu_parser::classify_block(&lite_result, ctx.registry()); + classified_block.block.expand_it_usage(); + Ok(classified_block) +} + +async fn evaluate_block( + block: ClassifiedBlock, + ctx: &mut Context, +) -> Result, ShellError> { + let input_stream = InputStream::empty(); + let env = ctx.get_env(); + + Ok(run_block(&block.block, ctx, input_stream, &Scope::env(env)) + .await? + .into_vec() + .await) +} + +// TODO probably something already available to do this +// TODO perhaps better panic messages when things don't compare + +// Deep value comparisons that ignore tags +fn values_equal(expected: &Value, actual: &Value) -> bool { + use nu_protocol::UntaggedValue::*; + + match (&expected.value, &actual.value) { + (Primitive(e), Primitive(a)) => e == a, + (Row(e), Row(a)) => { + if e.entries.len() != a.entries.len() { + return false; + } + + e.entries + .iter() + .zip(a.entries.iter()) + .all(|((ek, ev), (ak, av))| ek == ak && values_equal(ev, av)) + } + (Table(e), Table(a)) => e.iter().zip(a.iter()).all(|(e, a)| values_equal(e, a)), + (e, a) => unimplemented!("{} {}", e.type_name(), a.type_name()), + } +} diff --git a/crates/nu-cli/src/lib.rs b/crates/nu-cli/src/lib.rs index 9ee6917832..e840095ca8 100644 --- a/crates/nu-cli/src/lib.rs +++ b/crates/nu-cli/src/lib.rs @@ -28,6 +28,9 @@ mod shell; mod stream; pub mod utils; +#[cfg(test)] +mod examples; + pub use crate::cli::{ cli, create_default_context, load_plugins, run_pipeline_standalone, run_vec_of_pipelines, }; diff --git a/crates/nu-cli/tests/main.rs b/crates/nu-cli/tests/main.rs index 03fcbf2b1d..022f79a0fe 100644 --- a/crates/nu-cli/tests/main.rs +++ b/crates/nu-cli/tests/main.rs @@ -1,3 +1,4 @@ +extern crate nu_cli; extern crate nu_test_support; mod commands; diff --git a/crates/nu-protocol/src/value.rs b/crates/nu-protocol/src/value.rs index 91ae29907b..b55c126dbf 100644 --- a/crates/nu-protocol/src/value.rs +++ b/crates/nu-protocol/src/value.rs @@ -359,11 +359,11 @@ impl Value { } } -impl Into for String { - fn into(self) -> Value { - let end = self.len(); +impl From for Value { + fn from(s: String) -> Value { + let end = s.len(); Value { - value: self.into(), + value: s.into(), tag: Tag { anchor: None, span: Span::new(0, end), @@ -372,17 +372,49 @@ impl Into for String { } } -impl Into for &str { - /// Convert a string slice into an UntaggedValue - fn into(self) -> UntaggedValue { - UntaggedValue::Primitive(Primitive::String(self.to_string())) +impl From<&str> for Value { + fn from(s: &str) -> Value { + let end = s.len(); + Value { + value: s.into(), + tag: Tag { + anchor: None, + span: Span::new(0, end), + }, + } } } -impl Into for Value { +impl From for UntaggedValue +where + T: Into, +{ + /// Convert a Primitive to an UntaggedValue + fn from(input: T) -> UntaggedValue { + UntaggedValue::Primitive(input.into()) + } +} + +impl From for UntaggedValue { + fn from(e: ShellError) -> Self { + UntaggedValue::Error(e) + } +} + +impl From for Value { + /// Convert an UntaggedValue into a Value with a default tag + fn from(value: UntaggedValue) -> Value { + Value { + value, + tag: Tag::default(), + } + } +} + +impl From for UntaggedValue { /// Convert a Value into an UntaggedValue - fn into(self) -> UntaggedValue { - self.value + fn from(v: Value) -> UntaggedValue { + v.value } } @@ -420,26 +452,6 @@ impl ShellTypeName for UntaggedValue { } } -impl From for UntaggedValue { - /// Convert a Primitive to an UntaggedValue - fn from(input: Primitive) -> UntaggedValue { - UntaggedValue::Primitive(input) - } -} - -impl From for UntaggedValue { - /// Convert a String to an UntaggedValue - fn from(input: String) -> UntaggedValue { - UntaggedValue::Primitive(Primitive::String(input)) - } -} - -impl From for UntaggedValue { - fn from(e: ShellError) -> Self { - UntaggedValue::Error(e) - } -} - impl num_traits::Zero for Value { fn zero() -> Self { Value { diff --git a/crates/nu-protocol/src/value/primitive.rs b/crates/nu-protocol/src/value/primitive.rs index d517901ccf..649af434a6 100644 --- a/crates/nu-protocol/src/value/primitive.rs +++ b/crates/nu-protocol/src/value/primitive.rs @@ -171,6 +171,20 @@ impl std::ops::Mul for Primitive { } } +impl From<&str> for Primitive { + /// Helper to convert from string slices to a primitive + fn from(s: &str) -> Primitive { + Primitive::String(s.to_string()) + } +} + +impl From for Primitive { + /// Helper to convert from Strings to a primitive + fn from(s: String) -> Primitive { + Primitive::String(s) + } +} + impl From for Primitive { /// Helper to convert from decimals to a Primitive value fn from(decimal: BigDecimal) -> Primitive {