From b3f1f4f6ffc16a64287031ae83bd97b773783a58 Mon Sep 17 00:00:00 2001 From: imxyy_soope_ Date: Sun, 22 Mar 2026 16:41:13 +0800 Subject: [PATCH] remove redundant tests --- fix/tests/tests/basic_eval.rs | 69 ------ fix/tests/tests/builtins.rs | 326 ----------------------------- fix/tests/tests/builtins_store.rs | 193 ----------------- fix/tests/tests/free_globals.rs | 74 ------- fix/tests/tests/functions.rs | 120 ----------- fix/tests/tests/io_operations.rs | 190 +++++++++++++++++ fix/tests/tests/main.rs | 11 - fix/tests/tests/numeric_types.rs | 138 ------------ fix/tests/tests/operators.rs | 144 ------------- fix/tests/tests/path_operations.rs | 117 ----------- fix/tests/tests/regex.rs | 317 ---------------------------- fix/tests/tests/thunk_scope.rs | 119 ----------- fix/tests/tests/to_string.rs | 256 ---------------------- fix/tests/tests/utils.rs | 7 + 14 files changed, 197 insertions(+), 1884 deletions(-) delete mode 100644 fix/tests/tests/basic_eval.rs delete mode 100644 fix/tests/tests/builtins.rs delete mode 100644 fix/tests/tests/builtins_store.rs delete mode 100644 fix/tests/tests/free_globals.rs delete mode 100644 fix/tests/tests/functions.rs delete mode 100644 fix/tests/tests/numeric_types.rs delete mode 100644 fix/tests/tests/operators.rs delete mode 100644 fix/tests/tests/path_operations.rs delete mode 100644 fix/tests/tests/regex.rs delete mode 100644 fix/tests/tests/thunk_scope.rs delete mode 100644 fix/tests/tests/to_string.rs diff --git a/fix/tests/tests/basic_eval.rs b/fix/tests/tests/basic_eval.rs deleted file mode 100644 index 5fd7f60..0000000 --- a/fix/tests/tests/basic_eval.rs +++ /dev/null @@ -1,69 +0,0 @@ -use fix::value::Value; - -use crate::utils::{eval, eval_result}; - -#[test_log::test] -fn arithmetic() { - assert_eq!(eval("1 + 1"), Value::Int(2)); -} - -#[test_log::test] -fn simple_function_application() { - assert_eq!(eval("(x: x) 1"), Value::Int(1)); -} - -#[test_log::test] -fn curried_function() { - assert_eq!(eval("(x: y: x - y) 2 1"), Value::Int(1)); -} - -#[test_log::test] -fn rec_attrset() { - assert_eq!(eval("rec { b = a; a = 1; }.b"), Value::Int(1)); -} - -#[test_log::test] -fn let_binding() { - assert_eq!(eval("let b = a; a = 1; in b"), Value::Int(1)); -} - -#[test_log::test] -fn fibonacci() { - assert_eq!( - eval( - "let fib = n: if n == 1 || n == 2 then 1 else (fib (n - 1)) + (fib (n - 2)); in fib 30" - ), - Value::Int(832040) - ); -} - -#[test_log::test] -fn fixed_point_combinator() { - assert_eq!( - eval("((f: let x = f x; in x)(self: { x = 1; y = self.x + 1; })).y"), - Value::Int(2) - ); -} - -#[test_log::test] -fn conditional_true() { - assert_eq!(eval("if true then 1 else 0"), Value::Int(1)); -} - -#[test_log::test] -fn conditional_false() { - assert_eq!(eval("if false then 1 else 0"), Value::Int(0)); -} - -#[test_log::test] -fn nested_let() { - assert_eq!( - eval("let x = 1; in let y = x + 1; z = y + 1; in z"), - Value::Int(3) - ); -} - -#[test_log::test] -fn rec_inherit_fails() { - assert!(eval_result("{ inherit x; }").is_err()); -} diff --git a/fix/tests/tests/builtins.rs b/fix/tests/tests/builtins.rs deleted file mode 100644 index c4af9c3..0000000 --- a/fix/tests/tests/builtins.rs +++ /dev/null @@ -1,326 +0,0 @@ -use std::collections::BTreeMap; - -use fix::value::{AttrSet, List, Value}; - -use crate::utils::eval; - -#[test_log::test] -fn builtins_accessible() { - let result = eval("builtins"); - assert!(matches!(result, Value::AttrSet(_))); -} - -#[test_log::test] -fn builtins_self_reference() { - let result = eval("builtins.builtins"); - assert!(matches!(result, Value::AttrSet(_))); -} - -#[test_log::test] -fn builtins_add() { - assert_eq!(eval("builtins.add 1 2"), Value::Int(3)); -} - -#[test_log::test] -fn builtins_length() { - assert_eq!(eval("builtins.length [1 2 3]"), Value::Int(3)); -} - -#[test_log::test] -fn builtins_map() { - assert_eq!( - eval("builtins.map (x: x * 2) [1 2 3]"), - Value::List(List::new(vec![Value::Int(2), Value::Int(4), Value::Int(6)])) - ); -} - -#[test_log::test] -fn builtins_filter() { - assert_eq!( - eval("builtins.filter (x: x > 1) [1 2 3]"), - Value::List(List::new(vec![Value::Int(2), Value::Int(3)])) - ); -} - -#[test_log::test] -fn builtins_attrnames() { - let result = eval("builtins.attrNames { a = 1; b = 2; }"); - assert!(matches!(result, Value::List(_))); - if let Value::List(list) = result { - assert_eq!(format!("{:?}", list).matches(',').count() + 1, 2); - } -} - -#[test_log::test] -fn builtins_head() { - assert_eq!(eval("builtins.head [1 2 3]"), Value::Int(1)); -} - -#[test_log::test] -fn builtins_tail() { - assert_eq!( - eval("builtins.tail [1 2 3]"), - Value::List(List::new(vec![Value::Int(2), Value::Int(3)])) - ); -} - -#[test_log::test] -fn builtins_in_let() { - assert_eq!(eval("let b = builtins; in b.add 5 3"), Value::Int(8)); -} - -#[test_log::test] -fn builtins_in_with() { - assert_eq!(eval("with builtins; add 10 20"), Value::Int(30)); -} - -#[test_log::test] -fn builtins_nested_calls() { - assert_eq!( - eval("builtins.add (builtins.mul 2 3) (builtins.sub 10 5)"), - Value::Int(11) - ); -} - -#[test_log::test] -fn builtins_is_list() { - assert_eq!(eval("builtins.isList [1 2 3]"), Value::Bool(true)); -} - -#[test_log::test] -fn builtins_is_attrs() { - assert_eq!(eval("builtins.isAttrs { a = 1; }"), Value::Bool(true)); -} - -#[test_log::test] -fn builtins_is_function() { - assert_eq!(eval("builtins.isFunction (x: x)"), Value::Bool(true)); -} - -#[test_log::test] -fn builtins_is_null() { - assert_eq!(eval("builtins.isNull null"), Value::Bool(true)); -} - -#[test_log::test] -fn builtins_is_bool() { - assert_eq!(eval("builtins.isBool true"), Value::Bool(true)); -} - -#[test_log::test] -fn builtins_shadowing() { - assert_eq!( - eval("let builtins = { add = x: y: x - y; }; in builtins.add 5 3"), - Value::Int(2) - ); -} - -#[test_log::test] -fn builtins_lazy_evaluation() { - let result = eval("builtins.builtins.builtins.add 1 1"); - assert_eq!(result, Value::Int(2)); -} - -#[test_log::test] -fn builtins_foldl() { - assert_eq!( - eval("builtins.foldl' (acc: x: acc + x) 0 [1 2 3 4 5]"), - Value::Int(15) - ); -} - -#[test_log::test] -fn builtins_elem() { - assert_eq!(eval("builtins.elem 2 [1 2 3]"), Value::Bool(true)); - assert_eq!(eval("builtins.elem 5 [1 2 3]"), Value::Bool(false)); -} - -#[test_log::test] -fn builtins_concat_lists() { - assert_eq!( - eval("builtins.concatLists [[1 2] [3 4] [5]]"), - Value::List(List::new(vec![ - Value::Int(1), - Value::Int(2), - Value::Int(3), - Value::Int(4), - Value::Int(5) - ])) - ); -} - -#[test_log::test] -fn builtins_compare_versions_basic() { - assert_eq!( - eval("builtins.compareVersions \"1.0\" \"2.3\""), - Value::Int(-1) - ); - assert_eq!( - eval("builtins.compareVersions \"2.1\" \"2.3\""), - Value::Int(-1) - ); - assert_eq!( - eval("builtins.compareVersions \"2.3\" \"2.3\""), - Value::Int(0) - ); - assert_eq!( - eval("builtins.compareVersions \"2.5\" \"2.3\""), - Value::Int(1) - ); - assert_eq!( - eval("builtins.compareVersions \"3.1\" \"2.3\""), - Value::Int(1) - ); -} - -#[test_log::test] -fn builtins_compare_versions_components() { - assert_eq!( - eval("builtins.compareVersions \"2.3.1\" \"2.3\""), - Value::Int(1) - ); - assert_eq!( - eval("builtins.compareVersions \"2.3\" \"2.3.1\""), - Value::Int(-1) - ); -} - -#[test_log::test] -fn builtins_compare_versions_numeric_vs_alpha() { - // Numeric component comes before alpha component - assert_eq!( - eval("builtins.compareVersions \"2.3.1\" \"2.3a\""), - Value::Int(1) - ); - assert_eq!( - eval("builtins.compareVersions \"2.3a\" \"2.3.1\""), - Value::Int(-1) - ); -} - -#[test_log::test] -fn builtins_compare_versions_pre() { - // "pre" is special: comes before everything except another "pre" - assert_eq!( - eval("builtins.compareVersions \"2.3pre1\" \"2.3\""), - Value::Int(-1) - ); - assert_eq!( - eval("builtins.compareVersions \"2.3pre3\" \"2.3pre12\""), - Value::Int(-1) - ); - assert_eq!( - eval("builtins.compareVersions \"2.3pre1\" \"2.3c\""), - Value::Int(-1) - ); - assert_eq!( - eval("builtins.compareVersions \"2.3pre1\" \"2.3q\""), - Value::Int(-1) - ); -} - -#[test_log::test] -fn builtins_compare_versions_alpha() { - // Alphabetic comparison - assert_eq!( - eval("builtins.compareVersions \"2.3a\" \"2.3c\""), - Value::Int(-1) - ); - assert_eq!( - eval("builtins.compareVersions \"2.3c\" \"2.3a\""), - Value::Int(1) - ); -} - -#[test_log::test] -fn builtins_compare_versions_symmetry() { - // Test symmetry: compareVersions(a, b) == -compareVersions(b, a) - assert_eq!( - eval("builtins.compareVersions \"1.0\" \"2.3\""), - Value::Int(-1) - ); - assert_eq!( - eval("builtins.compareVersions \"2.3\" \"1.0\""), - Value::Int(1) - ); -} - -#[test_log::test] -fn builtins_compare_versions_complex() { - // Complex version strings with multiple components - assert_eq!( - eval("builtins.compareVersions \"1.2.3.4\" \"1.2.3.5\""), - Value::Int(-1) - ); - assert_eq!( - eval("builtins.compareVersions \"1.2.10\" \"1.2.9\""), - Value::Int(1) - ); - assert_eq!( - eval("builtins.compareVersions \"1.2a3\" \"1.2a10\""), - Value::Int(-1) - ); -} - -#[test_log::test] -fn builtins_generic_closure() { - assert_eq!( - eval( - "with builtins; length (genericClosure { startSet = [ { key = 1; } ]; operator = { key }: [ { key = key / 1.; } ]; a = 1; })" - ), - Value::Int(1), - ); - assert_eq!( - eval( - "with builtins; (elemAt (genericClosure { startSet = [ { key = 1; } ]; operator = { key }: [ { key = key / 1.; } ]; a = 1; }) 0).key" - ), - Value::Int(1), - ); -} - -#[test_log::test] -fn builtins_function_args() { - assert_eq!( - eval("builtins.functionArgs (x: 1)"), - Value::AttrSet(AttrSet::default()) - ); - assert_eq!( - eval("builtins.functionArgs ({}: 1)"), - Value::AttrSet(AttrSet::default()) - ); - assert_eq!( - eval("builtins.functionArgs ({...}: 1)"), - Value::AttrSet(AttrSet::default()) - ); - assert_eq!( - eval("builtins.functionArgs ({a}: 1)"), - Value::AttrSet(AttrSet::new(BTreeMap::from([( - "a".into(), - Value::Bool(false) - )]))) - ); - assert_eq!( - eval("builtins.functionArgs ({a, b ? 1}: 1)"), - Value::AttrSet(AttrSet::new(BTreeMap::from([ - ("a".into(), Value::Bool(false)), - ("b".into(), Value::Bool(true)) - ]))) - ); - assert_eq!( - eval("builtins.functionArgs ({a, b ? 1, ...}: 1)"), - Value::AttrSet(AttrSet::new(BTreeMap::from([ - ("a".into(), Value::Bool(false)), - ("b".into(), Value::Bool(true)) - ]))) - ); -} - -#[test_log::test] -fn builtins_parse_drv_name() { - let result = eval(r#"builtins.parseDrvName "nix-js-0.1.0pre""#).unwrap_attr_set(); - assert_eq!(result.get("name"), Some(&Value::String("nix-js".into()))); - assert_eq!( - result.get("version"), - Some(&Value::String("0.1.0pre".into())) - ); -} diff --git a/fix/tests/tests/builtins_store.rs b/fix/tests/tests/builtins_store.rs deleted file mode 100644 index 224cb49..0000000 --- a/fix/tests/tests/builtins_store.rs +++ /dev/null @@ -1,193 +0,0 @@ -use fix::value::Value; - -use crate::utils::eval_result; - -#[test_log::test] -fn to_file_simple() { - let result = - eval_result(r#"builtins.toFile "hello.txt" "Hello, World!""#).expect("Failed to evaluate"); - - match result { - Value::String(path) => { - assert!(path.contains("-hello.txt")); - assert!(std::path::Path::new(&path).exists()); - - let contents = std::fs::read_to_string(&path).expect("Failed to read file"); - assert_eq!(contents, "Hello, World!"); - } - _ => panic!("Expected string, got {:?}", result), - } -} - -#[test_log::test] -fn to_file_with_references() { - let result = eval_result( - r#" - let - dep = builtins.toFile "dep.txt" "dependency"; - in - builtins.toFile "main.txt" "Reference: ${dep}" - "#, - ) - .expect("Failed to evaluate"); - - match result { - Value::String(path) => { - assert!(path.contains("-main.txt")); - let contents = std::fs::read_to_string(&path).expect("Failed to read file"); - assert!(contents.contains("Reference: ")); - assert!(contents.contains("-dep.txt")); - } - _ => panic!("Expected string"), - } -} - -#[test_log::test] -fn to_file_invalid_name_with_slash() { - let result = eval_result(r#"builtins.toFile "foo/bar.txt" "content""#); - - assert!(result.is_err()); - assert!( - result - .unwrap_err() - .to_string() - .contains("name cannot contain '/'") - ); -} - -#[test_log::test] -fn to_file_invalid_name_dot() { - let result = eval_result(r#"builtins.toFile "." "content""#); - - assert!(result.is_err()); - assert!(result.unwrap_err().to_string().contains("invalid name")); -} - -#[test_log::test] -fn to_file_invalid_name_dotdot() { - let result = eval_result(r#"builtins.toFile ".." "content""#); - - assert!(result.is_err()); - assert!(result.unwrap_err().to_string().contains("invalid name")); -} - -#[test_log::test] -fn store_path_validation_not_in_store() { - let result = eval_result(r#"builtins.storePath "/tmp/foo""#); - - assert!(result.is_err()); - assert!( - result - .unwrap_err() - .to_string() - .contains("not in the Nix store") - ); -} - -#[test_log::test] -fn store_path_validation_malformed_hash() { - let dummy_file_result = eval_result(r#"builtins.toFile "dummy.txt" "content""#) - .expect("Failed to create dummy file"); - - let dummy_path = match dummy_file_result { - Value::String(ref p) => p.clone(), - _ => panic!("Expected string"), - }; - - let store_dir = std::path::Path::new(&dummy_path) - .parent() - .expect("Failed to get parent dir") - .to_str() - .expect("Failed to convert to string"); - - let test_path = format!("{}/invalid-hash-hello", store_dir); - let result = eval_result(&format!(r#"builtins.storePath "{}""#, test_path)); - - assert!(result.is_err()); - let err_str = result.unwrap_err().to_string(); - assert!( - err_str.contains("invalid") || err_str.contains("hash"), - "Expected hash validation error, got: {}", - err_str - ); -} - -#[test_log::test] -fn store_path_validation_missing_name() { - let dummy_file_result = eval_result(r#"builtins.toFile "dummy.txt" "content""#) - .expect("Failed to create dummy file"); - - let dummy_path = match dummy_file_result { - Value::String(ref p) => p.clone(), - _ => panic!("Expected string"), - }; - - let store_dir = std::path::Path::new(&dummy_path) - .parent() - .expect("Failed to get parent dir") - .to_str() - .expect("Failed to convert to string"); - - let test_path = format!("{}/abcd1234abcd1234abcd1234abcd1234", store_dir); - let result = eval_result(&format!(r#"builtins.storePath "{}""#, test_path)); - - assert!(result.is_err()); - let err_str = result.unwrap_err().to_string(); - assert!( - err_str.contains("missing name") || err_str.contains("format"), - "Expected missing name error, got: {}", - err_str - ); -} - -#[test_log::test] -fn to_file_curried_application() { - let result = eval_result( - r#" - let - makeFile = builtins.toFile "test.txt"; - in - makeFile "test content" - "#, - ) - .expect("Failed to evaluate"); - - match result { - Value::String(path) => { - assert!(path.contains("-test.txt")); - let contents = std::fs::read_to_string(&path).expect("Failed to read file"); - assert_eq!(contents, "test content"); - } - _ => panic!("Expected string"), - } -} - -#[test_log::test] -fn to_file_number_conversion() { - let result = eval_result(r#"builtins.toFile "number.txt" (builtins.toString 42)"#) - .expect("Failed to evaluate"); - - match result { - Value::String(path) => { - let contents = std::fs::read_to_string(&path).expect("Failed to read file"); - assert_eq!(contents, "42"); - } - _ => panic!("Expected string"), - } -} - -#[test_log::test] -fn to_file_list_conversion() { - let result = eval_result( - r#"builtins.toFile "list.txt" (builtins.concatStringsSep "\n" ["line1" "line2" "line3"])"#, - ) - .expect("Failed to evaluate"); - - match result { - Value::String(path) => { - let contents = std::fs::read_to_string(&path).expect("Failed to read file"); - assert_eq!(contents, "line1\nline2\nline3"); - } - _ => panic!("Expected string"), - } -} diff --git a/fix/tests/tests/free_globals.rs b/fix/tests/tests/free_globals.rs deleted file mode 100644 index 1eebca5..0000000 --- a/fix/tests/tests/free_globals.rs +++ /dev/null @@ -1,74 +0,0 @@ -use fix::value::{List, Value}; - -use crate::utils::{eval, eval_result}; - -#[test_log::test] -fn true_literal() { - assert_eq!(eval("true"), Value::Bool(true)); -} - -#[test_log::test] -fn false_literal() { - assert_eq!(eval("false"), Value::Bool(false)); -} - -#[test_log::test] -fn null_literal() { - assert_eq!(eval("null"), Value::Null); -} - -#[test_log::test] -fn map_function() { - assert_eq!( - eval("map (x: x * 2) [1 2 3]"), - Value::List(List::new(vec![Value::Int(2), Value::Int(4), Value::Int(6)])) - ); -} - -#[test_log::test] -fn is_null_function() { - assert_eq!(eval("isNull null"), Value::Bool(true)); - assert_eq!(eval("isNull 5"), Value::Bool(false)); -} - -#[test_log::test] -fn shadow_true() { - assert_eq!(eval("let true = false; in true"), Value::Bool(false)); -} - -#[test_log::test] -fn shadow_map() { - assert_eq!(eval("let map = x: y: x; in map 1 2"), Value::Int(1)); -} - -#[test_log::test] -fn mixed_usage() { - assert_eq!( - eval("if true then map (x: x + 1) [1 2] else []"), - Value::List(List::new(vec![Value::Int(2), Value::Int(3)])) - ); -} - -#[test_log::test] -fn in_let_bindings() { - assert_eq!( - eval("let x = true; y = false; in x && y"), - Value::Bool(false) - ); -} - -#[test_log::test] -fn shadow_in_function() { - assert_eq!(eval("(true: true) false"), Value::Bool(false)); -} - -#[test_log::test] -fn throw_function() { - let result = eval_result("throw \"error message\""); - assert!(result.is_err()); -} - -#[test_log::test] -fn to_string_function() { - assert_eq!(eval("toString 42"), Value::String("42".to_string())); -} diff --git a/fix/tests/tests/functions.rs b/fix/tests/tests/functions.rs deleted file mode 100644 index b354c57..0000000 --- a/fix/tests/tests/functions.rs +++ /dev/null @@ -1,120 +0,0 @@ -use fix::value::Value; - -use crate::utils::{eval, eval_result}; - -#[test_log::test] -fn required_parameters() { - assert_eq!(eval("({ a, b }: a + b) { a = 1; b = 2; }"), Value::Int(3)); -} - -#[test_log::test] -fn missing_required_parameter() { - let result = eval_result("({ a, b }: a + b) { a = 1; }"); - assert!(result.is_err()); -} - -#[test_log::test] -fn all_required_parameters_present() { - assert_eq!( - eval("({ x, y, z }: x + y + z) { x = 1; y = 2; z = 3; }"), - Value::Int(6) - ); -} - -#[test_log::test] -fn reject_unexpected_arguments() { - let result = eval_result("({ a, b }: a + b) { a = 1; b = 2; c = 3; }"); - assert!(result.is_err()); -} - -#[test_log::test] -fn ellipsis_accepts_extra_arguments() { - assert_eq!( - eval("({ a, b, ... }: a + b) { a = 1; b = 2; c = 3; }"), - Value::Int(3) - ); -} - -#[test_log::test] -fn default_parameters() { - assert_eq!(eval("({ a, b ? 5 }: a + b) { a = 1; }"), Value::Int(6)); -} - -#[test_log::test] -fn override_default_parameter() { - assert_eq!( - eval("({ a, b ? 5 }: a + b) { a = 1; b = 10; }"), - Value::Int(11) - ); -} - -#[test_log::test] -fn at_pattern_alias() { - assert_eq!( - eval("(args@{ a, b }: args.a + args.b) { a = 1; b = 2; }"), - Value::Int(3) - ); -} - -#[test_log::test] -fn simple_parameter_no_validation() { - assert_eq!(eval("(x: x.a + x.b) { a = 1; b = 2; }"), Value::Int(3)); -} - -#[test_log::test] -fn simple_parameter_accepts_any_argument() { - assert_eq!(eval("(x: x) 42"), Value::Int(42)); -} - -#[test_log::test] -fn nested_function_parameters() { - assert_eq!( - eval("({ a }: { b }: a + b) { a = 5; } { b = 3; }"), - Value::Int(8) - ); -} - -#[test_log::test] -fn pattern_param_simple_reference_in_default() { - assert_eq!(eval("({ a, b ? a }: b) { a = 10; }"), Value::Int(10)); -} - -#[test_log::test] -fn pattern_param_multiple_references_in_default() { - assert_eq!( - eval("({ a, b ? a + 5, c ? 1 }: b + c) { a = 10; }"), - Value::Int(16) - ); -} - -#[test_log::test] -fn pattern_param_mutual_reference() { - assert_eq!( - eval("({ a, b ? c + 1, c ? 5 }: b) { a = 1; }"), - Value::Int(6) - ); -} - -#[test_log::test] -fn pattern_param_override_mutual_reference() { - assert_eq!( - eval("({ a, b ? c + 1, c ? 5 }: b) { a = 1; c = 10; }"), - Value::Int(11) - ); -} - -#[test_log::test] -fn pattern_param_reference_list() { - assert_eq!( - eval("({ a, b ? [ a 2 ] }: builtins.elemAt b 0) { a = 42; }"), - Value::Int(42) - ); -} - -#[test_log::test] -fn pattern_param_alias_in_default() { - assert_eq!( - eval("(args@{ a, b ? args.a + 10 }: b) { a = 5; }"), - Value::Int(15) - ); -} diff --git a/fix/tests/tests/io_operations.rs b/fix/tests/tests/io_operations.rs index db48494..1fb0e1c 100644 --- a/fix/tests/tests/io_operations.rs +++ b/fix/tests/tests/io_operations.rs @@ -366,3 +366,193 @@ fn read_dir_on_file_fails() { let err_msg = result.unwrap_err().to_string(); assert!(err_msg.contains("not a directory")); } + +#[test_log::test] +fn to_file_simple() { + let result = + eval_result(r#"builtins.toFile "hello.txt" "Hello, World!""#).expect("Failed to evaluate"); + + match result { + Value::String(path) => { + assert!(path.contains("-hello.txt")); + assert!(std::path::Path::new(&path).exists()); + + let contents = std::fs::read_to_string(&path).expect("Failed to read file"); + assert_eq!(contents, "Hello, World!"); + } + _ => panic!("Expected string, got {:?}", result), + } +} + +#[test_log::test] +fn to_file_with_references() { + let result = eval_result( + r#" + let + dep = builtins.toFile "dep.txt" "dependency"; + in + builtins.toFile "main.txt" "Reference: ${dep}" + "#, + ) + .expect("Failed to evaluate"); + + match result { + Value::String(path) => { + assert!(path.contains("-main.txt")); + let contents = std::fs::read_to_string(&path).expect("Failed to read file"); + assert!(contents.contains("Reference: ")); + assert!(contents.contains("-dep.txt")); + } + _ => panic!("Expected string"), + } +} + +#[test_log::test] +fn to_file_invalid_name_with_slash() { + let result = eval_result(r#"builtins.toFile "foo/bar.txt" "content""#); + + assert!(result.is_err()); + assert!( + result + .unwrap_err() + .to_string() + .contains("name cannot contain '/'") + ); +} + +#[test_log::test] +fn to_file_invalid_name_dot() { + let result = eval_result(r#"builtins.toFile "." "content""#); + + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("invalid name")); +} + +#[test_log::test] +fn to_file_invalid_name_dotdot() { + let result = eval_result(r#"builtins.toFile ".." "content""#); + + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("invalid name")); +} + +#[test_log::test] +fn store_path_validation_not_in_store() { + let result = eval_result(r#"builtins.storePath "/tmp/foo""#); + + assert!(result.is_err()); + assert!( + result + .unwrap_err() + .to_string() + .contains("not in the Nix store") + ); +} + +#[test_log::test] +fn store_path_validation_malformed_hash() { + let dummy_file_result = eval_result(r#"builtins.toFile "dummy.txt" "content""#) + .expect("Failed to create dummy file"); + + let dummy_path = match dummy_file_result { + Value::String(ref p) => p.clone(), + _ => panic!("Expected string"), + }; + + let store_dir = std::path::Path::new(&dummy_path) + .parent() + .expect("Failed to get parent dir") + .to_str() + .expect("Failed to convert to string"); + + let test_path = format!("{}/invalid-hash-hello", store_dir); + let result = eval_result(&format!(r#"builtins.storePath "{}""#, test_path)); + + assert!(result.is_err()); + let err_str = result.unwrap_err().to_string(); + assert!( + err_str.contains("invalid") || err_str.contains("hash"), + "Expected hash validation error, got: {}", + err_str + ); +} + +#[test_log::test] +fn store_path_validation_missing_name() { + let dummy_file_result = eval_result(r#"builtins.toFile "dummy.txt" "content""#) + .expect("Failed to create dummy file"); + + let dummy_path = match dummy_file_result { + Value::String(ref p) => p.clone(), + _ => panic!("Expected string"), + }; + + let store_dir = std::path::Path::new(&dummy_path) + .parent() + .expect("Failed to get parent dir") + .to_str() + .expect("Failed to convert to string"); + + let test_path = format!("{}/abcd1234abcd1234abcd1234abcd1234", store_dir); + let result = eval_result(&format!(r#"builtins.storePath "{}""#, test_path)); + + assert!(result.is_err()); + let err_str = result.unwrap_err().to_string(); + assert!( + err_str.contains("missing name") || err_str.contains("format"), + "Expected missing name error, got: {}", + err_str + ); +} + +#[test_log::test] +fn to_file_curried_application() { + let result = eval_result( + r#" + let + makeFile = builtins.toFile "test.txt"; + in + makeFile "test content" + "#, + ) + .expect("Failed to evaluate"); + + match result { + Value::String(path) => { + assert!(path.contains("-test.txt")); + let contents = std::fs::read_to_string(&path).expect("Failed to read file"); + assert_eq!(contents, "test content"); + } + _ => panic!("Expected string"), + } +} + +#[test_log::test] +fn to_file_number_conversion() { + let result = eval_result(r#"builtins.toFile "number.txt" (builtins.toString 42)"#) + .expect("Failed to evaluate"); + + match result { + Value::String(path) => { + let contents = std::fs::read_to_string(&path).expect("Failed to read file"); + assert_eq!(contents, "42"); + } + _ => panic!("Expected string"), + } +} + +#[test_log::test] +fn to_file_list_conversion() { + let result = eval_result( + r#"builtins.toFile "list.txt" (builtins.concatStringsSep "\n" ["line1" "line2" "line3"])"#, + ) + .expect("Failed to evaluate"); + + match result { + Value::String(path) => { + let contents = std::fs::read_to_string(&path).expect("Failed to read file"); + assert_eq!(contents, "line1\nline2\nline3"); + } + _ => panic!("Expected string"), + } +} diff --git a/fix/tests/tests/main.rs b/fix/tests/tests/main.rs index 1f3b52c..65f11db 100644 --- a/fix/tests/tests/main.rs +++ b/fix/tests/tests/main.rs @@ -1,17 +1,6 @@ -mod basic_eval; -mod builtins; -mod builtins_store; mod derivation; mod findfile; -mod free_globals; -mod functions; mod io_operations; mod lang; -mod numeric_types; -mod operators; -mod path_operations; -mod regex; mod string_context; -mod thunk_scope; -mod to_string; mod utils; diff --git a/fix/tests/tests/numeric_types.rs b/fix/tests/tests/numeric_types.rs deleted file mode 100644 index 14a1151..0000000 --- a/fix/tests/tests/numeric_types.rs +++ /dev/null @@ -1,138 +0,0 @@ -use fix::value::Value; - -use crate::utils::eval; - -#[test_log::test] -fn large_i64_max() { - assert_eq!(eval("9223372036854775807"), Value::Int(9223372036854775807)); -} - -#[test_log::test] -fn large_i64_negative() { - assert_eq!( - eval("-9223372036854775807"), - Value::Int(-9223372036854775807) - ); -} - -#[test_log::test] -fn large_number_arithmetic() { - assert_eq!( - eval("5000000000000000000 + 3000000000000000000"), - Value::Int(8000000000000000000i64) - ); -} - -#[test_log::test] -fn is_int_with_int() { - assert_eq!(eval("builtins.isInt 42"), Value::Bool(true)); -} - -#[test_log::test] -fn is_int_with_float() { - assert_eq!(eval("builtins.isInt 42.0"), Value::Bool(false)); -} - -#[test_log::test] -fn is_float_with_int() { - assert_eq!(eval("builtins.isFloat 42"), Value::Bool(false)); -} - -#[test_log::test] -fn is_float_with_float() { - assert_eq!(eval("builtins.isFloat 42.5"), Value::Bool(true)); - assert_eq!(eval("builtins.isFloat 1.0"), Value::Bool(true)); -} - -#[test_log::test] -fn typeof_int() { - assert_eq!(eval("builtins.typeOf 1"), Value::String("int".to_string())); -} - -#[test_log::test] -fn typeof_float() { - assert_eq!( - eval("builtins.typeOf 1.0"), - Value::String("float".to_string()) - ); - assert_eq!( - eval("builtins.typeOf 3.14"), - Value::String("float".to_string()) - ); -} - -#[test_log::test] -fn int_literal() { - assert_eq!(eval("1"), Value::Int(1)); -} - -#[test_log::test] -fn float_literal() { - assert_eq!(eval("1."), Value::Float(1.)); -} - -#[test_log::test] -fn int_plus_int() { - assert_eq!( - eval("builtins.typeOf (1 + 2)"), - Value::String("int".to_string()) - ); -} - -#[test_log::test] -fn int_plus_float() { - assert_eq!( - eval("builtins.typeOf (1 + 2.0)"), - Value::String("float".to_string()) - ); -} - -#[test_log::test] -fn int_times_int() { - assert_eq!( - eval("builtins.typeOf (3 * 4)"), - Value::String("int".to_string()) - ); -} - -#[test_log::test] -fn int_times_float() { - assert_eq!( - eval("builtins.typeOf (3 * 4.0)"), - Value::String("float".to_string()) - ); -} - -#[test_log::test] -fn integer_division() { - assert_eq!(eval("5 / 2"), Value::Int(2)); - assert_eq!(eval("7 / 3"), Value::Int(2)); - assert_eq!(eval("10 / 3"), Value::Int(3)); -} - -#[test_log::test] -fn float_division() { - assert_eq!(eval("5 / 2.0"), Value::Float(2.5)); - assert_eq!(eval("7.0 / 2"), Value::Float(3.5)); -} - -#[test_log::test] -fn negative_integer_division() { - assert_eq!(eval("(-7) / 3"), Value::Int(-2)); -} - -#[test_log::test] -fn builtin_add_with_large_numbers() { - assert_eq!( - eval("builtins.add 5000000000000000000 3000000000000000000"), - Value::Int(8000000000000000000i64) - ); -} - -#[test_log::test] -fn builtin_mul_with_large_numbers() { - assert_eq!( - eval("builtins.mul 1000000000 1000000000"), - Value::Int(1000000000000000000i64) - ); -} diff --git a/fix/tests/tests/operators.rs b/fix/tests/tests/operators.rs deleted file mode 100644 index 8438f7e..0000000 --- a/fix/tests/tests/operators.rs +++ /dev/null @@ -1,144 +0,0 @@ -use std::collections::BTreeMap; - -use fix::value::{AttrSet, List, Symbol, Value}; - -use crate::utils::eval; - -#[test_log::test] -fn addition() { - assert_eq!(eval("1 + 1"), Value::Int(2)); -} - -#[test_log::test] -fn subtraction() { - assert_eq!(eval("2 - 1"), Value::Int(1)); -} - -#[test_log::test] -fn multiplication() { - assert_eq!(eval("1. * 1"), Value::Float(1.)); -} - -#[test_log::test] -fn division() { - assert_eq!(eval("1 / 1."), Value::Float(1.)); -} - -#[test_log::test] -fn equality() { - assert_eq!(eval("1 == 1"), Value::Bool(true)); -} - -#[test_log::test] -fn inequality() { - assert_eq!(eval("1 != 1"), Value::Bool(false)); -} - -#[test_log::test] -fn less_than() { - assert_eq!(eval("2 < 1"), Value::Bool(false)); -} - -#[test_log::test] -fn greater_than() { - assert_eq!(eval("2 > 1"), Value::Bool(true)); -} - -#[test_log::test] -fn less_than_or_equal() { - assert_eq!(eval("1 <= 1"), Value::Bool(true)); -} - -#[test_log::test] -fn greater_than_or_equal() { - assert_eq!(eval("1 >= 1"), Value::Bool(true)); -} - -#[test_log::test] -fn logical_or_short_circuit() { - assert_eq!(eval("true || (1 / 0)"), Value::Bool(true)); -} - -#[test_log::test] -fn logical_and() { - assert_eq!(eval("true && 1 == 0"), Value::Bool(false)); -} - -#[test_log::test] -fn list_concatenation() { - assert_eq!( - eval("[ 1 2 3 ] ++ [ 4 5 6 ]"), - Value::List(List::new((1..=6).map(Value::Int).collect())) - ); -} - -#[test_log::test] -fn attrset_update() { - assert_eq!( - eval("{ a.b = 1; b = 2; } // { a.c = 2; }"), - Value::AttrSet(AttrSet::new(BTreeMap::from([ - ( - Symbol::from("a"), - Value::AttrSet(AttrSet::new(BTreeMap::from([( - Symbol::from("c"), - Value::Int(2), - )]))), - ), - (Symbol::from("b"), Value::Int(2)), - ]))) - ); -} - -#[test_log::test] -fn unary_negation() { - assert_eq!(eval("-5"), Value::Int(-5)); -} - -#[test_log::test] -fn logical_not() { - assert_eq!(eval("!true"), Value::Bool(false)); - assert_eq!(eval("!false"), Value::Bool(true)); -} - -#[test_log::test] -fn select_with_default_lazy_evaluation() { - assert_eq!(eval("{ a = 1; }.a or (1 / 0)"), Value::Int(1)); -} - -#[test_log::test] -fn select_with_default_nested_lazy() { - assert_eq!( - eval("{ a.b = 42; }.a.b or (builtins.abort \"should not evaluate\")"), - Value::Int(42) - ); -} - -#[test_log::test] -fn select_with_default_fallback() { - assert_eq!(eval("{ a = 1; }.b or 999"), Value::Int(999)); -} - -#[test_log::test] -fn implication_false_false() { - assert_eq!(eval("false -> false"), Value::Bool(true)); -} - -#[test_log::test] -fn implication_false_true() { - assert_eq!(eval("false -> true"), Value::Bool(true)); -} - -#[test_log::test] -fn implication_true_false() { - assert_eq!(eval("true -> false"), Value::Bool(false)); -} - -#[test_log::test] -fn implication_true_true() { - assert_eq!(eval("true -> true"), Value::Bool(true)); -} - -#[test_log::test] -fn implication_short_circuit() { - assert_eq!(eval("false -> (1 / 0)"), Value::Bool(true)); -} diff --git a/fix/tests/tests/path_operations.rs b/fix/tests/tests/path_operations.rs deleted file mode 100644 index 06ad874..0000000 --- a/fix/tests/tests/path_operations.rs +++ /dev/null @@ -1,117 +0,0 @@ -use fix::value::Value; - -use crate::utils::{eval, eval_result}; - -#[test_log::test] -fn path_type_of() { - let result = eval("builtins.typeOf ./foo"); - assert_eq!(result, Value::String("path".to_string())); -} - -#[test_log::test] -fn is_path_true() { - let result = eval("builtins.isPath ./foo"); - assert_eq!(result, Value::Bool(true)); -} - -#[test_log::test] -fn is_path_false_string() { - let result = eval(r#"builtins.isPath "./foo""#); - assert_eq!(result, Value::Bool(false)); -} - -#[test_log::test] -fn is_path_false_number() { - let result = eval("builtins.isPath 42"); - assert_eq!(result, Value::Bool(false)); -} - -#[test_log::test] -fn path_concat_type() { - // path + string = path - let result = eval(r#"builtins.typeOf (./foo + "/bar")"#); - assert_eq!(result, Value::String("path".to_string())); -} - -#[test_log::test] -fn string_path_concat_type() { - // string + path = string - let result = eval(r#"builtins.typeOf ("prefix-" + ./foo)"#); - assert_eq!(result, Value::String("string".to_string())); -} - -#[test_log::test] -fn basename_of_path() { - let result = eval("builtins.baseNameOf ./path/to/file.nix"); - assert!(matches!(result, Value::String(s) if s == "file.nix")); -} - -#[test_log::test] -fn basename_of_string() { - let result = eval(r#"builtins.baseNameOf "/path/to/file.nix""#); - assert_eq!(result, Value::String("file.nix".to_string())); -} - -#[test_log::test] -fn dir_of_path_type() { - // dirOf preserves path type - let result = eval("builtins.typeOf (builtins.dirOf ./path/to/file.nix)"); - assert_eq!(result, Value::String("path".to_string())); -} - -#[test_log::test] -fn dir_of_string_type() { - // dirOf preserves string type - let result = eval(r#"builtins.typeOf (builtins.dirOf "/path/to/file.nix")"#); - assert_eq!(result, Value::String("string".to_string())); -} - -#[test_log::test] -fn path_equality() { - // Same path should be equal - let result = eval("./foo == ./foo"); - assert_eq!(result, Value::Bool(true)); -} - -#[test_log::test] -fn path_not_equal_string() { - // Paths and strings are different types - should not be equal - let result = eval(r#"./foo == "./foo""#); - assert_eq!(result, Value::Bool(false)); -} - -#[test_log::test] -fn to_path_absolute() { - // toPath with absolute path returns string - let result = eval(r#"builtins.toPath "/foo/bar""#); - assert_eq!(result, Value::String("/foo/bar".to_string())); -} - -#[test_log::test] -fn to_path_type_is_string() { - // toPath returns a string, not a path - let result = eval(r#"builtins.typeOf (builtins.toPath "/foo")"#); - assert_eq!(result, Value::String("string".to_string())); -} - -#[test_log::test] -fn to_path_relative_fails() { - // toPath with relative path should fail - let result = eval_result(r#"builtins.toPath "foo/bar""#); - assert!(result.is_err()); -} - -#[test_log::test] -fn to_path_empty_fails() { - // toPath with empty string should fail - let result = eval_result(r#"builtins.toPath """#); - assert!(result.is_err()); -} - -#[test_log::test] -fn to_path_from_path_value() { - // toPath can accept a path value too (coerces to string first) - let result = eval("builtins.toPath ./foo"); - // Should succeed and return the absolute path as a string - assert!(matches!(result, Value::String(s) if s.starts_with("/"))); -} diff --git a/fix/tests/tests/regex.rs b/fix/tests/tests/regex.rs deleted file mode 100644 index d0c909b..0000000 --- a/fix/tests/tests/regex.rs +++ /dev/null @@ -1,317 +0,0 @@ -use fix::value::{List, Value}; - -use crate::utils::eval; -use crate::utils::eval_result; - -#[test_log::test] -fn match_exact_full_string() { - assert_eq!( - eval(r#"builtins.match "foobar" "foobar""#), - Value::List(List::new(vec![])) - ); -} - -#[test_log::test] -fn match_partial_returns_null() { - assert_eq!(eval(r#"builtins.match "foo" "foobar""#), Value::Null); -} - -#[test_log::test] -fn match_with_capture_groups() { - assert_eq!( - eval(r#"builtins.match "(.*)\\.nix" "foobar.nix""#), - Value::List(List::new(vec![Value::String("foobar".into())])) - ); -} - -#[test_log::test] -fn match_multiple_capture_groups() { - assert_eq!( - eval(r#"builtins.match "((.*)/)?([^/]*)\\.nix" "foobar.nix""#), - Value::List(List::new(vec![ - Value::Null, - Value::Null, - Value::String("foobar".into()) - ])) - ); -} - -#[test_log::test] -fn match_with_path() { - assert_eq!( - eval(r#"builtins.match "((.*)/)?([^/]*)\\.nix" "/path/to/foobar.nix""#), - Value::List(List::new(vec![ - Value::String("/path/to/".into()), - Value::String("/path/to".into()), - Value::String("foobar".into()) - ])) - ); -} - -#[test_log::test] -fn match_posix_space_class() { - assert_eq!( - eval(r#"builtins.match "[[:space:]]+([^[:space:]]+)[[:space:]]+" " foo ""#), - Value::List(List::new(vec![Value::String("foo".into())])) - ); -} - -#[test_log::test] -fn match_posix_upper_class() { - assert_eq!( - eval(r#"builtins.match "[[:space:]]+([[:upper:]]+)[[:space:]]+" " foo ""#), - Value::Null - ); - - assert_eq!( - eval(r#"builtins.match "[[:space:]]+([[:upper:]]+)[[:space:]]+" " FOO ""#), - Value::List(List::new(vec![Value::String("FOO".into())])) - ); -} - -#[test_log::test] -fn match_quantifiers() { - assert_eq!( - eval(r#"builtins.match "fo*" "f""#), - Value::List(List::new(vec![])) - ); - - assert_eq!(eval(r#"builtins.match "fo+" "f""#), Value::Null); - - assert_eq!( - eval(r#"builtins.match "fo{1,2}" "foo""#), - Value::List(List::new(vec![])) - ); - - assert_eq!(eval(r#"builtins.match "fo{1,2}" "fooo""#), Value::Null); -} - -#[test_log::test] -fn split_non_capturing() { - assert_eq!( - eval(r#"builtins.split "foobar" "foobar""#), - Value::List(List::new(vec![ - Value::String("".into()), - Value::List(List::new(vec![])), - Value::String("".into()) - ])) - ); -} - -#[test_log::test] -fn split_no_match() { - assert_eq!( - eval(r#"builtins.split "fo+" "f""#), - Value::List(List::new(vec![Value::String("f".into())])) - ); -} - -#[test_log::test] -fn split_with_capture_group() { - assert_eq!( - eval(r#"builtins.split "(fo*)" "foobar""#), - Value::List(List::new(vec![ - Value::String("".into()), - Value::List(List::new(vec![Value::String("foo".into())])), - Value::String("bar".into()) - ])) - ); -} - -#[test_log::test] -fn split_multiple_matches() { - assert_eq!( - eval(r#"builtins.split "(b)" "foobarbaz""#), - Value::List(List::new(vec![ - Value::String("foo".into()), - Value::List(List::new(vec![Value::String("b".into())])), - Value::String("ar".into()), - Value::List(List::new(vec![Value::String("b".into())])), - Value::String("az".into()) - ])) - ); -} - -#[test_log::test] -fn split_with_multiple_groups() { - assert_eq!( - eval(r#"builtins.split "(f)(o*)" "foo""#), - Value::List(List::new(vec![ - Value::String("".into()), - Value::List(List::new(vec![ - Value::String("f".into()), - Value::String("oo".into()) - ])), - Value::String("".into()) - ])) - ); -} - -#[test_log::test] -fn split_with_optional_groups() { - assert_eq!( - eval(r#"builtins.split "(a)|(c)" "abc""#), - Value::List(List::new(vec![ - Value::String("".into()), - Value::List(List::new(vec![Value::String("a".into()), Value::Null])), - Value::String("b".into()), - Value::List(List::new(vec![Value::Null, Value::String("c".into())])), - Value::String("".into()) - ])) - ); -} - -#[test_log::test] -fn split_greedy_matching() { - assert_eq!( - eval(r#"builtins.split "(o+)" "oooofoooo""#), - Value::List(List::new(vec![ - Value::String("".into()), - Value::List(List::new(vec![Value::String("oooo".into())])), - Value::String("f".into()), - Value::List(List::new(vec![Value::String("oooo".into())])), - Value::String("".into()) - ])) - ); -} - -#[test_log::test] -fn split_posix_classes() { - assert_eq!( - eval(r#"builtins.split "([[:upper:]]+)" " FOO ""#), - Value::List(List::new(vec![ - Value::String(" ".into()), - Value::List(List::new(vec![Value::String("FOO".into())])), - Value::String(" ".into()) - ])) - ); -} - -#[test_log::test] -fn replace_basic() { - assert_eq!( - eval(r#"builtins.replaceStrings ["o"] ["a"] "foobar""#), - Value::String("faabar".into()) - ); -} - -#[test_log::test] -fn replace_with_empty() { - assert_eq!( - eval(r#"builtins.replaceStrings ["o"] [""] "foobar""#), - Value::String("fbar".into()) - ); -} - -#[test_log::test] -fn replace_multiple_patterns() { - assert_eq!( - eval(r#"builtins.replaceStrings ["oo" "a"] ["a" "oo"] "foobar""#), - Value::String("faboor".into()) - ); -} - -#[test_log::test] -fn replace_first_match_wins() { - assert_eq!( - eval(r#"builtins.replaceStrings ["oo" "oo"] ["u" "i"] "foobar""#), - Value::String("fubar".into()) - ); -} - -#[test_log::test] -fn replace_empty_pattern() { - assert_eq!( - eval(r#"builtins.replaceStrings [""] ["X"] "abc""#), - Value::String("XaXbXcX".into()) - ); -} - -#[test_log::test] -fn replace_empty_pattern_empty_string() { - assert_eq!( - eval(r#"builtins.replaceStrings [""] ["X"] """#), - Value::String("X".into()) - ); -} - -#[test_log::test] -fn replace_simple_char() { - assert_eq!( - eval(r#"builtins.replaceStrings ["-"] ["_"] "a-b""#), - Value::String("a_b".into()) - ); -} - -#[test_log::test] -fn replace_longer_pattern() { - assert_eq!( - eval(r#"builtins.replaceStrings ["oo"] ["u"] "foobar""#), - Value::String("fubar".into()) - ); -} - -#[test_log::test] -fn replace_different_lengths() { - let result = eval_result(r#"builtins.replaceStrings ["a" "b"] ["x"] "test""#); - assert!(result.is_err()); -} - -#[test_log::test] -fn split_version_simple() { - assert_eq!( - eval(r#"builtins.splitVersion "1.2.3""#), - Value::List(List::new(vec![ - Value::String("1".into()), - Value::String("2".into()), - Value::String("3".into()) - ])) - ); -} - -#[test_log::test] -fn split_version_with_pre() { - assert_eq!( - eval(r#"builtins.splitVersion "2.3.0pre1234""#), - Value::List(List::new(vec![ - Value::String("2".into()), - Value::String("3".into()), - Value::String("0".into()), - Value::String("pre".into()), - Value::String("1234".into()) - ])) - ); -} - -#[test_log::test] -fn split_version_with_letters() { - assert_eq!( - eval(r#"builtins.splitVersion "2.3a""#), - Value::List(List::new(vec![ - Value::String("2".into()), - Value::String("3".into()), - Value::String("a".into()) - ])) - ); -} - -#[test_log::test] -fn split_version_with_dashes() { - assert_eq!( - eval(r#"builtins.splitVersion "2.3-beta1""#), - Value::List(List::new(vec![ - Value::String("2".into()), - Value::String("3".into()), - Value::String("beta".into()), - Value::String("1".into()) - ])) - ); -} - -#[test_log::test] -fn split_version_empty() { - assert_eq!( - eval(r#"builtins.splitVersion """#), - Value::List(List::new(vec![])) - ); -} diff --git a/fix/tests/tests/thunk_scope.rs b/fix/tests/tests/thunk_scope.rs deleted file mode 100644 index e6603a4..0000000 --- a/fix/tests/tests/thunk_scope.rs +++ /dev/null @@ -1,119 +0,0 @@ -use fix::value::Value; - -use crate::utils::eval; - -#[test_log::test] -fn non_recursive_bindings() { - assert_eq!(eval("let x = 1; y = 2; z = x + y; in z"), Value::Int(3)); -} - -#[test_log::test] -fn non_recursive_multiple_bindings() { - assert_eq!( - eval("let a = 10; b = 20; c = 30; d = a + b + c; in d"), - Value::Int(60) - ); -} - -#[test_log::test] -fn recursive_fibonacci() { - assert_eq!( - eval("let fib = n: if n <= 1 then 1 else fib (n - 1) + fib (n - 2); in fib 5"), - Value::Int(8) - ); -} - -#[test_log::test] -fn recursive_factorial() { - assert_eq!( - eval("let factorial = n: if n == 0 then 1 else n * factorial (n - 1); in factorial 5"), - Value::Int(120) - ); -} - -#[test_log::test] -fn mutual_recursion_simple() { - assert_eq!( - eval( - "let f = n: if n == 0 then 0 else g (n - 1); g = n: if n == 0 then 1 else f (n - 1); in f 5" - ), - Value::Int(1) - ); -} - -#[test_log::test] -fn mutual_recursion_even_odd() { - assert_eq!( - eval( - "let even = n: if n == 0 then true else odd (n - 1); odd = n: if n == 0 then false else even (n - 1); in even 4" - ), - Value::Bool(true) - ); -} - -#[test_log::test] -fn mixed_recursive_and_non_recursive() { - assert_eq!( - eval("let x = 1; f = n: if n == 0 then x else f (n - 1); in f 5"), - Value::Int(1) - ); -} - -#[test_log::test] -fn mixed_with_multiple_non_recursive() { - assert_eq!( - eval( - "let a = 10; b = 20; sum = a + b; countdown = n: if n == 0 then sum else countdown (n - 1); in countdown 3" - ), - Value::Int(30) - ); -} - -#[test_log::test] -fn rec_attrset_non_recursive() { - assert_eq!(eval("rec { x = 1; y = 2; z = x + y; }.z"), Value::Int(3)); -} - -#[test_log::test] -fn rec_attrset_recursive() { - assert_eq!( - eval("rec { f = n: if n == 0 then 0 else f (n - 1); }.f 10"), - Value::Int(0) - ); -} - -#[test_log::test] -fn nested_let_non_recursive() { - assert_eq!( - eval("let x = 1; in let y = x + 1; z = y + 1; in z"), - Value::Int(3) - ); -} - -#[test_log::test] -fn nested_let_with_recursive() { - assert_eq!( - eval("let f = n: if n == 0 then 0 else f (n - 1); in let g = m: f m; in g 5"), - Value::Int(0) - ); -} - -#[test_log::test] -fn three_way_mutual_recursion() { - assert_eq!( - eval( - "let a = n: if n == 0 then 1 else b (n - 1); b = n: if n == 0 then 2 else c (n - 1); c = n: if n == 0 then 3 else a (n - 1); in a 6" - ), - Value::Int(1) - ); -} - -#[test_log::test] -fn complex_mixed_dependencies() { - assert_eq!( - eval( - "let x = 5; y = 10; sum = x + y; fib = n: if n <= 1 then 1 else fib (n - 1) + fib (n - 2); result = sum + fib 5; in result" - ), - Value::Int(23) - ); -} diff --git a/fix/tests/tests/to_string.rs b/fix/tests/tests/to_string.rs deleted file mode 100644 index f0f4261..0000000 --- a/fix/tests/tests/to_string.rs +++ /dev/null @@ -1,256 +0,0 @@ -use fix::value::Value; - -use crate::utils::{eval, eval_result}; - -#[test_log::test] -fn string_returns_as_is() { - assert_eq!( - eval(r#"toString "hello""#), - Value::String("hello".to_string()) - ); -} - -#[test_log::test] -fn integer_to_string() { - assert_eq!(eval("toString 42"), Value::String("42".to_string())); - assert_eq!(eval("toString (-5)"), Value::String("-5".to_string())); - assert_eq!(eval("toString 0"), Value::String("0".to_string())); -} - -#[test_log::test] -fn float_to_string() { - assert_eq!(eval("toString 3.14"), Value::String("3.14".to_string())); - assert_eq!(eval("toString 0.0"), Value::String("0".to_string())); - assert_eq!(eval("toString (-2.5)"), Value::String("-2.5".to_string())); -} - -#[test_log::test] -fn bool_to_string() { - assert_eq!(eval("toString true"), Value::String("1".to_string())); - assert_eq!(eval("toString false"), Value::String("".to_string())); -} - -#[test_log::test] -fn null_to_string() { - assert_eq!(eval("toString null"), Value::String("".to_string())); -} - -#[test_log::test] -fn simple_list_to_string() { - assert_eq!(eval("toString [1 2 3]"), Value::String("1 2 3".to_string())); - assert_eq!( - eval(r#"toString ["a" "b" "c"]"#), - Value::String("a b c".to_string()) - ); -} - -#[test_log::test] -fn nested_list_flattens() { - assert_eq!( - eval("toString [[1 2] [3 4]]"), - Value::String("1 2 3 4".to_string()) - ); - assert_eq!( - eval("toString [1 [2 3] 4]"), - Value::String("1 2 3 4".to_string()) - ); -} - -#[test_log::test] -fn empty_list_in_list_no_extra_space() { - assert_eq!(eval("toString [1 [] 2]"), Value::String("1 2".to_string())); - assert_eq!(eval("toString [[] 1 2]"), Value::String("1 2".to_string())); - assert_eq!(eval("toString [1 2 []]"), Value::String("1 2 ".to_string())); -} - -#[test_log::test] -fn list_with_multiple_empty_lists() { - assert_eq!( - eval("toString [1 [] [] 2]"), - Value::String("1 2".to_string()) - ); - assert_eq!(eval("toString [[] [] 1]"), Value::String("1".to_string())); -} - -#[test_log::test] -fn list_with_bool_and_null() { - assert_eq!( - eval("toString [true false null]"), - Value::String("1 ".to_string()) - ); - assert_eq!( - eval("toString [1 true 2 false 3]"), - Value::String("1 1 2 3".to_string()) - ); -} - -#[test_log::test] -fn mixed_type_list() { - assert_eq!( - eval(r#"toString [1 "hello" 2.5 true]"#), - Value::String("1 hello 2.5 1".to_string()) - ); -} - -#[test_log::test] -fn attrs_with_out_path() { - assert_eq!( - eval(r#"toString { outPath = "/nix/store/foo"; }"#), - Value::String("/nix/store/foo".to_string()) - ); -} - -#[test_log::test] -fn attrs_with_to_string_method() { - assert_eq!( - eval(r#"toString { __toString = self: "custom"; }"#), - Value::String("custom".to_string()) - ); -} - -#[test_log::test] -fn attrs_to_string_self_reference() { - assert_eq!( - eval( - r#"let obj = { x = 42; __toString = self: "x is ${toString self.x}"; }; in toString obj"# - ), - Value::String("x is 42".to_string()) - ); -} - -#[test_log::test] -fn attrs_to_string_priority() { - assert_eq!( - eval(r#"toString { __toString = self: "custom"; outPath = "/nix/store/foo"; }"#), - Value::String("custom".to_string()) - ); -} - -#[test_log::test] -fn derivation_like_object() { - assert_eq!( - eval( - r#"let drv = { type = "derivation"; outPath = "/nix/store/hash-pkg"; }; in toString drv"# - ), - Value::String("/nix/store/hash-pkg".to_string()) - ); -} - -#[test_log::test] -fn string_interpolation_with_int() { - assert_eq!( - eval(r#""value: ${toString 42}""#), - Value::String("value: 42".to_string()) - ); -} - -#[test_log::test] -fn string_interpolation_with_list() { - assert_eq!( - eval(r#""items: ${toString [1 2 3]}""#), - Value::String("items: 1 2 3".to_string()) - ); -} - -#[test_log::test] -fn nested_to_string_calls() { - assert_eq!( - eval(r#"toString (toString 42)"#), - Value::String("42".to_string()) - ); -} - -#[test_log::test] -fn to_string_in_let_binding() { - assert_eq!( - eval(r#"let x = toString 42; y = toString 10; in "${x}-${y}""#), - Value::String("42-10".to_string()) - ); -} - -#[test_log::test] -fn empty_string() { - assert_eq!(eval(r#"toString """#), Value::String("".to_string())); -} - -#[test_log::test] -fn empty_list() { - assert_eq!(eval("toString []"), Value::String("".to_string())); -} - -#[test_log::test] -fn to_string_preserves_spaces_in_strings() { - assert_eq!( - eval(r#"toString "hello world""#), - Value::String("hello world".to_string()) - ); -} - -#[test_log::test] -fn list_of_empty_strings() { - assert_eq!( - eval(r#"toString ["" "" ""]"#), - Value::String(" ".to_string()) - ); -} - -#[test_log::test] -fn deeply_nested_lists() { - assert_eq!( - eval("toString [[[1] [2]] [[3] [4]]]"), - Value::String("1 2 3 4".to_string()) - ); -} - -#[test_log::test] -fn list_with_nested_empty_lists() { - assert_eq!( - eval("toString [1 [[]] 2]"), - Value::String("1 2".to_string()) - ); -} - -#[test_log::test] -fn attrs_without_out_path_or_to_string_fails() { - let result = eval_result(r#"toString { foo = "bar"; }"#); - assert!(result.is_err()); -} - -#[test_log::test] -fn function_to_string_fails() { - let result = eval_result("toString (x: x)"); - assert!(result.is_err()); -} - -#[test_log::test] -fn to_string_method_must_return_string() { - assert_eq!( - eval(r#"toString { __toString = self: 42; }"#), - Value::String("42".into()) - ); - assert_eq!( - eval(r#"toString { __toString = self: true; }"#), - Value::String("1".into()) - ); -} - -#[test_log::test] -fn out_path_can_be_nested() { - assert_eq!( - eval(r#"toString { outPath = { outPath = "/final/path"; }; }"#), - Value::String("/final/path".to_string()) - ); -} - -#[test_log::test] -fn list_spacing_matches_nix_behavior() { - assert_eq!( - eval(r#"toString ["a" "b"]"#), - Value::String("a b".to_string()) - ); - - assert_eq!( - eval(r#"toString ["a" ["b" "c"] "d"]"#), - Value::String("a b c d".to_string()) - ); -} diff --git a/fix/tests/tests/utils.rs b/fix/tests/tests/utils.rs index 7fb28b6..c317c27 100644 --- a/fix/tests/tests/utils.rs +++ b/fix/tests/tests/utils.rs @@ -11,6 +11,13 @@ pub fn eval(expr: &str) -> Value { .unwrap() } +pub fn eval_shallow(expr: &str) -> Value { + Runtime::new() + .unwrap() + .eval_shallow(Source::new_eval(expr.into()).unwrap()) + .unwrap() +} + pub fn eval_deep(expr: &str) -> Value { Runtime::new() .unwrap()