1 /*
2  * Copyright (C) 2022 The Android Open Source Project
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 <AtomicState.h>
18 
19 #include <chrono>
20 #include <thread>
21 
22 #include <gtest/gtest.h>
23 
24 using namespace std::chrono_literals;
25 
26 namespace android {
27 
28 enum AtomicStateTestEnum {
29   A,
30   B,
31   C,
32   D,
33   E,
34 };
35 
36 class AtomicStateTest : public testing::Test {
37  protected:
AtomicStateTest()38   AtomicStateTest() : state_(A) {}
SetUp()39   virtual void SetUp() {}
TearDown()40   virtual void TearDown() {}
41 
42   AtomicState<AtomicStateTestEnum> state_;
43 };
44 
TEST_F(AtomicStateTest,transition)45 TEST_F(AtomicStateTest, transition) {
46   ASSERT_EQ(A, state_.state_);
47 
48   // Starts as A, transition from B fails
49   ASSERT_FALSE(state_.transition(B, C));
50   ASSERT_EQ(A, state_.state_);
51 
52   // transition from A to B
53   ASSERT_TRUE(state_.transition(A, B));
54   ASSERT_EQ(B, state_.state_);
55 
56   // State is B, transition from A fails
57   ASSERT_FALSE(state_.transition(A, B));
58   ASSERT_EQ(B, state_.state_);
59 
60   // State is B, transition_or from A calls the lambda
61   bool lambda = false;
62   state_.transition_or(A, B, [&] {
63     lambda = true;
64     return B;
65   });
66   ASSERT_TRUE(lambda);
67   ASSERT_EQ(B, state_.state_);
68 
69   // State is C, transition_or from B to C does not call the lambda
70   lambda = false;
71   state_.transition_or(B, C, [&] {
72     lambda = true;
73     return C;
74   });
75   ASSERT_FALSE(lambda);
76   ASSERT_EQ(C, state_.state_);
77 }
78 
TEST_F(AtomicStateTest,wait)79 TEST_F(AtomicStateTest, wait) {
80   ASSERT_EQ(A, state_.state_);
81 
82   // Starts as A, wait_for_either_of B, C returns false
83   ASSERT_FALSE(state_.wait_for_either_of(B, C, 10ms));
84 
85   // Starts as A, wait_for_either_of A, B returns true
86   ASSERT_TRUE(state_.wait_for_either_of(A, B, 1s));
87 
88   {
89     std::thread t([&] {
90       usleep(10000);
91       state_.set(B);
92     });
93 
94     // Wait ing for B or C returns true after state is set to B
95     ASSERT_TRUE(state_.wait_for_either_of(B, C, 1s));
96 
97     t.join();
98   }
99 
100   ASSERT_EQ(B, state_.state_);
101   {
102     std::thread t([&] {
103       usleep(10000);
104       state_.transition(B, C);
105     });
106 
107     // Waiting for A or C returns true after state is transitioned to C
108     ASSERT_TRUE(state_.wait_for_either_of(A, C, 1s));
109 
110     t.join();
111   }
112 
113   ASSERT_EQ(C, state_.state_);
114   {
115     std::thread t([&] {
116       usleep(10000);
117       state_.transition(C, D);
118     });
119 
120     // Waiting for A or B returns false after state is transitioned to D
121     ASSERT_FALSE(state_.wait_for_either_of(A, B, 100ms));
122 
123     t.join();
124   }
125 }
126 
127 }  // namespace android
128