Allow methods on mocks to be called with a range of times in a Sequence#660
Allow methods on mocks to be called with a range of times in a Sequence#660asomers merged 1 commit intoasomers:masterfrom
Conversation
asomers
left a comment
There was a problem hiding this comment.
This looks like a very good feature. I definitely want to get it merged. In order to help me review it, could you please adjust the doc comments on SeqHandle to reflect the give states mentioned in the commit message, and how they relate to seq and min_seq? If it would make sense, you could even replace those two variables with an Enum.
And you'll have to rebase it, because I just committed some related comments to the master branch. Also, could you please wrap all lines to 80 columns and add a changelog entry?
| } | ||
|
|
||
| #[test] | ||
| #[should_panic] |
There was a problem hiding this comment.
Can you please put an "expected" message here?
| /// mock1.bar(); | ||
| /// ``` | ||
| /// | ||
| /// But, the previous count needs to suffice before a sequence may make progress |
There was a problem hiding this comment.
"needs to suffice" doesn't make sense. Do you mean "must be satisfied"? Also, there should be a period at the end of the sentence.
| /// Furthermore, sequences are greedy, and will only perform the earliest element in sequence | ||
| /// that is allowed. This results in the following example failing the second expectation, as | ||
| /// the first expectation is used for both calls to `foo`. | ||
| /// ```should_panic |
There was a problem hiding this comment.
Please add an "expected" message.
There was a problem hiding this comment.
Unlike the normal tests, doctests don't seem to have this feature. I've extended the documentation to clarify this, instead.
|
I've added and expanded the documentation, fixed line-wrapping (in so far I am able to without breaking things) added a changelog entry, and squashed all of these changes into the original commit. |
The requirement that the count on the times an expectation is an exact value is restricting,
as I sometimes do not wish to define the amount of times a mocked method is called.
For example, in one of my own codebases I have a method that is called at least once,
but may be called multiple times without issue.
The goal of this PR is to relax this exact requirement, i.e., to allow a method to be called a variable
number of times, within a range. This range may include zero, and may go off to infinity*. It does
so while maintaining the original behavior for exact cases, while allowing these new cases to be
handled.
A SeqHandle after the change can be interpreted to be in one of five states:
1. Uncallable - Other elements earlier in the sequence need to be satisfied first.
2. Callable - Previous element(s) are satisified, and we can progress to the current element,
but preceding elements may still be called further.
3. Called - The method has been called, and preceding elements may no longer be called
otherwise, this would constitute an ordering violation.
However, the current count has not been satisfied yet, and the next element
in sequence is not allowed to be called.
4. Satisfied - This element in the sequence has had its lower bound satisfied, and the next
element in sequence is allowed to be called.
5. History - This element can no longer be called, as succeeding elements have been performed
in the sequence.
Not all of these states are always possible, or in use, and these states may overlap.
For example, if the range includes calling zero times, a method cannot be in state 3.
Furthermore, once a method is (2) callable it may also be deemed to be in state (4) - satisified,
as it does not need to be called in order to be satisified. As such, these steps which may be
called zero times in the sequence may be *skipped*. This is covered by test `ok_variable_count_skip`.
For any element which has to be called at least once, skipping is not a possibility. However, state
3 still does not exist, as a single call suffices to go immediately to state 4, satisfied.
To encode these particularities this each handle now has two properties:
1. seq - the position ( / state) within the sequence that we are processing, calling will move
the counter to this position.
2. min_seq - the lowest permissible position in this sequence before this element is deemed callable.
Note: is not incremented when the new handle being requested is allowed to be zero count
to allow for skipping.
If the minimum is greater than zero times, min_seq is updated to seq if minimum count
is 1, or seq + 1 if minimum count is at least two, to ensure the previous element has
has gone through the called state.
When a method which has a corresponding sequence is being called, it is checked whether:
1. The current sequence state is equal to seq, or, if minimum count is at least two, seq + 1
In this case, the method is currently in called or satisified state, check whether this state
needs to be updated and update accordingly.
2. The current sequence state is at least min_seq, if (1) was not the case, we are in callable state.
Sequence is updated to seq, potentially skipping elements.
If the state precedes min_seq, we are in state (1) Uncallable. If the sequence state is greater than
seq, or seq + 1 if the minimum call count is at least 2, we are in state (5) History.
Finally, in the original implementation, a sequence was always in line with the state provided by Times:
Being in a certain spot in the sequence implies certain expectations have ran their course - with exact
counts any preceding elements would have been fully satisfied, unable to handle any further calls
and hence marked as done.
With the potential indefinite count this change provides, an earlier expectation may match arguments
and proceed to fail as their spot in the sequence has passed, without this task being done.
This change ensures that an Expectation is marked as done if their states in the Sequence
have passed, as to allow earlier elements in a sequence to be succeeded once further methods are called.
This is covered in the test `single_method_variable_count_mixed`
|
I hijacked the PR and rebased it in order to resolve a merge conflict. |
The requirement that the count on the times an expectation is an exact value is restricting, as I sometimes do not wish to define the amount of times a mocked method is called. For example, in one of my own codebases I have a method that is called at least once, but may be called multiple times without issue. As a simple minimum example of what works now:
The goal of this PR is to relax the exact value requirement, i.e., to allow a method to be called a variable number of times, within a range, including zero. It does so while maintaining the original behavior for exact cases, while enabling sequences to mark an earlier expectation as done to allow indefinite (with unset times()) to enforce ordering between calls.
For example, the following would work
While altering the ordering would result in a failure: