radn-rs/src/func/test_suite.rs
timofey 7f37bcbd49
Some checks failed
buildbot/cargo fmt (1.72) Build done.
buildbot/cargo doc (1.72) Build done.
buildbot/cargo clippy (1.65) Build done.
buildbot/cargo clippy (1.72) Build done.
buildbot/cargo test (1.65) Build done.
fail_follows_laws
2023-10-15 18:05:36 +00:00

147 lines
4.3 KiB
Rust

use std::sync::Arc;
use super::fail::*;
use super::shared::*;
use super::tests::*;
use super::*;
pub trait WrapFunction<'a, A, B>: 'a + Send + Sync + Fn(A) -> B {}
impl<'a, A, B, F: 'a + Send + Sync + Clone + Fn(A) -> B> WrapFunction<'a, A, B> for F {}
pub trait FunctorTestSuite<'a>: WeakFunctor<'a> + Eqr<'a> {
fn sample<A: 'a + Send, F: FnMut(Arc<dyn WrapFunction<'a, A, Self::F<A>>>)>(f: F);
}
pub trait FailTestSuite<'a, E: 'a + Send>: FunctorTestSuite<'a> + Fail<'a, E> {
fn sample_fail<F: FnMut(Arc<dyn 'a + Send + Sync + Fn() -> E>)>(f: F);
}
pub fn functor_follows_laws<'a, T: Functor<'a> + FunctorTestSuite<'a>>() -> R {
let mut res = R::default();
T::sample(|pa| {
res += fmap_respects_identity::<T, _>(|| pa(2));
});
T::sample(|pa| {
res += fmap_respects_composition::<T, _, _, _>(|x| x + 5, |x| x + 3, || pa(2));
});
T::sample(|pa| {
res += void_can_be_exressed_via_replace::<T, _>(|| pa(2));
});
res
}
pub fn applicative_follows_laws<'a, T: Applicative<'a> + FunctorTestSuite<'a>>() -> R {
let mut res = functor_follows_laws::<T>();
T::sample(|pa| {
res += seq_respects_identity::<T, _>(|| pa(2));
});
T::sample(|pa| {
T::sample(|pg| {
T::sample(|pf| {
res += seq_respects_composition::<T, _, _, _, _, _>(
|| pf(|x| x + 5),
|| pg(|x| x + 3),
|| pa(2),
);
})
})
});
res += seq_is_homomorphic::<T, _, _>(|x| x + 3, || 2);
T::sample(|pf| {
res += seq_respects_interchange::<T, _, _, _>(|| pf(|x| x + 3), || 2);
});
T::sample(|pa| {
T::sample(|pf| {
res += seq_can_be_expressed_via_la2::<T, _, _, _>(|| pf(|x| x + 3), || pa(2));
})
});
T::sample(|pa| {
res += fmap_can_be_expressed_via_seq::<T, _, _>(|x| x + 3, || pa(2));
});
T::sample(|pa| {
T::sample(|pb| {
let pa = pa.clone();
res += discard_can_be_expressed_via_seq_or_la2::<T, _, _>(move || pa(2), move || pb(2));
})
});
T::sample(|pa| {
T::sample(|pb| {
res += tuple_can_be_expressed_via_la2::<T, _, _>(|| pa(2), || pb(2));
})
});
T::sample(|pa| {
res += select_of_equal_is_same::<T, _>(move || pa(2));
});
res
}
pub fn monad_follows_laws<'a, T: Monad<'a> + FunctorTestSuite<'a>>() -> R {
let mut res = applicative_follows_laws::<T>();
T::sample(|pa| {
res += bind_respects_left_identity::<T, _, _>(move |x| pa(x + 3), || 2);
});
T::sample(|pa| {
res += bind_respects_right_identity::<T, _>(|| pa(2));
});
T::sample(|pa| {
T::sample(|pg| {
let pa = pa.clone();
T::sample(|pf| {
let pg = pg.clone();
res += bind_is_associative::<T, _, _, _>(
move |x| pf(x + 5),
move |x| pg(x + 3),
|| pa(2),
);
})
})
});
T::sample(|pa| {
T::sample(|pf| {
let pa = pa.clone();
seq_can_be_expressed_via_bind::<T, _, _, _>(|| pf(|x| x + 3), move || pa(2));
})
});
T::sample(|pa| {
res += fmap_can_be_expressed_via_bind::<T, _, _>(|x| x + 3, || pa(2));
});
T::sample(|pa| {
T::sample(|pb| {
res += join_can_be_expressed_via_bind::<T, _>(|| pa(pb(2)));
})
});
T::sample(|pa| {
T::sample(|pb| {
let pa = pa.clone();
res += iterate_can_be_expressed_via_bind::<T, _, _, _>(
move || pa(2),
move || {
let pb = pb.clone();
move |x| pb(x + 3)
},
);
})
});
res
}
pub fn shared_follows_laws<'a, T: SharedFunctor<'a> + FunctorTestSuite<'a>>() -> R {
let mut res = R::default();
T::sample(|pa| {
res += shared_is_same_as_original::<T, _>(move || pa(2));
});
T::sample(|pa| {
res += shared_is_same_after_clone::<T, _>(move || pa(2));
});
res
}
pub fn fail_functor_follows_laws<'a, T: Functor<'a> + FailTestSuite<'a, E>, E: 'a + Send>() -> R {
let mut res = R::default();
T::sample_fail(|pe| {
res += fmap_keeps_fail::<T, _, _, _>(move || pe(), |x: i32| x + 2);
});
res
}