diff --git a/src/arguments.rs b/src/arguments.rs index 2c836d4..c8e8929 100644 --- a/src/arguments.rs +++ b/src/arguments.rs @@ -243,34 +243,35 @@ mod tests { use {super::*, clap::Parser, std::path::PathBuf}; #[test] - fn filename_only() { - let arguments = Arguments::parse_from(vec!["program", "file.txt"]); - - assert!(arguments.filename.is_some()); - assert!(arguments.expression.is_none()); - - assert_eq!(arguments.filename.unwrap(), PathBuf::from("file.txt")); + fn both_should_fail() { + assert!( + Arguments::try_parse_from(vec![ + "program", + "file.txt", + "--expression", + "1 + 2" + ]) + .is_err() + ); } #[test] - fn expression_only() { - let arguments = - Arguments::parse_from(vec!["program", "--expression", "1 + 2"]); - - assert!(arguments.filename.is_none()); - assert!(arguments.expression.is_some()); - - assert_eq!(arguments.expression.unwrap(), "1 + 2"); - } + fn conflict_error_message() { + let result = Arguments::try_parse_from(vec![ + "program", + "file.txt", + "--expression", + "1 + 2", + ]); - #[test] - fn expression_short_form() { - let arguments = Arguments::parse_from(vec!["program", "-e", "1 + 2"]); + assert!(result.is_err()); - assert!(arguments.filename.is_none()); - assert!(arguments.expression.is_some()); + let error = result.unwrap_err().to_string(); - assert_eq!(arguments.expression.unwrap(), "1 + 2"); + assert!( + error.contains("cannot be used with"), + "Error should mention conflicts: {error}" + ); } #[test] @@ -294,52 +295,34 @@ mod tests { } #[test] - fn nonzero_arguments_reject_zero() { - for argument in ["--precision", "--stack-size"] { - let result = Arguments::try_parse_from(vec!["program", argument, "0"]); + fn expression_only() { + let arguments = + Arguments::parse_from(vec!["program", "--expression", "1 + 2"]); - assert!(result.is_err()); - } - } + assert!(arguments.filename.is_none()); + assert!(arguments.expression.is_some()); - #[test] - fn both_should_fail() { - assert!( - Arguments::try_parse_from(vec![ - "program", - "file.txt", - "--expression", - "1 + 2" - ]) - .is_err() - ); + assert_eq!(arguments.expression.unwrap(), "1 + 2"); } #[test] - fn neither_provided() { - let arguments = Arguments::parse_from(vec!["program"]); + fn expression_short_form() { + let arguments = Arguments::parse_from(vec!["program", "-e", "1 + 2"]); assert!(arguments.filename.is_none()); - assert!(arguments.expression.is_none()); + assert!(arguments.expression.is_some()); + + assert_eq!(arguments.expression.unwrap(), "1 + 2"); } #[test] - fn conflict_error_message() { - let result = Arguments::try_parse_from(vec![ - "program", - "file.txt", - "--expression", - "1 + 2", - ]); - - assert!(result.is_err()); + fn filename_only() { + let arguments = Arguments::parse_from(vec!["program", "file.txt"]); - let error = result.unwrap_err().to_string(); + assert!(arguments.filename.is_some()); + assert!(arguments.expression.is_none()); - assert!( - error.contains("cannot be used with"), - "Error should mention conflicts: {error}" - ); + assert_eq!(arguments.filename.unwrap(), PathBuf::from("file.txt")); } #[test] @@ -360,4 +343,21 @@ mod tests { "Error should mention conflicts: {error}" ); } + + #[test] + fn neither_provided() { + let arguments = Arguments::parse_from(vec!["program"]); + + assert!(arguments.filename.is_none()); + assert!(arguments.expression.is_none()); + } + + #[test] + fn nonzero_arguments_reject_zero() { + for argument in ["--precision", "--stack-size"] { + let result = Arguments::try_parse_from(vec!["program", argument, "0"]); + + assert!(result.is_err()); + } + } } diff --git a/src/number.rs b/src/number.rs index 5678cb6..213910d 100644 --- a/src/number.rs +++ b/src/number.rs @@ -499,20 +499,6 @@ mod tests { assert_eq!(Number::Approx(Float::with_val(8, 23)).to_string(), "23"); } - #[test] - fn zero_precision_uses_minimum() { - let config = Config { - precision: 0, - ..Config::default() - }; - - let Number::Approx(number) = Number::e(config) else { - panic!("expected approximate number"); - }; - - assert_eq!(number.prec(), 1); - } - #[test] fn display_approx_rounded_large_integer() { assert_eq!( @@ -569,4 +555,18 @@ mod tests { assert!(approx < greater); assert!(greater > approx); } + + #[test] + fn zero_precision_uses_minimum() { + let config = Config { + precision: 0, + ..Config::default() + }; + + let Number::Approx(number) = Number::e(config) else { + panic!("expected approximate number"); + }; + + assert_eq!(number.prec(), 1); + } } diff --git a/src/parser.rs b/src/parser.rs index 9a53cde..f67f936 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -492,14 +492,6 @@ mod tests { Test::new().program("break").ast("statements(break)").run(); } - #[test] - fn continue_statement() { - Test::new() - .program("continue") - .ast("statements(continue)") - .run(); - } - #[test] fn comments() { Test::new() @@ -513,6 +505,14 @@ mod tests { .run(); } + #[test] + fn continue_statement() { + Test::new() + .program("continue") + .ast("statements(continue)") + .run(); + } + #[test] fn for_loop() { Test::new() @@ -734,19 +734,6 @@ mod tests { .run(); } - #[test] - fn return_statement() { - Test::new() - .program("return 5") - .ast("statements(return(number(5)))") - .run(); - - Test::new() - .program("return") - .ast("statements(return())") - .run(); - } - #[test] fn reserved_words_are_not_identifiers() { #[track_caller] @@ -774,6 +761,19 @@ mod tests { } } + #[test] + fn return_statement() { + Test::new() + .program("return 5") + .ast("statements(return(number(5)))") + .run(); + + Test::new() + .program("return") + .ast("statements(return())") + .run(); + } + #[test] fn unclosed_string() { Test::new() diff --git a/tests/integration.rs b/tests/integration.rs index bc913d3..7620364 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -748,6 +748,45 @@ fn comparison_with_expressions() -> Result { .run() } +#[test] +fn configured_digits() -> Result { + #[track_caller] + fn case(argument: &str) -> Result { + Test::new()? + .argument(argument) + .argument("4") + .program("println(2 / 5555222222222)") + .expected_status(0) + .expected_stdout(Exact("3.6e-13\n")) + .run() + } + + Test::new()? + .program("println(2 / 5555222222222)") + .expected_status(0) + .expected_stdout(Exact("3.600216012960922e-13\n")) + .run()?; + + case("--digits")?; + case("-d") +} + +#[test] +fn configured_digits_in_concatenation() -> Result { + Test::new()? + .argument("--digits") + .argument("4") + .program(indoc! { + " + value = 2 / 5555222222222 + println('value = ' + value) + println(value + ' = value') + " + }) + .expected_stdout(Exact("value = 3.6e-13\n3.6e-13 = value\n")) + .run() +} + #[test] fn continue_in_if_outside_loop() -> Result { Test::new()? @@ -937,46 +976,6 @@ fn division() -> Result { .run() } -#[test] -fn exact_decimal_arithmetic() -> Result { - Test::new()? - .program(indoc! { - " - a = 0.001 - - while (a < 1) { - a = a + 0.001 - } - - println(a) - " - }) - .expected_status(0) - .expected_stdout(Exact("1\n")) - .run()?; - - Test::new()? - .program("println(0.1 + 0.2)") - .expected_status(0) - .expected_stdout(Exact("0.3\n")) - .run() -} - -#[test] -fn exact_rational_arithmetic() -> Result { - Test::new()? - .program("println(1 / 3)") - .expected_status(0) - .expected_stdout(Exact("0.3333333333333333\n")) - .run()?; - - Test::new()? - .program("println((1 / 3) * 3)") - .expected_status(0) - .expected_stdout(Exact("1\n")) - .run() -} - #[test] fn division_by_zero() -> Result { Test::new()? @@ -1027,6 +1026,46 @@ fn equal_to() -> Result { .run() } +#[test] +fn exact_decimal_arithmetic() -> Result { + Test::new()? + .program(indoc! { + " + a = 0.001 + + while (a < 1) { + a = a + 0.001 + } + + println(a) + " + }) + .expected_status(0) + .expected_stdout(Exact("1\n")) + .run()?; + + Test::new()? + .program("println(0.1 + 0.2)") + .expected_status(0) + .expected_stdout(Exact("0.3\n")) + .run() +} + +#[test] +fn exact_rational_arithmetic() -> Result { + Test::new()? + .program("println(1 / 3)") + .expected_status(0) + .expected_stdout(Exact("0.3333333333333333\n")) + .run()?; + + Test::new()? + .program("println((1 / 3) * 3)") + .expected_status(0) + .expected_stdout(Exact("1\n")) + .run() +} + #[test] fn exit_or_quit() -> Result { Test::new()?.program("exit()").expected_status(0).run()?; @@ -1138,45 +1177,6 @@ fn float_literals() -> Result { .run() } -#[test] -fn configured_digits() -> Result { - #[track_caller] - fn case(argument: &str) -> Result { - Test::new()? - .argument(argument) - .argument("4") - .program("println(2 / 5555222222222)") - .expected_status(0) - .expected_stdout(Exact("3.6e-13\n")) - .run() - } - - Test::new()? - .program("println(2 / 5555222222222)") - .expected_status(0) - .expected_stdout(Exact("3.600216012960922e-13\n")) - .run()?; - - case("--digits")?; - case("-d") -} - -#[test] -fn configured_digits_in_concatenation() -> Result { - Test::new()? - .argument("--digits") - .argument("4") - .program(indoc! { - " - value = 2 / 5555222222222 - println('value = ' + value) - println(value + ' = value') - " - }) - .expected_stdout(Exact("value = 3.6e-13\n3.6e-13 = value\n")) - .run() -} - #[test] fn floor_function() -> Result { Test::new()? @@ -2245,21 +2245,6 @@ fn list_element_assignment_updates_value() -> Result { .run() } -#[test] -fn nested_list_element_assignment_updates_value() -> Result { - Test::new()? - .program(indoc! { - " - nums = [[1, 2], [3, 4]] - nums[1][0] = 5 - println(nums) - " - }) - .expected_status(0) - .expected_stdout(Exact("[[1, 2], [5, 4]]\n")) - .run() -} - #[test] fn list_literals() -> Result { Test::new()? @@ -2632,6 +2617,21 @@ fn nested_if_statements() -> Result { .run() } +#[test] +fn nested_list_element_assignment_updates_value() -> Result { + Test::new()? + .program(indoc! { + " + nums = [[1, 2], [3, 4]] + nums[1][0] = 5 + println(nums) + " + }) + .expected_status(0) + .expected_stdout(Exact("[[1, 2], [5, 4]]\n")) + .run() +} + #[test] fn nested_loops() -> Result { Test::new()?