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