Sleuth

Extremely opinionated testing framework generating an exact specification and reducing code to its minimal implementation.

At a Glance

This library takes the idea behind mutation testing to its extreme.

Mutation testing believes that small errors in your source code (like a > b instead of a >= b) are likely errors; when they happen, your tests should fail, and mutation testing frameworks make sure they do. When your test suite fails to recognize a bug, it means you need to add a new test.

Rust already has mutation testing frameworks (like mutagen) which I admire and in no way attempt to replace. However, with relatively short functions, this library is an experiment in mutating all of your code, proving by brute force that no function shorter than the one you've written can meet your specifications. This encourages test-driven development without the burden of writing an exhaustive test suite beforehand; after an initial attempt, your tests and your implementation evolve together as you encounter all the ways something might be done on the way to what you wanted all along.

The library also takes inspiration from property-based testing like Haskell's QuickCheck. Your tests can be written with reusable properties and told not to pass with !, like the following: ```rust use ::sleuth::sleuth;

fn roundtrip(f: F, g: G, x: T) -> bool where T: PartialEq + Clone, F: Fn(U) -> T, G: Fn(T) -> U, { x.clone() == f(g(x)) }

[sleuth(roundtrip(subone, 42), !roundtrip(addone, 42))]

fn add_one(x: u8) -> u8 { x + 1 }

[sleuth(roundtrip(addone, 42), !roundtrip(subone, 42))]

fn subone(x: u8) -> u8 { x - 1 } `` Note a few things: -roundtripreturns a bool to indicate success or failure instead ofpanicking like a usual test. - Thesleuthattribute takes a function with its first argument missing (here,roundtripwithoutf), and that argument is filled in at compile time with the function the attribute is applied to (here,addoneandsub_one). - We don't spamroundtripwith a bunch of random inputs (though you can do that separately!). Instead, you choose your inputs (here,42` both times), and the library helps you find the minimal set that knocks out all mutations.

The library is still under development—I'm an undergrad with a chronic lack of free time—but currently, it can run a test suite of properties like above, and fairly soon it should be able to reduce common cases like the following: rust fn is_true(b: bool) -> bool { if b { true } else { false } } to their minimal implementations: rust fn is_true(b: bool) -> bool { b } which usual mutation testing could never (and doesn't aim to) fix.