Skip to content
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

Feature request: Sequencing synchronization #35

Open
mlimber opened this issue Mar 3, 2017 · 3 comments
Open

Feature request: Sequencing synchronization #35

mlimber opened this issue Mar 3, 2017 · 3 comments

Comments

@mlimber
Copy link
Contributor

mlimber commented Mar 3, 2017

I'm using multiple sequences as described in your blog post. I'm wishing I had something to allow me to insert sequencing points without allowing/requiring/forbidding calls on my mocks. It comes up mostly when I want to synchronize between blocks of events but don't have a good end point (like your reader->available() expectation) to attach all the sequences to and want the next expectation (like your appendReadBytes()) to be in an arbitrary order with its subsequent call.

Within the current release, I could create a dummy mock object and forbid/allow a call on it with all the sequences to synchronize, OR I could create yet another sequence to be the metasequence for all of them. But it seems like having something like SYNCRONIZE( seq1, seq2, seq3 ) would make it clearer and easier.

Or maybe there's already a way to do this that I haven't thought of, or maybe I'm doing it wrong.

What do you think?

@rollbear
Copy link
Owner

rollbear commented Mar 3, 2017

I've had some thoughts along the same line, but since I haven't found a real world need I haven't given it priority.

Would 'join' be a better word than 'synchronize'?

I'll need to think about how to implement.

@mlimber
Copy link
Contributor Author

mlimber commented Mar 3, 2017

Join or synchronize, whatever. I tried the workarounds I mentioned, and didn't have success. I tried something like this:

struct Synchronize
{
    MAKE_MOCK0( Sync, void() );
};

struct Foo
{
    MAKE_MOCK0( f, void() );
    MAKE_MOCK0( g, void() );
    MAKE_MOCK0( h, void() );
    MAKE_MOCK0( i, void() );
};

auto seq1 = sequence{};
auto seq2 = sequence{};
auto foo = std::make_unique<Foo>();
auto bar = std::make_unique<Foo>();
auto sync = std::make_unique<Synchronize>();

REQUIRE_CALL( *foo, f() ).IN_SEQUENCE( seq1 );
REQUIRE_CALL( *foo, g() ).IN_SEQUENCE( seq1 );
REQUIRE_CALL( *bar, h() ).IN_SEQUENCE( seq2 );
REQUIRE_CALL( *bar, i() ).IN_SEQUENCE( seq2 );

ALLOW_CALL( *sync, Sync() ).IN_SEQUENCE( seq1, seq2 );

REQUIRE_CALL( *foo, f() ).IN_SEQUENCE( seq1 );
REQUIRE_CALL( *bar, h() ).IN_SEQUENCE( seq2 );

// trigger calls to foo and bar
Trigger1();
Trigger2();

Alas, the ALLOW_CALL was not sufficient to require both sequences to synchronize and FORBID_CALL with an IN_SEQUENCE() was forbidden by the framework as not making sense. I could have inserted REQUIRE_CALL() instead and then added sync->Sync() in the appropriate places in my code that was triggering the expected behavior, but since I could do that, I realized I could just break up the sequences into scoped paragraphs and get the same effect:

{
    REQUIRE_CALL( *foo, f() ).IN_SEQUENCE( seq1 );
    REQUIRE_CALL( *foo, g() ).IN_SEQUENCE( seq1 );
    REQUIRE_CALL( *bar, h() ).IN_SEQUENCE( seq2 );
    REQUIRE_CALL( *bar, i() ).IN_SEQUENCE( seq2 );

    // trigger calls to foo and bar
    Trigger1();
}
{
    REQUIRE_CALL( *foo, f() ).IN_SEQUENCE( seq1 );
    REQUIRE_CALL( *bar, h() ).IN_SEQUENCE( seq2 );

    // trigger more calls to foo and bar
    Trigger2();
}

That wouldn't work in the general case (e.g., in your blog post on sequences) because all the actions are triggered by a single indivisible line (there, to dispatcher.readMessage()).

@rollbear
Copy link
Owner

rollbear commented Mar 3, 2017

Yes, I know. It's not quite that simple. Sequences are driven by things that happen to them, and the synchronization barrier is not an event that's triggered, it's a rule governing their joint behaviour. Like I mentioned, I need to think a bit about how to implement this.

Using scopes is often the right thing, but as you so correctly observe, it's not always possible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants