# GTest Unit Tests

[TOC]

## GTest Unit Tests

[GTest](https://github.com/google/googletest) is a Google developed open source
unit testing framework for C++ and C code. As the majority of GD code is writeen
in C++, GTest provide the first layer of defence against bugs from the
implementation level. Used in combination with
[GMock](https://github.com/google/googlemock) developers can easily isolate
classes and functions from their code to conduct unit testing.

*   [GTest Primer](https://github.com/google/googletest/blob/master/googletest/docs/primer.md)
*   [GMock for Dummies](https://github.com/google/googletest/blob/master/googlemock/docs/for_dummies.md)

### Test Binary

All Gd unit test classes are compiled into a single binary
[bluetooth_test_gd](https://android.googlesource.com/platform/packages/modules/Bluetooth/system/+/master/gd/Android.bp).

### Test Sources Definitions

*   Tests should live in the same directory as the source code
*   Mocks should live in the same directory as the source header so that it can
    be shared among multiple tests
*   Tests should not modify global states that would affect other tests, so that
    all tests could be executed using the same binary
*   Each module can define a filegroup() that includes all test sources. This
    filegroup is then included in a single cc_test() target that produce a
    single test binary
    [bluetooth_test_gd](https://android.googlesource.com/platform/packages/modules/Bluetooth/system/+/master/gd/Android.bp).
    A single test binary simplifies the configuration effort needed for
    compilation, presubmit and postsubmit execution, and so on.

### How to run tests

#### Use `atest`

[ATest](https://source.android.com/compatibility/tests/development/atest) is an
Android tool that allows a developers to run multiple modes of tests from the
same `atest` command, including Java Instrumentation Tests, C/C++ GTests,
CTS/GTS tests, etc. To use `atest` with GD, simplying sync your Android tree,
run `source build/envsetup.sh` and `lunch` to a desired target. Then

*   To run tests on device, the following command will automatically build,
    push, and execute tests on a connected Android device

    ```shell
    atest bluetooth_test_gd
    ```

*   To run tests on host, the following command will automatically build and run
    tests on your host machine

    ```shell
    atest --host bluetooth_test_gd
    ```

*   To run a single test case, use `:#`
    format, such as

    ```shell
    atest --host bluetooth_test_gd:AclManagerTest#invoke_registered_callback_connection_complete_success
    ```

    See `atest --help` for more documentation on how to use atest to run various
    tests

#### Run it yourself (Not receommended unless really needed)

Sometimes, you may want to execute the test binary directly because you want to
attach a debugger or you want to avoid the test boostrap delay in `atest`. You
can do it with the following steps

1.  Sync Android tree, run `build/envsetup` and `lunch` desired target, `cd`
    into Android checkout root directory

1.  Make bluetooth_test_gd binary

    ```shell
    m -j40 bluetooth_test_gd
    ```

1.  Run the test on host {value=3}

    ```shell
    $ANDROID_HOST_OUT/nativetest64/bluetooth_test_gd/bluetooth_test_gd
    ```

1.  Run the test on device {value=4}

    Push test to device

    ```shell
    adb push $ANDROID_PRODUCT_OUT/testcases/bluetooth_test_gd/arm64/bluetooth_test_gd /data/nativetest64/bluetooth_test_gd
    ```

    Run test using ADB

    ```shell
    adb shell /data/nativetest64/bluetooth_test_gd
    ```

1.  Run test with filter (Works the same way for device based test) {value=5}

    ```shell
    $ANDROID_HOST_OUT/nativetest64/bluetooth_test_gd/bluetooth_test_gd --gtest_filter=AclManagerTest.invoke_registered_callback_connection_complete_success*
    ```

    Note: the '*' wildcard is very important

1.  Get command line help {value=6}

    ```shell
    $ANDROID_HOST_OUT/nativetest64/bluetooth_test_gd/bluetooth_test_gd --help
    ```

### Example: L2capClassicFixedChannelImplTest

Note: All paths are relative to
[packages/modules/Bluetooth/system/gd](https://android.googlesource.com/platform/packages/modules/Bluetooth/system/+/master/gd)

#### Source code:

*   [l2cap/classic/internal/fixed_channel_impl.h](https://android.googlesource.com/platform/packages/modules/Bluetooth/system/+/master/gd/l2cap/classic/internal/fixed_channel_impl.h)

```c++
#pragma once

#include "common/bidi_queue.h"
#include "l2cap/cid.h"
#include "l2cap/classic/fixed_channel.h"
#include "l2cap/internal/channel_impl.h"
#include "l2cap/l2cap_packets.h"
#include "os/handler.h"
#include "os/log.h"

namespace bluetooth {
namespace l2cap {
namespace classic {
namespace internal {

class Link;

class FixedChannelImpl : public l2cap::internal::ChannelImpl {
 public:
  FixedChannelImpl(Cid cid, Link* link, os::Handler* l2cap_handler);
  virtual ~FixedChannelImpl() = default;
  hci::Address GetDevice() const;
  virtual void RegisterOnCloseCallback(os::Handler* user_handler, FixedChannel::OnCloseCallback on_close_callback);
  virtual void Acquire();
  virtual void Release();
  virtual bool IsAcquired() const;
  virtual void OnClosed(hci::ErrorCode status);
  virtual std::string ToString();
  common::BidiQueueEnd>* GetQueueUpEnd();
  common::BidiQueueEnd, packet::BasePacketBuilder>* GetQueueDownEnd();
  Cid GetCid() const;
  Cid GetRemoteCid() const;
 private:
  // private fields omitted in doc ...
};

}  // namespace internal
}  // namespace classic
}  // namespace l2cap
}  // namespace bluetooth
```

*   [packages/modules/Bluetooth/system/gd/l2cap/classic/internal/fixed_channel_impl.cc](https://android.googlesource.com/platform/packages/modules/Bluetooth/system/+/master/gd/l2cap/classic/internal/fixed_channel_impl.cc)

#### Mocks for dependencies' unit tests

*   [l2cap/classic/internal/fixed_channel_impl_mock.h](https://android.googlesource.com/platform/packages/modules/Bluetooth/system/+/master/gd/l2cap/classic/internal/fixed_channel_impl_mock.h)

```c++
#pragma once

#include "l2cap/classic/internal/fixed_channel_impl.h"

#include 

// Unit test interfaces
namespace bluetooth {
namespace l2cap {
namespace classic {
namespace internal {
namespace testing {

class MockFixedChannelImpl : public FixedChannelImpl {
 public:
  MockFixedChannelImpl(Cid cid, Link* link, os::Handler* l2cap_handler) : FixedChannelImpl(cid, link, l2cap_handler) {}
  MOCK_METHOD(void, RegisterOnCloseCallback,
              (os::Handler * user_handler, FixedChannel::OnCloseCallback on_close_callback), (override));
  MOCK_METHOD(void, Acquire, (), (override));
  MOCK_METHOD(void, Release, (), (override));
  MOCK_METHOD(bool, IsAcquired, (), (override, const));
  MOCK_METHOD(void, OnClosed, (hci::ErrorCode status), (override));
};

}  // namespace testing
}  // namespace internal
}  // namespace classic
}  // namespace l2cap
}  // namespace bluetooth
```

#### Tests

*   [l2cap/classic/internal/fixed_channel_impl_test.cc](https://android.googlesource.com/platform/packages/modules/Bluetooth/system/+/master/gd/l2cap/classic/internal/fixed_channel_impl_test.cc)

```c++
#include "l2cap/classic/internal/fixed_channel_impl.h"

#include "common/testing/bind_test_util.h"
#include "l2cap/cid.h"
#include "l2cap/classic/internal/link_mock.h"
#include "l2cap/internal/parameter_provider_mock.h"
#include "os/handler.h"

#include 
#include 

namespace bluetooth {
namespace l2cap {
namespace classic {
namespace internal {

using l2cap::internal::testing::MockParameterProvider;
using ::testing::_;
using testing::MockLink;
using ::testing::Return;

class L2capClassicFixedChannelImplTest : public ::testing::Test {
 public:
  static void SyncHandler(os::Handler* handler) {
    std::promise promise;
    auto future = promise.get_future();
    handler->Post(common::BindOnce(&std::promise::set_value, common::Unretained(&promise)));
    future.wait_for(std::chrono::seconds(1));
  }

 protected:
  void SetUp() override {
    thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
    l2cap_handler_ = new os::Handler(thread_);
  }

  void TearDown() override {
    l2cap_handler_->Clear();
    delete l2cap_handler_;
    delete thread_;
  }

  os::Thread* thread_ = nullptr;
  os::Handler* l2cap_handler_ = nullptr;
};

TEST_F(L2capClassicFixedChannelImplTest, get_device) {
  MockParameterProvider mock_parameter_provider;
  EXPECT_CALL(mock_parameter_provider, GetClassicLinkIdleDisconnectTimeout())
      .WillRepeatedly(Return(std::chrono::seconds(5)));
  testing::MockClassicAclConnection* mock_acl_connection = new testing::MockClassicAclConnection();
  EXPECT_CALL(*mock_acl_connection, GetAddress()).Times(1);
  EXPECT_CALL(*mock_acl_connection, RegisterCallbacks(_, l2cap_handler_)).Times(1);
  EXPECT_CALL(*mock_acl_connection, UnregisterCallbacks(_)).Times(1);
  MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider,
                             std::unique_ptr(mock_acl_connection));
  hci::AddressWithType device{hci::Address{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}},
                              hci::AddressType::PUBLIC_IDENTITY_ADDRESS};
  EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
  FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_classic_link, l2cap_handler_);
  EXPECT_EQ(device.GetAddress(), fixed_channel_impl.GetDevice());
}

// Other test cases omitted in doc ...

}  // namespace internal
}  // namespace classic
}  // namespace l2cap
}  // namespace bluetooth
```