1dd4f6bbfce83af08265816af85b64232139c9be
[folly.git] / folly / futures / test / FSMTest.cpp
1 /*
2  * Copyright 2016 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <gtest/gtest.h>
18
19 #include <folly/futures/detail/FSM.h>
20
21 using namespace folly::detail;
22
23 enum class State { A, B };
24
25 TEST(FSM, example) {
26   FSM<State> fsm(State::A);
27   int count = 0;
28   int unprotectedCount = 0;
29
30   // somebody set up us the switch
31   auto tryTransition = [&]{
32     switch (fsm.getState()) {
33     case State::A:
34       return fsm.updateState(State::A, State::B, [&]{ count++; });
35     case State::B:
36       return fsm.updateState(State::B, State::A,
37                              [&]{ count--; }, [&]{ unprotectedCount--; });
38     }
39     return false; // unreachable
40   };
41
42   // keep retrying until success (like a cas)
43   while (!tryTransition()) ;
44   EXPECT_EQ(State::B, fsm.getState());
45   EXPECT_EQ(1, count);
46   EXPECT_EQ(0, unprotectedCount);
47
48   while (!tryTransition()) ;
49   EXPECT_EQ(State::A, fsm.getState());
50   EXPECT_EQ(0, count);
51   EXPECT_EQ(-1, unprotectedCount);
52 }
53
54 TEST(FSM, magicMacrosExample) {
55   struct MyFSM {
56     FSM<State> fsm_;
57     int count = 0;
58     int unprotectedCount = 0;
59     MyFSM() : fsm_(State::A) {}
60     void twiddle() {
61       FSM_START(fsm_)
62         FSM_CASE(fsm_, State::A, State::B, [&]{ count++; });
63         FSM_CASE2(fsm_, State::B, State::A,
64                   [&]{ count--; }, [&]{ unprotectedCount--; });
65       FSM_END
66     }
67   };
68
69   MyFSM fsm;
70
71   fsm.twiddle();
72   EXPECT_EQ(State::B, fsm.fsm_.getState());
73   EXPECT_EQ(1, fsm.count);
74   EXPECT_EQ(0, fsm.unprotectedCount);
75
76   fsm.twiddle();
77   EXPECT_EQ(State::A, fsm.fsm_.getState());
78   EXPECT_EQ(0, fsm.count);
79   EXPECT_EQ(-1, fsm.unprotectedCount);
80 }
81
82
83 TEST(FSM, ctor) {
84   FSM<State> fsm(State::A);
85   EXPECT_EQ(State::A, fsm.getState());
86 }
87
88 TEST(FSM, update) {
89   FSM<State> fsm(State::A);
90   EXPECT_TRUE(fsm.updateState(State::A, State::B, []{}));
91   EXPECT_EQ(State::B, fsm.getState());
92 }
93
94 TEST(FSM, badUpdate) {
95   FSM<State> fsm(State::A);
96   EXPECT_FALSE(fsm.updateState(State::B, State::A, []{}));
97 }
98
99 TEST(FSM, actionOnUpdate) {
100   FSM<State> fsm(State::A);
101   int count = 0;
102   fsm.updateState(State::A, State::B, [&]{ count++; });
103   EXPECT_EQ(1, count);
104 }
105
106 TEST(FSM, noActionOnBadUpdate) {
107   FSM<State> fsm(State::A);
108   int count = 0;
109   fsm.updateState(State::B, State::A, [&]{ count++; });
110   EXPECT_EQ(0, count);
111 }
112
113 TEST(FSM, stateTransitionAfterAction) {
114   FSM<State> fsm(State::A);
115   fsm.updateState(State::A, State::B,
116                   [&]{ EXPECT_EQ(State::A, fsm.getState()); });
117 }