-
Notifications
You must be signed in to change notification settings - Fork 151
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] State machine support #84
base: master
Are you sure you want to change the base?
Conversation
Still needs more documentation and definitely more tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work :) Here are some initial thoughts.
@@ -92,7 +92,7 @@ impl<T : fmt::Debug> fmt::Display for TestError<T> { | |||
TestError::Abort(ref why) => | |||
write!(f, "Test aborted: {}", why), | |||
TestError::Fail(ref why, ref what) => | |||
write!(f, "Test failed: {}; minimal failing input: {:?}", | |||
write!(f, "Test failed: {}; minimal failing input: {:#?}", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm; this is a non-trivial change in proptest wrt. UX;
While it will it will help for complex structures (because they would have overflowed the screen horizontally and so the terminal would have line-split...) I think it will also be less great for simple structs and tuples.
#[macro_use] | ||
extern crate proptest; | ||
|
||
use std::cmp; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any specific reason to do cmp::Ord
? The trait should be well know so Ord
seems simpler.
// We define a strategy for our starting state. Here, we always start with | ||
// an empty heap. | ||
fn initial_heap_strategy<T : cmp::Ord + fmt::Debug + Clone> | ||
() -> impl Strategy<Value = MyHeapState<T>> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should probably stick to a consistent style wrt. where
or direct bounds?
Also, running rustfmt after merging the PR would be good (on the whole of proptest).
fn push(&mut state, value: T) { | ||
// Add it to the heap... | ||
state.heap.push(value.clone()); | ||
// ... and also the Vec where we track what the heap contains. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/track what/track of what/
fn pop(&mut state) { | ||
let was_empty = state.heap.is_empty(); | ||
|
||
match state.heap.pop() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
perhaps use if let
here to reduce rightward drift?
/// the value. | ||
pub fn new(mutation_strategy: impl Strategy<Value = Box<dyn Mutator<S>>> + 'static, | ||
invariants: Arc<dyn Fn (&mut S) -> TestCaseResult>) -> Self { | ||
StateMachine { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Self { .. }
pub fn run(mut self) -> Result<S, TestCaseError> { | ||
if self.trace { | ||
println!("initial state: {:?}", self.state); | ||
println!("check initial invariants"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A thought for later: It might be nice to change from using println
to use some more principled logging facility that users can control. I think the quickcheck crate does this. But this is out of scope for this PR.
/// Mutate `state`. | ||
/// | ||
/// This effectively consumes `self`, but it is passed as a mutable | ||
/// reference so that this trait is object-safe and so that the mutator can |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a test that asserts object safety.
function: Option<F>, | ||
arguments: Option<A>, | ||
formatted_arguments: Option<Cow<'static, str>>, | ||
name: &'static str, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These fields are in common from the previous struct... Reuse?
let args = self.arguments.take().expect("Mutator applied more than once"); | ||
if self.formatted_arguments.is_none() { | ||
self.formatted_arguments = Some(Cow::Owned(format!("{:?}", args))); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This bit is identical from DirectMutator
; refactor?
Additional thoughts:
|
I was working on a data structure in Cargos internals and remembered this work. How is it going? What are the next steps? |
To be honest, I haven't really done anything here since I made the PR. IIRC I ran into some fundamental flaw in the way this is designed and put it on the backburner, but I've forgotten what that was now. |
I'd be interested in continuing work on this if someone is able to mentor me |
Something I've been working on here and there for a while, originally suggested in #28.
As noted in the first commit, this absolutely needs more tests and is probably still a bit deficient on documentation. I wanted to get this up now though to solicit opinions on the model/ergonomics now that the implementation is basically functional.
I'd recommend starting by reading the (still incomplete) tutorial and then the syntax docs above it.
@Centril I'd appreciate your thoughts when you have time.