From e530e7d654e9a8175fec10cdba8a698dffb54390 Mon Sep 17 00:00:00 2001 From: Qnbie <39221504+Qnbie@users.noreply.github.com> Date: Wed, 7 Aug 2024 22:20:33 +0200 Subject: [PATCH] Make the math commands const (#13566) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR closes [Issue #13482](https://github.com/nushell/nushell/issues/13482) # Description This PR tend to make all math function to be constant. # User-Facing Changes The math commands now can be used as constant methods. ### Some Example ``` > const MODE = [3 3 9 12 12 15] | math mode > $MODE ╭───┬────╮ │ 0 │ 3 │ │ 1 │ 12 │ ╰───┴────╯ > const LOG = [16 8 4] | math log 2 > $LOG ╭───┬──────╮ │ 0 │ 4.00 │ │ 1 │ 3.00 │ │ 2 │ 2.00 │ ╰───┴──────╯ > const VAR = [1 3 5] | math variance > $VAR 2.6666666666666665 ``` # Tests + Formatting Tests are added for all of the math command to test there constant behavior. I mostly focused on the actual user experience, not the correctness of the methods and algorithms. # After Submitting I think this change don't require any additional documentation. Feel free to correct me in this topic please. --- crates/nu-command/src/math/abs.rs | 17 ++++++++++ crates/nu-command/src/math/avg.rs | 13 ++++++++ crates/nu-command/src/math/ceil.rs | 21 ++++++++++++ crates/nu-command/src/math/floor.rs | 21 ++++++++++++ crates/nu-command/src/math/log.rs | 32 +++++++++++++++++++ crates/nu-command/src/math/max.rs | 13 ++++++++ crates/nu-command/src/math/median.rs | 13 ++++++++ crates/nu-command/src/math/min.rs | 13 ++++++++ crates/nu-command/src/math/mode.rs | 13 ++++++++ crates/nu-command/src/math/product.rs | 13 ++++++++ crates/nu-command/src/math/round.rs | 22 +++++++++++++ crates/nu-command/src/math/stddev.rs | 14 ++++++++ crates/nu-command/src/math/sum.rs | 13 ++++++++ crates/nu-command/src/math/variance.rs | 14 ++++++++ crates/nu-command/tests/commands/math/abs.rs | 7 ++++ crates/nu-command/tests/commands/math/avg.rs | 6 ++++ crates/nu-command/tests/commands/math/ceil.rs | 7 ++++ .../nu-command/tests/commands/math/floor.rs | 7 ++++ crates/nu-command/tests/commands/math/log.rs | 7 ++++ crates/nu-command/tests/commands/math/max.rs | 7 ++++ .../nu-command/tests/commands/math/median.rs | 6 ++++ crates/nu-command/tests/commands/math/min.rs | 7 ++++ crates/nu-command/tests/commands/math/mod.rs | 10 ++++++ crates/nu-command/tests/commands/math/mode.rs | 7 ++++ .../nu-command/tests/commands/math/product.rs | 7 ++++ .../nu-command/tests/commands/math/round.rs | 6 ++++ crates/nu-command/tests/commands/math/sqrt.rs | 6 ++++ .../nu-command/tests/commands/math/stddev.rs | 7 ++++ crates/nu-command/tests/commands/math/sum.rs | 6 ++++ .../tests/commands/math/variance.rs | 7 ++++ 30 files changed, 342 insertions(+) create mode 100644 crates/nu-command/tests/commands/math/abs.rs create mode 100644 crates/nu-command/tests/commands/math/ceil.rs create mode 100644 crates/nu-command/tests/commands/math/floor.rs create mode 100644 crates/nu-command/tests/commands/math/log.rs create mode 100644 crates/nu-command/tests/commands/math/max.rs create mode 100644 crates/nu-command/tests/commands/math/min.rs create mode 100644 crates/nu-command/tests/commands/math/mode.rs create mode 100644 crates/nu-command/tests/commands/math/product.rs create mode 100644 crates/nu-command/tests/commands/math/stddev.rs create mode 100644 crates/nu-command/tests/commands/math/variance.rs diff --git a/crates/nu-command/src/math/abs.rs b/crates/nu-command/src/math/abs.rs index b16097ba8d..86e913e3ee 100644 --- a/crates/nu-command/src/math/abs.rs +++ b/crates/nu-command/src/math/abs.rs @@ -34,6 +34,10 @@ impl Command for SubCommand { vec!["absolute", "modulus", "positive", "distance"] } + fn is_const(&self) -> bool { + true + } + fn run( &self, engine_state: &EngineState, @@ -45,6 +49,19 @@ impl Command for SubCommand { input.map(move |value| abs_helper(value, head), engine_state.signals()) } + fn run_const( + &self, + working_set: &StateWorkingSet, + call: &Call, + input: PipelineData, + ) -> Result { + let head = call.head; + input.map( + move |value| abs_helper(value, head), + working_set.permanent().signals(), + ) + } + fn examples(&self) -> Vec { vec![Example { description: "Compute absolute value of each number in a list of numbers", diff --git a/crates/nu-command/src/math/avg.rs b/crates/nu-command/src/math/avg.rs index 8b1b1640f0..fbc2aa327c 100644 --- a/crates/nu-command/src/math/avg.rs +++ b/crates/nu-command/src/math/avg.rs @@ -38,6 +38,10 @@ impl Command for SubCommand { vec!["average", "mean", "statistics"] } + fn is_const(&self) -> bool { + true + } + fn run( &self, _engine_state: &EngineState, @@ -48,6 +52,15 @@ impl Command for SubCommand { run_with_function(call, input, average) } + fn run_const( + &self, + _working_set: &StateWorkingSet, + call: &Call, + input: PipelineData, + ) -> Result { + run_with_function(call, input, average) + } + fn examples(&self) -> Vec { vec![ Example { diff --git a/crates/nu-command/src/math/ceil.rs b/crates/nu-command/src/math/ceil.rs index 0886ff0bc5..6a98e6da91 100644 --- a/crates/nu-command/src/math/ceil.rs +++ b/crates/nu-command/src/math/ceil.rs @@ -29,6 +29,10 @@ impl Command for SubCommand { vec!["ceiling", "round up", "rounding", "integer"] } + fn is_const(&self) -> bool { + true + } + fn run( &self, engine_state: &EngineState, @@ -44,6 +48,23 @@ impl Command for SubCommand { input.map(move |value| operate(value, head), engine_state.signals()) } + fn run_const( + &self, + working_set: &StateWorkingSet, + call: &Call, + input: PipelineData, + ) -> Result { + let head = call.head; + // This doesn't match explicit nulls + if matches!(input, PipelineData::Empty) { + return Err(ShellError::PipelineEmpty { dst_span: head }); + } + input.map( + move |value| operate(value, head), + working_set.permanent().signals(), + ) + } + fn examples(&self) -> Vec { vec![Example { description: "Apply the ceil function to a list of numbers", diff --git a/crates/nu-command/src/math/floor.rs b/crates/nu-command/src/math/floor.rs index c2b34c2cf9..cfd7a60981 100644 --- a/crates/nu-command/src/math/floor.rs +++ b/crates/nu-command/src/math/floor.rs @@ -29,6 +29,10 @@ impl Command for SubCommand { vec!["round down", "rounding", "integer"] } + fn is_const(&self) -> bool { + true + } + fn run( &self, engine_state: &EngineState, @@ -44,6 +48,23 @@ impl Command for SubCommand { input.map(move |value| operate(value, head), engine_state.signals()) } + fn run_const( + &self, + working_set: &StateWorkingSet, + call: &Call, + input: PipelineData, + ) -> Result { + let head = call.head; + // This doesn't match explicit nulls + if matches!(input, PipelineData::Empty) { + return Err(ShellError::PipelineEmpty { dst_span: head }); + } + input.map( + move |value| operate(value, head), + working_set.permanent().signals(), + ) + } + fn examples(&self) -> Vec { vec![Example { description: "Apply the floor function to a list of numbers", diff --git a/crates/nu-command/src/math/log.rs b/crates/nu-command/src/math/log.rs index 7a7e4bd27b..0ac967b3b2 100644 --- a/crates/nu-command/src/math/log.rs +++ b/crates/nu-command/src/math/log.rs @@ -34,6 +34,10 @@ impl Command for SubCommand { vec!["base", "exponent", "inverse", "euler"] } + fn is_const(&self) -> bool { + true + } + fn run( &self, engine_state: &EngineState, @@ -63,6 +67,34 @@ impl Command for SubCommand { ) } + fn run_const( + &self, + working_set: &StateWorkingSet, + call: &Call, + input: PipelineData, + ) -> Result { + let head = call.head; + let base: Spanned = call.req_const(working_set, 0)?; + + if base.item <= 0.0f64 { + return Err(ShellError::UnsupportedInput { + msg: "Base has to be greater 0".into(), + input: "value originates from here".into(), + msg_span: head, + input_span: base.span, + }); + } + // This doesn't match explicit nulls + if matches!(input, PipelineData::Empty) { + return Err(ShellError::PipelineEmpty { dst_span: head }); + } + let base = base.item; + input.map( + move |value| operate(value, head, base), + working_set.permanent().signals(), + ) + } + fn examples(&self) -> Vec { vec![ Example { diff --git a/crates/nu-command/src/math/max.rs b/crates/nu-command/src/math/max.rs index edda0526ed..ce88f4d244 100644 --- a/crates/nu-command/src/math/max.rs +++ b/crates/nu-command/src/math/max.rs @@ -35,6 +35,10 @@ impl Command for SubCommand { vec!["maximum", "largest"] } + fn is_const(&self) -> bool { + true + } + fn run( &self, _engine_state: &EngineState, @@ -45,6 +49,15 @@ impl Command for SubCommand { run_with_function(call, input, maximum) } + fn run_const( + &self, + _working_set: &StateWorkingSet, + call: &Call, + input: PipelineData, + ) -> Result { + run_with_function(call, input, maximum) + } + fn examples(&self) -> Vec { vec![ Example { diff --git a/crates/nu-command/src/math/median.rs b/crates/nu-command/src/math/median.rs index 32c4fd04a8..eeb3b4a199 100644 --- a/crates/nu-command/src/math/median.rs +++ b/crates/nu-command/src/math/median.rs @@ -32,6 +32,10 @@ impl Command for SubCommand { vec!["middle", "statistics"] } + fn is_const(&self) -> bool { + true + } + fn run( &self, _engine_state: &EngineState, @@ -42,6 +46,15 @@ impl Command for SubCommand { run_with_function(call, input, median) } + fn run_const( + &self, + _working_set: &StateWorkingSet, + call: &Call, + input: PipelineData, + ) -> Result { + run_with_function(call, input, median) + } + fn examples(&self) -> Vec { vec![ Example { diff --git a/crates/nu-command/src/math/min.rs b/crates/nu-command/src/math/min.rs index 5c7d43d4d8..4998a93a15 100644 --- a/crates/nu-command/src/math/min.rs +++ b/crates/nu-command/src/math/min.rs @@ -35,6 +35,10 @@ impl Command for SubCommand { vec!["minimum", "smallest"] } + fn is_const(&self) -> bool { + true + } + fn run( &self, _engine_state: &EngineState, @@ -45,6 +49,15 @@ impl Command for SubCommand { run_with_function(call, input, minimum) } + fn run_const( + &self, + _working_set: &StateWorkingSet, + call: &Call, + input: PipelineData, + ) -> Result { + run_with_function(call, input, minimum) + } + fn examples(&self) -> Vec { vec![ Example { diff --git a/crates/nu-command/src/math/mode.rs b/crates/nu-command/src/math/mode.rs index 7ce87ad842..6890e3f5b4 100644 --- a/crates/nu-command/src/math/mode.rs +++ b/crates/nu-command/src/math/mode.rs @@ -62,6 +62,10 @@ impl Command for SubCommand { vec!["common", "often"] } + fn is_const(&self) -> bool { + true + } + fn run( &self, _engine_state: &EngineState, @@ -72,6 +76,15 @@ impl Command for SubCommand { run_with_function(call, input, mode) } + fn run_const( + &self, + _working_set: &StateWorkingSet, + call: &Call, + input: PipelineData, + ) -> Result { + run_with_function(call, input, mode) + } + fn examples(&self) -> Vec { vec![ Example { diff --git a/crates/nu-command/src/math/product.rs b/crates/nu-command/src/math/product.rs index d42ede8150..2e457767bd 100644 --- a/crates/nu-command/src/math/product.rs +++ b/crates/nu-command/src/math/product.rs @@ -32,6 +32,10 @@ impl Command for SubCommand { vec!["times", "multiply", "x", "*"] } + fn is_const(&self) -> bool { + true + } + fn run( &self, _engine_state: &EngineState, @@ -42,6 +46,15 @@ impl Command for SubCommand { run_with_function(call, input, product) } + fn run_const( + &self, + _working_set: &StateWorkingSet, + call: &Call, + input: PipelineData, + ) -> Result { + run_with_function(call, input, product) + } + fn examples(&self) -> Vec { vec![ Example { diff --git a/crates/nu-command/src/math/round.rs b/crates/nu-command/src/math/round.rs index eafe669cf1..2faf7842d9 100644 --- a/crates/nu-command/src/math/round.rs +++ b/crates/nu-command/src/math/round.rs @@ -35,6 +35,10 @@ impl Command for SubCommand { vec!["approx", "closest", "nearest"] } + fn is_const(&self) -> bool { + true + } + fn run( &self, engine_state: &EngineState, @@ -54,6 +58,24 @@ impl Command for SubCommand { ) } + fn run_const( + &self, + working_set: &StateWorkingSet, + call: &Call, + input: PipelineData, + ) -> Result { + let precision_param: Option = call.get_flag_const(working_set, "precision")?; + let head = call.head; + // This doesn't match explicit nulls + if matches!(input, PipelineData::Empty) { + return Err(ShellError::PipelineEmpty { dst_span: head }); + } + input.map( + move |value| operate(value, head, precision_param), + working_set.permanent().signals(), + ) + } + fn examples(&self) -> Vec { vec![ Example { diff --git a/crates/nu-command/src/math/stddev.rs b/crates/nu-command/src/math/stddev.rs index d200275aa9..2e221e3b1f 100644 --- a/crates/nu-command/src/math/stddev.rs +++ b/crates/nu-command/src/math/stddev.rs @@ -41,6 +41,10 @@ impl Command for SubCommand { ] } + fn is_const(&self) -> bool { + true + } + fn run( &self, engine_state: &EngineState, @@ -52,6 +56,16 @@ impl Command for SubCommand { run_with_function(call, input, compute_stddev(sample)) } + fn run_const( + &self, + working_set: &StateWorkingSet, + call: &Call, + input: PipelineData, + ) -> Result { + let sample = call.has_flag_const(working_set, "sample")?; + run_with_function(call, input, compute_stddev(sample)) + } + fn examples(&self) -> Vec { vec![ Example { diff --git a/crates/nu-command/src/math/sum.rs b/crates/nu-command/src/math/sum.rs index 9a8285c6c5..cd4b6b4540 100644 --- a/crates/nu-command/src/math/sum.rs +++ b/crates/nu-command/src/math/sum.rs @@ -34,6 +34,10 @@ impl Command for SubCommand { vec!["plus", "add", "total", "+"] } + fn is_const(&self) -> bool { + true + } + fn run( &self, _engine_state: &EngineState, @@ -44,6 +48,15 @@ impl Command for SubCommand { run_with_function(call, input, summation) } + fn run_const( + &self, + _working_set: &StateWorkingSet, + call: &Call, + input: PipelineData, + ) -> Result { + run_with_function(call, input, summation) + } + fn examples(&self) -> Vec { vec![ Example { diff --git a/crates/nu-command/src/math/variance.rs b/crates/nu-command/src/math/variance.rs index a20a3f262a..7def47bb19 100644 --- a/crates/nu-command/src/math/variance.rs +++ b/crates/nu-command/src/math/variance.rs @@ -33,6 +33,10 @@ impl Command for SubCommand { vec!["deviation", "dispersion", "variation", "statistics"] } + fn is_const(&self) -> bool { + true + } + fn run( &self, engine_state: &EngineState, @@ -44,6 +48,16 @@ impl Command for SubCommand { run_with_function(call, input, compute_variance(sample)) } + fn run_const( + &self, + working_set: &StateWorkingSet, + call: &Call, + input: PipelineData, + ) -> Result { + let sample = call.has_flag_const(working_set, "sample")?; + run_with_function(call, input, compute_variance(sample)) + } + fn examples(&self) -> Vec { vec![ Example { diff --git a/crates/nu-command/tests/commands/math/abs.rs b/crates/nu-command/tests/commands/math/abs.rs new file mode 100644 index 0000000000..4d61c8ed11 --- /dev/null +++ b/crates/nu-command/tests/commands/math/abs.rs @@ -0,0 +1,7 @@ +use nu_test_support::nu; + +#[test] +fn const_abs() { + let actual = nu!("const ABS = -5.5 | math abs; $ABS"); + assert_eq!(actual.out, "5.5"); +} diff --git a/crates/nu-command/tests/commands/math/avg.rs b/crates/nu-command/tests/commands/math/avg.rs index 8e2f545071..744b2f6067 100644 --- a/crates/nu-command/tests/commands/math/avg.rs +++ b/crates/nu-command/tests/commands/math/avg.rs @@ -20,3 +20,9 @@ fn can_average_bytes() { assert_eq!(actual.out, "34985870"); } + +#[test] +fn const_avg() { + let actual = nu!("const AVG = [1 3 5] | math avg; $AVG"); + assert_eq!(actual.out, "3"); +} diff --git a/crates/nu-command/tests/commands/math/ceil.rs b/crates/nu-command/tests/commands/math/ceil.rs new file mode 100644 index 0000000000..760fb0a503 --- /dev/null +++ b/crates/nu-command/tests/commands/math/ceil.rs @@ -0,0 +1,7 @@ +use nu_test_support::nu; + +#[test] +fn const_ceil() { + let actual = nu!("const CEIL = 1.5 | math ceil; $CEIL"); + assert_eq!(actual.out, "2"); +} diff --git a/crates/nu-command/tests/commands/math/floor.rs b/crates/nu-command/tests/commands/math/floor.rs new file mode 100644 index 0000000000..91184c8f58 --- /dev/null +++ b/crates/nu-command/tests/commands/math/floor.rs @@ -0,0 +1,7 @@ +use nu_test_support::nu; + +#[test] +fn const_floor() { + let actual = nu!("const FLOOR = 15.5 | math floor; $FLOOR"); + assert_eq!(actual.out, "15"); +} diff --git a/crates/nu-command/tests/commands/math/log.rs b/crates/nu-command/tests/commands/math/log.rs new file mode 100644 index 0000000000..a8e54689b5 --- /dev/null +++ b/crates/nu-command/tests/commands/math/log.rs @@ -0,0 +1,7 @@ +use nu_test_support::nu; + +#[test] +fn const_log() { + let actual = nu!("const LOG = 16 | math log 2; $LOG"); + assert_eq!(actual.out, "4"); +} diff --git a/crates/nu-command/tests/commands/math/max.rs b/crates/nu-command/tests/commands/math/max.rs new file mode 100644 index 0000000000..cd940d3811 --- /dev/null +++ b/crates/nu-command/tests/commands/math/max.rs @@ -0,0 +1,7 @@ +use nu_test_support::nu; + +#[test] +fn const_max() { + let actual = nu!("const MAX = [1 3 5] | math max; $MAX"); + assert_eq!(actual.out, "5"); +} diff --git a/crates/nu-command/tests/commands/math/median.rs b/crates/nu-command/tests/commands/math/median.rs index a84adec686..5e118e3b06 100644 --- a/crates/nu-command/tests/commands/math/median.rs +++ b/crates/nu-command/tests/commands/math/median.rs @@ -35,3 +35,9 @@ fn median_mixed_numbers() { assert_eq!(actual.out, "-11.5") } + +#[test] +fn const_median() { + let actual = nu!("const MEDIAN = [1 3 5] | math median; $MEDIAN"); + assert_eq!(actual.out, "3"); +} diff --git a/crates/nu-command/tests/commands/math/min.rs b/crates/nu-command/tests/commands/math/min.rs new file mode 100644 index 0000000000..1384562c08 --- /dev/null +++ b/crates/nu-command/tests/commands/math/min.rs @@ -0,0 +1,7 @@ +use nu_test_support::nu; + +#[test] +fn const_min() { + let actual = nu!("const MIN = [1 3 5] | math min; $MIN"); + assert_eq!(actual.out, "1"); +} diff --git a/crates/nu-command/tests/commands/math/mod.rs b/crates/nu-command/tests/commands/math/mod.rs index 3b120f730a..7918b3262a 100644 --- a/crates/nu-command/tests/commands/math/mod.rs +++ b/crates/nu-command/tests/commands/math/mod.rs @@ -1,8 +1,18 @@ +mod abs; mod avg; +mod ceil; +mod floor; +mod log; +mod max; mod median; +mod min; +mod mode; +mod product; mod round; mod sqrt; +mod stddev; mod sum; +mod variance; use nu_test_support::{nu, pipeline}; diff --git a/crates/nu-command/tests/commands/math/mode.rs b/crates/nu-command/tests/commands/math/mode.rs new file mode 100644 index 0000000000..160d2b6897 --- /dev/null +++ b/crates/nu-command/tests/commands/math/mode.rs @@ -0,0 +1,7 @@ +use nu_test_support::nu; + +#[test] +fn const_avg() { + let actual = nu!("const MODE = [1 3 3 5] | math mode; $MODE"); + assert_eq!(actual.out, "╭───┬───╮│ 0 │ 3 │╰───┴───╯"); +} diff --git a/crates/nu-command/tests/commands/math/product.rs b/crates/nu-command/tests/commands/math/product.rs new file mode 100644 index 0000000000..f31ba9c6bc --- /dev/null +++ b/crates/nu-command/tests/commands/math/product.rs @@ -0,0 +1,7 @@ +use nu_test_support::nu; + +#[test] +fn const_product() { + let actual = nu!("const PROD = [1 3 5] | math product; $PROD"); + assert_eq!(actual.out, "15"); +} diff --git a/crates/nu-command/tests/commands/math/round.rs b/crates/nu-command/tests/commands/math/round.rs index b05bcf2d13..61a3199701 100644 --- a/crates/nu-command/tests/commands/math/round.rs +++ b/crates/nu-command/tests/commands/math/round.rs @@ -34,3 +34,9 @@ fn fails_with_wrong_input_type() { assert!(actual.err.contains("command doesn't support")) } + +#[test] +fn const_round() { + let actual = nu!("const ROUND = 18.345 | math round; $ROUND"); + assert_eq!(actual.out, "18"); +} diff --git a/crates/nu-command/tests/commands/math/sqrt.rs b/crates/nu-command/tests/commands/math/sqrt.rs index 655e0125d5..a0ba35b233 100644 --- a/crates/nu-command/tests/commands/math/sqrt.rs +++ b/crates/nu-command/tests/commands/math/sqrt.rs @@ -20,3 +20,9 @@ fn can_sqrt_perfect_square() { assert_eq!(actual.out, "2"); } + +#[test] +fn const_sqrt() { + let actual = nu!("const SQRT = 4 | math sqrt; $SQRT"); + assert_eq!(actual.out, "2"); +} diff --git a/crates/nu-command/tests/commands/math/stddev.rs b/crates/nu-command/tests/commands/math/stddev.rs new file mode 100644 index 0000000000..83fc472396 --- /dev/null +++ b/crates/nu-command/tests/commands/math/stddev.rs @@ -0,0 +1,7 @@ +use nu_test_support::nu; + +#[test] +fn const_avg() { + let actual = nu!("const SDEV = [1 2] | math stddev; $SDEV"); + assert_eq!(actual.out, "0.5"); +} diff --git a/crates/nu-command/tests/commands/math/sum.rs b/crates/nu-command/tests/commands/math/sum.rs index 327eadee11..048a12e9e3 100644 --- a/crates/nu-command/tests/commands/math/sum.rs +++ b/crates/nu-command/tests/commands/math/sum.rs @@ -77,3 +77,9 @@ fn sum_of_a_row_containing_a_table_is_an_error() { .err .contains("Attempted to compute the sum of a value that cannot be summed")); } + +#[test] +fn const_sum() { + let actual = nu!("const SUM = [1 3] | math sum; $SUM"); + assert_eq!(actual.out, "4"); +} diff --git a/crates/nu-command/tests/commands/math/variance.rs b/crates/nu-command/tests/commands/math/variance.rs new file mode 100644 index 0000000000..1e27484bf0 --- /dev/null +++ b/crates/nu-command/tests/commands/math/variance.rs @@ -0,0 +1,7 @@ +use nu_test_support::nu; + +#[test] +fn const_variance() { + let actual = nu!("const VAR = [1 2 3 4 5] | math variance; $VAR"); + assert_eq!(actual.out, "2"); +}