final class DiffTests: XCTestCase { override static func setUp() { sranddev() } typealias Term = RangedTerm.Term typealias Diff = Free> let interpreter = Interpreter(equal: ==, comparable: const(true), cost: Diff.sum(const(1))) func testEqualTermsProduceIdentityDiffs() { property("equal terms produce identity diffs") <- forAll { (term: RangedTerm) in Diff.sum(const(1))(self.interpreter.run(term.term, term.term)) == 0 } } func testInequalTermsProduceNonIdentityDiffs() { property("inequal terms produce non-identity diffs") <- forAll { (diff: RangedDiff) in (!Term.equals(annotation: const(true), leaf: ==)(diff.a.term, diff.b.term)) ==> Diff.sum(const(1))(diff.diff) > 0 } } func testEqualityIsReflexive() { property("equality is reflexive") <- forAll { (diff: RangedDiff) in equal(diff.diff, diff.diff) } } func testDoubleInversionIsIdempotent() { property("double inversion is idempotent") <- forAll { (diff: RangedDiff) in equal(diff.diff, diff.diff.inverse.inverse) } } func testOriginalTermsAreRecoverable() { let equal = Cofree.equals(annotation: const(true), leaf: ==) property("before state is recoverable") <- forAll { (diff: RangedDiff) in diff.diff.map { $0.map { $0.map(const(())) } }.before.map { equal($0, diff.a.stripped.term) } ?? false } property("after state is recoverable") <- forAll { (diff: RangedDiff) in diff.diff.map { $0.map { $0.map(const(())) } }.after.map { equal($0, diff.b.stripped.term) } ?? false } } } private func equal(a: DiffTests.Diff, _ b: DiffTests.Diff) -> Bool { return Free.equals(pure: Patch.equals(Cofree.equals(annotation: ==, leaf: ==)), leaf: ==, annotation: const(true))(a, b) } @testable import Doubt import Prelude import SwiftCheck import XCTest