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()) ); }