mirror of
https://github.com/google/googletest.git
synced 2025-12-07 01:06:50 +08:00
add docs
This commit is contained in:
parent
f030c43724
commit
8a8e114cbc
32
coroutines/crf_constraints.md
Normal file
32
coroutines/crf_constraints.md
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
## CRF Constraints
|
||||||
|
|
||||||
|
### 1
|
||||||
|
Test setup in coroutine => Test coroutine must run as soon as its constructed, so as to allow it to
|
||||||
|
create mock objects, watches etc before the mock source runs. Also in phase 2, coroutine can create mock
|
||||||
|
sources.
|
||||||
|
|
||||||
|
### 2
|
||||||
|
Mock args passed by ref => MUT must not do anything between making a mock call and the coroutine body
|
||||||
|
receiving the args. Note that the coroutine CAN run during this period, since the args are owned
|
||||||
|
by the mock source.
|
||||||
|
|
||||||
|
### 3
|
||||||
|
Mock return passed by ref => Test coroutine must not do anything between Return() and the mock source receiving the
|
||||||
|
return value. Mock source could in principle run during this period, since coro owns the return object, but
|
||||||
|
in practice it won't because it's waiting for the return value.
|
||||||
|
|
||||||
|
### 4
|
||||||
|
Updated cardinality state => coroutine must run so that it can do SATISFY(), RETIRE() or run to exit BEFORE
|
||||||
|
allowing GMock/CotestWatcher code to query eg IsSatisfied() etc. This is extra_iteration_requested reason
|
||||||
|
inside TestCoroutine::DestructionIterations().
|
||||||
|
|
||||||
|
### 5
|
||||||
|
Global mock handler finding => After getting an event that is a mock call, test coroutines must call DROP()
|
||||||
|
ACCEPT() or RETURN() on the event before doing anything elase with the cotest UI. This is because the
|
||||||
|
process of deciding which expectation or coroutine will handle the call is global and must complete before
|
||||||
|
anything happens that could generate more mock calls.
|
||||||
|
|
||||||
|
### 6
|
||||||
|
True event sequence => Most of the time, a LAUNCH() or RETURN() should be followed by NEXT_EVENT() because
|
||||||
|
they will usually lead to an event for the test coro to pick up and handle. There is an exception in the
|
||||||
|
case of a second coroutine whose response is to exit. See test case ObserverQueue.
|
||||||
13
coroutines/design_notes.md
Normal file
13
coroutines/design_notes.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
## Design Notes
|
||||||
|
|
||||||
|
- A "corouine" is officially a class or factory object bound to a coro body.
|
||||||
|
It creates an RAII object, so an instance must be created and should be in
|
||||||
|
a local scope (i.e. of the test case). Coroutines are implemented as lambdas
|
||||||
|
because a lambda can be a C++20 coroutine, and we can capture the mock objects.
|
||||||
|
This breeches S/S guidelines, but the UI is designed to make unsafe usafe difficult.
|
||||||
|
|
||||||
|
- All cardinality functionality belongs interior to the coroutine. Therefore WillOnce(), Times()
|
||||||
|
etc are not supported when routing calls to a coroutine. That's why the interior UI
|
||||||
|
should not say "EXPECT". Filtering (ultimately) can be done in interior or exterior,
|
||||||
|
so we don't want to be too imperitive in the terminology here because the coro can just
|
||||||
|
drop the call. Call it WATCH_CALL().
|
||||||
54
coroutines/sheared-ordering.md
Normal file
54
coroutines/sheared-ordering.md
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
## Notes on hyper-flexible ordering
|
||||||
|
|
||||||
|
This analysis is of a version of cotest that allows test corotuines more
|
||||||
|
flexibility, so that they can queue up incoming events and then
|
||||||
|
pull them from the queue out of order.
|
||||||
|
|
||||||
|
### NEXT_EVENT_ONLY_FROM(DC) or BLOCK_EVENT()
|
||||||
|
- Consider launches A() and B() invoking mockA() and mockB() respectively. Suppose the
|
||||||
|
test case requires:
|
||||||
|
- A() must be called before B() eg because at least one has side effects and
|
||||||
|
they affect each other's behaviour.
|
||||||
|
- But mockA()'s handling in the test depends on an arg to mockB()
|
||||||
|
- Assume it isn't enough for mockB() to affect mockA()'s return value
|
||||||
|
(because we could leave mockA.RETURN() until after mockB.ACCEPT())
|
||||||
|
- Assume it isn't enough to do checking using EXPECT_EQ() etc either
|
||||||
|
- This leaves the case where the decision of whether to accept or drop
|
||||||
|
mockA() depends on mockB()'s argument.
|
||||||
|
- Now, based on GMock design:
|
||||||
|
- In order to have mockB() arguments we need to have entered ShouldHandleCall()
|
||||||
|
on B(). If we look at B's PreMock, we might see arguments for a mock
|
||||||
|
call that is accepted by a higher prio expectation or watch. So
|
||||||
|
higher prio expectations/watches on mockB() can affect the arg values we see.
|
||||||
|
- We have to decide whether to accept or drop mockA() before we exit
|
||||||
|
ShouldHandleCall() on A(). Our decision here will obviously affect
|
||||||
|
the lower prio expectations/watches on mockA().
|
||||||
|
- So we're stuck with searching mockB() higher priorities before mockA()
|
||||||
|
lower priorities, which is out of sequence. Consequences:
|
||||||
|
- Thread safety: we'd re-enter GMock's call hander search. At present this
|
||||||
|
causes a deadlock, but that could be changed.
|
||||||
|
- Expectations would be OK, if we checked eg mockA() highers,
|
||||||
|
mockB() highers, mockA() lowers, mockB() lowers. This generalises
|
||||||
|
to checking in sequence within each prio level. An expectation only
|
||||||
|
exists at one prio level, so it would see everything in the right order.
|
||||||
|
Call this a shear ordering.
|
||||||
|
- If another coro is watching mockA() at a lower prio and mockB() at
|
||||||
|
a higher prio, and it expects to see mockA() first, then we have
|
||||||
|
conflicting requirements. If the original coro gets its way, then
|
||||||
|
this coro will see mockB() and may drop it, fail a check, etc.
|
||||||
|
So shear ordering is not good enough for coroutines.
|
||||||
|
- Note that this is not an isue of side-effects inside ShouldHandleCall()
|
||||||
|
and purely relates to the order in which mock calls are passed to it.
|
||||||
|
|
||||||
|
### Architectural interpretation
|
||||||
|
- Coroutines should be able to infer the order in which mock calls
|
||||||
|
are happening from the order in which they are passed to
|
||||||
|
ShouldHandleCall(). Shear ordering prevents this.
|
||||||
|
- Without threads, this can be well-defined because coroutines have
|
||||||
|
well-defined ordering.
|
||||||
|
- With threads, we'd probably want an overall serialisation/rendez-vous point.
|
||||||
|
- To provide for the above scenario without using shear ordering,
|
||||||
|
we need to intervene and change the global ordering as seen
|
||||||
|
by GMock search. This should be explicit, since it will have side
|
||||||
|
effects on other coroutines.
|
||||||
|
- Leads to the PreMockSynchroniser and CRF constraint #5
|
||||||
Loading…
x
Reference in New Issue
Block a user