From b04d429f19b405763f9f2e565f34d90900bfab94 Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Fri, 14 Jun 2024 19:29:33 +0200 Subject: [PATCH] test: Make sure require_* functions force thunks (cherry picked from commit 69b661db22e4b16fb08d322f5fede480438e2b71) --- rust/nix-expr/src/eval_state.rs | 78 +++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/rust/nix-expr/src/eval_state.rs b/rust/nix-expr/src/eval_state.rs index f958ee4..592abb1 100644 --- a/rust/nix-expr/src/eval_state.rs +++ b/rust/nix-expr/src/eval_state.rs @@ -529,6 +529,29 @@ mod tests { .unwrap(); } + /// A helper that turns an expression into a thunk. + fn make_thunk(es: &EvalState, expr: &str) -> Value { + // This would be silly in real code, but it works for the current Nix implementation. + // A Nix implementation that applies the identity function eagerly would be a valid + // Nix implementation, but annoying because we'll have to change this helper to do + // something more complicated that isn't optimized away. + let f = es.eval_from_string("x: x", "").unwrap(); + let v = es.eval_from_string(expr, "").unwrap(); + es.new_value_apply(&f, &v).unwrap() + } + + #[test] + fn make_thunk_helper_works() { + gc_registering_current_thread(|| { + let store = Store::open("auto", HashMap::new()).unwrap(); + let es = EvalState::new(store, []).unwrap(); + let v = make_thunk(&es, "1"); + let t = es.value_type_unforced(&v); + assert!(t == None); + }) + .unwrap(); + } + #[test] fn eval_state_value_attrs_names_empty() { gc_registering_current_thread(|| { @@ -544,6 +567,20 @@ mod tests { .unwrap() } + #[test] + fn eval_state_require_attrs_names_forces_thunk() { + gc_registering_current_thread(|| { + let store = Store::open("auto", HashMap::new()).unwrap(); + let es = EvalState::new(store, []).unwrap(); + let v = make_thunk(&es, "{ a = 1; b = 2; }"); + let t = es.value_type_unforced(&v); + assert!(t == None); + let attrs = es.require_attrs_names(&v).unwrap(); + assert_eq!(attrs.len(), 2); + }) + .unwrap() + } + #[test] fn eval_state_require_attrs_names_bad_type() { gc_registering_current_thread(|| { @@ -603,6 +640,20 @@ mod tests { .unwrap() } + #[test] + fn eval_state_require_attrs_select_forces_thunk() { + gc_registering_current_thread(|| { + let store = Store::open("auto", HashMap::new()).unwrap(); + let es = EvalState::new(store, []).unwrap(); + let expr = r#"{ a = "aye"; b = "bee"; }"#; + let v = make_thunk(&es, expr); + assert!(es.value_type_unforced(&v).is_none()); + let r = es.require_attrs_select(&v, "a"); + assert!(r.is_ok()); + }) + .unwrap() + } + #[test] fn eval_state_require_attrs_select_error() { gc_registering_current_thread(|| { @@ -641,6 +692,20 @@ mod tests { .unwrap() } + #[test] + fn eval_state_require_attrs_select_opt_forces_thunk() { + gc_registering_current_thread(|| { + let store = Store::open("auto", HashMap::new()).unwrap(); + let es = EvalState::new(store, []).unwrap(); + let expr = r#"{ a = "aye"; b = "bee"; }"#; + let v = make_thunk(&es, expr); + assert!(es.value_type_unforced(&v).is_none()); + let r = es.require_attrs_select_opt(&v, "a"); + assert!(r.is_ok()); + }) + .unwrap() + } + #[test] fn eval_state_require_attrs_select_opt_error() { gc_registering_current_thread(|| { @@ -677,6 +742,19 @@ mod tests { .unwrap(); } + #[test] + fn eval_state_value_string_forces_thunk() { + gc_registering_current_thread(|| { + let store = Store::open("auto", HashMap::new()).unwrap(); + let es = EvalState::new(store, []).unwrap(); + let v = make_thunk(&es, "\"hello\""); + assert!(es.value_type_unforced(&v).is_none()); + let s = es.require_string(&v).unwrap(); + assert!(s == "hello"); + }) + .unwrap(); + } + #[test] fn eval_state_value_string_unexpected_bool() { gc_registering_current_thread(|| {