普通文本  |  262行  |  7.8 KB

/******************************************************************************
 *
 *  Copyright 2017 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 <gtest/gtest.h>

#include "btif/include/btif_state_machine.h"

namespace {
static constexpr uint32_t kInvalidEvent = 0xffffffff;
static constexpr uint32_t kEventZero = 0;
static constexpr uint32_t kEventOne = 1;
static constexpr uint32_t kEventTwo = 2;

static char dataZero = 0;
static char dataOne = 1;
static char dataTwo = 2;
}  // namespace

class BtifStateMachineImpl : public BtifStateMachine {
 public:
  enum {
    kStateZero,
    kStateOne,
    kStateTwo,
  };

  class StateZero : public State {
   public:
    StateZero(BtifStateMachine& sm)
        : State(sm, kStateZero),
          on_enter_(false),
          on_exit_(false),
          event_(kInvalidEvent),
          data_(nullptr) {}
    void OnEnter() override {
      on_enter_ = true;
      on_exit_ = false;
    }
    void OnExit() override {
      on_exit_ = true;
      on_enter_ = false;
    }
    bool ProcessEvent(uint32_t event, void* p_data) override {
      event_ = event;
      data_ = p_data;
      TransitionTo(kStateOne);
      return true;
    }

    bool on_enter_;
    bool on_exit_;
    uint32_t event_;
    void* data_;
  };

  class StateOne : public State {
   public:
    StateOne(BtifStateMachine& sm)
        : State(sm, kStateOne),
          on_enter_(false),
          on_exit_(false),
          event_(kInvalidEvent),
          data_(nullptr) {}
    void OnEnter() override {
      on_enter_ = true;
      on_exit_ = false;
    }
    void OnExit() override {
      on_exit_ = true;
      on_enter_ = false;
    }
    bool ProcessEvent(uint32_t event, void* p_data) override {
      event_ = event;
      data_ = p_data;
      TransitionTo(kStateTwo);
      return true;
    }

    bool on_enter_;
    bool on_exit_;
    uint32_t event_;
    void* data_;
  };

  class StateTwo : public State {
   public:
    StateTwo(BtifStateMachine& sm)
        : State(sm, kStateTwo),
          on_enter_(false),
          on_exit_(false),
          event_(kInvalidEvent),
          data_(nullptr) {}
    void OnEnter() override {
      on_enter_ = true;
      on_exit_ = false;
    }
    void OnExit() override {
      on_exit_ = true;
      on_enter_ = false;
    }
    bool ProcessEvent(uint32_t event, void* p_data) override {
      event_ = event;
      data_ = p_data;
      TransitionTo(kStateZero);
      return true;
    }

    bool on_enter_;
    bool on_exit_;
    uint32_t event_;
    void* data_;
  };

  BtifStateMachineImpl() {
    state_zero_ = new StateZero(*this);
    state_one_ = new StateOne(*this);
    state_two_ = new StateTwo(*this);

    AddState(state_zero_);
    AddState(state_one_);
    AddState(state_two_);
    SetInitialState(state_zero_);
  }

  StateZero* state_zero_;
  StateOne* state_one_;
  StateTwo* state_two_;
};

class BtifStateMachineTest : public ::testing::Test {
 protected:
  BtifStateMachineTest() {}

  void SetUp() override { sm_.Start(); }

  void TearDown() override { sm_.Quit(); }

  BtifStateMachineImpl sm_;
};

TEST_F(BtifStateMachineTest, test_initial_state) {
  ASSERT_EQ(sm_.kStateZero, sm_.StateId());
  ASSERT_EQ(sm_.kStateInvalid, sm_.PreviousStateId());
}

TEST_F(BtifStateMachineTest, test_invalid_state) {
  sm_.Quit();
  ASSERT_EQ(sm_.kStateInvalid, sm_.StateId());
  ASSERT_EQ(sm_.kStateInvalid, sm_.PreviousStateId());
  sm_.Start();
  ASSERT_EQ(sm_.kStateZero, sm_.StateId());
  ASSERT_EQ(sm_.kStateInvalid, sm_.PreviousStateId());
}

TEST_F(BtifStateMachineTest, test_transition_to) {
  // Initial state: StateZero
  ASSERT_EQ(sm_.kStateZero, sm_.StateId());
  ASSERT_EQ(sm_.kStateInvalid, sm_.PreviousStateId());
  ASSERT_TRUE(sm_.state_zero_->on_enter_);
  ASSERT_FALSE(sm_.state_zero_->on_exit_);

  // Transition to StateOne
  ASSERT_FALSE(sm_.state_one_->on_enter_);
  ASSERT_FALSE(sm_.state_one_->on_exit_);
  sm_.TransitionTo(sm_.kStateOne);
  ASSERT_EQ(sm_.kStateOne, sm_.StateId());
  ASSERT_EQ(sm_.kStateZero, sm_.PreviousStateId());
  ASSERT_TRUE(sm_.state_zero_->on_exit_);
  ASSERT_TRUE(sm_.state_one_->on_enter_);
  ASSERT_FALSE(sm_.state_one_->on_exit_);

  // Transition to StateTwo
  ASSERT_FALSE(sm_.state_two_->on_enter_);
  ASSERT_FALSE(sm_.state_two_->on_exit_);
  sm_.TransitionTo(sm_.kStateTwo);
  ASSERT_EQ(sm_.kStateTwo, sm_.StateId());
  ASSERT_EQ(sm_.kStateOne, sm_.PreviousStateId());
  ASSERT_TRUE(sm_.state_one_->on_exit_);
  ASSERT_TRUE(sm_.state_two_->on_enter_);
  ASSERT_FALSE(sm_.state_two_->on_exit_);
}

TEST_F(BtifStateMachineTest, test_process_event) {
  // Initial state: StateZero
  ASSERT_EQ(sm_.kStateZero, sm_.StateId());
  ASSERT_EQ(sm_.kStateInvalid, sm_.PreviousStateId());
  ASSERT_TRUE(sm_.state_zero_->on_enter_);
  ASSERT_FALSE(sm_.state_zero_->on_exit_);
  ASSERT_EQ(sm_.state_zero_->event_, kInvalidEvent);
  ASSERT_EQ(sm_.state_zero_->data_, nullptr);

  // Process an event and transition to StateOne
  ASSERT_FALSE(sm_.state_one_->on_enter_);
  ASSERT_FALSE(sm_.state_one_->on_exit_);
  ASSERT_EQ(sm_.state_one_->event_, kInvalidEvent);
  ASSERT_EQ(sm_.state_one_->data_, nullptr);
  ASSERT_TRUE(sm_.ProcessEvent(kEventZero, &dataZero));
  ASSERT_EQ(sm_.kStateOne, sm_.StateId());
  ASSERT_EQ(sm_.kStateZero, sm_.PreviousStateId());
  // Check StateZero
  ASSERT_EQ(sm_.state_zero_->event_, kEventZero);
  ASSERT_EQ(sm_.state_zero_->data_, &dataZero);
  ASSERT_TRUE(sm_.state_zero_->on_exit_);
  // Check StateOne
  ASSERT_TRUE(sm_.state_one_->on_enter_);
  ASSERT_FALSE(sm_.state_one_->on_exit_);
  ASSERT_EQ(sm_.state_one_->event_, kInvalidEvent);
  ASSERT_EQ(sm_.state_one_->data_, nullptr);

  // Process an event and transition to StateTwo
  ASSERT_FALSE(sm_.state_two_->on_enter_);
  ASSERT_FALSE(sm_.state_two_->on_exit_);
  ASSERT_EQ(sm_.state_two_->event_, kInvalidEvent);
  ASSERT_EQ(sm_.state_two_->data_, nullptr);
  ASSERT_TRUE(sm_.ProcessEvent(kEventOne, &dataOne));
  ASSERT_EQ(sm_.kStateTwo, sm_.StateId());
  ASSERT_EQ(sm_.kStateOne, sm_.PreviousStateId());
  // Check StateOne
  ASSERT_EQ(sm_.state_one_->event_, kEventOne);
  ASSERT_EQ(sm_.state_one_->data_, &dataOne);
  ASSERT_TRUE(sm_.state_one_->on_exit_);
  // Check StateTwo
  ASSERT_TRUE(sm_.state_two_->on_enter_);
  ASSERT_FALSE(sm_.state_two_->on_exit_);
  ASSERT_EQ(sm_.state_two_->event_, kInvalidEvent);
  ASSERT_EQ(sm_.state_two_->data_, nullptr);

  // Process an event and transition to StateZero
  // NOTE: StateZero was exited before and has local state
  ASSERT_FALSE(sm_.state_zero_->on_enter_);
  ASSERT_TRUE(sm_.state_zero_->on_exit_);  // NOTE: already exited before
  ASSERT_EQ(sm_.state_zero_->event_, kEventZero);  // NOTE: state from before
  ASSERT_EQ(sm_.state_zero_->data_, &dataZero);    // NOTE: state from before
  ASSERT_TRUE(sm_.ProcessEvent(kEventTwo, &dataTwo));
  ASSERT_EQ(sm_.kStateZero, sm_.StateId());
  ASSERT_EQ(sm_.kStateTwo, sm_.PreviousStateId());
  // Check StateTwo
  ASSERT_EQ(sm_.state_two_->event_, kEventTwo);
  ASSERT_EQ(sm_.state_two_->data_, &dataTwo);
  ASSERT_TRUE(sm_.state_two_->on_exit_);
  // Check StateZero
  ASSERT_TRUE(sm_.state_zero_->on_enter_);
  ASSERT_FALSE(sm_.state_zero_->on_exit_);
  ASSERT_EQ(sm_.state_zero_->event_, kEventZero);  // NOTE: state from before
  ASSERT_EQ(sm_.state_zero_->data_, &dataZero);    // NOTE: state from before
}