use proptest::prelude::*;
use proptest::strategy::BoxedStrategy;
use crate::tests::property_tests::generators::directives::arb_directives;
use crate::tests::property_tests::generators::names::arb_field_name;
use crate::tests::property_tests::generators::names::arb_fragment_name;
use crate::tests::property_tests::generators::names::arb_type_name;
use crate::tests::property_tests::generators::values::arb_value;
use crate::tests::property_tests::generators::whitespace::arb_separator;
use crate::tests::property_tests::generators::whitespace::join_items;
pub fn arb_selection_set(depth: usize) -> BoxedStrategy<String> {
prop::collection::vec((arb_selection(depth), arb_separator()), 1..4)
.prop_map(|pairs| format!("{{ {} }}", join_items(&pairs)))
.boxed()
}
fn arb_selection(depth: usize) -> BoxedStrategy<String> {
if depth == 0 {
arb_simple_field()
} else {
prop_oneof![
4 => arb_field(depth),
1 => arb_fragment_spread(depth),
1 => arb_inline_fragment(depth),
]
.boxed()
}
}
fn arb_simple_field() -> BoxedStrategy<String> {
(
prop::option::weighted(0.2, arb_field_name()),
arb_field_name(),
arb_directives(0),
)
.prop_map(|(alias, name, dirs)| match alias {
Some(a) => format!("{a}: {name}{dirs}"),
None => format!("{name}{dirs}"),
})
.boxed()
}
fn arb_field(depth: usize) -> BoxedStrategy<String> {
(
prop::option::weighted(0.2, arb_field_name()),
arb_field_name(),
prop::option::weighted(0.3, arb_field_arguments(depth)),
arb_directives(depth.min(1)),
prop::option::weighted(0.4, arb_selection_set(depth - 1)),
)
.prop_map(|(alias, name, args, dirs, sub_sel)| {
let alias_str = alias.map_or(String::new(), |a| format!("{a}: "));
let args_str = args.map_or(String::new(), |a| format!("({a})"));
let sub_str = sub_sel.map_or(String::new(), |s| format!(" {s}"));
format!("{alias_str}{name}{args_str}{dirs}{sub_str}")
})
.boxed()
}
fn arb_field_arguments(depth: usize) -> BoxedStrategy<String> {
let arb_arg = (arb_field_name(), arb_value(depth.min(2)))
.prop_map(|(name, val)| format!("{name}: {val}"));
prop::collection::vec((arb_arg, arb_separator()), 1..4)
.prop_map(|pairs| join_items(&pairs))
.boxed()
}
fn arb_fragment_spread(depth: usize) -> BoxedStrategy<String> {
(arb_fragment_name(), arb_directives(depth.min(1)))
.prop_map(|(name, dirs)| format!("...{name}{dirs}"))
.boxed()
}
fn arb_inline_fragment(depth: usize) -> BoxedStrategy<String> {
(
prop::option::weighted(0.8, arb_type_name()),
arb_directives(depth.min(1)),
arb_selection_set(depth - 1),
)
.prop_map(|(type_cond, dirs, sel_set)| {
let tc_str = type_cond.map_or(String::new(), |t| format!(" on {t}"));
format!("...{tc_str}{dirs} {sel_set}")
})
.boxed()
}