clean up
This commit is contained in:
69
fix/tests/tests/basic_eval.rs
Normal file
69
fix/tests/tests/basic_eval.rs
Normal file
@@ -0,0 +1,69 @@
|
||||
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());
|
||||
}
|
||||
326
fix/tests/tests/builtins.rs
Normal file
326
fix/tests/tests/builtins.rs
Normal file
@@ -0,0 +1,326 @@
|
||||
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()))
|
||||
);
|
||||
}
|
||||
193
fix/tests/tests/builtins_store.rs
Normal file
193
fix/tests/tests/builtins_store.rs
Normal file
@@ -0,0 +1,193 @@
|
||||
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"),
|
||||
}
|
||||
}
|
||||
687
fix/tests/tests/derivation.rs
Normal file
687
fix/tests/tests/derivation.rs
Normal file
@@ -0,0 +1,687 @@
|
||||
use fix::value::Value;
|
||||
|
||||
use crate::utils::{eval_deep, eval_deep_result};
|
||||
|
||||
#[test_log::test]
|
||||
fn add_operator_preserves_derivation_context() {
|
||||
let result = eval_deep(
|
||||
r#"
|
||||
let
|
||||
dep = derivation { name = "dep"; builder = "/bin/sh"; system = "x86_64-linux"; outputs = ["out" "dev"]; };
|
||||
getOutput = output: pkg: pkg.${output} or pkg.out or pkg;
|
||||
user = derivation {
|
||||
name = "user";
|
||||
builder = "/bin/sh";
|
||||
system = "x86_64-linux";
|
||||
libPath = (getOutput "lib" dep) + "/lib";
|
||||
devPath = dep.dev + "/include";
|
||||
};
|
||||
in user.drvPath
|
||||
"#,
|
||||
);
|
||||
|
||||
let nix_result = eval_deep(
|
||||
r#"
|
||||
let
|
||||
dep = derivation { name = "dep"; builder = "/bin/sh"; system = "x86_64-linux"; outputs = ["out" "dev"]; };
|
||||
user = derivation {
|
||||
name = "user";
|
||||
builder = "/bin/sh";
|
||||
system = "x86_64-linux";
|
||||
libPath = "${dep.out}/lib";
|
||||
devPath = "${dep.dev}/include";
|
||||
};
|
||||
in user.drvPath
|
||||
"#,
|
||||
);
|
||||
|
||||
assert_eq!(result, nix_result);
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn derivation_minimal() {
|
||||
let result = eval_deep(
|
||||
r#"derivation { name = "hello"; builder = "/bin/sh"; system = "x86_64-linux"; }"#,
|
||||
);
|
||||
|
||||
match result {
|
||||
Value::AttrSet(attrs) => {
|
||||
assert_eq!(attrs.get("type"), Some(&Value::String("derivation".into())));
|
||||
assert_eq!(attrs.get("name"), Some(&Value::String("hello".into())));
|
||||
assert_eq!(attrs.get("builder"), Some(&Value::String("/bin/sh".into())));
|
||||
assert_eq!(
|
||||
attrs.get("system"),
|
||||
Some(&Value::String("x86_64-linux".into()))
|
||||
);
|
||||
|
||||
assert!(attrs.contains_key("outPath"));
|
||||
assert!(attrs.contains_key("drvPath"));
|
||||
|
||||
if let Some(Value::String(path)) = attrs.get("outPath") {
|
||||
assert_eq!(path, "/nix/store/pnwh4xsfs4j508bs9iw6bpkyc4zw6ryx-hello");
|
||||
} else {
|
||||
panic!("outPath should be a string");
|
||||
}
|
||||
|
||||
if let Some(Value::String(path)) = attrs.get("drvPath") {
|
||||
assert_eq!(
|
||||
path,
|
||||
"/nix/store/x0sj6ynccvc1a8kxr8fifnlf7qlxw6hd-hello.drv"
|
||||
);
|
||||
} else {
|
||||
panic!("drvPath should be a string");
|
||||
}
|
||||
}
|
||||
_ => panic!("Expected AttrSet, got {:?}", result),
|
||||
}
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn derivation_with_args() {
|
||||
let result = eval_deep(
|
||||
r#"derivation {
|
||||
name = "test";
|
||||
builder = "/bin/sh";
|
||||
system = "x86_64-linux";
|
||||
args = ["-c" "echo hello"];
|
||||
}"#,
|
||||
);
|
||||
|
||||
match result {
|
||||
Value::AttrSet(attrs) => {
|
||||
assert!(attrs.contains_key("args"));
|
||||
if let Some(Value::List(args)) = attrs.get("args") {
|
||||
assert_eq!(args.len(), 2);
|
||||
}
|
||||
}
|
||||
_ => panic!("Expected AttrSet"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn derivation_to_string() {
|
||||
let result = eval_deep(
|
||||
r#"toString (derivation { name = "foo"; builder = "/bin/sh"; system = "x86_64-linux"; })"#,
|
||||
);
|
||||
|
||||
match result {
|
||||
Value::String(s) => assert_eq!(s, "/nix/store/xpcvxsx5sw4rbq666blz6sxqlmsqphmr-foo"),
|
||||
_ => panic!("Expected String, got {:?}", result),
|
||||
}
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn derivation_missing_name() {
|
||||
let result =
|
||||
eval_deep_result(r#"derivation { builder = "/bin/sh"; system = "x86_64-linux"; }"#);
|
||||
|
||||
assert!(result.is_err());
|
||||
let err_msg = result.unwrap_err().to_string();
|
||||
assert!(err_msg.contains("missing required attribute 'name'"));
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn derivation_invalid_name_with_drv_suffix() {
|
||||
let result = eval_deep_result(
|
||||
r#"derivation { name = "foo.drv"; builder = "/bin/sh"; system = "x86_64-linux"; }"#,
|
||||
);
|
||||
|
||||
assert!(result.is_err());
|
||||
let err_msg = result.unwrap_err().to_string();
|
||||
assert!(err_msg.contains("cannot end with .drv"));
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn derivation_missing_builder() {
|
||||
let result = eval_deep_result(r#"derivation { name = "test"; system = "x86_64-linux"; }"#);
|
||||
|
||||
assert!(result.is_err());
|
||||
let err_msg = result.unwrap_err().to_string();
|
||||
assert!(err_msg.contains("missing required attribute 'builder'"));
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn derivation_missing_system() {
|
||||
let result = eval_deep_result(r#"derivation { name = "test"; builder = "/bin/sh"; }"#);
|
||||
|
||||
assert!(result.is_err());
|
||||
let err_msg = result.unwrap_err().to_string();
|
||||
assert!(err_msg.contains("missing required attribute 'system'"));
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn derivation_with_env_vars() {
|
||||
let result = eval_deep(
|
||||
r#"derivation {
|
||||
name = "test";
|
||||
builder = "/bin/sh";
|
||||
system = "x86_64-linux";
|
||||
MY_VAR = "hello";
|
||||
ANOTHER = "world";
|
||||
}"#,
|
||||
);
|
||||
|
||||
match result {
|
||||
Value::AttrSet(attrs) => {
|
||||
assert_eq!(attrs.get("MY_VAR"), Some(&Value::String("hello".into())));
|
||||
assert_eq!(attrs.get("ANOTHER"), Some(&Value::String("world".into())));
|
||||
}
|
||||
_ => panic!("Expected AttrSet"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn derivation_strict() {
|
||||
let result = eval_deep(
|
||||
r#"builtins.derivationStrict { name = "test"; builder = "/bin/sh"; system = "x86_64-linux"; }"#,
|
||||
);
|
||||
|
||||
match result {
|
||||
Value::AttrSet(attrs) => {
|
||||
assert!(attrs.contains_key("drvPath"));
|
||||
assert!(attrs.contains_key("out"));
|
||||
assert!(!attrs.contains_key("type"));
|
||||
assert!(!attrs.contains_key("outPath"));
|
||||
}
|
||||
_ => panic!("Expected AttrSet"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn derivation_deterministic_paths() {
|
||||
let expr = r#"derivation { name = "hello"; builder = "/bin/sh"; system = "x86_64-linux"; }"#;
|
||||
|
||||
let result1 = eval_deep(expr);
|
||||
let result2 = eval_deep(expr);
|
||||
|
||||
match (result1, result2) {
|
||||
(Value::AttrSet(attrs1), Value::AttrSet(attrs2)) => {
|
||||
assert_eq!(attrs1.get("drvPath"), attrs2.get("drvPath"));
|
||||
assert_eq!(attrs1.get("outPath"), attrs2.get("outPath"));
|
||||
}
|
||||
_ => panic!("Expected AttrSet"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn derivation_escaping_in_aterm() {
|
||||
let result = eval_deep(
|
||||
r#"derivation {
|
||||
name = "test";
|
||||
builder = "/bin/sh";
|
||||
system = "x86_64-linux";
|
||||
args = ["-c" "echo \"hello\nworld\""];
|
||||
}"#,
|
||||
);
|
||||
|
||||
match result {
|
||||
Value::AttrSet(attrs) => {
|
||||
assert!(attrs.contains_key("drvPath"));
|
||||
assert!(attrs.contains_key("outPath"));
|
||||
}
|
||||
_ => panic!("Expected AttrSet"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn multi_output_two_outputs() {
|
||||
let drv = eval_deep(
|
||||
r#"derivation {
|
||||
name = "multi";
|
||||
builder = "/bin/sh";
|
||||
system = "x86_64-linux";
|
||||
outputs = ["out" "dev"];
|
||||
}"#,
|
||||
);
|
||||
|
||||
match drv {
|
||||
Value::AttrSet(attrs) => {
|
||||
assert!(attrs.contains_key("drvPath"));
|
||||
assert!(attrs.contains_key("out"));
|
||||
assert!(attrs.contains_key("dev"));
|
||||
assert!(attrs.contains_key("outPath"));
|
||||
|
||||
if let Some(Value::String(drv_path)) = attrs.get("drvPath") {
|
||||
assert_eq!(
|
||||
drv_path,
|
||||
"/nix/store/vmyjryfipkn9ss3ya23hk8p3m58l6dsl-multi.drv"
|
||||
);
|
||||
} else {
|
||||
panic!(
|
||||
"drvPath should be a string, got: {:?}",
|
||||
attrs.get("drvPath")
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(Value::String(out_path)) = attrs.get("outPath") {
|
||||
assert_eq!(
|
||||
out_path,
|
||||
"/nix/store/a3d95yg9d215c54n0ybr4npmpnj29229-multi"
|
||||
);
|
||||
} else {
|
||||
panic!("outPath should be a string");
|
||||
}
|
||||
}
|
||||
_ => panic!("Expected AttrSet"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn multi_output_three_outputs() {
|
||||
let result = eval_deep(
|
||||
r#"derivation {
|
||||
name = "three";
|
||||
builder = "/bin/sh";
|
||||
system = "x86_64-linux";
|
||||
outputs = ["out" "dev" "doc"];
|
||||
}"#,
|
||||
);
|
||||
|
||||
match result {
|
||||
Value::AttrSet(attrs) => {
|
||||
assert!(attrs.contains_key("out"));
|
||||
assert!(attrs.contains_key("dev"));
|
||||
assert!(attrs.contains_key("doc"));
|
||||
|
||||
// Verify exact paths match CppNix
|
||||
if let Some(Value::String(drv_path)) = attrs.get("drvPath") {
|
||||
assert_eq!(
|
||||
drv_path,
|
||||
"/nix/store/w08rpwvs5j9yxvdx5f5yg0p5i3ncazdx-three.drv"
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(Value::String(out_path)) = attrs.get("out") {
|
||||
assert_eq!(
|
||||
out_path,
|
||||
"/nix/store/i479clih5pb6bn2d2b758sbaylvbs2cl-three"
|
||||
);
|
||||
}
|
||||
if let Some(Value::String(dev_path)) = attrs.get("dev") {
|
||||
assert_eq!(
|
||||
dev_path,
|
||||
"/nix/store/gg8v395vci5xg1i9grc8ifh5xagw5f2j-three-dev"
|
||||
);
|
||||
}
|
||||
if let Some(Value::String(doc_path)) = attrs.get("doc") {
|
||||
assert_eq!(
|
||||
doc_path,
|
||||
"/nix/store/p2avgz16qx5k2jgnq3ch04k154xj1ac0-three-doc"
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => panic!("Expected AttrSet"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn multi_output_backward_compat() {
|
||||
let result = eval_deep(
|
||||
r#"derivation {
|
||||
name = "compat";
|
||||
builder = "/bin/sh";
|
||||
system = "x86_64-linux";
|
||||
outputs = ["out"];
|
||||
}"#,
|
||||
);
|
||||
|
||||
match result {
|
||||
Value::AttrSet(attrs) => {
|
||||
assert!(attrs.contains_key("outPath"));
|
||||
assert!(attrs.contains_key("out"));
|
||||
|
||||
if let (Some(Value::String(out_path)), Some(Value::String(out))) =
|
||||
(attrs.get("outPath"), attrs.get("out"))
|
||||
{
|
||||
assert_eq!(out_path, out);
|
||||
}
|
||||
}
|
||||
_ => panic!("Expected AttrSet"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn multi_output_deterministic() {
|
||||
let result1 = eval_deep(
|
||||
r#"derivation {
|
||||
name = "determ";
|
||||
builder = "/bin/sh";
|
||||
system = "x86_64-linux";
|
||||
outputs = ["out" "dev"];
|
||||
}"#,
|
||||
);
|
||||
|
||||
let result2 = eval_deep(
|
||||
r#"derivation {
|
||||
name = "determ";
|
||||
builder = "/bin/sh";
|
||||
system = "x86_64-linux";
|
||||
outputs = ["out" "dev"];
|
||||
}"#,
|
||||
);
|
||||
|
||||
assert_eq!(result1, result2);
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn fixed_output_sha256_flat() {
|
||||
let result = eval_deep(
|
||||
r#"derivation {
|
||||
name = "fixed";
|
||||
builder = "/bin/sh";
|
||||
system = "x86_64-linux";
|
||||
outputHash = "0000000000000000000000000000000000000000000000000000000000000000";
|
||||
outputHashAlgo = "sha256";
|
||||
outputHashMode = "flat";
|
||||
}"#,
|
||||
);
|
||||
|
||||
match result {
|
||||
Value::AttrSet(attrs) => {
|
||||
assert!(attrs.contains_key("outPath"));
|
||||
assert!(attrs.contains_key("drvPath"));
|
||||
|
||||
// Verify exact paths match CppNix
|
||||
if let Some(Value::String(out_path)) = attrs.get("outPath") {
|
||||
assert_eq!(
|
||||
out_path,
|
||||
"/nix/store/ap9h69qwrm5060ldi96axyklh3pr3yjn-fixed"
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(Value::String(drv_path)) = attrs.get("drvPath") {
|
||||
assert_eq!(
|
||||
drv_path,
|
||||
"/nix/store/kj9gsfz5cngc38n1xlf6ljlgvnsfg0cj-fixed.drv"
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => panic!("Expected AttrSet"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn fixed_output_missing_hashalgo() {
|
||||
assert!(
|
||||
eval_deep_result(
|
||||
r#"derivation {
|
||||
name = "default";
|
||||
builder = "/bin/sh";
|
||||
system = "x86_64-linux";
|
||||
outputHash = "0000000000000000000000000000000000000000000000000000000000000000";
|
||||
}"#,
|
||||
)
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn fixed_output_recursive_mode() {
|
||||
let result = eval_deep(
|
||||
r#"derivation {
|
||||
name = "recursive";
|
||||
builder = "/bin/sh";
|
||||
system = "x86_64-linux";
|
||||
outputHash = "1111111111111111111111111111111111111111111111111111111111111111";
|
||||
outputHashAlgo = "sha256";
|
||||
outputHashMode = "recursive";
|
||||
}"#,
|
||||
);
|
||||
|
||||
match result {
|
||||
Value::AttrSet(attrs) => {
|
||||
assert!(attrs.contains_key("outPath"));
|
||||
assert!(attrs.contains_key("drvPath"));
|
||||
|
||||
// Verify exact path matches CppNix
|
||||
if let Some(Value::String(out_path)) = attrs.get("outPath") {
|
||||
assert_eq!(
|
||||
out_path,
|
||||
"/nix/store/qyal5s16hfwxhz5zwpf8h8yv2bs84z56-recursive"
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => panic!("Expected AttrSet"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn fixed_output_rejects_multi_output() {
|
||||
let result = eval_deep_result(
|
||||
r#"derivation {
|
||||
name = "invalid";
|
||||
builder = "/bin/sh";
|
||||
system = "x86_64-linux";
|
||||
outputHash = "0000000000000000000000000000000000000000000000000000000000000000";
|
||||
outputHashAlgo = "sha256";
|
||||
outputs = ["out" "dev"];
|
||||
}"#,
|
||||
);
|
||||
|
||||
assert!(result.is_err());
|
||||
let err_msg = result.unwrap_err().to_string();
|
||||
assert!(err_msg.contains("fixed-output") && err_msg.contains("one"));
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn fixed_output_invalid_hash_mode() {
|
||||
let result = eval_deep_result(
|
||||
r#"derivation {
|
||||
name = "invalid";
|
||||
builder = "/bin/sh";
|
||||
system = "x86_64-linux";
|
||||
outputHash = "0000000000000000000000000000000000000000000000000000000000000000";
|
||||
outputHashMode = "invalid";
|
||||
}"#,
|
||||
);
|
||||
|
||||
assert!(result.is_err());
|
||||
let err_msg = result.unwrap_err().to_string();
|
||||
assert!(err_msg.contains("outputHashMode") && err_msg.contains("invalid"));
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn structured_attrs_basic() {
|
||||
let result = eval_deep(
|
||||
r#"derivation {
|
||||
name = "struct";
|
||||
builder = "/bin/sh";
|
||||
system = "x86_64-linux";
|
||||
__structuredAttrs = true;
|
||||
foo = "bar";
|
||||
count = 42;
|
||||
enabled = true;
|
||||
}"#,
|
||||
);
|
||||
|
||||
match result {
|
||||
Value::AttrSet(attrs) => {
|
||||
assert!(attrs.contains_key("drvPath"));
|
||||
assert!(attrs.contains_key("outPath"));
|
||||
assert!(attrs.contains_key("foo"));
|
||||
assert!(attrs.contains_key("count"));
|
||||
}
|
||||
_ => panic!("Expected AttrSet"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn structured_attrs_nested() {
|
||||
let result = eval_deep(
|
||||
r#"derivation {
|
||||
name = "nested";
|
||||
builder = "/bin/sh";
|
||||
system = "x86_64-linux";
|
||||
__structuredAttrs = true;
|
||||
data = { x = 1; y = [2 3]; };
|
||||
}"#,
|
||||
);
|
||||
|
||||
match result {
|
||||
Value::AttrSet(attrs) => {
|
||||
assert!(attrs.contains_key("drvPath"));
|
||||
assert!(attrs.contains_key("data"));
|
||||
}
|
||||
_ => panic!("Expected AttrSet"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn structured_attrs_rejects_functions() {
|
||||
let result = eval_deep_result(
|
||||
r#"derivation {
|
||||
name = "invalid";
|
||||
builder = "/bin/sh";
|
||||
system = "x86_64-linux";
|
||||
__structuredAttrs = true;
|
||||
func = x: x + 1;
|
||||
}"#,
|
||||
);
|
||||
|
||||
assert!(result.is_err());
|
||||
let err_msg = result.unwrap_err().to_string();
|
||||
assert!(err_msg.contains("cannot convert lambda to JSON"));
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn structured_attrs_false() {
|
||||
let result = eval_deep(
|
||||
r#"derivation {
|
||||
name = "normal";
|
||||
builder = "/bin/sh";
|
||||
system = "x86_64-linux";
|
||||
__structuredAttrs = false;
|
||||
foo = "bar";
|
||||
}"#,
|
||||
);
|
||||
|
||||
match result {
|
||||
Value::AttrSet(attrs) => {
|
||||
assert!(attrs.contains_key("foo"));
|
||||
if let Some(Value::String(val)) = attrs.get("foo") {
|
||||
assert_eq!(val, "bar");
|
||||
}
|
||||
}
|
||||
_ => panic!("Expected AttrSet"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn ignore_nulls_true() {
|
||||
let result = eval_deep(
|
||||
r#"derivation {
|
||||
name = "ignore";
|
||||
builder = "/bin/sh";
|
||||
system = "x86_64-linux";
|
||||
__ignoreNulls = true;
|
||||
foo = "bar";
|
||||
nullValue = null;
|
||||
}"#,
|
||||
);
|
||||
|
||||
match result {
|
||||
Value::AttrSet(attrs) => {
|
||||
assert!(attrs.contains_key("foo"));
|
||||
assert!(attrs.contains_key("nullValue"));
|
||||
}
|
||||
_ => panic!("Expected AttrSet"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn ignore_nulls_false() {
|
||||
let result = eval_deep(
|
||||
r#"derivation {
|
||||
name = "keep";
|
||||
builder = "/bin/sh";
|
||||
system = "x86_64-linux";
|
||||
__ignoreNulls = false;
|
||||
nullValue = null;
|
||||
}"#,
|
||||
);
|
||||
|
||||
match result {
|
||||
Value::AttrSet(attrs) => {
|
||||
assert!(attrs.contains_key("nullValue"));
|
||||
if let Some(Value::String(val)) = attrs.get("nullValue") {
|
||||
assert_eq!(val, "");
|
||||
}
|
||||
}
|
||||
_ => panic!("Expected AttrSet"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn ignore_nulls_with_structured_attrs() {
|
||||
let result = eval_deep(
|
||||
r#"derivation {
|
||||
name = "combined";
|
||||
builder = "/bin/sh";
|
||||
system = "x86_64-linux";
|
||||
__structuredAttrs = true;
|
||||
__ignoreNulls = true;
|
||||
foo = "bar";
|
||||
nullValue = null;
|
||||
}"#,
|
||||
);
|
||||
|
||||
match result {
|
||||
Value::AttrSet(attrs) => {
|
||||
assert!(attrs.contains_key("drvPath"));
|
||||
assert!(attrs.contains_key("foo"));
|
||||
assert!(attrs.contains_key("nullValue"));
|
||||
}
|
||||
_ => panic!("Expected AttrSet"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn all_features_combined() {
|
||||
let result = eval_deep(
|
||||
r#"derivation {
|
||||
name = "all";
|
||||
builder = "/bin/sh";
|
||||
system = "x86_64-linux";
|
||||
outputs = ["out" "dev"];
|
||||
__structuredAttrs = true;
|
||||
__ignoreNulls = true;
|
||||
data = { x = 1; };
|
||||
nullValue = null;
|
||||
}"#,
|
||||
);
|
||||
|
||||
match result {
|
||||
Value::AttrSet(attrs) => {
|
||||
assert!(attrs.contains_key("out"));
|
||||
assert!(attrs.contains_key("dev"));
|
||||
assert!(attrs.contains_key("outPath"));
|
||||
assert!(attrs.contains_key("data"));
|
||||
assert!(attrs.contains_key("nullValue"));
|
||||
}
|
||||
_ => panic!("Expected AttrSet"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn fixed_output_with_structured_attrs() {
|
||||
let result = eval_deep(
|
||||
r#"derivation {
|
||||
name = "fixstruct";
|
||||
builder = "/bin/sh";
|
||||
system = "x86_64-linux";
|
||||
outputHash = "0000000000000000000000000000000000000000000000000000000000000000";
|
||||
outputHashAlgo = "sha256";
|
||||
__structuredAttrs = true;
|
||||
data = { key = "value"; };
|
||||
}"#,
|
||||
);
|
||||
|
||||
match result {
|
||||
Value::AttrSet(attrs) => {
|
||||
assert!(attrs.contains_key("outPath"));
|
||||
assert!(attrs.contains_key("drvPath"));
|
||||
assert!(attrs.contains_key("data"));
|
||||
}
|
||||
_ => panic!("Expected AttrSet"),
|
||||
}
|
||||
}
|
||||
36
fix/tests/tests/findfile.rs
Normal file
36
fix/tests/tests/findfile.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
use crate::utils::eval;
|
||||
|
||||
#[test_log::test]
|
||||
fn test_find_file_corepkg_fetchurl() {
|
||||
let result = eval(
|
||||
r#"
|
||||
let
|
||||
searchPath = [];
|
||||
lookupPath = "nix/fetchurl.nix";
|
||||
in
|
||||
builtins.findFile searchPath lookupPath
|
||||
"#,
|
||||
);
|
||||
|
||||
assert!(result.to_string().contains("fetchurl.nix"));
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn test_lookup_path_syntax() {
|
||||
let result = eval(r#"<nix/fetchurl.nix>"#);
|
||||
assert!(result.to_string().contains("fetchurl.nix"));
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn test_import_corepkg() {
|
||||
let result = eval(
|
||||
r#"
|
||||
let
|
||||
fetchurl = import <nix/fetchurl.nix>;
|
||||
in
|
||||
builtins.typeOf fetchurl
|
||||
"#,
|
||||
);
|
||||
|
||||
assert_eq!(result.to_string(), "\"lambda\"");
|
||||
}
|
||||
74
fix/tests/tests/free_globals.rs
Normal file
74
fix/tests/tests/free_globals.rs
Normal file
@@ -0,0 +1,74 @@
|
||||
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()));
|
||||
}
|
||||
120
fix/tests/tests/functions.rs
Normal file
120
fix/tests/tests/functions.rs
Normal file
@@ -0,0 +1,120 @@
|
||||
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)
|
||||
);
|
||||
}
|
||||
368
fix/tests/tests/io_operations.rs
Normal file
368
fix/tests/tests/io_operations.rs
Normal file
@@ -0,0 +1,368 @@
|
||||
use fix::context::Context;
|
||||
use fix::error::Source;
|
||||
use fix::value::Value;
|
||||
|
||||
use crate::utils::{eval, eval_result};
|
||||
|
||||
#[test_log::test]
|
||||
fn import_absolute_path() {
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let lib_path = temp_dir.path().join("nix_test_lib.nix");
|
||||
|
||||
std::fs::write(&lib_path, "{ add = a: b: a + b; }").unwrap();
|
||||
|
||||
let expr = format!(r#"(import "{}").add 3 5"#, lib_path.display());
|
||||
assert_eq!(eval(&expr), Value::Int(8));
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn import_nested() {
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
|
||||
let lib_path = temp_dir.path().join("lib.nix");
|
||||
std::fs::write(&lib_path, "{ add = a: b: a + b; }").unwrap();
|
||||
|
||||
let main_path = temp_dir.path().join("main.nix");
|
||||
let main_content = format!(
|
||||
r#"let lib = import {}; in {{ result = lib.add 10 20; }}"#,
|
||||
lib_path.display()
|
||||
);
|
||||
std::fs::write(&main_path, main_content).unwrap();
|
||||
|
||||
let expr = format!(r#"(import "{}").result"#, main_path.display());
|
||||
assert_eq!(eval(&expr), Value::Int(30));
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn import_relative_path() {
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let subdir = temp_dir.path().join("subdir");
|
||||
std::fs::create_dir_all(&subdir).unwrap();
|
||||
|
||||
let lib_path = temp_dir.path().join("lib.nix");
|
||||
std::fs::write(&lib_path, "{ multiply = a: b: a * b; }").unwrap();
|
||||
|
||||
let helper_path = subdir.join("helper.nix");
|
||||
std::fs::write(&helper_path, "{ subtract = a: b: a - b; }").unwrap();
|
||||
|
||||
let main_path = temp_dir.path().join("main.nix");
|
||||
let main_content = r#"
|
||||
let
|
||||
lib = import ./lib.nix;
|
||||
helper = import ./subdir/helper.nix;
|
||||
in {
|
||||
result1 = lib.multiply 3 4;
|
||||
result2 = helper.subtract 10 3;
|
||||
}
|
||||
"#;
|
||||
std::fs::write(&main_path, main_content).unwrap();
|
||||
|
||||
let expr = format!(r#"let x = import "{}"; in x.result1"#, main_path.display());
|
||||
assert_eq!(eval(&expr), Value::Int(12));
|
||||
|
||||
let expr = format!(r#"let x = import "{}"; in x.result2"#, main_path.display());
|
||||
assert_eq!(eval(&expr), Value::Int(7));
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn import_returns_function() {
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let func_path = temp_dir.path().join("nix_test_func.nix");
|
||||
std::fs::write(&func_path, "x: x * 2").unwrap();
|
||||
|
||||
let expr = format!(r#"(import "{}") 5"#, func_path.display());
|
||||
assert_eq!(eval(&expr), Value::Int(10));
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn import_with_complex_dependency_graph() {
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
|
||||
let utils_path = temp_dir.path().join("utils.nix");
|
||||
std::fs::write(&utils_path, "{ double = x: x * 2; }").unwrap();
|
||||
|
||||
let math_path = temp_dir.path().join("math.nix");
|
||||
let math_content = r#"let utils = import ./utils.nix; in { triple = x: x + utils.double x; }"#;
|
||||
std::fs::write(&math_path, math_content).unwrap();
|
||||
|
||||
let main_path = temp_dir.path().join("main.nix");
|
||||
let main_content = r#"let math = import ./math.nix; in math.triple 5"#;
|
||||
std::fs::write(&main_path, main_content).unwrap();
|
||||
|
||||
let expr = format!(r#"import "{}""#, main_path.display());
|
||||
assert_eq!(eval(&expr), Value::Int(15));
|
||||
}
|
||||
|
||||
// Tests for builtins.path
|
||||
|
||||
#[test_log::test]
|
||||
fn path_with_file() {
|
||||
let mut ctx = Context::new().unwrap();
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let test_file = temp_dir.path().join("test.txt");
|
||||
std::fs::write(&test_file, "Hello, World!").unwrap();
|
||||
|
||||
let expr = format!(r#"builtins.path {{ path = {}; }}"#, test_file.display());
|
||||
let result = ctx.eval(Source::new_eval(expr).unwrap()).unwrap();
|
||||
|
||||
// Should return a store path string
|
||||
if let Value::String(store_path) = result {
|
||||
assert!(store_path.starts_with(ctx.get_store_dir()));
|
||||
assert!(store_path.contains("test.txt"));
|
||||
} else {
|
||||
panic!("Expected string, got {:?}", result);
|
||||
}
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn path_with_custom_name() {
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let test_file = temp_dir.path().join("original.txt");
|
||||
std::fs::write(&test_file, "Content").unwrap();
|
||||
|
||||
let expr = format!(
|
||||
r#"builtins.path {{ path = {}; name = "custom-name"; }}"#,
|
||||
test_file.display()
|
||||
);
|
||||
let result = eval(&expr);
|
||||
|
||||
if let Value::String(store_path) = result {
|
||||
assert!(store_path.contains("custom-name"));
|
||||
assert!(!store_path.contains("original.txt"));
|
||||
} else {
|
||||
panic!("Expected string, got {:?}", result);
|
||||
}
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn path_with_directory_recursive() {
|
||||
let mut ctx = Context::new().unwrap();
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let test_dir = temp_dir.path().join("mydir");
|
||||
std::fs::create_dir_all(&test_dir).unwrap();
|
||||
std::fs::write(test_dir.join("file1.txt"), "Content 1").unwrap();
|
||||
std::fs::write(test_dir.join("file2.txt"), "Content 2").unwrap();
|
||||
|
||||
let expr = format!(
|
||||
r#"builtins.path {{ path = {}; recursive = true; }}"#,
|
||||
test_dir.display()
|
||||
);
|
||||
let result = ctx.eval(Source::new_eval(expr).unwrap()).unwrap();
|
||||
|
||||
if let Value::String(store_path) = result {
|
||||
assert!(store_path.starts_with(ctx.get_store_dir()));
|
||||
assert!(store_path.contains("mydir"));
|
||||
} else {
|
||||
panic!("Expected string, got {:?}", result);
|
||||
}
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn path_flat_with_file() {
|
||||
let mut ctx = Context::new().unwrap();
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let test_file = temp_dir.path().join("flat.txt");
|
||||
std::fs::write(&test_file, "Flat content").unwrap();
|
||||
|
||||
let expr = format!(
|
||||
r#"builtins.path {{ path = {}; recursive = false; }}"#,
|
||||
test_file.display()
|
||||
);
|
||||
let result = ctx.eval(Source::new_eval(expr).unwrap()).unwrap();
|
||||
|
||||
if let Value::String(store_path) = result {
|
||||
assert!(store_path.starts_with(ctx.get_store_dir()));
|
||||
} else {
|
||||
panic!("Expected string, got {:?}", result);
|
||||
}
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn path_flat_with_directory_fails() {
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let test_dir = temp_dir.path().join("mydir");
|
||||
std::fs::create_dir_all(&test_dir).unwrap();
|
||||
|
||||
let expr = format!(
|
||||
r#"builtins.path {{ path = {}; recursive = false; }}"#,
|
||||
test_dir.display()
|
||||
);
|
||||
let result = eval_result(&expr);
|
||||
|
||||
assert!(result.is_err());
|
||||
let err_msg = result.unwrap_err().to_string();
|
||||
assert!(err_msg.contains("recursive") || err_msg.contains("regular file"));
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn path_nonexistent_fails() {
|
||||
let expr = r#"builtins.path { path = "/nonexistent/path/that/should/not/exist"; }"#;
|
||||
let result = eval_result(expr);
|
||||
|
||||
assert!(result.is_err());
|
||||
let err_msg = result.unwrap_err().to_string();
|
||||
assert!(err_msg.contains("does not exist"));
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn path_missing_path_param() {
|
||||
let expr = r#"builtins.path { name = "test"; }"#;
|
||||
let result = eval_result(expr);
|
||||
|
||||
assert!(result.is_err());
|
||||
let err_msg = result.unwrap_err().to_string();
|
||||
assert!(err_msg.contains("path") && err_msg.contains("required"));
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn path_with_sha256() {
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let test_file = temp_dir.path().join("hash_test.txt");
|
||||
std::fs::write(&test_file, "Test content for hashing").unwrap();
|
||||
|
||||
// First, get the hash by calling without sha256
|
||||
let expr1 = format!(r#"builtins.path {{ path = {}; }}"#, test_file.display());
|
||||
let result1 = eval(&expr1);
|
||||
let store_path1 = match result1 {
|
||||
Value::String(s) => s,
|
||||
_ => panic!("Expected string"),
|
||||
};
|
||||
|
||||
// Compute the actual hash (for testing, we'll just verify the same path is returned)
|
||||
// In real usage, the user would know the hash beforehand
|
||||
let expr2 = format!(r#"builtins.path {{ path = {}; }}"#, test_file.display());
|
||||
let result2 = eval(&expr2);
|
||||
let store_path2 = match result2 {
|
||||
Value::String(s) => s,
|
||||
_ => panic!("Expected string"),
|
||||
};
|
||||
|
||||
// Same input should produce same output
|
||||
assert_eq!(store_path1, store_path2);
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn path_deterministic() {
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let test_file = temp_dir.path().join("deterministic.txt");
|
||||
std::fs::write(&test_file, "Same content").unwrap();
|
||||
|
||||
let expr = format!(
|
||||
r#"builtins.path {{ path = {}; name = "myfile"; }}"#,
|
||||
test_file.display()
|
||||
);
|
||||
|
||||
let result1 = eval(&expr);
|
||||
let result2 = eval(&expr);
|
||||
|
||||
// Same inputs should produce same store path
|
||||
assert_eq!(result1, result2);
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn read_file_type_regular_file() {
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let test_file = temp_dir.path().join("test.txt");
|
||||
std::fs::write(&test_file, "Test content").unwrap();
|
||||
|
||||
let expr = format!(r#"builtins.readFileType {}"#, test_file.display());
|
||||
assert_eq!(eval(&expr), Value::String("regular".to_string()));
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn read_file_type_directory() {
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let test_dir = temp_dir.path().join("testdir");
|
||||
std::fs::create_dir(&test_dir).unwrap();
|
||||
|
||||
let expr = format!(r#"builtins.readFileType {}"#, test_dir.display());
|
||||
assert_eq!(eval(&expr), Value::String("directory".to_string()));
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn read_file_type_symlink() {
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let target = temp_dir.path().join("target.txt");
|
||||
let symlink = temp_dir.path().join("link.txt");
|
||||
|
||||
std::fs::write(&target, "Target content").unwrap();
|
||||
|
||||
#[cfg(unix)]
|
||||
std::os::unix::fs::symlink(&target, &symlink).unwrap();
|
||||
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let expr = format!(r#"builtins.readFileType {}"#, symlink.display());
|
||||
assert_eq!(eval(&expr), Value::String("symlink".to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn read_dir_basic() {
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let test_dir = temp_dir.path().join("readdir_test");
|
||||
std::fs::create_dir(&test_dir).unwrap();
|
||||
|
||||
std::fs::write(test_dir.join("file1.txt"), "Content 1").unwrap();
|
||||
std::fs::write(test_dir.join("file2.txt"), "Content 2").unwrap();
|
||||
std::fs::create_dir(test_dir.join("subdir")).unwrap();
|
||||
|
||||
let expr = format!(r#"builtins.readDir {}"#, test_dir.display());
|
||||
let result = eval(&expr);
|
||||
|
||||
if let Value::AttrSet(attrs) = result {
|
||||
assert_eq!(
|
||||
attrs.get("file1.txt"),
|
||||
Some(&Value::String("regular".to_string()))
|
||||
);
|
||||
assert_eq!(
|
||||
attrs.get("file2.txt"),
|
||||
Some(&Value::String("regular".to_string()))
|
||||
);
|
||||
assert_eq!(
|
||||
attrs.get("subdir"),
|
||||
Some(&Value::String("directory".to_string()))
|
||||
);
|
||||
assert_eq!(attrs.len(), 3);
|
||||
} else {
|
||||
panic!("Expected AttrSet, got {:?}", result);
|
||||
}
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn read_dir_empty() {
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let test_dir = temp_dir.path().join("empty_dir");
|
||||
std::fs::create_dir(&test_dir).unwrap();
|
||||
|
||||
let expr = format!(r#"builtins.readDir {}"#, test_dir.display());
|
||||
let result = eval(&expr);
|
||||
|
||||
if let Value::AttrSet(attrs) = result {
|
||||
assert_eq!(attrs.len(), 0);
|
||||
} else {
|
||||
panic!("Expected AttrSet, got {:?}", result);
|
||||
}
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn read_dir_nonexistent_fails() {
|
||||
let expr = r#"builtins.readDir "/nonexistent/directory""#;
|
||||
let result = eval_result(expr);
|
||||
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test_log::test]
|
||||
fn read_dir_on_file_fails() {
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let test_file = temp_dir.path().join("test.txt");
|
||||
std::fs::write(&test_file, "Test content").unwrap();
|
||||
|
||||
let expr = format!(r#"builtins.readDir {}"#, test_file.display());
|
||||
let result = eval_result(&expr);
|
||||
|
||||
assert!(result.is_err());
|
||||
let err_msg = result.unwrap_err().to_string();
|
||||
assert!(err_msg.contains("not a directory"));
|
||||
}
|
||||
319
fix/tests/tests/lang.rs
Normal file
319
fix/tests/tests/lang.rs
Normal file
@@ -0,0 +1,319 @@
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use fix::context::Context;
|
||||
use fix::error::Source;
|
||||
use fix::value::Value;
|
||||
|
||||
fn get_lang_dir() -> PathBuf {
|
||||
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/tests/lang")
|
||||
}
|
||||
|
||||
fn eval_file(name: &str) -> Result<(Value, Source), String> {
|
||||
let lang_dir = get_lang_dir();
|
||||
let nix_path = lang_dir.join(format!("{name}.nix"));
|
||||
|
||||
let expr = format!(r#"import "{}""#, nix_path.display());
|
||||
|
||||
let mut ctx = Context::new().map_err(|e| e.to_string())?;
|
||||
let source = Source {
|
||||
ty: fix::error::SourceType::File(nix_path.into()),
|
||||
src: expr.into(),
|
||||
};
|
||||
ctx.eval_deep(source.clone())
|
||||
.map(|val| (val, source))
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
fn read_expected(name: &str) -> String {
|
||||
let lang_dir = get_lang_dir();
|
||||
let exp_path = lang_dir.join(format!("{name}.exp"));
|
||||
std::fs::read_to_string(exp_path)
|
||||
.expect("expected file should exist")
|
||||
.trim_end()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
fn format_value(value: &Value) -> String {
|
||||
value.display_compat().to_string()
|
||||
}
|
||||
|
||||
macro_rules! eval_okay_test {
|
||||
($(#[$attr:meta])* $name:ident$(, $pre:expr)?) => {
|
||||
$(#[$attr])*
|
||||
#[test_log::test]
|
||||
fn $name() {
|
||||
$(($pre)();)?
|
||||
let test_name = concat!("eval-okay-", stringify!($name))
|
||||
.replace("_", "-")
|
||||
.replace("r#", "");
|
||||
let result = eval_file(&test_name);
|
||||
match result {
|
||||
Ok((value, source)) => {
|
||||
let actual = format_value(&value);
|
||||
let actual = actual.replace(
|
||||
source
|
||||
.get_dir()
|
||||
.parent()
|
||||
.unwrap()
|
||||
.to_string_lossy()
|
||||
.as_ref(),
|
||||
"/pwd",
|
||||
);
|
||||
let expected = read_expected(&test_name);
|
||||
assert_eq!(actual, expected, "Output mismatch for {}", test_name);
|
||||
}
|
||||
Err(e) => {
|
||||
panic!("Test {} failed to evaluate: {}", test_name, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! eval_fail_test {
|
||||
($name:ident) => {
|
||||
#[test_log::test]
|
||||
fn $name() {
|
||||
let test_name = concat!("eval-fail-", stringify!($name))
|
||||
.replace("_", "-")
|
||||
.replace("r#", "");
|
||||
let result = eval_file(&test_name);
|
||||
assert!(
|
||||
result.is_err(),
|
||||
"Test {} should have failed but succeeded with: {:?}",
|
||||
test_name,
|
||||
result
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
eval_okay_test!(any_all);
|
||||
eval_okay_test!(arithmetic);
|
||||
eval_okay_test!(attrnames);
|
||||
eval_okay_test!(attrs);
|
||||
eval_okay_test!(attrs2);
|
||||
eval_okay_test!(attrs3);
|
||||
eval_okay_test!(attrs4);
|
||||
eval_okay_test!(attrs5);
|
||||
eval_okay_test!(
|
||||
#[ignore = "__overrides is not supported"]
|
||||
attrs6
|
||||
);
|
||||
eval_okay_test!(
|
||||
#[ignore = "requires --arg/--argstr CLI flags"]
|
||||
autoargs
|
||||
);
|
||||
eval_okay_test!(backslash_newline_1);
|
||||
eval_okay_test!(backslash_newline_2);
|
||||
eval_okay_test!(baseNameOf);
|
||||
eval_okay_test!(builtins);
|
||||
eval_okay_test!(builtins_add);
|
||||
eval_okay_test!(callable_attrs);
|
||||
eval_okay_test!(catattrs);
|
||||
eval_okay_test!(closure);
|
||||
eval_okay_test!(comments);
|
||||
eval_okay_test!(concat);
|
||||
eval_okay_test!(concatmap);
|
||||
eval_okay_test!(concatstringssep);
|
||||
eval_okay_test!(context);
|
||||
eval_okay_test!(context_introspection);
|
||||
eval_okay_test!(convertHash);
|
||||
eval_okay_test!(curpos);
|
||||
eval_okay_test!(deepseq);
|
||||
eval_okay_test!(delayed_with);
|
||||
eval_okay_test!(delayed_with_inherit);
|
||||
eval_okay_test!(deprecate_cursed_or);
|
||||
eval_okay_test!(derivation_legacy);
|
||||
eval_okay_test!(dynamic_attrs);
|
||||
eval_okay_test!(dynamic_attrs_2);
|
||||
eval_okay_test!(dynamic_attrs_bare);
|
||||
eval_okay_test!(elem);
|
||||
eval_okay_test!(empty_args);
|
||||
eval_okay_test!(eq);
|
||||
eval_okay_test!(eq_derivations);
|
||||
eval_okay_test!(filter);
|
||||
eval_okay_test!(
|
||||
#[ignore = "not implemented: flakeRefToString"]
|
||||
flake_ref_to_string
|
||||
);
|
||||
eval_okay_test!(flatten);
|
||||
eval_okay_test!(float);
|
||||
eval_okay_test!(floor_ceil);
|
||||
eval_okay_test!(foldlStrict);
|
||||
eval_okay_test!(foldlStrict_lazy_elements);
|
||||
eval_okay_test!(foldlStrict_lazy_initial_accumulator);
|
||||
eval_okay_test!(fromjson);
|
||||
eval_okay_test!(fromjson_escapes);
|
||||
eval_okay_test!(fromTOML);
|
||||
eval_okay_test!(
|
||||
#[ignore = "timestamps are not supported"]
|
||||
fromTOML_timestamps
|
||||
);
|
||||
eval_okay_test!(functionargs);
|
||||
eval_okay_test!(hashfile);
|
||||
eval_okay_test!(hashstring);
|
||||
eval_okay_test!(getattrpos);
|
||||
eval_okay_test!(getattrpos_functionargs);
|
||||
eval_okay_test!(getattrpos_undefined);
|
||||
eval_okay_test!(getenv, || {
|
||||
unsafe { std::env::set_var("TEST_VAR", "foo") };
|
||||
});
|
||||
eval_okay_test!(groupBy);
|
||||
eval_okay_test!(r#if);
|
||||
eval_okay_test!(ind_string);
|
||||
eval_okay_test!(import);
|
||||
eval_okay_test!(inherit_attr_pos);
|
||||
eval_okay_test!(
|
||||
#[ignore = "__overrides is not supported"]
|
||||
inherit_from
|
||||
);
|
||||
eval_okay_test!(intersectAttrs);
|
||||
eval_okay_test!(r#let);
|
||||
eval_okay_test!(list);
|
||||
eval_okay_test!(listtoattrs);
|
||||
eval_okay_test!(logic);
|
||||
eval_okay_test!(map);
|
||||
eval_okay_test!(mapattrs);
|
||||
eval_okay_test!(merge_dynamic_attrs);
|
||||
eval_okay_test!(nested_with);
|
||||
eval_okay_test!(new_let);
|
||||
eval_okay_test!(null_dynamic_attrs);
|
||||
eval_okay_test!(
|
||||
#[ignore = "__overrides is not supported"]
|
||||
overrides
|
||||
);
|
||||
eval_okay_test!(
|
||||
#[ignore = "not implemented: parseFlakeRef"]
|
||||
parse_flake_ref
|
||||
);
|
||||
eval_okay_test!(partition);
|
||||
eval_okay_test!(path);
|
||||
eval_okay_test!(pathexists);
|
||||
eval_okay_test!(path_string_interpolation, || {
|
||||
unsafe {
|
||||
std::env::set_var("HOME", "/fake-home");
|
||||
}
|
||||
});
|
||||
eval_okay_test!(patterns);
|
||||
eval_okay_test!(print);
|
||||
eval_okay_test!(readDir);
|
||||
eval_okay_test!(readfile);
|
||||
eval_okay_test!(readFileType);
|
||||
eval_okay_test!(redefine_builtin);
|
||||
eval_okay_test!(regex_match);
|
||||
eval_okay_test!(regex_split);
|
||||
eval_okay_test!(regression_20220122);
|
||||
eval_okay_test!(regression_20220125);
|
||||
eval_okay_test!(regrettable_rec_attrset_merge);
|
||||
eval_okay_test!(remove);
|
||||
eval_okay_test!(repeated_empty_attrs);
|
||||
eval_okay_test!(repeated_empty_list);
|
||||
eval_okay_test!(replacestrings);
|
||||
eval_okay_test!(
|
||||
#[ignore = "requires -I CLI flags"]
|
||||
search_path
|
||||
);
|
||||
eval_okay_test!(scope_1);
|
||||
eval_okay_test!(scope_2);
|
||||
eval_okay_test!(scope_3);
|
||||
eval_okay_test!(scope_4);
|
||||
eval_okay_test!(scope_6);
|
||||
eval_okay_test!(scope_7);
|
||||
eval_okay_test!(seq);
|
||||
eval_okay_test!(sort);
|
||||
eval_okay_test!(splitversion);
|
||||
eval_okay_test!(string);
|
||||
eval_okay_test!(strings_as_attrs_names);
|
||||
eval_okay_test!(substring);
|
||||
eval_okay_test!(substring_context);
|
||||
eval_okay_test!(symlink_resolution);
|
||||
eval_okay_test!(
|
||||
#[ignore = "TCO not implemented, also disabled in CppNix"]
|
||||
tail_call_1
|
||||
);
|
||||
eval_okay_test!(tojson);
|
||||
eval_okay_test!(toxml);
|
||||
eval_okay_test!(toxml2);
|
||||
eval_okay_test!(tryeval);
|
||||
eval_okay_test!(types);
|
||||
eval_okay_test!(versions);
|
||||
eval_okay_test!(with);
|
||||
eval_okay_test!(zipAttrsWith);
|
||||
|
||||
eval_fail_test!(fail_abort);
|
||||
eval_fail_test!(fail_addDrvOutputDependencies_empty_context);
|
||||
eval_fail_test!(fail_addDrvOutputDependencies_multi_elem_context);
|
||||
eval_fail_test!(fail_addDrvOutputDependencies_wrong_element_kind);
|
||||
eval_fail_test!(fail_addErrorContext_example);
|
||||
eval_fail_test!(fail_assert);
|
||||
eval_fail_test!(fail_assert_equal_attrs_names);
|
||||
eval_fail_test!(fail_assert_equal_attrs_names_2);
|
||||
eval_fail_test!(fail_assert_equal_derivations);
|
||||
eval_fail_test!(fail_assert_equal_derivations_extra);
|
||||
eval_fail_test!(fail_assert_equal_floats);
|
||||
eval_fail_test!(fail_assert_equal_function_direct);
|
||||
eval_fail_test!(fail_assert_equal_int_float);
|
||||
eval_fail_test!(fail_assert_equal_ints);
|
||||
eval_fail_test!(fail_assert_equal_list_length);
|
||||
eval_fail_test!(fail_assert_equal_paths);
|
||||
eval_fail_test!(fail_assert_equal_type);
|
||||
eval_fail_test!(fail_assert_equal_type_nested);
|
||||
eval_fail_test!(fail_assert_nested_bool);
|
||||
eval_fail_test!(fail_attr_name_type);
|
||||
eval_fail_test!(fail_attrset_merge_drops_later_rec);
|
||||
eval_fail_test!(fail_bad_string_interpolation_1);
|
||||
eval_fail_test!(fail_bad_string_interpolation_2);
|
||||
eval_fail_test!(fail_bad_string_interpolation_3);
|
||||
eval_fail_test!(fail_bad_string_interpolation_4);
|
||||
eval_fail_test!(fail_blackhole);
|
||||
eval_fail_test!(fail_call_primop);
|
||||
eval_fail_test!(fail_deepseq);
|
||||
eval_fail_test!(fail_derivation_name);
|
||||
eval_fail_test!(fail_dup_dynamic_attrs);
|
||||
eval_fail_test!(fail_duplicate_traces);
|
||||
eval_fail_test!(fail_eol_1);
|
||||
eval_fail_test!(fail_eol_2);
|
||||
eval_fail_test!(fail_eol_3);
|
||||
eval_fail_test!(fail_fetchTree_negative);
|
||||
eval_fail_test!(fail_fetchurl_baseName);
|
||||
eval_fail_test!(fail_fetchurl_baseName_attrs);
|
||||
eval_fail_test!(fail_fetchurl_baseName_attrs_name);
|
||||
eval_fail_test!(fail_flake_ref_to_string_negative_integer);
|
||||
eval_fail_test!(fail_foldlStrict_strict_op_application);
|
||||
eval_fail_test!(fail_fromJSON_keyWithNullByte);
|
||||
eval_fail_test!(fail_fromJSON_overflowing);
|
||||
eval_fail_test!(fail_fromJSON_valueWithNullByte);
|
||||
eval_fail_test!(fail_fromTOML_keyWithNullByte);
|
||||
eval_fail_test!(fail_fromTOML_timestamps);
|
||||
eval_fail_test!(fail_fromTOML_valueWithNullByte);
|
||||
eval_fail_test!(fail_hashfile_missing);
|
||||
eval_fail_test!(fail_infinite_recursion_lambda);
|
||||
eval_fail_test!(fail_list);
|
||||
eval_fail_test!(fail_missing_arg);
|
||||
eval_fail_test!(fail_mutual_recursion);
|
||||
eval_fail_test!(fail_nested_list_items);
|
||||
eval_fail_test!(fail_nonexist_path);
|
||||
eval_fail_test!(fail_not_throws);
|
||||
eval_fail_test!(fail_overflowing_add);
|
||||
eval_fail_test!(fail_overflowing_div);
|
||||
eval_fail_test!(fail_overflowing_mul);
|
||||
eval_fail_test!(fail_overflowing_sub);
|
||||
eval_fail_test!(fail_path_slash);
|
||||
eval_fail_test!(fail_pipe_operators);
|
||||
eval_fail_test!(fail_recursion);
|
||||
eval_fail_test!(fail_remove);
|
||||
eval_fail_test!(fail_scope_5);
|
||||
eval_fail_test!(fail_seq);
|
||||
eval_fail_test!(fail_set);
|
||||
eval_fail_test!(fail_set_override);
|
||||
eval_fail_test!(fail_string_nul_1);
|
||||
eval_fail_test!(fail_string_nul_2);
|
||||
eval_fail_test!(fail_substring);
|
||||
eval_fail_test!(fail_toJSON);
|
||||
eval_fail_test!(fail_toJSON_non_utf_8);
|
||||
eval_fail_test!(fail_to_path);
|
||||
eval_fail_test!(fail_undeclared_arg);
|
||||
eval_fail_test!(fail_using_set_as_attr_name);
|
||||
BIN
fix/tests/tests/lang/binary-data
Normal file
BIN
fix/tests/tests/lang/binary-data
Normal file
Binary file not shown.
1
fix/tests/tests/lang/data
Normal file
1
fix/tests/tests/lang/data
Normal file
@@ -0,0 +1 @@
|
||||
foo
|
||||
1
fix/tests/tests/lang/dir1/a.nix
Normal file
1
fix/tests/tests/lang/dir1/a.nix
Normal file
@@ -0,0 +1 @@
|
||||
"a"
|
||||
1
fix/tests/tests/lang/dir2/a.nix
Normal file
1
fix/tests/tests/lang/dir2/a.nix
Normal file
@@ -0,0 +1 @@
|
||||
"X"
|
||||
1
fix/tests/tests/lang/dir2/b.nix
Normal file
1
fix/tests/tests/lang/dir2/b.nix
Normal file
@@ -0,0 +1 @@
|
||||
"b"
|
||||
1
fix/tests/tests/lang/dir3/a.nix
Normal file
1
fix/tests/tests/lang/dir3/a.nix
Normal file
@@ -0,0 +1 @@
|
||||
"X"
|
||||
1
fix/tests/tests/lang/dir3/b.nix
Normal file
1
fix/tests/tests/lang/dir3/b.nix
Normal file
@@ -0,0 +1 @@
|
||||
"X"
|
||||
1
fix/tests/tests/lang/dir3/c.nix
Normal file
1
fix/tests/tests/lang/dir3/c.nix
Normal file
@@ -0,0 +1 @@
|
||||
"c"
|
||||
1
fix/tests/tests/lang/dir4/a.nix
Normal file
1
fix/tests/tests/lang/dir4/a.nix
Normal file
@@ -0,0 +1 @@
|
||||
"X"
|
||||
1
fix/tests/tests/lang/dir4/c.nix
Normal file
1
fix/tests/tests/lang/dir4/c.nix
Normal file
@@ -0,0 +1 @@
|
||||
"X"
|
||||
8
fix/tests/tests/lang/eval-fail-abort.err.exp
Normal file
8
fix/tests/tests/lang/eval-fail-abort.err.exp
Normal file
@@ -0,0 +1,8 @@
|
||||
error:
|
||||
… while calling the 'abort' builtin
|
||||
at /pwd/lang/eval-fail-abort.nix:1:14:
|
||||
1| if true then abort "this should fail" else 1
|
||||
| ^
|
||||
2|
|
||||
|
||||
error: evaluation aborted with the following error message: 'this should fail'
|
||||
1
fix/tests/tests/lang/eval-fail-abort.nix
Normal file
1
fix/tests/tests/lang/eval-fail-abort.nix
Normal file
@@ -0,0 +1 @@
|
||||
if true then abort "this should fail" else 1
|
||||
@@ -0,0 +1,8 @@
|
||||
error:
|
||||
… while calling the 'addDrvOutputDependencies' builtin
|
||||
at /pwd/lang/eval-fail-addDrvOutputDependencies-empty-context.nix:1:1:
|
||||
1| builtins.addDrvOutputDependencies ""
|
||||
| ^
|
||||
2|
|
||||
|
||||
error: context of string '' must have exactly one element, but has 0
|
||||
@@ -0,0 +1 @@
|
||||
builtins.addDrvOutputDependencies ""
|
||||
@@ -0,0 +1,9 @@
|
||||
error:
|
||||
… while calling the 'addDrvOutputDependencies' builtin
|
||||
at /pwd/lang/eval-fail-addDrvOutputDependencies-multi-elem-context.nix:25:1:
|
||||
24| in
|
||||
25| builtins.addDrvOutputDependencies combo-path
|
||||
| ^
|
||||
26|
|
||||
|
||||
error: context of string '/nix/store/pg9yqs4yd85yhdm3f4i5dyaqp5jahrsz-fail.drv/nix/store/2dxd5frb715z451vbf7s8birlf3argbk-fail-2.drv' must have exactly one element, but has 2
|
||||
@@ -0,0 +1,25 @@
|
||||
let
|
||||
drv0 = derivation {
|
||||
name = "fail";
|
||||
builder = "/bin/false";
|
||||
system = "x86_64-linux";
|
||||
outputs = [
|
||||
"out"
|
||||
"foo"
|
||||
];
|
||||
};
|
||||
|
||||
drv1 = derivation {
|
||||
name = "fail-2";
|
||||
builder = "/bin/false";
|
||||
system = "x86_64-linux";
|
||||
outputs = [
|
||||
"out"
|
||||
"foo"
|
||||
];
|
||||
};
|
||||
|
||||
combo-path = "${drv0.drvPath}${drv1.drvPath}";
|
||||
|
||||
in
|
||||
builtins.addDrvOutputDependencies combo-path
|
||||
@@ -0,0 +1,9 @@
|
||||
error:
|
||||
… while calling the 'addDrvOutputDependencies' builtin
|
||||
at /pwd/lang/eval-fail-addDrvOutputDependencies-wrong-element-kind.nix:13:1:
|
||||
12| in
|
||||
13| builtins.addDrvOutputDependencies drv.outPath
|
||||
| ^
|
||||
14|
|
||||
|
||||
error: `addDrvOutputDependencies` can only act on derivations, not on a derivation output such as 'out'
|
||||
@@ -0,0 +1,13 @@
|
||||
let
|
||||
drv = derivation {
|
||||
name = "fail";
|
||||
builder = "/bin/false";
|
||||
system = "x86_64-linux";
|
||||
outputs = [
|
||||
"out"
|
||||
"foo"
|
||||
];
|
||||
};
|
||||
|
||||
in
|
||||
builtins.addDrvOutputDependencies drv.outPath
|
||||
@@ -0,0 +1,24 @@
|
||||
error:
|
||||
… while counting down; n = 10
|
||||
|
||||
… while counting down; n = 9
|
||||
|
||||
… while counting down; n = 8
|
||||
|
||||
… while counting down; n = 7
|
||||
|
||||
… while counting down; n = 6
|
||||
|
||||
… while counting down; n = 5
|
||||
|
||||
… while counting down; n = 4
|
||||
|
||||
… while counting down; n = 3
|
||||
|
||||
… while counting down; n = 2
|
||||
|
||||
… while counting down; n = 1
|
||||
|
||||
(stack trace truncated; use '--show-trace' to show the full, detailed trace)
|
||||
|
||||
error: kaboom
|
||||
@@ -0,0 +1,9 @@
|
||||
let
|
||||
countDown =
|
||||
n:
|
||||
if n == 0 then
|
||||
throw "kaboom"
|
||||
else
|
||||
builtins.addErrorContext "while counting down; n = ${toString n}" ("x" + countDown (n - 1));
|
||||
in
|
||||
countDown 10
|
||||
@@ -0,0 +1,8 @@
|
||||
error:
|
||||
… while evaluating the condition of the assertion '({ a = true; } == { a = true; b = true; })'
|
||||
at /pwd/lang/eval-fail-assert-equal-attrs-names-2.nix:1:1:
|
||||
1| assert
|
||||
| ^
|
||||
2| {
|
||||
|
||||
error: attribute names of attribute set '{ a = true; }' differs from attribute set '{ a = true; b = true; }'
|
||||
@@ -0,0 +1,8 @@
|
||||
assert
|
||||
{
|
||||
a = true;
|
||||
} == {
|
||||
a = true;
|
||||
b = true;
|
||||
};
|
||||
throw "unreachable"
|
||||
@@ -0,0 +1,8 @@
|
||||
error:
|
||||
… while evaluating the condition of the assertion '({ a = true; b = true; } == { a = true; })'
|
||||
at /pwd/lang/eval-fail-assert-equal-attrs-names.nix:1:1:
|
||||
1| assert
|
||||
| ^
|
||||
2| {
|
||||
|
||||
error: attribute names of attribute set '{ a = true; b = true; }' differs from attribute set '{ a = true; }'
|
||||
@@ -0,0 +1,8 @@
|
||||
assert
|
||||
{
|
||||
a = true;
|
||||
b = true;
|
||||
} == {
|
||||
a = true;
|
||||
};
|
||||
throw "unreachable"
|
||||
@@ -0,0 +1,26 @@
|
||||
error:
|
||||
… while evaluating the condition of the assertion '({ foo = { outPath = "/nix/store/0"; type = "derivation"; }; } == { foo = { devious = true; outPath = "/nix/store/1"; type = "derivation"; }; })'
|
||||
at /pwd/lang/eval-fail-assert-equal-derivations-extra.nix:1:1:
|
||||
1| assert
|
||||
| ^
|
||||
2| {
|
||||
|
||||
… while comparing attribute 'foo'
|
||||
|
||||
… where left hand side is
|
||||
at /pwd/lang/eval-fail-assert-equal-derivations-extra.nix:3:5:
|
||||
2| {
|
||||
3| foo = {
|
||||
| ^
|
||||
4| type = "derivation";
|
||||
|
||||
… where right hand side is
|
||||
at /pwd/lang/eval-fail-assert-equal-derivations-extra.nix:8:5:
|
||||
7| } == {
|
||||
8| foo = {
|
||||
| ^
|
||||
9| type = "derivation";
|
||||
|
||||
… while comparing a derivation by its 'outPath' attribute
|
||||
|
||||
error: string '"/nix/store/0"' is not equal to string '"/nix/store/1"'
|
||||
@@ -0,0 +1,14 @@
|
||||
assert
|
||||
{
|
||||
foo = {
|
||||
type = "derivation";
|
||||
outPath = "/nix/store/0";
|
||||
};
|
||||
} == {
|
||||
foo = {
|
||||
type = "derivation";
|
||||
outPath = "/nix/store/1";
|
||||
devious = true;
|
||||
};
|
||||
};
|
||||
throw "unreachable"
|
||||
@@ -0,0 +1,26 @@
|
||||
error:
|
||||
… while evaluating the condition of the assertion '({ foo = { ignored = (abort "not ignored"); outPath = "/nix/store/0"; type = "derivation"; }; } == { foo = { ignored = (abort "not ignored"); outPath = "/nix/store/1"; type = "derivation"; }; })'
|
||||
at /pwd/lang/eval-fail-assert-equal-derivations.nix:1:1:
|
||||
1| assert
|
||||
| ^
|
||||
2| {
|
||||
|
||||
… while comparing attribute 'foo'
|
||||
|
||||
… where left hand side is
|
||||
at /pwd/lang/eval-fail-assert-equal-derivations.nix:3:5:
|
||||
2| {
|
||||
3| foo = {
|
||||
| ^
|
||||
4| type = "derivation";
|
||||
|
||||
… where right hand side is
|
||||
at /pwd/lang/eval-fail-assert-equal-derivations.nix:9:5:
|
||||
8| } == {
|
||||
9| foo = {
|
||||
| ^
|
||||
10| type = "derivation";
|
||||
|
||||
… while comparing a derivation by its 'outPath' attribute
|
||||
|
||||
error: string '"/nix/store/0"' is not equal to string '"/nix/store/1"'
|
||||
15
fix/tests/tests/lang/eval-fail-assert-equal-derivations.nix
Normal file
15
fix/tests/tests/lang/eval-fail-assert-equal-derivations.nix
Normal file
@@ -0,0 +1,15 @@
|
||||
assert
|
||||
{
|
||||
foo = {
|
||||
type = "derivation";
|
||||
outPath = "/nix/store/0";
|
||||
ignored = abort "not ignored";
|
||||
};
|
||||
} == {
|
||||
foo = {
|
||||
type = "derivation";
|
||||
outPath = "/nix/store/1";
|
||||
ignored = abort "not ignored";
|
||||
};
|
||||
};
|
||||
throw "unreachable"
|
||||
22
fix/tests/tests/lang/eval-fail-assert-equal-floats.err.exp
Normal file
22
fix/tests/tests/lang/eval-fail-assert-equal-floats.err.exp
Normal file
@@ -0,0 +1,22 @@
|
||||
error:
|
||||
… while evaluating the condition of the assertion '({ b = 1; } == { b = 1.01; })'
|
||||
at /pwd/lang/eval-fail-assert-equal-floats.nix:1:1:
|
||||
1| assert { b = 1.0; } == { b = 1.01; };
|
||||
| ^
|
||||
2| abort "unreachable"
|
||||
|
||||
… while comparing attribute 'b'
|
||||
|
||||
… where left hand side is
|
||||
at /pwd/lang/eval-fail-assert-equal-floats.nix:1:10:
|
||||
1| assert { b = 1.0; } == { b = 1.01; };
|
||||
| ^
|
||||
2| abort "unreachable"
|
||||
|
||||
… where right hand side is
|
||||
at /pwd/lang/eval-fail-assert-equal-floats.nix:1:26:
|
||||
1| assert { b = 1.0; } == { b = 1.01; };
|
||||
| ^
|
||||
2| abort "unreachable"
|
||||
|
||||
error: a float with value '1' is not equal to a float with value '1.01'
|
||||
2
fix/tests/tests/lang/eval-fail-assert-equal-floats.nix
Normal file
2
fix/tests/tests/lang/eval-fail-assert-equal-floats.nix
Normal file
@@ -0,0 +1,2 @@
|
||||
assert { b = 1.0; } == { b = 1.01; };
|
||||
abort "unreachable"
|
||||
@@ -0,0 +1,9 @@
|
||||
error:
|
||||
… while evaluating the condition of the assertion '((x: x) == (x: x))'
|
||||
at /pwd/lang/eval-fail-assert-equal-function-direct.nix:3:1:
|
||||
2| # This only compares a direct comparison and makes no claims about functions in nested structures.
|
||||
3| assert (x: x) == (x: x);
|
||||
| ^
|
||||
4| abort "unreachable"
|
||||
|
||||
error: distinct functions and immediate comparisons of identical functions compare as unequal
|
||||
@@ -0,0 +1,4 @@
|
||||
# Note: functions in nested structures, e.g. attributes, may be optimized away by pointer identity optimization.
|
||||
# This only compares a direct comparison and makes no claims about functions in nested structures.
|
||||
assert (x: x) == (x: x);
|
||||
abort "unreachable"
|
||||
@@ -0,0 +1,8 @@
|
||||
error:
|
||||
… while evaluating the condition of the assertion '(1 == 1.1)'
|
||||
at /pwd/lang/eval-fail-assert-equal-int-float.nix:1:1:
|
||||
1| assert 1 == 1.1;
|
||||
| ^
|
||||
2| throw "unreachable"
|
||||
|
||||
error: an integer with value '1' is not equal to a float with value '1.1'
|
||||
@@ -0,0 +1,2 @@
|
||||
assert 1 == 1.1;
|
||||
throw "unreachable"
|
||||
22
fix/tests/tests/lang/eval-fail-assert-equal-ints.err.exp
Normal file
22
fix/tests/tests/lang/eval-fail-assert-equal-ints.err.exp
Normal file
@@ -0,0 +1,22 @@
|
||||
error:
|
||||
… while evaluating the condition of the assertion '({ b = 1; } == { b = 2; })'
|
||||
at /pwd/lang/eval-fail-assert-equal-ints.nix:1:1:
|
||||
1| assert { b = 1; } == { b = 2; };
|
||||
| ^
|
||||
2| abort "unreachable"
|
||||
|
||||
… while comparing attribute 'b'
|
||||
|
||||
… where left hand side is
|
||||
at /pwd/lang/eval-fail-assert-equal-ints.nix:1:10:
|
||||
1| assert { b = 1; } == { b = 2; };
|
||||
| ^
|
||||
2| abort "unreachable"
|
||||
|
||||
… where right hand side is
|
||||
at /pwd/lang/eval-fail-assert-equal-ints.nix:1:24:
|
||||
1| assert { b = 1; } == { b = 2; };
|
||||
| ^
|
||||
2| abort "unreachable"
|
||||
|
||||
error: an integer with value '1' is not equal to an integer with value '2'
|
||||
2
fix/tests/tests/lang/eval-fail-assert-equal-ints.nix
Normal file
2
fix/tests/tests/lang/eval-fail-assert-equal-ints.nix
Normal file
@@ -0,0 +1,2 @@
|
||||
assert { b = 1; } == { b = 2; };
|
||||
abort "unreachable"
|
||||
@@ -0,0 +1,8 @@
|
||||
error:
|
||||
… while evaluating the condition of the assertion '([ (1) (0) ] == [ (10) ])'
|
||||
at /pwd/lang/eval-fail-assert-equal-list-length.nix:1:1:
|
||||
1| assert
|
||||
| ^
|
||||
2| [
|
||||
|
||||
error: list of size '2' is not equal to list of size '1', left hand side is '[ 1 0 ]', right hand side is '[ 10 ]'
|
||||
@@ -0,0 +1,6 @@
|
||||
assert
|
||||
[
|
||||
1
|
||||
0
|
||||
] == [ 10 ];
|
||||
throw "unreachable"
|
||||
@@ -0,0 +1,8 @@
|
||||
error:
|
||||
… while evaluating the condition of the assertion '(/pwd/lang/foo == /pwd/lang/bar)'
|
||||
at /pwd/lang/eval-fail-assert-equal-paths.nix:1:1:
|
||||
1| assert ./foo == ./bar;
|
||||
| ^
|
||||
2| throw "unreachable"
|
||||
|
||||
error: path '/pwd/lang/foo' is not equal to path '/pwd/lang/bar'
|
||||
2
fix/tests/tests/lang/eval-fail-assert-equal-paths.nix
Normal file
2
fix/tests/tests/lang/eval-fail-assert-equal-paths.nix
Normal file
@@ -0,0 +1,2 @@
|
||||
assert ./foo == ./bar;
|
||||
throw "unreachable"
|
||||
@@ -0,0 +1,22 @@
|
||||
error:
|
||||
… while evaluating the condition of the assertion '({ ding = false; } == { ding = null; })'
|
||||
at /pwd/lang/eval-fail-assert-equal-type-nested.nix:1:1:
|
||||
1| assert { ding = false; } == { ding = null; };
|
||||
| ^
|
||||
2| abort "unreachable"
|
||||
|
||||
… while comparing attribute 'ding'
|
||||
|
||||
… where left hand side is
|
||||
at /pwd/lang/eval-fail-assert-equal-type-nested.nix:1:10:
|
||||
1| assert { ding = false; } == { ding = null; };
|
||||
| ^
|
||||
2| abort "unreachable"
|
||||
|
||||
… where right hand side is
|
||||
at /pwd/lang/eval-fail-assert-equal-type-nested.nix:1:31:
|
||||
1| assert { ding = false; } == { ding = null; };
|
||||
| ^
|
||||
2| abort "unreachable"
|
||||
|
||||
error: a Boolean of value 'false' is not equal to null of value 'null'
|
||||
@@ -0,0 +1,2 @@
|
||||
assert { ding = false; } == { ding = null; };
|
||||
abort "unreachable"
|
||||
8
fix/tests/tests/lang/eval-fail-assert-equal-type.err.exp
Normal file
8
fix/tests/tests/lang/eval-fail-assert-equal-type.err.exp
Normal file
@@ -0,0 +1,8 @@
|
||||
error:
|
||||
… while evaluating the condition of the assertion '(false == null)'
|
||||
at /pwd/lang/eval-fail-assert-equal-type.nix:1:1:
|
||||
1| assert false == null;
|
||||
| ^
|
||||
2| abort "unreachable"
|
||||
|
||||
error: a Boolean of value 'false' is not equal to null of value 'null'
|
||||
2
fix/tests/tests/lang/eval-fail-assert-equal-type.nix
Normal file
2
fix/tests/tests/lang/eval-fail-assert-equal-type.nix
Normal file
@@ -0,0 +1,2 @@
|
||||
assert false == null;
|
||||
abort "unreachable"
|
||||
66
fix/tests/tests/lang/eval-fail-assert-nested-bool.err.exp
Normal file
66
fix/tests/tests/lang/eval-fail-assert-nested-bool.err.exp
Normal file
@@ -0,0 +1,66 @@
|
||||
error:
|
||||
… while evaluating the condition of the assertion '({ a = { b = [ ({ c = { d = true; }; }) ]; }; } == { a = { b = [ ({ c = { d = false; }; }) ]; }; })'
|
||||
at /pwd/lang/eval-fail-assert-nested-bool.nix:1:1:
|
||||
1| assert { a.b = [ { c.d = true; } ]; } == { a.b = [ { c.d = false; } ]; };
|
||||
| ^
|
||||
2|
|
||||
|
||||
… while comparing attribute 'a'
|
||||
|
||||
… where left hand side is
|
||||
at /pwd/lang/eval-fail-assert-nested-bool.nix:1:10:
|
||||
1| assert { a.b = [ { c.d = true; } ]; } == { a.b = [ { c.d = false; } ]; };
|
||||
| ^
|
||||
2|
|
||||
|
||||
… where right hand side is
|
||||
at /pwd/lang/eval-fail-assert-nested-bool.nix:1:44:
|
||||
1| assert { a.b = [ { c.d = true; } ]; } == { a.b = [ { c.d = false; } ]; };
|
||||
| ^
|
||||
2|
|
||||
|
||||
… while comparing attribute 'b'
|
||||
|
||||
… where left hand side is
|
||||
at /pwd/lang/eval-fail-assert-nested-bool.nix:1:10:
|
||||
1| assert { a.b = [ { c.d = true; } ]; } == { a.b = [ { c.d = false; } ]; };
|
||||
| ^
|
||||
2|
|
||||
|
||||
… where right hand side is
|
||||
at /pwd/lang/eval-fail-assert-nested-bool.nix:1:44:
|
||||
1| assert { a.b = [ { c.d = true; } ]; } == { a.b = [ { c.d = false; } ]; };
|
||||
| ^
|
||||
2|
|
||||
|
||||
… while comparing list element 0
|
||||
|
||||
… while comparing attribute 'c'
|
||||
|
||||
… where left hand side is
|
||||
at /pwd/lang/eval-fail-assert-nested-bool.nix:1:20:
|
||||
1| assert { a.b = [ { c.d = true; } ]; } == { a.b = [ { c.d = false; } ]; };
|
||||
| ^
|
||||
2|
|
||||
|
||||
… where right hand side is
|
||||
at /pwd/lang/eval-fail-assert-nested-bool.nix:1:54:
|
||||
1| assert { a.b = [ { c.d = true; } ]; } == { a.b = [ { c.d = false; } ]; };
|
||||
| ^
|
||||
2|
|
||||
|
||||
… while comparing attribute 'd'
|
||||
|
||||
… where left hand side is
|
||||
at /pwd/lang/eval-fail-assert-nested-bool.nix:1:20:
|
||||
1| assert { a.b = [ { c.d = true; } ]; } == { a.b = [ { c.d = false; } ]; };
|
||||
| ^
|
||||
2|
|
||||
|
||||
… where right hand side is
|
||||
at /pwd/lang/eval-fail-assert-nested-bool.nix:1:54:
|
||||
1| assert { a.b = [ { c.d = true; } ]; } == { a.b = [ { c.d = false; } ]; };
|
||||
| ^
|
||||
2|
|
||||
|
||||
error: boolean 'true' is not equal to boolean 'false'
|
||||
3
fix/tests/tests/lang/eval-fail-assert-nested-bool.nix
Normal file
3
fix/tests/tests/lang/eval-fail-assert-nested-bool.nix
Normal file
@@ -0,0 +1,3 @@
|
||||
assert { a.b = [ { c.d = true; } ]; } == { a.b = [ { c.d = false; } ]; };
|
||||
|
||||
abort "unreachable"
|
||||
30
fix/tests/tests/lang/eval-fail-assert.err.exp
Normal file
30
fix/tests/tests/lang/eval-fail-assert.err.exp
Normal file
@@ -0,0 +1,30 @@
|
||||
error:
|
||||
… while evaluating the attribute 'body'
|
||||
at /pwd/lang/eval-fail-assert.nix:7:3:
|
||||
6|
|
||||
7| body = x "x";
|
||||
| ^
|
||||
8| }
|
||||
|
||||
… from call site
|
||||
at /pwd/lang/eval-fail-assert.nix:7:10:
|
||||
6|
|
||||
7| body = x "x";
|
||||
| ^
|
||||
8| }
|
||||
|
||||
… while calling 'x'
|
||||
at /pwd/lang/eval-fail-assert.nix:3:5:
|
||||
2| x =
|
||||
3| arg:
|
||||
| ^
|
||||
4| assert arg == "y";
|
||||
|
||||
… while evaluating the condition of the assertion '(arg == "y")'
|
||||
at /pwd/lang/eval-fail-assert.nix:4:5:
|
||||
3| arg:
|
||||
4| assert arg == "y";
|
||||
| ^
|
||||
5| 123;
|
||||
|
||||
error: string '"x"' is not equal to string '"y"'
|
||||
8
fix/tests/tests/lang/eval-fail-assert.nix
Normal file
8
fix/tests/tests/lang/eval-fail-assert.nix
Normal file
@@ -0,0 +1,8 @@
|
||||
let {
|
||||
x =
|
||||
arg:
|
||||
assert arg == "y";
|
||||
123;
|
||||
|
||||
body = x "x";
|
||||
}
|
||||
21
fix/tests/tests/lang/eval-fail-attr-name-type.err.exp
Normal file
21
fix/tests/tests/lang/eval-fail-attr-name-type.err.exp
Normal file
@@ -0,0 +1,21 @@
|
||||
error:
|
||||
… while evaluating the attribute 'puppy."${key}"'
|
||||
at /pwd/lang/eval-fail-attr-name-type.nix:3:5:
|
||||
2| attrs = {
|
||||
3| puppy.doggy = { };
|
||||
| ^
|
||||
4| };
|
||||
|
||||
… while evaluating an attribute name
|
||||
at /pwd/lang/eval-fail-attr-name-type.nix:7:15:
|
||||
6| in
|
||||
7| attrs.puppy.${key}
|
||||
| ^
|
||||
8|
|
||||
|
||||
error: expected a string but found an integer: 1
|
||||
at /pwd/lang/eval-fail-attr-name-type.nix:7:15:
|
||||
6| in
|
||||
7| attrs.puppy.${key}
|
||||
| ^
|
||||
8|
|
||||
7
fix/tests/tests/lang/eval-fail-attr-name-type.nix
Normal file
7
fix/tests/tests/lang/eval-fail-attr-name-type.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
let
|
||||
attrs = {
|
||||
puppy.doggy = { };
|
||||
};
|
||||
key = 1;
|
||||
in
|
||||
attrs.puppy.${key}
|
||||
@@ -0,0 +1,6 @@
|
||||
error: undefined variable 'd'
|
||||
at /pwd/lang/eval-fail-attrset-merge-drops-later-rec.nix:4:9:
|
||||
3| a = rec {
|
||||
4| c = d + 2;
|
||||
| ^
|
||||
5| d = 3;
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
a.b = 1;
|
||||
a = rec {
|
||||
c = d + 2;
|
||||
d = 3;
|
||||
};
|
||||
}
|
||||
.c
|
||||
@@ -0,0 +1,8 @@
|
||||
error:
|
||||
… while evaluating a path segment
|
||||
at /pwd/lang/eval-fail-bad-string-interpolation-1.nix:1:2:
|
||||
1| "${x: x}"
|
||||
| ^
|
||||
2|
|
||||
|
||||
error: cannot coerce a function to a string: «lambda @ /pwd/lang/eval-fail-bad-string-interpolation-1.nix:1:4»
|
||||
@@ -0,0 +1 @@
|
||||
"${x: x}"
|
||||
@@ -0,0 +1 @@
|
||||
error: path '/pwd/lang/fnord' does not exist
|
||||
@@ -0,0 +1 @@
|
||||
"${./fnord}"
|
||||
@@ -0,0 +1,8 @@
|
||||
error:
|
||||
… while evaluating a path segment
|
||||
at /pwd/lang/eval-fail-bad-string-interpolation-3.nix:1:3:
|
||||
1| ''${x: x}''
|
||||
| ^
|
||||
2|
|
||||
|
||||
error: cannot coerce a function to a string: «lambda @ /pwd/lang/eval-fail-bad-string-interpolation-3.nix:1:5»
|
||||
@@ -0,0 +1 @@
|
||||
''${x: x}''
|
||||
@@ -0,0 +1,9 @@
|
||||
error:
|
||||
… while evaluating a path segment
|
||||
at /pwd/lang/eval-fail-bad-string-interpolation-4.nix:19:3:
|
||||
18| # The error message should not be too long.
|
||||
19| ''${pkgs}''
|
||||
| ^
|
||||
20|
|
||||
|
||||
error: cannot coerce a set to a string: { a = { a = { a = { a = "ha"; b = "ha"; c = "ha"; d = "ha"; e = "ha"; f = "ha"; g = "ha"; h = "ha"; j = "ha"; }; «8 attributes elided» }; «8 attributes elided» }; «8 attributes elided» }
|
||||
@@ -0,0 +1,19 @@
|
||||
let
|
||||
# Basically a "billion laughs" attack, but toned down to simulated `pkgs`.
|
||||
ha = x: y: {
|
||||
a = x y;
|
||||
b = x y;
|
||||
c = x y;
|
||||
d = x y;
|
||||
e = x y;
|
||||
f = x y;
|
||||
g = x y;
|
||||
h = x y;
|
||||
j = x y;
|
||||
};
|
||||
has = ha (ha (ha (ha (x: x)))) "ha";
|
||||
# A large structure that has already been evaluated.
|
||||
pkgs = builtins.deepSeq has has;
|
||||
in
|
||||
# The error message should not be too long.
|
||||
''${pkgs}''
|
||||
14
fix/tests/tests/lang/eval-fail-blackhole.err.exp
Normal file
14
fix/tests/tests/lang/eval-fail-blackhole.err.exp
Normal file
@@ -0,0 +1,14 @@
|
||||
error:
|
||||
… while evaluating the attribute 'body'
|
||||
at /pwd/lang/eval-fail-blackhole.nix:2:3:
|
||||
1| let {
|
||||
2| body = x;
|
||||
| ^
|
||||
3| x = y;
|
||||
|
||||
error: infinite recursion encountered
|
||||
at /pwd/lang/eval-fail-blackhole.nix:3:7:
|
||||
2| body = x;
|
||||
3| x = y;
|
||||
| ^
|
||||
4| y = x;
|
||||
5
fix/tests/tests/lang/eval-fail-blackhole.nix
Normal file
5
fix/tests/tests/lang/eval-fail-blackhole.nix
Normal file
@@ -0,0 +1,5 @@
|
||||
let {
|
||||
body = x;
|
||||
x = y;
|
||||
y = x;
|
||||
}
|
||||
10
fix/tests/tests/lang/eval-fail-call-primop.err.exp
Normal file
10
fix/tests/tests/lang/eval-fail-call-primop.err.exp
Normal file
@@ -0,0 +1,10 @@
|
||||
error:
|
||||
… while calling the 'length' builtin
|
||||
at /pwd/lang/eval-fail-call-primop.nix:1:1:
|
||||
1| builtins.length 1
|
||||
| ^
|
||||
2|
|
||||
|
||||
… while evaluating the first argument passed to builtins.length
|
||||
|
||||
error: expected a list but found an integer: 1
|
||||
1
fix/tests/tests/lang/eval-fail-call-primop.nix
Normal file
1
fix/tests/tests/lang/eval-fail-call-primop.nix
Normal file
@@ -0,0 +1 @@
|
||||
builtins.length 1
|
||||
20
fix/tests/tests/lang/eval-fail-deepseq.err.exp
Normal file
20
fix/tests/tests/lang/eval-fail-deepseq.err.exp
Normal file
@@ -0,0 +1,20 @@
|
||||
error:
|
||||
… while calling the 'deepSeq' builtin
|
||||
at /pwd/lang/eval-fail-deepseq.nix:1:1:
|
||||
1| builtins.deepSeq { x = abort "foo"; } 456
|
||||
| ^
|
||||
2|
|
||||
|
||||
… while evaluating the attribute 'x'
|
||||
at /pwd/lang/eval-fail-deepseq.nix:1:20:
|
||||
1| builtins.deepSeq { x = abort "foo"; } 456
|
||||
| ^
|
||||
2|
|
||||
|
||||
… while calling the 'abort' builtin
|
||||
at /pwd/lang/eval-fail-deepseq.nix:1:24:
|
||||
1| builtins.deepSeq { x = abort "foo"; } 456
|
||||
| ^
|
||||
2|
|
||||
|
||||
error: evaluation aborted with the following error message: 'foo'
|
||||
1
fix/tests/tests/lang/eval-fail-deepseq.nix
Normal file
1
fix/tests/tests/lang/eval-fail-deepseq.nix
Normal file
@@ -0,0 +1 @@
|
||||
builtins.deepSeq { x = abort "foo"; } 456
|
||||
26
fix/tests/tests/lang/eval-fail-derivation-name.err.exp
Normal file
26
fix/tests/tests/lang/eval-fail-derivation-name.err.exp
Normal file
@@ -0,0 +1,26 @@
|
||||
error:
|
||||
… while evaluating the attribute 'outPath'
|
||||
at <nix/derivation-internal.nix>:<number>:<number>:
|
||||
<number>| value = commonAttrs // {
|
||||
<number>| outPath = builtins.getAttr outputName strict;
|
||||
| ^
|
||||
<number>| drvPath = strict.drvPath;
|
||||
|
||||
… while calling the 'getAttr' builtin
|
||||
at <nix/derivation-internal.nix>:<number>:<number>:
|
||||
<number>| value = commonAttrs // {
|
||||
<number>| outPath = builtins.getAttr outputName strict;
|
||||
| ^
|
||||
<number>| drvPath = strict.drvPath;
|
||||
|
||||
… while calling the 'derivationStrict' builtin
|
||||
at <nix/derivation-internal.nix>:<number>:<number>:
|
||||
<number>|
|
||||
<number>| strict = derivationStrict drvAttrs;
|
||||
| ^
|
||||
<number>|
|
||||
|
||||
… while evaluating derivation '~jiggle~'
|
||||
whose name attribute is located at /pwd/lang/eval-fail-derivation-name.nix:<number>:<number>
|
||||
|
||||
error: invalid derivation name: name '~jiggle~' contains illegal character '~'. Please pass a different 'name'.
|
||||
5
fix/tests/tests/lang/eval-fail-derivation-name.nix
Normal file
5
fix/tests/tests/lang/eval-fail-derivation-name.nix
Normal file
@@ -0,0 +1,5 @@
|
||||
derivation {
|
||||
name = "~jiggle~";
|
||||
system = "some-system";
|
||||
builder = "/dontcare";
|
||||
}
|
||||
14
fix/tests/tests/lang/eval-fail-dup-dynamic-attrs.err.exp
Normal file
14
fix/tests/tests/lang/eval-fail-dup-dynamic-attrs.err.exp
Normal file
@@ -0,0 +1,14 @@
|
||||
error:
|
||||
… while evaluating the attribute 'set'
|
||||
at /pwd/lang/eval-fail-dup-dynamic-attrs.nix:2:3:
|
||||
1| {
|
||||
2| set = {
|
||||
| ^
|
||||
3| "${"" + "b"}" = 1;
|
||||
|
||||
error: dynamic attribute 'b' already defined at /pwd/lang/eval-fail-dup-dynamic-attrs.nix:3:5
|
||||
at /pwd/lang/eval-fail-dup-dynamic-attrs.nix:6:5:
|
||||
5| set = {
|
||||
6| "${"b" + ""}" = 2;
|
||||
| ^
|
||||
7| };
|
||||
8
fix/tests/tests/lang/eval-fail-dup-dynamic-attrs.nix
Normal file
8
fix/tests/tests/lang/eval-fail-dup-dynamic-attrs.nix
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
set = {
|
||||
"${"" + "b"}" = 1;
|
||||
};
|
||||
set = {
|
||||
"${"b" + ""}" = 2;
|
||||
};
|
||||
}
|
||||
51
fix/tests/tests/lang/eval-fail-duplicate-traces.err.exp
Normal file
51
fix/tests/tests/lang/eval-fail-duplicate-traces.err.exp
Normal file
@@ -0,0 +1,51 @@
|
||||
error:
|
||||
… from call site
|
||||
at /pwd/lang/eval-fail-duplicate-traces.nix:6:1:
|
||||
5| in
|
||||
6| throwAfter 2
|
||||
| ^
|
||||
7|
|
||||
|
||||
… while calling 'throwAfter'
|
||||
at /pwd/lang/eval-fail-duplicate-traces.nix:4:16:
|
||||
3| let
|
||||
4| throwAfter = n: if n > 0 then throwAfter (n - 1) else throw "Uh oh!";
|
||||
| ^
|
||||
5| in
|
||||
|
||||
… from call site
|
||||
at /pwd/lang/eval-fail-duplicate-traces.nix:4:33:
|
||||
3| let
|
||||
4| throwAfter = n: if n > 0 then throwAfter (n - 1) else throw "Uh oh!";
|
||||
| ^
|
||||
5| in
|
||||
|
||||
… while calling 'throwAfter'
|
||||
at /pwd/lang/eval-fail-duplicate-traces.nix:4:16:
|
||||
3| let
|
||||
4| throwAfter = n: if n > 0 then throwAfter (n - 1) else throw "Uh oh!";
|
||||
| ^
|
||||
5| in
|
||||
|
||||
… from call site
|
||||
at /pwd/lang/eval-fail-duplicate-traces.nix:4:33:
|
||||
3| let
|
||||
4| throwAfter = n: if n > 0 then throwAfter (n - 1) else throw "Uh oh!";
|
||||
| ^
|
||||
5| in
|
||||
|
||||
… while calling 'throwAfter'
|
||||
at /pwd/lang/eval-fail-duplicate-traces.nix:4:16:
|
||||
3| let
|
||||
4| throwAfter = n: if n > 0 then throwAfter (n - 1) else throw "Uh oh!";
|
||||
| ^
|
||||
5| in
|
||||
|
||||
… while calling the 'throw' builtin
|
||||
at /pwd/lang/eval-fail-duplicate-traces.nix:4:57:
|
||||
3| let
|
||||
4| throwAfter = n: if n > 0 then throwAfter (n - 1) else throw "Uh oh!";
|
||||
| ^
|
||||
5| in
|
||||
|
||||
error: Uh oh!
|
||||
6
fix/tests/tests/lang/eval-fail-duplicate-traces.nix
Normal file
6
fix/tests/tests/lang/eval-fail-duplicate-traces.nix
Normal file
@@ -0,0 +1,6 @@
|
||||
# Check that we only omit duplicate stack traces when there's a bunch of them.
|
||||
# Here, there's only a couple duplicate entries, so we output them all.
|
||||
let
|
||||
throwAfter = n: if n > 0 then throwAfter (n - 1) else throw "Uh oh!";
|
||||
in
|
||||
throwAfter 2
|
||||
6
fix/tests/tests/lang/eval-fail-eol-1.err.exp
Normal file
6
fix/tests/tests/lang/eval-fail-eol-1.err.exp
Normal file
@@ -0,0 +1,6 @@
|
||||
error: undefined variable 'invalid'
|
||||
at /pwd/lang/eval-fail-eol-1.nix:2:1:
|
||||
1| # foo
|
||||
2| invalid
|
||||
| ^
|
||||
3| # bar
|
||||
3
fix/tests/tests/lang/eval-fail-eol-1.nix
Normal file
3
fix/tests/tests/lang/eval-fail-eol-1.nix
Normal file
@@ -0,0 +1,3 @@
|
||||
# foo
|
||||
invalid
|
||||
# bar
|
||||
6
fix/tests/tests/lang/eval-fail-eol-2.err.exp
Normal file
6
fix/tests/tests/lang/eval-fail-eol-2.err.exp
Normal file
@@ -0,0 +1,6 @@
|
||||
error: undefined variable 'invalid'
|
||||
at /pwd/lang/eval-fail-eol-2.nix:2:1:
|
||||
1| # foo
|
||||
2| invalid
|
||||
| ^
|
||||
3| # bar
|
||||
2
fix/tests/tests/lang/eval-fail-eol-2.nix
Normal file
2
fix/tests/tests/lang/eval-fail-eol-2.nix
Normal file
@@ -0,0 +1,2 @@
|
||||
# foo
|
||||
invalid
|
||||
6
fix/tests/tests/lang/eval-fail-eol-3.err.exp
Normal file
6
fix/tests/tests/lang/eval-fail-eol-3.err.exp
Normal file
@@ -0,0 +1,6 @@
|
||||
error: undefined variable 'invalid'
|
||||
at /pwd/lang/eval-fail-eol-3.nix:2:1:
|
||||
1| # foo
|
||||
2| invalid
|
||||
| ^
|
||||
3| # bar
|
||||
3
fix/tests/tests/lang/eval-fail-eol-3.nix
Normal file
3
fix/tests/tests/lang/eval-fail-eol-3.nix
Normal file
@@ -0,0 +1,3 @@
|
||||
# foo
|
||||
invalid
|
||||
# bar
|
||||
@@ -0,0 +1,8 @@
|
||||
error:
|
||||
… while calling the 'fetchTree' builtin
|
||||
at /pwd/lang/eval-fail-fetchTree-negative.nix:1:1:
|
||||
1| builtins.fetchTree {
|
||||
| ^
|
||||
2| type = "file";
|
||||
|
||||
error: negative value given for 'fetchTree' argument 'owner': -1
|
||||
5
fix/tests/tests/lang/eval-fail-fetchTree-negative.nix
Normal file
5
fix/tests/tests/lang/eval-fail-fetchTree-negative.nix
Normal file
@@ -0,0 +1,5 @@
|
||||
builtins.fetchTree {
|
||||
type = "file";
|
||||
url = "file://eval-fail-fetchTree-negative.nix";
|
||||
owner = -1;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
error:
|
||||
… while calling the 'fetchurl' builtin
|
||||
at /pwd/lang/eval-fail-fetchurl-baseName-attrs-name.nix:1:1:
|
||||
1| builtins.fetchurl {
|
||||
| ^
|
||||
2| url = "https://example.com/foo.tar.gz";
|
||||
|
||||
error: invalid store path name when fetching URL 'https://example.com/foo.tar.gz': name '~wobble~' contains illegal character '~'. Please change the value for the 'name' attribute passed to 'fetchurl', so that it can create a valid store path.
|
||||
@@ -0,0 +1,4 @@
|
||||
builtins.fetchurl {
|
||||
url = "https://example.com/foo.tar.gz";
|
||||
name = "~wobble~";
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
error:
|
||||
… while calling the 'fetchurl' builtin
|
||||
at /pwd/lang/eval-fail-fetchurl-baseName-attrs.nix:1:1:
|
||||
1| builtins.fetchurl { url = "https://example.com/~wiggle~"; }
|
||||
| ^
|
||||
2|
|
||||
|
||||
error: invalid store path name when fetching URL 'https://example.com/~wiggle~': name '~wiggle~' contains illegal character '~'. Please add a valid 'name' attribute to the argument for 'fetchurl', so that it can create a valid store path.
|
||||
@@ -0,0 +1 @@
|
||||
builtins.fetchurl { url = "https://example.com/~wiggle~"; }
|
||||
8
fix/tests/tests/lang/eval-fail-fetchurl-baseName.err.exp
Normal file
8
fix/tests/tests/lang/eval-fail-fetchurl-baseName.err.exp
Normal file
@@ -0,0 +1,8 @@
|
||||
error:
|
||||
… while calling the 'fetchurl' builtin
|
||||
at /pwd/lang/eval-fail-fetchurl-baseName.nix:1:1:
|
||||
1| builtins.fetchurl "https://example.com/~wiggle~"
|
||||
| ^
|
||||
2|
|
||||
|
||||
error: invalid store path name when fetching URL 'https://example.com/~wiggle~': name '~wiggle~' contains illegal character '~'. Please pass an attribute set with 'url' and 'name' attributes to 'fetchurl', so that it can create a valid store path.
|
||||
1
fix/tests/tests/lang/eval-fail-fetchurl-baseName.nix
Normal file
1
fix/tests/tests/lang/eval-fail-fetchurl-baseName.nix
Normal file
@@ -0,0 +1 @@
|
||||
builtins.fetchurl "https://example.com/~wiggle~"
|
||||
@@ -0,0 +1,16 @@
|
||||
error:
|
||||
… while calling the 'seq' builtin
|
||||
at /pwd/lang/eval-fail-flake-ref-to-string-negative-integer.nix:4:1:
|
||||
3| in
|
||||
4| builtins.seq n (
|
||||
| ^
|
||||
5| builtins.flakeRefToString {
|
||||
|
||||
… while calling the 'flakeRefToString' builtin
|
||||
at /pwd/lang/eval-fail-flake-ref-to-string-negative-integer.nix:5:3:
|
||||
4| builtins.seq n (
|
||||
5| builtins.flakeRefToString {
|
||||
| ^
|
||||
6| type = "github";
|
||||
|
||||
error: negative value given for flake ref attr repo: -1
|
||||
@@ -0,0 +1,12 @@
|
||||
let
|
||||
n = -1;
|
||||
in
|
||||
builtins.seq n (
|
||||
builtins.flakeRefToString {
|
||||
type = "github";
|
||||
owner = "NixOS";
|
||||
repo = n;
|
||||
ref = "23.05";
|
||||
dir = "lib";
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,37 @@
|
||||
error:
|
||||
… while calling the 'foldl'' builtin
|
||||
at /pwd/lang/eval-fail-foldlStrict-strict-op-application.nix:2:1:
|
||||
1| # Tests that the result of applying op is forced even if the value is never used
|
||||
2| builtins.foldl' (_: f: f null) null [
|
||||
| ^
|
||||
3| (_: throw "Not the final value, but is still forced!")
|
||||
|
||||
… while calling anonymous lambda
|
||||
at /pwd/lang/eval-fail-foldlStrict-strict-op-application.nix:2:21:
|
||||
1| # Tests that the result of applying op is forced even if the value is never used
|
||||
2| builtins.foldl' (_: f: f null) null [
|
||||
| ^
|
||||
3| (_: throw "Not the final value, but is still forced!")
|
||||
|
||||
… from call site
|
||||
at /pwd/lang/eval-fail-foldlStrict-strict-op-application.nix:2:24:
|
||||
1| # Tests that the result of applying op is forced even if the value is never used
|
||||
2| builtins.foldl' (_: f: f null) null [
|
||||
| ^
|
||||
3| (_: throw "Not the final value, but is still forced!")
|
||||
|
||||
… while calling anonymous lambda
|
||||
at /pwd/lang/eval-fail-foldlStrict-strict-op-application.nix:3:4:
|
||||
2| builtins.foldl' (_: f: f null) null [
|
||||
3| (_: throw "Not the final value, but is still forced!")
|
||||
| ^
|
||||
4| (_: 23)
|
||||
|
||||
… while calling the 'throw' builtin
|
||||
at /pwd/lang/eval-fail-foldlStrict-strict-op-application.nix:3:7:
|
||||
2| builtins.foldl' (_: f: f null) null [
|
||||
3| (_: throw "Not the final value, but is still forced!")
|
||||
| ^
|
||||
4| (_: 23)
|
||||
|
||||
error: Not the final value, but is still forced!
|
||||
@@ -0,0 +1,5 @@
|
||||
# Tests that the result of applying op is forced even if the value is never used
|
||||
builtins.foldl' (_: f: f null) null [
|
||||
(_: throw "Not the final value, but is still forced!")
|
||||
(_: 23)
|
||||
]
|
||||
@@ -0,0 +1,8 @@
|
||||
error:
|
||||
… while calling the 'fromJSON' builtin
|
||||
at /pwd/lang/eval-fail-fromJSON-keyWithNullByte.nix:1:1:
|
||||
1| builtins.fromJSON ''{"a\u0000b": 1}''
|
||||
| ^
|
||||
2|
|
||||
|
||||
error: input string 'a␀b' cannot be represented as Nix string because it contains null bytes
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user