diff options
Diffstat (limited to 'tests/AtomicState_test.cpp')
-rw-r--r-- | tests/AtomicState_test.cpp | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/tests/AtomicState_test.cpp b/tests/AtomicState_test.cpp new file mode 100644 index 0000000..7fb2806 --- /dev/null +++ b/tests/AtomicState_test.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <AtomicState.h> + +#include <chrono> +#include <thread> + +#include <gtest/gtest.h> + +using namespace std::chrono_literals; + +namespace android { + +enum AtomicStateTestEnum { + A, + B, + C, + D, + E, +}; + +class AtomicStateTest : public testing::Test { + protected: + AtomicStateTest() : state_(A) {} + virtual void SetUp() {} + virtual void TearDown() {} + + AtomicState<AtomicStateTestEnum> state_; +}; + +TEST_F(AtomicStateTest, transition) { + ASSERT_EQ(A, state_.state_); + + // Starts as A, transition from B fails + ASSERT_FALSE(state_.transition(B, C)); + ASSERT_EQ(A, state_.state_); + + // transition from A to B + ASSERT_TRUE(state_.transition(A, B)); + ASSERT_EQ(B, state_.state_); + + // State is B, transition from A fails + ASSERT_FALSE(state_.transition(A, B)); + ASSERT_EQ(B, state_.state_); + + // State is B, transition_or from A calls the lambda + bool lambda = false; + bool already_locked = false; + state_.transition_or(A, B, [&] { + // The lock should be held in the lambda + if (state_.m_.try_lock()) { + state_.m_.unlock(); + } else { + already_locked = true; + } + lambda = true; + return B; + }); + ASSERT_TRUE(lambda); + ASSERT_TRUE(already_locked); + ASSERT_EQ(B, state_.state_); + + // State is C, transition_or from B to C does not call the lambda + lambda = false; + state_.transition_or(B, C, [&] { + lambda = true; + return C; + }); + ASSERT_FALSE(lambda); + ASSERT_EQ(C, state_.state_); +} + +TEST_F(AtomicStateTest, wait) { + ASSERT_EQ(A, state_.state_); + + // Starts as A, wait_for_either_of B, C returns false + ASSERT_FALSE(state_.wait_for_either_of(B, C, 10ms)); + + // Starts as A, wait_for_either_of A, B returns true + ASSERT_TRUE(state_.wait_for_either_of(A, B, 1s)); + + { + std::thread t([&] { + usleep(10000); + state_.set(B); + }); + + // Wait ing for B or C returns true after state is set to B + ASSERT_TRUE(state_.wait_for_either_of(B, C, 1s)); + + t.join(); + } + + ASSERT_EQ(B, state_.state_); + { + std::thread t([&] { + usleep(10000); + state_.transition(B, C); + }); + + // Waiting for A or C returns true after state is transitioned to C + ASSERT_TRUE(state_.wait_for_either_of(A, C, 1s)); + + t.join(); + } + + ASSERT_EQ(C, state_.state_); + { + std::thread t([&] { + usleep(10000); + state_.transition(C, D); + }); + + // Waiting for A or B returns false after state is transitioned to D + ASSERT_FALSE(state_.wait_for_either_of(A, B, 100ms)); + + t.join(); + } +} + +} // namespace android |