composition tests
Some checks failed
buildbot/cargo fmt (1.72) Build done.
buildbot/cargo clippy (1.65) Build done.
buildbot/cargo doc (1.72) Build done.
buildbot/cargo test (1.65) Build done.
buildbot/cargo clippy (1.72) Build done.

This commit is contained in:
AF 2023-10-15 17:02:22 +00:00
parent ee86a0092f
commit 3fb5d996fa
9 changed files with 107 additions and 27 deletions

View File

@ -176,3 +176,41 @@ impl<'a, U: SharedFunctor<'a> + Functor<'a>, V: SharedFunctor<'a>> SharedFunctor
U::fmap(U::unshare(sa), V::unshare) U::fmap(U::unshare(sa), V::unshare)
} }
} }
#[cfg(test)]
mod composition_tests {
use crate::func::instances::{option::OptionInstance, result::ResultInstance};
use super::{test_suite, tests, CompositionInstance};
type T = CompositionInstance<OptionInstance, ResultInstance<i32>>;
impl<'a> tests::Eqr<'a> for T {
fn eqr<A: 'a + Send + PartialEq + std::fmt::Debug>(
name: &'a str,
left: Self::F<A>,
right: Self::F<A>,
) -> tests::R {
tests::eqr(name, left, right)
}
}
impl<'a> test_suite::FunctorTestSuite<'a> for T {
fn sample<A: 'a + Send, F: FnMut(Box<dyn test_suite::WrapFunction<'a, A, Self::F<A>>>)>(
mut f: F,
) {
OptionInstance::sample(|ua0| {
ResultInstance::sample(|a0| {
let ua0 = std::sync::Arc::new(ua0.clone_boxed());
let a0 = std::sync::Arc::new(a0.clone_boxed());
f(Box::new(move |a| ua0(a0(a))))
})
});
}
}
#[test]
fn monad_follows_laws() {
test_suite::monad_follows_laws::<T>().unwrap();
}
}

View File

@ -232,11 +232,13 @@ mod effect_tests {
} }
impl<'a> test_suite::FunctorTestSuite<'a> for T { impl<'a> test_suite::FunctorTestSuite<'a> for T {
fn sample<A: 'a + Send, F: FnMut(&'a (dyn Send + Sync + Fn(A) -> Self::F<A>))>(mut f: F) { fn sample<A: 'a + Send, F: FnMut(Box<dyn test_suite::WrapFunction<'a, A, Self::F<A>>>)>(
f(&|a| WithEffect { mut f: F,
) {
f(Box::new(|a| WithEffect {
value: a, value: a,
effect: TestEffect::Sample, effect: TestEffect::Sample,
}); }));
} }
} }

View File

@ -160,8 +160,10 @@ mod future_tests {
} }
impl<'a> test_suite::FunctorTestSuite<'a> for T { impl<'a> test_suite::FunctorTestSuite<'a> for T {
fn sample<A: 'a + Send, F: FnMut(&'a (dyn Send + Sync + Fn(A) -> Self::F<A>))>(mut f: F) { fn sample<A: 'a + Send, F: FnMut(Box<dyn test_suite::WrapFunction<'a, A, Self::F<A>>>)>(
f(&|a| Box::pin(futures::future::ready(a))); mut f: F,
) {
f(Box::new(|a| Box::pin(futures::future::ready(a))));
} }
} }

View File

@ -120,8 +120,10 @@ mod lazy_tests {
} }
impl<'a> test_suite::FunctorTestSuite<'a> for T { impl<'a> test_suite::FunctorTestSuite<'a> for T {
fn sample<A: 'a + Send, F: FnMut(&'a (dyn Send + Sync + Fn(A) -> Self::F<A>))>(mut f: F) { fn sample<A: 'a + Send, F: FnMut(Box<dyn test_suite::WrapFunction<'a, A, Self::F<A>>>)>(
f(&|a| Box::new(|| a)); mut f: F,
) {
f(Box::new(|a| Box::new(|| a)));
} }
} }

View File

@ -149,9 +149,11 @@ mod option_tests {
} }
impl<'a> test_suite::FunctorTestSuite<'a> for T { impl<'a> test_suite::FunctorTestSuite<'a> for T {
fn sample<A: 'a + Send, F: FnMut(&'a (dyn Send + Sync + Fn(A) -> Self::F<A>))>(mut f: F) { fn sample<A: 'a + Send, F: FnMut(Box<dyn test_suite::WrapFunction<'a, A, Self::F<A>>>)>(
f(&|_| None); mut f: F,
f(&|a| Some(a)); ) {
f(Box::new(|_| None));
f(Box::new(|a| Some(a)));
} }
} }

View File

@ -263,12 +263,14 @@ mod result_tests {
} }
impl<'a> test_suite::FunctorTestSuite<'a> for T { impl<'a> test_suite::FunctorTestSuite<'a> for T {
fn sample<A: 'a + Send, F: FnMut(&'a (dyn Send + Sync + Fn(A) -> Self::F<A>))>(mut f: F) { fn sample<A: 'a + Send, F: FnMut(Box<dyn test_suite::WrapFunction<'a, A, Self::F<A>>>)>(
f(&|_| Err(0)); mut f: F,
f(&|_| Err(1)); ) {
f(&|_| Err(2)); f(Box::new(|_| Err(0)));
f(&|_| Err(3)); f(Box::new(|_| Err(1)));
f(&|a| Ok(a)); f(Box::new(|_| Err(2)));
f(Box::new(|_| Err(3)));
f(Box::new(|a| Ok(a)));
} }
} }

View File

@ -134,8 +134,10 @@ mod solo_tests {
} }
impl<'a> test_suite::FunctorTestSuite<'a> for T { impl<'a> test_suite::FunctorTestSuite<'a> for T {
fn sample<A: 'a + Send, F: FnMut(&'a (dyn Send + Sync + Fn(A) -> Self::F<A>))>(mut f: F) { fn sample<A: 'a + Send, F: FnMut(Box<dyn test_suite::WrapFunction<'a, A, Self::F<A>>>)>(
f(&|a| a); mut f: F,
) {
f(Box::new(|a| a));
} }
} }

View File

@ -279,8 +279,10 @@ mod stackless_test {
} }
impl<'a> test_suite::FunctorTestSuite<'a> for T { impl<'a> test_suite::FunctorTestSuite<'a> for T {
fn sample<A: 'a + Send, F: FnMut(&'a (dyn Send + Sync + Fn(A) -> Self::F<A>))>(mut f: F) { fn sample<A: 'a + Send, F: FnMut(Box<dyn test_suite::WrapFunction<'a, A, Self::F<A>>>)>(
f(&|a| a.into()); mut f: F,
) {
f(Box::new(|a| a.into()));
} }
} }

View File

@ -1,8 +1,20 @@
use std::sync::Arc;
use super::tests::*; use super::tests::*;
use super::*; use super::*;
pub trait WrapFunction<'a, A, B>: 'a + Send + Sync + Fn(A) -> B {
fn clone_boxed(&self) -> Box<dyn WrapFunction<'a, A, B>>;
}
impl<'a, A, B, F: 'a + Send + Sync + Clone + Fn(A) -> B> WrapFunction<'a, A, B> for F {
fn clone_boxed(&self) -> Box<dyn WrapFunction<'a, A, B>> {
Box::new(self.clone())
}
}
pub trait FunctorTestSuite<'a>: WeakFunctor<'a> + Eqr<'a> { pub trait FunctorTestSuite<'a>: WeakFunctor<'a> + Eqr<'a> {
fn sample<A: 'a + Send, F: FnMut(&'a (dyn Send + Sync + Fn(A) -> Self::F<A>))>(f: F); fn sample<A: 'a + Send, F: FnMut(Box<dyn WrapFunction<'a, A, Self::F<A>>>)>(f: F);
} }
pub fn functor_follows_laws<'a, T: Functor<'a> + FunctorTestSuite<'a>>() -> R { pub fn functor_follows_laws<'a, T: Functor<'a> + FunctorTestSuite<'a>>() -> R {
@ -49,7 +61,8 @@ pub fn applicative_follows_laws<'a, T: Applicative<'a> + FunctorTestSuite<'a>>()
}); });
T::sample(|pa| { T::sample(|pa| {
T::sample(|pb| { T::sample(|pb| {
res += discard_can_be_expressed_via_seq_or_la2::<T, _, _>(|| pa(2), || pb(2)); let pa = pa.clone_boxed();
res += discard_can_be_expressed_via_seq_or_la2::<T, _, _>(move || pa(2), move || pb(2));
}) })
}); });
T::sample(|pa| { T::sample(|pa| {
@ -58,7 +71,7 @@ pub fn applicative_follows_laws<'a, T: Applicative<'a> + FunctorTestSuite<'a>>()
}) })
}); });
T::sample(|pa| { T::sample(|pa| {
res += select_of_equal_is_same::<T, _>(|| pa(2)); res += select_of_equal_is_same::<T, _>(move || pa(2));
}); });
res res
} }
@ -66,21 +79,29 @@ pub fn applicative_follows_laws<'a, T: Applicative<'a> + FunctorTestSuite<'a>>()
pub fn monad_follows_laws<'a, T: Monad<'a> + FunctorTestSuite<'a>>() -> R { pub fn monad_follows_laws<'a, T: Monad<'a> + FunctorTestSuite<'a>>() -> R {
let mut res = applicative_follows_laws::<T>(); let mut res = applicative_follows_laws::<T>();
T::sample(|pa| { T::sample(|pa| {
res += bind_respects_left_identity::<T, _, _>(|x| pa(x + 3), || 2); res += bind_respects_left_identity::<T, _, _>(move |x| pa(x + 3), || 2);
}); });
T::sample(|pa| { T::sample(|pa| {
res += bind_respects_right_identity::<T, _>(|| pa(2)); res += bind_respects_right_identity::<T, _>(|| pa(2));
}); });
T::sample(|pa| { T::sample(|pa| {
T::sample(|pg| { T::sample(|pg| {
let pa = pa.clone_boxed();
T::sample(|pf| { T::sample(|pf| {
res += bind_is_associative::<T, _, _, _>(|x| pf(x + 5), |x| pg(x + 3), || pa(2)); let pg = Arc::new(pg.clone_boxed());
let pf = Arc::new(pf);
res += bind_is_associative::<T, _, _, _>(
move |x| pf(x + 5),
move |x| pg(x + 3),
|| pa(2),
);
}) })
}) })
}); });
T::sample(|pa| { T::sample(|pa| {
T::sample(|pf| { T::sample(|pf| {
seq_can_be_expressed_via_bind::<T, _, _, _>(|| pf(|x| x + 3), || pa(2)); let pa = pa.clone_boxed();
seq_can_be_expressed_via_bind::<T, _, _, _>(|| pf(|x| x + 3), move || pa(2));
}) })
}); });
T::sample(|pa| { T::sample(|pa| {
@ -93,7 +114,14 @@ pub fn monad_follows_laws<'a, T: Monad<'a> + FunctorTestSuite<'a>>() -> R {
}); });
T::sample(|pa| { T::sample(|pa| {
T::sample(|pb| { T::sample(|pb| {
res += iterate_can_be_expressed_via_bind::<T, _, _, _>(|| pa(2), || |x| pb(x + 3)); let pa = pa.clone_boxed();
res += iterate_can_be_expressed_via_bind::<T, _, _, _>(
move || pa(2),
move || {
let pb = pb.clone_boxed();
move |x| pb(x + 3)
},
);
}) })
}); });
res res