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