tvix_eval/value/
arbitrary.rs1use proptest::collection::{hash_map, vec};
4use proptest::{prelude::*, strategy::BoxedStrategy};
5use rustc_hash::FxHashMap;
6use std::ffi::OsString;
7
8use super::{NixAttrs, NixList, NixString, Value};
9
10#[derive(Clone)]
11pub enum Parameters {
12 Strategy(BoxedStrategy<Value>),
13 Parameters {
14 generate_internal_values: bool,
15 generate_functions: bool,
16 generate_nested: bool,
17 },
18}
19
20impl Default for Parameters {
21 fn default() -> Self {
22 Self::Parameters {
23 generate_internal_values: false,
24 generate_functions: false,
25 generate_nested: true,
26 }
27 }
28}
29
30impl Arbitrary for NixAttrs {
31 type Parameters = Parameters;
32 type Strategy = BoxedStrategy<Self>;
33
34 fn arbitrary_with(args: Self::Parameters) -> Self::Strategy {
35 hash_map(NixString::arbitrary(), Value::arbitrary_with(args), 0..100)
36 .prop_map(|map| FxHashMap::from_iter(map).into())
37 .boxed()
38 }
39}
40
41impl Arbitrary for NixList {
42 type Parameters = <Value as Arbitrary>::Parameters;
43 type Strategy = BoxedStrategy<Self>;
44
45 fn arbitrary_with(args: Self::Parameters) -> Self::Strategy {
46 vec(<Value as Arbitrary>::arbitrary_with(args), 0..100)
47 .prop_map(NixList::from)
48 .boxed()
49 }
50}
51
52impl Arbitrary for Value {
53 type Parameters = Parameters;
54 type Strategy = BoxedStrategy<Self>;
55
56 fn arbitrary_with(args: Self::Parameters) -> Self::Strategy {
57 match args {
58 Parameters::Strategy(s) => s,
59 Parameters::Parameters {
60 generate_internal_values,
61 generate_functions,
62 generate_nested,
63 } => {
64 if generate_internal_values || generate_functions {
65 todo!("Generating internal values and functions not implemented yet")
66 } else if generate_nested {
67 non_internal_value().boxed()
68 } else {
69 leaf_value().boxed()
70 }
71 }
72 }
73 }
74}
75
76fn leaf_value() -> impl Strategy<Value = Value> {
77 use Value::*;
78
79 prop_oneof![
80 Just(Null),
81 any::<bool>().prop_map(Bool),
82 any::<i64>().prop_map(Integer),
83 any::<f64>().prop_map(Float),
84 any::<NixString>().prop_map(String),
85 any::<OsString>().prop_map(|s| Path(Box::new(s.into()))),
86 ]
87}
88
89fn non_internal_value() -> impl Strategy<Value = Value> {
90 leaf_value().prop_recursive(3, 5, 5, |inner| {
91 prop_oneof![
92 NixAttrs::arbitrary_with(Parameters::Strategy(inner.clone())).prop_map(Value::attrs),
93 any_with::<NixList>(Parameters::Strategy(inner)).prop_map(Value::List)
94 ]
95 })
96}