--- /dev/null
+/*
+ * Copyright 2019 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 <cstdint>
+
+#define LOG_TAG "bt_shim_test"
+
+#include "osi/include/log.h"
+#include "shim/l2cap.h"
+#include "shim/test_stack.h"
+#include "types/raw_address.h"
+
+TestStack test_stack_;
+
+bluetooth::shim::IStack* bluetooth::shim::GetGabeldorscheStack() {
+ return (bluetooth::shim::IStack*)&test_stack_;
+}
+
+namespace bluetooth {
+namespace legacy {
+
+namespace {
+
+constexpr uint16_t kPsm = 123;
+constexpr uint16_t kCid = 987;
+constexpr size_t kDataBufferSize = 1024;
+
+uint8_t bt_hdr_data[] = {
+ 0x00, 0x00, /* event */
+ 0x08, 0x00, /* len */
+ 0x00, 0x00, /* offset */
+ 0x00, 0x00, /* layer specific */
+ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, /* data */
+ 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, /* data */
+};
+
+class L2capTest;
+L2capTest* l2cap_test_ = nullptr;
+
+class L2capTest : public ::testing::Test {
+ public:
+ static shim::L2cap* l2cap_;
+
+ struct {
+ int L2caConnectCfmCb;
+ int L2caConnectPndCb;
+ int L2caConfigIndCb;
+ int L2caConfigCfmCb;
+ int L2caDisconnectIndCb;
+ int L2caDisconnectCfmCb;
+ int L2caQosViolationIndCb;
+ int L2caDataIndCb;
+ int L2caCongestionStatusCb;
+ int L2caTxCompleteCb;
+ int L2caCreditsReceivedCb;
+ } cnt_{
+ .L2caConnectCfmCb = 0,
+ .L2caConnectPndCb = 0,
+ .L2caConfigIndCb = 0,
+ .L2caConfigCfmCb = 0,
+ .L2caDisconnectIndCb = 0,
+ .L2caDisconnectCfmCb = 0,
+ .L2caQosViolationIndCb = 0,
+ .L2caDataIndCb = 0,
+ .L2caCongestionStatusCb = 0,
+ .L2caTxCompleteCb = 0,
+ .L2caCreditsReceivedCb = 0,
+ };
+
+ protected:
+ void SetUp() override {
+ l2cap_ = new shim::L2cap();
+ l2cap_test_ = this;
+ }
+
+ void TearDown() override {
+ delete l2cap_;
+ l2cap_ = nullptr;
+ }
+
+ uint8_t data_buffer_[kDataBufferSize];
+};
+
+shim::L2cap* L2capTest::l2cap_ = nullptr;
+// Indication of remotely initiated connection response sent
+void L2caConnectIndCb(const RawAddress& raw_address, uint16_t a, uint16_t b,
+ uint8_t c) {
+ LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+// Confirms locally initiated connection request completed
+void L2caConnectCfmCb(uint16_t cid, uint16_t result) {
+ l2cap_test_->cnt_.L2caConnectCfmCb++;
+ LOG_INFO(LOG_TAG, "%s cid:%hd result:%hd", __func__, cid, result);
+}
+
+void L2caConnectPndCb(uint16_t cid) {
+ l2cap_test_->cnt_.L2caConnectPndCb++;
+ LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+// Indication of remotely initiated configuration response sent
+void L2caConfigIndCb(uint16_t cid, tL2CAP_CFG_INFO* callbacks) {
+ l2cap_test_->cnt_.L2caConfigIndCb++;
+ LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+// Confirms locally initiated config request completed
+void L2caConfigCfmCb(uint16_t cid, tL2CAP_CFG_INFO* callbacks) {
+ l2cap_test_->cnt_.L2caConfigCfmCb++;
+ LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+// Indication of remotely initiated disconnection response sent
+void L2caDisconnectIndCb(uint16_t cid, bool needs_ack) {
+ l2cap_test_->cnt_.L2caDisconnectIndCb++;
+ LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+// Confirms locally initiated disconnect request completed
+void L2caDisconnectCfmCb(uint16_t cid, uint16_t result) {
+ l2cap_test_->cnt_.L2caDisconnectCfmCb++;
+ LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+void L2caQosViolationIndCb(const RawAddress& raw_address) {
+ l2cap_test_->cnt_.L2caQosViolationIndCb++;
+ LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+void L2caDataIndCb(uint16_t cid, BT_HDR* bt_hdr) {
+ l2cap_test_->cnt_.L2caDataIndCb++;
+ LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+void L2caCongestionStatusCb(uint16_t cid, bool is_congested) {
+ l2cap_test_->cnt_.L2caCongestionStatusCb++;
+ LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+void L2caTxCompleteCb(uint16_t cid, uint16_t sdu_cnt) {
+ l2cap_test_->cnt_.L2caTxCompleteCb++;
+ LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+void L2caCreditsReceivedCb(uint16_t cid, uint16_t credits_received,
+ uint16_t credit_count) {
+ l2cap_test_->cnt_.L2caCreditsReceivedCb++;
+ LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+tL2CAP_APPL_INFO test_callbacks{
+ .pL2CA_ConnectInd_Cb = L2caConnectIndCb,
+ .pL2CA_ConnectCfm_Cb = L2caConnectCfmCb,
+ .pL2CA_ConnectPnd_Cb = L2caConnectPndCb,
+ .pL2CA_ConfigInd_Cb = L2caConfigIndCb,
+ .pL2CA_ConfigCfm_Cb = L2caConfigCfmCb,
+ .pL2CA_DisconnectInd_Cb = L2caDisconnectIndCb,
+ .pL2CA_DisconnectCfm_Cb = L2caDisconnectCfmCb,
+ .pL2CA_QoSViolationInd_Cb = L2caQosViolationIndCb,
+ .pL2CA_DataInd_Cb = L2caDataIndCb,
+ .pL2CA_CongestionStatus_Cb = L2caCongestionStatusCb,
+ .pL2CA_TxComplete_Cb = L2caTxCompleteCb,
+ .pL2CA_CreditsReceived_Cb = L2caCreditsReceivedCb,
+};
+
+TEST_F(L2capTest, Base) { LOG_INFO(LOG_TAG, "Got test %p", &test_callbacks); }
+
+TEST_F(L2capTest, Callbacks) {
+ bool rc = l2cap_->SetCallbacks(kPsm, &test_callbacks);
+ CHECK(rc == true);
+}
+
+TEST_F(L2capTest, RegisterService) {
+ l2cap_->RegisterService(123, &test_callbacks, false);
+}
+
+TEST_F(L2capTest, CreateConnection_NotRegistered) {
+ RawAddress raw_address;
+ std::string string_address("11:22:33:44:55:66");
+ RawAddress::FromString(string_address, raw_address);
+ uint16_t cid = l2cap_->CreateConnection(123, raw_address);
+ CHECK(cid == 0);
+}
+
+TEST_F(L2capTest, CreateConnection_Registered) {
+ test_stack_.test_l2cap_.cid_ = kCid;
+ l2cap_->RegisterService(123, &test_callbacks, false);
+
+ RawAddress raw_address;
+ std::string string_address("11:22:33:44:55:66");
+ RawAddress::FromString(string_address, raw_address);
+ uint16_t cid = l2cap_->CreateConnection(123, raw_address);
+ CHECK(cid != 0);
+}
+
+TEST_F(L2capTest, CreateConnection_WithHandshake) {
+ test_stack_.test_l2cap_.cid_ = kCid;
+ l2cap_->RegisterService(kPsm, &test_callbacks, false);
+
+ RawAddress raw_address;
+ std::string string_address("11:22:33:44:55:66");
+ RawAddress::FromString(string_address, raw_address);
+ uint16_t cid = l2cap_->CreateConnection(kPsm, raw_address);
+ CHECK(cid != 0);
+
+ {
+ // Simulate a successful connection response
+ l2cap_->OnConnectionReady(kPsm, kCid,
+ [&cid](std::function<void(uint16_t)> func) {
+ LOG_INFO(LOG_TAG, "In closure cid:%d", cid);
+ func(cid);
+ });
+ }
+ CHECK(cnt_.L2caConnectCfmCb == 1);
+
+ CHECK(l2cap_->ConfigRequest(cid, nullptr) == true);
+ CHECK(cnt_.L2caConfigCfmCb == 1);
+
+ BT_HDR* bt_hdr = (BT_HDR*)bt_hdr_data;
+
+ test_stack_.test_l2cap_.data_buffer_ = data_buffer_;
+ test_stack_.test_l2cap_.data_buffer_size_ = kDataBufferSize;
+
+ l2cap_->Write(cid, bt_hdr);
+
+ CHECK(data_buffer_[0] == 0x11);
+ CHECK(data_buffer_[1] == 0x22);
+ CHECK(data_buffer_[2] == 0x33);
+ CHECK(data_buffer_[3] == 0x44);
+ CHECK(data_buffer_[4] == 0x55);
+ CHECK(data_buffer_[5] == 0x66);
+ CHECK(data_buffer_[6] == 0x77);
+ CHECK(data_buffer_[7] == 0x88);
+ CHECK(data_buffer_[8] == 0x00);
+}
+
+} // namespace
+} // namespace legacy
+} // namespace bluetooth
--- /dev/null
+/*
+ * Copyright 2019 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 <cstdint>
+#include <future>
+
+#include "gd/shim/only_include_this_file_into_legacy_stack___ever.h"
+#include "main/shim/entry.h"
+#include "main/shim/test_stack.h"
+#include "osi/include/log.h"
+
+#define ASSERT(condition) \
+ do { \
+ if (!(condition)) { \
+ LOG_ALWAYS_FATAL("assertion '" #condition "' failed"); \
+ } \
+ } while (false)
+
+void TestGdShimL2cap::RegisterService(
+ uint16_t psm, bluetooth::shim::ConnectionOpenCallback on_open,
+ std::promise<void> completed) {
+ completed.set_value();
+}
+
+void TestGdShimL2cap::CreateConnection(uint16_t psm, const std::string address,
+ std::promise<uint16_t> completed) {
+ completed.set_value(cid_);
+}
+
+void TestGdShimL2cap::SetReadDataReadyCallback(
+ uint16_t cid, bluetooth::shim::ReadDataReadyCallback on_data_ready) {}
+
+void TestGdShimL2cap::SetConnectionClosedCallback(
+ uint16_t cid, bluetooth::shim::ConnectionClosedCallback on_closed) {}
+
+bool TestGdShimL2cap::Write(uint16_t cid, const uint8_t* data, size_t len) {
+ ASSERT(data_buffer_ != nullptr);
+ ASSERT(data_buffer_size_ > len);
+ memcpy(data_buffer_, data, len);
+ return write_success_;
+}
+
+bool TestGdShimL2cap::WriteFlushable(uint16_t cid, const uint8_t* data,
+ size_t len) {
+ return write_success_;
+}
+
+bool TestGdShimL2cap::WriteNonFlushable(uint16_t cid, const uint8_t* data,
+ size_t len) {
+ return write_success_;
+}
+
+bool TestGdShimL2cap::IsCongested(uint16_t cid) { return is_congested_; }
+
+void TestStack::Start() {}
+
+void TestStack::Stop() {}
+
+bluetooth::shim::IController* TestStack::GetController() { return nullptr; }
+
+bluetooth::shim::IConnectability* TestStack::GetConnectability() {
+ return nullptr;
+}
+
+bluetooth::shim::IDiscoverability* TestStack::GetDiscoverability() {
+ return nullptr;
+}
+
+bluetooth::shim::IHciLayer* TestStack::GetHciLayer() { return nullptr; }
+
+bluetooth::shim::IInquiry* TestStack::GetInquiry() { return nullptr; }
+
+bluetooth::shim::IL2cap* TestStack::GetL2cap() { return &test_l2cap_; }
+
+bluetooth::shim::IPage* TestStack::GetPage() { return nullptr; }
--- /dev/null
+/*
+ * Copyright 2019 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 <cstdint>
+#include <future>
+
+#include "gd/shim/only_include_this_file_into_legacy_stack___ever.h"
+#include "main/shim/entry.h"
+
+class TestGdShimL2cap : public bluetooth::shim::IL2cap {
+ public:
+ uint16_t cid_{0};
+ bool write_success_{false};
+ bool is_congested_{false};
+ uint8_t* data_buffer_{nullptr};
+ size_t data_buffer_size_{0};
+
+ void RegisterService(uint16_t psm,
+ bluetooth::shim::ConnectionOpenCallback on_open,
+ std::promise<void> completed) override;
+ void CreateConnection(uint16_t psm, const std::string address,
+ std::promise<uint16_t> completed) override;
+ void SetReadDataReadyCallback(
+ uint16_t cid,
+ bluetooth::shim::ReadDataReadyCallback on_data_ready) override;
+ void SetConnectionClosedCallback(
+ uint16_t cid,
+ bluetooth::shim::ConnectionClosedCallback on_closed) override;
+ bool Write(uint16_t cid, const uint8_t* data, size_t len) override;
+ bool WriteFlushable(uint16_t cid, const uint8_t* data, size_t len) override;
+ bool WriteNonFlushable(uint16_t cid, const uint8_t* data,
+ size_t len) override;
+ bool IsCongested(uint16_t cid) override;
+};
+
+class TestStack : public bluetooth::shim::IStack {
+ public:
+ TestStack() = default;
+
+ bluetooth::shim::IController* GetController();
+ bluetooth::shim::IConnectability* GetConnectability();
+ bluetooth::shim::IDiscoverability* GetDiscoverability();
+ bluetooth::shim::IHciLayer* GetHciLayer();
+ bluetooth::shim::IInquiry* GetInquiry();
+ bluetooth::shim::IL2cap* GetL2cap();
+ bluetooth::shim::IPage* GetPage();
+
+ TestGdShimL2cap test_l2cap_;
+
+ void Start();
+ void Stop();
+};