hegeltest 0.36.0

Property-based testing for Rust, built on Hypothesis
Documentation
use super::{DefaultGenerator, Generator, PrintableGenerator, TestCase, labels};
use crate::pretty::PrettyPrinter;
use std::marker::PhantomData;

/// Creates a tuple generator from 0–12 component generators.
///
/// The component generators keep their concrete types, so the result is a
/// nameable, arity-specific generator type: [`Tuple0Generator`](crate::generators::Tuple0Generator)
/// through [`Tuple12Generator`](crate::generators::Tuple12Generator).
///
/// # Examples
///
/// ```no_run
/// use hegel::generators as gs;
/// use hegel::tuples;
///
/// // 0-tuple (unit)
/// let gen0 = tuples!();
///
/// // 1-tuple
/// let gen1 = tuples!(gs::integers::<i32>());
///
/// // 2-tuple
/// let gen2 = tuples!(gs::integers::<i32>(), gs::booleans());
///
/// // 3-tuple
/// let gen3 = tuples!(gs::integers::<i32>(), gs::booleans(), gs::text());
/// ```
#[macro_export]
macro_rules! tuples {
    () => {
        $crate::generators::tuples0()
    };
    ($g1:expr $(,)?) => {
        $crate::generators::tuples1($g1)
    };
    ($g1:expr, $g2:expr $(,)?) => {
        $crate::generators::tuples2($g1, $g2)
    };
    ($g1:expr, $g2:expr, $g3:expr $(,)?) => {
        $crate::generators::tuples3($g1, $g2, $g3)
    };
    ($g1:expr, $g2:expr, $g3:expr, $g4:expr $(,)?) => {
        $crate::generators::tuples4($g1, $g2, $g3, $g4)
    };
    ($g1:expr, $g2:expr, $g3:expr, $g4:expr, $g5:expr $(,)?) => {
        $crate::generators::tuples5($g1, $g2, $g3, $g4, $g5)
    };
    ($g1:expr, $g2:expr, $g3:expr, $g4:expr, $g5:expr, $g6:expr $(,)?) => {
        $crate::generators::tuples6($g1, $g2, $g3, $g4, $g5, $g6)
    };
    ($g1:expr, $g2:expr, $g3:expr, $g4:expr, $g5:expr, $g6:expr, $g7:expr $(,)?) => {
        $crate::generators::tuples7($g1, $g2, $g3, $g4, $g5, $g6, $g7)
    };
    ($g1:expr, $g2:expr, $g3:expr, $g4:expr, $g5:expr, $g6:expr, $g7:expr, $g8:expr $(,)?) => {
        $crate::generators::tuples8($g1, $g2, $g3, $g4, $g5, $g6, $g7, $g8)
    };
    ($g1:expr, $g2:expr, $g3:expr, $g4:expr, $g5:expr, $g6:expr, $g7:expr, $g8:expr, $g9:expr $(,)?) => {
        $crate::generators::tuples9($g1, $g2, $g3, $g4, $g5, $g6, $g7, $g8, $g9)
    };
    ($g1:expr, $g2:expr, $g3:expr, $g4:expr, $g5:expr, $g6:expr, $g7:expr, $g8:expr, $g9:expr, $g10:expr $(,)?) => {
        $crate::generators::tuples10($g1, $g2, $g3, $g4, $g5, $g6, $g7, $g8, $g9, $g10)
    };
    ($g1:expr, $g2:expr, $g3:expr, $g4:expr, $g5:expr, $g6:expr, $g7:expr, $g8:expr, $g9:expr, $g10:expr, $g11:expr $(,)?) => {
        $crate::generators::tuples11($g1, $g2, $g3, $g4, $g5, $g6, $g7, $g8, $g9, $g10, $g11)
    };
    ($g1:expr, $g2:expr, $g3:expr, $g4:expr, $g5:expr, $g6:expr, $g7:expr, $g8:expr, $g9:expr, $g10:expr, $g11:expr, $g12:expr $(,)?) => {
        $crate::generators::tuples12(
            $g1, $g2, $g3, $g4, $g5, $g6, $g7, $g8, $g9, $g10, $g11, $g12,
        )
    };
    ($g1:expr, $g2:expr, $g3:expr, $g4:expr, $g5:expr, $g6:expr, $g7:expr, $g8:expr, $g9:expr, $g10:expr, $g11:expr, $g12:expr, $($rest:tt)+) => {
        compile_error!(
            "tuples! supports at most 12 generators; for wider shapes, nest \
             tuples! calls or write a composite generator"
        )
    };
}

macro_rules! impl_tuple {
    ($name:ident, $fn_name:ident, $arity:literal, $(($idx:tt, $field:ident, $G:ident, $T:ident)),+) => {
        #[doc = concat!(
            "The ", $arity, "-element tuple generator created by [`tuples!`](crate::tuples)."
        )]
        pub struct $name<$($G,)+ $($T,)+> {
            $($field: $G,)+
            _phantom: PhantomData<fn($($T,)+)>,
        }

        impl<$($T,)+ $($G,)+> Generator<($($T,)+)> for $name<$($G,)+ $($T,)+>
        where
            $($G: Generator<$T>,)+
        {
            fn do_draw(&self, tc: &TestCase) -> ($($T,)+) {
                tc.start_span(labels::TUPLE);
                let result = ($(self.$field.do_draw(tc),)+);
                tc.stop_span(false);
                result
            }
        }

        impl<$($T,)+ $($G,)+> PrintableGenerator<($($T,)+)> for $name<$($G,)+ $($T,)+>
        where
            $($G: PrintableGenerator<$T>,)+
        {
            fn do_draw_and_print(
                &self,
                tc: &TestCase,
                printer: &mut PrettyPrinter,
            ) -> ($($T,)+) {
                tc.start_span(labels::TUPLE);
                printer.begin_group(1, "(");
                let mut index = 0usize;
                let result = ($(
                    {
                        if index > 0 {
                            printer.text(",");
                            printer.breakable(" ");
                        }
                        index += 1;
                        tc.draw_and_print(&self.$field, printer)
                    },
                )+);
                if index == 1 {
                    printer.text(",");
                }
                printer.end_group(")");
                tc.stop_span(false);
                result
            }
        }

        #[doc(hidden)]
        pub fn $fn_name<$($T,)+ $($G: Generator<$T>,)+>(
            $($field: $G,)+
        ) -> $name<$($G,)+ $($T,)+> {
            $name {
                $($field,)+
                _phantom: PhantomData,
            }
        }

        impl<$($T: DefaultGenerator + 'static,)+> DefaultGenerator for ($($T,)+)
        where
            $(<$T as DefaultGenerator>::Generator: Send + Sync,)+
        {
            type Generator = $name<$(<$T as DefaultGenerator>::Generator,)+ $($T,)+>;
            fn default_generator() -> Self::Generator {
                $fn_name($(<$T>::default_generator(),)+)
            }
        }
    };
}

/// Generator for the unit type `()`. Created by [`tuples0()`].
pub struct Tuple0Generator;

impl Generator<()> for Tuple0Generator {
    fn do_draw(&self, _tc: &TestCase) {}
}

impl PrintableGenerator<()> for Tuple0Generator {
    fn do_draw_and_print(&self, _tc: &TestCase, printer: &mut PrettyPrinter) {
        printer.text("()");
    }
}

#[doc(hidden)]
pub fn tuples0() -> Tuple0Generator {
    Tuple0Generator
}

impl DefaultGenerator for () {
    type Generator = Tuple0Generator;
    fn default_generator() -> Self::Generator {
        tuples0()
    }
}

impl_tuple!(Tuple1Generator, tuples1, 1, (0, gen1, G1, T1));
impl_tuple!(
    Tuple2Generator,
    tuples2,
    2,
    (0, gen1, G1, T1),
    (1, gen2, G2, T2)
);
impl_tuple!(
    Tuple3Generator,
    tuples3,
    3,
    (0, gen1, G1, T1),
    (1, gen2, G2, T2),
    (2, gen3, G3, T3)
);
impl_tuple!(
    Tuple4Generator,
    tuples4,
    4,
    (0, gen1, G1, T1),
    (1, gen2, G2, T2),
    (2, gen3, G3, T3),
    (3, gen4, G4, T4)
);
impl_tuple!(
    Tuple5Generator,
    tuples5,
    5,
    (0, gen1, G1, T1),
    (1, gen2, G2, T2),
    (2, gen3, G3, T3),
    (3, gen4, G4, T4),
    (4, gen5, G5, T5)
);
impl_tuple!(
    Tuple6Generator,
    tuples6,
    6,
    (0, gen1, G1, T1),
    (1, gen2, G2, T2),
    (2, gen3, G3, T3),
    (3, gen4, G4, T4),
    (4, gen5, G5, T5),
    (5, gen6, G6, T6)
);
impl_tuple!(
    Tuple7Generator,
    tuples7,
    7,
    (0, gen1, G1, T1),
    (1, gen2, G2, T2),
    (2, gen3, G3, T3),
    (3, gen4, G4, T4),
    (4, gen5, G5, T5),
    (5, gen6, G6, T6),
    (6, gen7, G7, T7)
);
impl_tuple!(
    Tuple8Generator,
    tuples8,
    8,
    (0, gen1, G1, T1),
    (1, gen2, G2, T2),
    (2, gen3, G3, T3),
    (3, gen4, G4, T4),
    (4, gen5, G5, T5),
    (5, gen6, G6, T6),
    (6, gen7, G7, T7),
    (7, gen8, G8, T8)
);
impl_tuple!(
    Tuple9Generator,
    tuples9,
    9,
    (0, gen1, G1, T1),
    (1, gen2, G2, T2),
    (2, gen3, G3, T3),
    (3, gen4, G4, T4),
    (4, gen5, G5, T5),
    (5, gen6, G6, T6),
    (6, gen7, G7, T7),
    (7, gen8, G8, T8),
    (8, gen9, G9, T9)
);
impl_tuple!(
    Tuple10Generator,
    tuples10,
    10,
    (0, gen1, G1, T1),
    (1, gen2, G2, T2),
    (2, gen3, G3, T3),
    (3, gen4, G4, T4),
    (4, gen5, G5, T5),
    (5, gen6, G6, T6),
    (6, gen7, G7, T7),
    (7, gen8, G8, T8),
    (8, gen9, G9, T9),
    (9, gen10, G10, T10)
);
impl_tuple!(
    Tuple11Generator,
    tuples11,
    11,
    (0, gen1, G1, T1),
    (1, gen2, G2, T2),
    (2, gen3, G3, T3),
    (3, gen4, G4, T4),
    (4, gen5, G5, T5),
    (5, gen6, G6, T6),
    (6, gen7, G7, T7),
    (7, gen8, G8, T8),
    (8, gen9, G9, T9),
    (9, gen10, G10, T10),
    (10, gen11, G11, T11)
);
impl_tuple!(
    Tuple12Generator,
    tuples12,
    12,
    (0, gen1, G1, T1),
    (1, gen2, G2, T2),
    (2, gen3, G3, T3),
    (3, gen4, G4, T4),
    (4, gen5, G5, T5),
    (5, gen6, G6, T6),
    (6, gen7, G7, T7),
    (7, gen8, G8, T8),
    (8, gen9, G9, T9),
    (9, gen10, G10, T10),
    (10, gen11, G11, T11),
    (11, gen12, G12, T12)
);