/* * Copyright 2023 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 "test/fake/fake_osi.h" #include #include "test/mock/mock_osi_alarm.h" #include "test/mock/mock_osi_allocator.h" #include "test/mock/mock_osi_fixed_queue.h" #include "test/mock/mock_osi_list.h" using namespace bluetooth; // Must be global to resolve the symbol within the legacy stack struct alarm_t { alarm_callback_t cb; void* data; alarm_t(const char* /* name */) { cb = nullptr; data = nullptr; }; }; struct list_node_t { void* data_; list_node_t* next_; list_node_t(void* data, list_node_t* next) { data_ = data; next_ = next; } }; struct list_t { list_node_t* head_; list_node_t* tail_; size_t length_; list_free_cb free_cb_; list_t(list_free_cb free_cb) { head_ = tail_ = nullptr; free_cb_ = free_cb; length_ = 0; } }; struct fixed_queue_t { list_t* list_; size_t capacity_; fixed_queue_t(size_t capacity) { list_ = test::mock::osi_list::list_new(nullptr); capacity_ = capacity; } }; namespace test { namespace fake { static list_node_t* list_free_node_(list_t* l, list_node_t* node) { log::assert_that(l != nullptr, "assert failed: l != nullptr"); log::assert_that(node != nullptr, "assert failed: node != nullptr"); auto next = node->next_; if (l->free_cb_) l->free_cb_(node->data_); delete node; --l->length_; return next; } FakeOsi::FakeOsi() { test::mock::osi_alarm::alarm_free.body = [](alarm_t* alarm) { if (alarm) { delete alarm; } }; test::mock::osi_alarm::alarm_new.body = [](const char* name) { return new alarm_t(name); }; test::mock::osi_alarm::alarm_set_on_mloop.body = [](alarm_t* alarm, uint64_t /* interval_ms */, alarm_callback_t cb, void* data) { alarm->cb = cb; alarm->data = data; }; test::mock::osi_alarm::alarm_cancel.body = [](alarm_t* alarm) { if (alarm) { alarm->cb = nullptr; alarm->data = nullptr; } }; test::mock::osi_allocator::osi_calloc.body = [](size_t size) { return calloc(1UL, size); }; test::mock::osi_allocator::osi_free.body = [](void* ptr) { free(ptr); }; test::mock::osi_allocator::osi_free_and_reset.body = [](void** ptr) { free(*ptr); *ptr = nullptr; }; test::mock::osi_allocator::osi_malloc.body = [](size_t size) { return malloc(size); }; test::mock::osi_list::list_new.body = [](list_free_cb callback) { return new list_t(callback); }; test::mock::osi_list::list_free.body = [](list_t* l) { log::assert_that(l != nullptr, "assert failed: l != nullptr"); test::mock::osi_list::list_clear(l); delete l; }; test::mock::osi_list::list_is_empty.body = [](const list_t* l) { return test::mock::osi_list::list_length(l) == 0; }; test::mock::osi_list::list_foreach.body = [](const list_t* l, list_iter_cb callback, void* context) { log::assert_that(l != nullptr, "assert failed: l != nullptr"); for (auto node = l->head_; node;) { auto next = node->next_; if (!callback(node->data_, context)) return node; node = next; } return (list_node_t*)nullptr; }; test::mock::osi_list::list_contains.body = [](const list_t* l, const void* data) { auto node = test::mock::osi_list::list_foreach( l, [](void* data, void* context) { return data != context; }, const_cast(data)); return node; }; test::mock::osi_list::list_length.body = [](const list_t* l) { log::assert_that(l != nullptr, "assert failed: l != nullptr"); return l->length_; }; test::mock::osi_list::list_front.body = [](const list_t* l) { log::assert_that(l != nullptr, "assert failed: l != nullptr"); log::assert_that(l->head_, "assert failed: l->head_"); return l->head_->data_; }; test::mock::osi_list::list_back.body = [](const list_t* l) { log::assert_that(l != nullptr, "assert failed: l != nullptr"); log::assert_that(l->tail_, "assert failed: l->tail_"); return l->tail_->data_; }; test::mock::osi_list::list_back_node.body = [](const list_t* l) { log::assert_that(l != nullptr, "assert failed: l != nullptr"); return l->tail_; }; test::mock::osi_list::list_insert_after.body = [](list_t* l, list_node_t* prev_node, void* data) { log::assert_that(l != nullptr, "assert failed: l != nullptr"); log::assert_that(prev_node != nullptr, "assert failed: prev_node != nullptr"); log::assert_that(data != nullptr, "assert failed: data != nullptr"); auto node = new list_node_t(data, prev_node->next_); prev_node->next_ = node; if (l->tail_ == prev_node) l->tail_ = node; ++l->length_; return true; }; test::mock::osi_list::list_prepend.body = [](list_t* l, void* data) { log::assert_that(l != nullptr, "assert failed: l != nullptr"); log::assert_that(data != nullptr, "assert failed: data != nullptr"); auto node = new list_node_t(data, l->head_); l->head_ = node; if (l->tail_ == NULL) l->tail_ = l->head_; ++l->length_; return true; }; test::mock::osi_list::list_append.body = [](list_t* l, void* data) { log::assert_that(l != nullptr, "assert failed: l != nullptr"); log::assert_that(data != nullptr, "assert failed: data != nullptr"); auto node = new list_node_t(data, nullptr); if (l->tail_) { l->tail_->next_ = node; l->tail_ = node; } else { l->head_ = l->tail_ = node; } ++l->length_; return true; }; test::mock::osi_list::list_remove.body = [](list_t* l, void* data) { log::assert_that(l != nullptr, "assert failed: l != nullptr"); log::assert_that(data != nullptr, "assert failed: data != nullptr"); if (test::mock::osi_list::list_is_empty(l)) return false; if (l->head_->data_ == data) { auto next = list_free_node_(l, l->head_); if (l->tail_ == l->head_) l->tail_ = next; l->head_ = next; return true; } for (auto prev = l->head_, node = l->head_->next_; node; prev = node, node = node->next_) if (node->data_ == data) { prev->next_ = list_free_node_(l, node); if (l->tail_ == node) l->tail_ = prev; return true; } return false; }; test::mock::osi_list::list_clear.body = [](list_t* l) { log::assert_that(l != nullptr, "assert failed: l != nullptr"); for (auto node = l->head_; node;) { node = list_free_node_(l, node); } l->head_ = NULL; l->tail_ = NULL; l->length_ = 0; return; }; test::mock::osi_list::list_begin.body = [](const list_t* l) { log::assert_that(l != nullptr, "assert failed: l != nullptr"); return l->head_; }; test::mock::osi_list::list_end.body = [](const list_t* l) { log::assert_that(l != nullptr, "assert failed: l != nullptr"); return l->tail_; }; test::mock::osi_list::list_next.body = [](const list_node_t* node) { log::assert_that(node != nullptr, "assert failed: node != nullptr"); return node->next_; }; test::mock::osi_list::list_node.body = [](const list_node_t* node) { log::assert_that(node != nullptr, "assert failed: node != nullptr"); return node->data_; }; test::mock::osi_fixed_queue::fixed_queue_new.body = [](size_t capacity) { return new fixed_queue_t(capacity); }; test::mock::osi_fixed_queue::fixed_queue_flush.body = [](fixed_queue_t* q, fixed_queue_free_cb cb) { if (q) { if (cb) { test::mock::osi_list::list_foreach( q->list_, [](void* data, void* cb) { reinterpret_cast(cb)(data); return true; }, reinterpret_cast(cb)); } test::mock::osi_list::list_clear(q->list_); } }; test::mock::osi_fixed_queue::fixed_queue_free.body = [](fixed_queue_t* q, fixed_queue_free_cb free_cb) { if (q) { test::mock::osi_fixed_queue::fixed_queue_flush(q, free_cb); delete q->list_; delete q; } }; test::mock::osi_fixed_queue::fixed_queue_enqueue.body = [](fixed_queue_t* q, void* data) { if (q) test::mock::osi_list::list_append(q->list_, data); }; test::mock::osi_fixed_queue::fixed_queue_dequeue.body = [](fixed_queue_t* q) { void* ret = nullptr; if (q) { ret = test::mock::osi_list::list_front(q->list_); test::mock::osi_list::list_remove(q->list_, ret); } return ret; }; test::mock::osi_fixed_queue::fixed_queue_length.body = [](fixed_queue_t* q) { return q ? test::mock::osi_list::list_length(q->list_) : 0; }; test::mock::osi_fixed_queue::fixed_queue_is_empty.body = [](fixed_queue_t* q) { return test::mock::osi_fixed_queue::fixed_queue_length(q) == 0; }; test::mock::osi_fixed_queue::fixed_queue_capacity.body = [](fixed_queue_t* q) { return q ? q->capacity_ : 0; }; test::mock::osi_fixed_queue::fixed_queue_try_enqueue.body = [](fixed_queue_t* q, void* data) { test::mock::osi_fixed_queue::fixed_queue_enqueue(q, data); return true; }; test::mock::osi_fixed_queue::fixed_queue_try_dequeue.body = [](fixed_queue_t* q) { void* ret = nullptr; if (q && !test::mock::osi_fixed_queue::fixed_queue_is_empty(q)) { ret = test::mock::osi_fixed_queue::fixed_queue_dequeue(q); } return ret; }; test::mock::osi_fixed_queue::fixed_queue_try_peek_first.body = [](fixed_queue_t* q) { return (q && !test::mock::osi_list::list_is_empty(q->list_)) ? test::mock::osi_list::list_front(q->list_) : nullptr; }; test::mock::osi_fixed_queue::fixed_queue_try_peek_last.body = [](fixed_queue_t* q) { return (q && !test::mock::osi_list::list_is_empty(q->list_)) ? test::mock::osi_list::list_back(q->list_) : nullptr; }; test::mock::osi_fixed_queue::fixed_queue_get_list.body = [](fixed_queue_t* q) { return q ? q->list_ : nullptr; }; test::mock::osi_fixed_queue::fixed_queue_try_remove_from_queue.body = [](fixed_queue_t* /* q */, void* /* data */) { // not implemented abort(); return nullptr; }; test::mock::osi_fixed_queue::fixed_queue_get_enqueue_fd.body = [](const fixed_queue_t* /* q */) { // not implemented abort(); return 0; }; test::mock::osi_fixed_queue::fixed_queue_get_dequeue_fd.body = [](const fixed_queue_t* /* q */) { // not implemented abort(); return 0; }; test::mock::osi_fixed_queue::fixed_queue_register_dequeue.body = [](fixed_queue_t* /* q */, reactor_t* /* reactor */, fixed_queue_cb /* ready_cb */, void* /* context */) { // not implemented abort(); }; test::mock::osi_fixed_queue::fixed_queue_unregister_dequeue.body = [](fixed_queue_t* /* q */) { // not implemented abort(); }; } FakeOsi::~FakeOsi() { test::mock::osi_alarm::alarm_free = {}; test::mock::osi_alarm::alarm_new = {}; test::mock::osi_allocator::osi_calloc = {}; test::mock::osi_allocator::osi_free = {}; test::mock::osi_allocator::osi_free_and_reset = {}; test::mock::osi_allocator::osi_malloc = {}; test::mock::osi_list::list_new = {}; test::mock::osi_list::list_free = {}; test::mock::osi_list::list_is_empty = {}; test::mock::osi_list::list_foreach = {}; test::mock::osi_list::list_contains = {}; test::mock::osi_list::list_length = {}; test::mock::osi_list::list_front = {}; test::mock::osi_list::list_back = {}; test::mock::osi_list::list_back_node = {}; test::mock::osi_list::list_insert_after = {}; test::mock::osi_list::list_prepend = {}; test::mock::osi_list::list_append = {}; test::mock::osi_list::list_remove = {}; test::mock::osi_list::list_clear = {}; test::mock::osi_list::list_begin = {}; test::mock::osi_list::list_end = {}; test::mock::osi_list::list_next = {}; test::mock::osi_list::list_node = {}; test::mock::osi_fixed_queue::fixed_queue_new = {}; test::mock::osi_fixed_queue::fixed_queue_flush = {}; test::mock::osi_fixed_queue::fixed_queue_free = {}; test::mock::osi_fixed_queue::fixed_queue_enqueue = {}; test::mock::osi_fixed_queue::fixed_queue_dequeue = {}; test::mock::osi_fixed_queue::fixed_queue_length = {}; test::mock::osi_fixed_queue::fixed_queue_is_empty = {}; test::mock::osi_fixed_queue::fixed_queue_capacity = {}; test::mock::osi_fixed_queue::fixed_queue_try_enqueue = {}; test::mock::osi_fixed_queue::fixed_queue_try_dequeue = {}; test::mock::osi_fixed_queue::fixed_queue_try_peek_first = {}; test::mock::osi_fixed_queue::fixed_queue_try_peek_last = {}; test::mock::osi_fixed_queue::fixed_queue_try_remove_from_queue = {}; test::mock::osi_fixed_queue::fixed_queue_get_list = {}; test::mock::osi_fixed_queue::fixed_queue_get_enqueue_fd = {}; test::mock::osi_fixed_queue::fixed_queue_get_dequeue_fd = {}; test::mock::osi_fixed_queue::fixed_queue_register_dequeue = {}; test::mock::osi_fixed_queue::fixed_queue_unregister_dequeue = {}; } } // namespace fake } // namespace test