use monadify::applicative::kind::Applicative;
use monadify::identity::{Identity, IdentityKind};
use monadify::mdo;
use monadify::monad::kind::Bind;
use proptest::prelude::*;
use super::super::proptest_laws::arb_identity_i32;
#[test]
fn identity_mdo_two_bindings() {
let result: Identity<i32> = mdo! {
IdentityKind;
x <- Identity(2);
y <- Identity(3);
IdentityKind::pure(x + y)
};
assert_eq!(result, Identity(5));
}
#[test]
fn identity_mdo_let_binding_inside_block() {
let result: Identity<i32> = mdo! {
IdentityKind;
x <- Identity(10);
let doubled = x * 2;
IdentityKind::pure(doubled)
};
assert_eq!(result, Identity(20));
}
#[test]
fn identity_mdo_let_binding_combines_two_values() {
let result: Identity<i32> = mdo! {
IdentityKind;
x <- Identity(4);
y <- Identity(6);
let sum = x + y;
IdentityKind::pure(sum * 2)
};
assert_eq!(result, Identity(20));
}
#[test]
fn identity_mdo_bare_expr_sequencing() {
let result: Identity<i32> = mdo! {
IdentityKind;
x <- Identity(5);
Identity(());
IdentityKind::pure(x * 3)
};
assert_eq!(result, Identity(15));
}
#[test]
fn identity_mdo_let_and_bare_expr_combined() {
let result: Identity<String> = mdo! {
IdentityKind;
x <- Identity(7i32);
let label = "value";
Identity(());
IdentityKind::pure(format!("{}: {}", label, x))
};
assert_eq!(result, Identity("value: 7".to_string()));
}
#[test]
fn identity_mdo_equivalence_concrete() {
let ma: Identity<i32> = Identity(2);
let mb: Identity<i32> = Identity(3);
let ma_lhs = ma.clone();
let mb_lhs = mb.clone();
let lhs: Identity<i32> = mdo! {
IdentityKind;
x <- ma_lhs;
y <- mb_lhs;
IdentityKind::pure(x + y)
};
let rhs: Identity<i32> = IdentityKind::bind(ma.clone(), move |x| {
IdentityKind::bind(mb.clone(), move |y| IdentityKind::pure(x + y))
});
assert_eq!(lhs, rhs);
assert_eq!(lhs, Identity(5));
}
#[test]
fn identity_mdo_equivalence_negative_values() {
let ma: Identity<i32> = Identity(-10);
let mb: Identity<i32> = Identity(4);
let ma_lhs = ma.clone();
let mb_lhs = mb.clone();
let lhs: Identity<i32> = mdo! {
IdentityKind;
x <- ma_lhs;
y <- mb_lhs;
IdentityKind::pure(x + y)
};
let rhs: Identity<i32> = IdentityKind::bind(ma.clone(), move |x| {
IdentityKind::bind(mb.clone(), move |y| IdentityKind::pure(x + y))
});
assert_eq!(lhs, rhs);
assert_eq!(lhs, Identity(-6));
}
proptest! {
#![proptest_config(ProptestConfig { cases: 256, ..ProptestConfig::default() })]
#[test]
fn identity_mdo_equivalence_prop(
ma in arb_identity_i32(),
mb in arb_identity_i32(),
) {
let ma_lhs = ma.clone();
let mb_lhs = mb.clone();
let lhs: Identity<i32> = mdo! {
IdentityKind;
x <- ma_lhs;
y <- mb_lhs;
IdentityKind::pure(x.wrapping_add(y))
};
let rhs: Identity<i32> = IdentityKind::bind(ma.clone(), move |x| {
IdentityKind::bind(mb.clone(), move |y| IdentityKind::pure(x.wrapping_add(y)))
});
prop_assert_eq!(lhs, rhs);
}
}
#[test]
fn identity_mdo_three_bindings_chain() {
let result: Identity<i32> = mdo! {
IdentityKind;
x <- Identity(1);
y <- Identity(2);
z <- Identity(3);
IdentityKind::pure(x + y + z)
};
assert_eq!(result, Identity(6));
}
#[test]
fn identity_mdo_four_bindings_chain() {
let result: Identity<i32> = mdo! {
IdentityKind;
a <- Identity(10);
b <- Identity(20);
c <- Identity(30);
d <- Identity(40);
IdentityKind::pure(a + b + c + d)
};
assert_eq!(result, Identity(100));
}
#[test]
fn identity_mdo_three_bindings_with_let_mid_chain() {
let result: Identity<i32> = mdo! {
IdentityKind;
x <- Identity(3);
y <- Identity(4);
let product = x * y;
z <- Identity(product + 1);
IdentityKind::pure(z)
};
assert_eq!(result, Identity(13)); }