use proptest::prelude::*;
use test_lang::{Change, Diff, Snapshot};
fn reconstruct(diff: &Diff, keep: impl Fn(Change) -> bool) -> String {
let kept: Vec<&str> = diff
.changes()
.filter(|(change, _)| keep(*change))
.map(|(_, line)| line)
.collect();
kept.join("\n")
}
proptest! {
#[test]
fn prop_snapshot_matches_its_own_text(input in ".*") {
let snapshot = Snapshot::new(&input);
prop_assert!(snapshot.check(snapshot.as_str()).is_ok());
}
#[test]
fn prop_normalization_is_idempotent(input in ".*") {
let once = Snapshot::new(&input);
let twice = Snapshot::new(once.as_str());
prop_assert_eq!(once.as_str(), twice.as_str());
}
#[test]
fn prop_check_ok_iff_normalized_equal(a in ".*", b in ".*") {
let sa = Snapshot::new(&a);
let sb = Snapshot::new(&b);
let normalized_equal = sa.as_str() == sb.as_str();
prop_assert_eq!(sa.check(sb.as_str()).is_ok(), normalized_equal);
}
#[test]
fn prop_diff_reconstructs_both_sides(
expected in "[a-c\n]{0,40}",
actual in "[a-c\n]{0,40}",
) {
let expected = Snapshot::new(&expected);
let actual = Snapshot::new(&actual);
let diff = Diff::lines(expected.as_str(), actual.as_str());
let rebuilt_expected = reconstruct(&diff, |c| c != Change::Insert);
let rebuilt_actual = reconstruct(&diff, |c| c != Change::Delete);
prop_assert_eq!(rebuilt_expected, expected.as_str());
prop_assert_eq!(rebuilt_actual, actual.as_str());
}
#[test]
fn prop_diff_empty_iff_equal(
expected in "[a-c\n]{0,40}",
actual in "[a-c\n]{0,40}",
) {
let expected = Snapshot::new(&expected);
let actual = Snapshot::new(&actual);
let diff = Diff::lines(expected.as_str(), actual.as_str());
prop_assert_eq!(diff.is_empty(), expected.as_str() == actual.as_str());
}
#[test]
fn prop_per_line_equals_newline_join(items in prop::collection::vec("[a-z]{1,6}", 0..20)) {
let snapshot = Snapshot::per_line(&items);
prop_assert!(snapshot.check(items.join("\n")).is_ok());
}
}