1 /*
2  * Copyright 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "test/fake/fake_osi.h"
17 
18 #include <bluetooth/log.h>
19 
20 #include "test/mock/mock_osi_alarm.h"
21 #include "test/mock/mock_osi_allocator.h"
22 #include "test/mock/mock_osi_fixed_queue.h"
23 #include "test/mock/mock_osi_list.h"
24 
25 using namespace bluetooth;
26 
27 // Must be global to resolve the symbol within the legacy stack
28 struct alarm_t {
29   alarm_callback_t cb;
30   void* data;
31 
alarm_talarm_t32   alarm_t(const char* /* name */) {
33     cb = nullptr;
34     data = nullptr;
35   };
36 };
37 
38 struct list_node_t {
39   void* data_;
40   list_node_t* next_;
41 
list_node_tlist_node_t42   list_node_t(void* data, list_node_t* next) {
43     data_ = data;
44     next_ = next;
45   }
46 };
47 
48 struct list_t {
49   list_node_t* head_;
50   list_node_t* tail_;
51   size_t length_;
52   list_free_cb free_cb_;
53 
list_tlist_t54   list_t(list_free_cb free_cb) {
55     head_ = tail_ = nullptr;
56     free_cb_ = free_cb;
57     length_ = 0;
58   }
59 };
60 
61 struct fixed_queue_t {
62   list_t* list_;
63   size_t capacity_;
64 
fixed_queue_tfixed_queue_t65   fixed_queue_t(size_t capacity) {
66     list_ = test::mock::osi_list::list_new(nullptr);
67     capacity_ = capacity;
68   }
69 };
70 
71 namespace test {
72 namespace fake {
73 
list_free_node_(list_t * l,list_node_t * node)74 static list_node_t* list_free_node_(list_t* l, list_node_t* node) {
75   log::assert_that(l != nullptr, "assert failed: l != nullptr");
76   log::assert_that(node != nullptr, "assert failed: node != nullptr");
77 
78   auto next = node->next_;
79 
80   if (l->free_cb_) l->free_cb_(node->data_);
81   delete node;
82   --l->length_;
83   return next;
84 }
85 
FakeOsi()86 FakeOsi::FakeOsi() {
87   test::mock::osi_alarm::alarm_free.body = [](alarm_t* alarm) {
88     if (alarm) {
89       delete alarm;
90     }
91   };
92 
93   test::mock::osi_alarm::alarm_new.body = [](const char* name) {
94     return new alarm_t(name);
95   };
96 
97   test::mock::osi_alarm::alarm_set_on_mloop.body =
98       [](alarm_t* alarm, uint64_t /* interval_ms */, alarm_callback_t cb,
99          void* data) {
100         alarm->cb = cb;
101         alarm->data = data;
102       };
103 
104   test::mock::osi_alarm::alarm_cancel.body = [](alarm_t* alarm) {
105     if (alarm) {
106       alarm->cb = nullptr;
107       alarm->data = nullptr;
108     }
109   };
110 
111   test::mock::osi_allocator::osi_calloc.body = [](size_t size) {
112     return calloc(1UL, size);
113   };
114   test::mock::osi_allocator::osi_free.body = [](void* ptr) { free(ptr); };
115   test::mock::osi_allocator::osi_free_and_reset.body = [](void** ptr) {
116     free(*ptr);
117     *ptr = nullptr;
118   };
119   test::mock::osi_allocator::osi_malloc.body = [](size_t size) {
120     return malloc(size);
121   };
122 
123   test::mock::osi_list::list_new.body = [](list_free_cb callback) {
124     return new list_t(callback);
125   };
126 
127   test::mock::osi_list::list_free.body = [](list_t* l) {
128     log::assert_that(l != nullptr, "assert failed: l != nullptr");
129     test::mock::osi_list::list_clear(l);
130     delete l;
131   };
132   test::mock::osi_list::list_is_empty.body = [](const list_t* l) {
133     return test::mock::osi_list::list_length(l) == 0;
134   };
135   test::mock::osi_list::list_foreach.body =
136       [](const list_t* l, list_iter_cb callback, void* context) {
137         log::assert_that(l != nullptr, "assert failed: l != nullptr");
138         for (auto node = l->head_; node;) {
139           auto next = node->next_;
140           if (!callback(node->data_, context)) return node;
141           node = next;
142         }
143         return (list_node_t*)nullptr;
144       };
145   test::mock::osi_list::list_contains.body = [](const list_t* l,
146                                                 const void* data) {
147     auto node = test::mock::osi_list::list_foreach(
148         l, [](void* data, void* context) { return data != context; },
149         const_cast<void*>(data));
150     return node;
151   };
152   test::mock::osi_list::list_length.body = [](const list_t* l) {
153     log::assert_that(l != nullptr, "assert failed: l != nullptr");
154     return l->length_;
155   };
156   test::mock::osi_list::list_front.body = [](const list_t* l) {
157     log::assert_that(l != nullptr, "assert failed: l != nullptr");
158     log::assert_that(l->head_, "assert failed: l->head_");
159     return l->head_->data_;
160   };
161   test::mock::osi_list::list_back.body = [](const list_t* l) {
162     log::assert_that(l != nullptr, "assert failed: l != nullptr");
163     log::assert_that(l->tail_, "assert failed: l->tail_");
164     return l->tail_->data_;
165   };
166   test::mock::osi_list::list_back_node.body = [](const list_t* l) {
167     log::assert_that(l != nullptr, "assert failed: l != nullptr");
168     return l->tail_;
169   };
170 
171   test::mock::osi_list::list_insert_after.body =
172       [](list_t* l, list_node_t* prev_node, void* data) {
173         log::assert_that(l != nullptr, "assert failed: l != nullptr");
174         log::assert_that(prev_node != nullptr,
175                          "assert failed: prev_node != nullptr");
176         log::assert_that(data != nullptr, "assert failed: data != nullptr");
177         auto node = new list_node_t(data, prev_node->next_);
178         prev_node->next_ = node;
179         if (l->tail_ == prev_node) l->tail_ = node;
180         ++l->length_;
181         return true;
182       };
183   test::mock::osi_list::list_prepend.body = [](list_t* l, void* data) {
184     log::assert_that(l != nullptr, "assert failed: l != nullptr");
185     log::assert_that(data != nullptr, "assert failed: data != nullptr");
186 
187     auto node = new list_node_t(data, l->head_);
188     l->head_ = node;
189     if (l->tail_ == NULL) l->tail_ = l->head_;
190     ++l->length_;
191     return true;
192   };
193   test::mock::osi_list::list_append.body = [](list_t* l, void* data) {
194     log::assert_that(l != nullptr, "assert failed: l != nullptr");
195     log::assert_that(data != nullptr, "assert failed: data != nullptr");
196 
197     auto node = new list_node_t(data, nullptr);
198     if (l->tail_) {
199       l->tail_->next_ = node;
200       l->tail_ = node;
201     } else {
202       l->head_ = l->tail_ = node;
203     }
204     ++l->length_;
205     return true;
206   };
207   test::mock::osi_list::list_remove.body = [](list_t* l, void* data) {
208     log::assert_that(l != nullptr, "assert failed: l != nullptr");
209     log::assert_that(data != nullptr, "assert failed: data != nullptr");
210 
211     if (test::mock::osi_list::list_is_empty(l)) return false;
212 
213     if (l->head_->data_ == data) {
214       auto next = list_free_node_(l, l->head_);
215       if (l->tail_ == l->head_) l->tail_ = next;
216       l->head_ = next;
217       return true;
218     }
219 
220     for (auto prev = l->head_, node = l->head_->next_; node;
221          prev = node, node = node->next_)
222       if (node->data_ == data) {
223         prev->next_ = list_free_node_(l, node);
224         if (l->tail_ == node) l->tail_ = prev;
225         return true;
226       }
227 
228     return false;
229   };
230   test::mock::osi_list::list_clear.body = [](list_t* l) {
231     log::assert_that(l != nullptr, "assert failed: l != nullptr");
232     for (auto node = l->head_; node;) {
233       node = list_free_node_(l, node);
234     }
235     l->head_ = NULL;
236     l->tail_ = NULL;
237     l->length_ = 0;
238     return;
239   };
240 
241   test::mock::osi_list::list_begin.body = [](const list_t* l) {
242     log::assert_that(l != nullptr, "assert failed: l != nullptr");
243     return l->head_;
244   };
245   test::mock::osi_list::list_end.body = [](const list_t* l) {
246     log::assert_that(l != nullptr, "assert failed: l != nullptr");
247     return l->tail_;
248   };
249   test::mock::osi_list::list_next.body = [](const list_node_t* node) {
250     log::assert_that(node != nullptr, "assert failed: node != nullptr");
251     return node->next_;
252   };
253   test::mock::osi_list::list_node.body = [](const list_node_t* node) {
254     log::assert_that(node != nullptr, "assert failed: node != nullptr");
255     return node->data_;
256   };
257 
258   test::mock::osi_fixed_queue::fixed_queue_new.body = [](size_t capacity) {
259     return new fixed_queue_t(capacity);
260   };
261   test::mock::osi_fixed_queue::fixed_queue_flush.body =
262       [](fixed_queue_t* q, fixed_queue_free_cb cb) {
263         if (q) {
264           if (cb) {
265             test::mock::osi_list::list_foreach(
266                 q->list_,
267                 [](void* data, void* cb) {
268                   reinterpret_cast<fixed_queue_free_cb>(cb)(data);
269                   return true;
270                 },
271                 reinterpret_cast<void*>(cb));
272           }
273           test::mock::osi_list::list_clear(q->list_);
274         }
275       };
276   test::mock::osi_fixed_queue::fixed_queue_free.body =
277       [](fixed_queue_t* q, fixed_queue_free_cb free_cb) {
278         if (q) {
279           test::mock::osi_fixed_queue::fixed_queue_flush(q, free_cb);
280           delete q->list_;
281           delete q;
282         }
283       };
284   test::mock::osi_fixed_queue::fixed_queue_enqueue.body = [](fixed_queue_t* q,
285                                                              void* data) {
286     if (q) test::mock::osi_list::list_append(q->list_, data);
287   };
288   test::mock::osi_fixed_queue::fixed_queue_dequeue.body = [](fixed_queue_t* q) {
289     void* ret = nullptr;
290     if (q) {
291       ret = test::mock::osi_list::list_front(q->list_);
292       test::mock::osi_list::list_remove(q->list_, ret);
293     }
294     return ret;
295   };
296 
297   test::mock::osi_fixed_queue::fixed_queue_length.body = [](fixed_queue_t* q) {
298     return q ? test::mock::osi_list::list_length(q->list_) : 0;
299   };
300 
301   test::mock::osi_fixed_queue::fixed_queue_is_empty.body =
302       [](fixed_queue_t* q) {
303         return test::mock::osi_fixed_queue::fixed_queue_length(q) == 0;
304       };
305 
306   test::mock::osi_fixed_queue::fixed_queue_capacity.body =
307       [](fixed_queue_t* q) { return q ? q->capacity_ : 0; };
308 
309   test::mock::osi_fixed_queue::fixed_queue_try_enqueue.body =
310       [](fixed_queue_t* q, void* data) {
311         test::mock::osi_fixed_queue::fixed_queue_enqueue(q, data);
312         return true;
313       };
314   test::mock::osi_fixed_queue::fixed_queue_try_dequeue.body =
315       [](fixed_queue_t* q) {
316         void* ret = nullptr;
317         if (q && !test::mock::osi_fixed_queue::fixed_queue_is_empty(q)) {
318           ret = test::mock::osi_fixed_queue::fixed_queue_dequeue(q);
319         }
320         return ret;
321       };
322   test::mock::osi_fixed_queue::fixed_queue_try_peek_first.body =
323       [](fixed_queue_t* q) {
324         return (q && !test::mock::osi_list::list_is_empty(q->list_))
325                    ? test::mock::osi_list::list_front(q->list_)
326                    : nullptr;
327       };
328 
329   test::mock::osi_fixed_queue::fixed_queue_try_peek_last.body =
330       [](fixed_queue_t* q) {
331         return (q && !test::mock::osi_list::list_is_empty(q->list_))
332                    ? test::mock::osi_list::list_back(q->list_)
333                    : nullptr;
334       };
335 
336   test::mock::osi_fixed_queue::fixed_queue_get_list.body =
337       [](fixed_queue_t* q) { return q ? q->list_ : nullptr; };
338 
339   test::mock::osi_fixed_queue::fixed_queue_try_remove_from_queue.body =
340       [](fixed_queue_t* /* q */, void* /* data */) {
341         // not implemented
342         abort();
343         return nullptr;
344       };
345 
346   test::mock::osi_fixed_queue::fixed_queue_get_enqueue_fd.body =
347       [](const fixed_queue_t* /* q */) {
348         // not implemented
349         abort();
350         return 0;
351       };
352 
353   test::mock::osi_fixed_queue::fixed_queue_get_dequeue_fd.body =
354       [](const fixed_queue_t* /* q */) {
355         // not implemented
356         abort();
357         return 0;
358       };
359 
360   test::mock::osi_fixed_queue::fixed_queue_register_dequeue.body =
361       [](fixed_queue_t* /* q */, reactor_t* /* reactor */,
362          fixed_queue_cb /* ready_cb */, void* /* context */) {
363         // not implemented
364         abort();
365       };
366   test::mock::osi_fixed_queue::fixed_queue_unregister_dequeue.body =
367       [](fixed_queue_t* /* q */) {
368         // not implemented
369         abort();
370       };
371 }
372 
~FakeOsi()373 FakeOsi::~FakeOsi() {
374   test::mock::osi_alarm::alarm_free = {};
375   test::mock::osi_alarm::alarm_new = {};
376 
377   test::mock::osi_allocator::osi_calloc = {};
378   test::mock::osi_allocator::osi_free = {};
379   test::mock::osi_allocator::osi_free_and_reset = {};
380   test::mock::osi_allocator::osi_malloc = {};
381 
382   test::mock::osi_list::list_new = {};
383   test::mock::osi_list::list_free = {};
384   test::mock::osi_list::list_is_empty = {};
385   test::mock::osi_list::list_foreach = {};
386   test::mock::osi_list::list_contains = {};
387   test::mock::osi_list::list_length = {};
388   test::mock::osi_list::list_front = {};
389   test::mock::osi_list::list_back = {};
390   test::mock::osi_list::list_back_node = {};
391   test::mock::osi_list::list_insert_after = {};
392   test::mock::osi_list::list_prepend = {};
393   test::mock::osi_list::list_append = {};
394   test::mock::osi_list::list_remove = {};
395   test::mock::osi_list::list_clear = {};
396   test::mock::osi_list::list_begin = {};
397   test::mock::osi_list::list_end = {};
398   test::mock::osi_list::list_next = {};
399   test::mock::osi_list::list_node = {};
400 
401   test::mock::osi_fixed_queue::fixed_queue_new = {};
402   test::mock::osi_fixed_queue::fixed_queue_flush = {};
403   test::mock::osi_fixed_queue::fixed_queue_free = {};
404   test::mock::osi_fixed_queue::fixed_queue_enqueue = {};
405   test::mock::osi_fixed_queue::fixed_queue_dequeue = {};
406   test::mock::osi_fixed_queue::fixed_queue_length = {};
407   test::mock::osi_fixed_queue::fixed_queue_is_empty = {};
408   test::mock::osi_fixed_queue::fixed_queue_capacity = {};
409   test::mock::osi_fixed_queue::fixed_queue_try_enqueue = {};
410   test::mock::osi_fixed_queue::fixed_queue_try_dequeue = {};
411   test::mock::osi_fixed_queue::fixed_queue_try_peek_first = {};
412   test::mock::osi_fixed_queue::fixed_queue_try_peek_last = {};
413   test::mock::osi_fixed_queue::fixed_queue_try_remove_from_queue = {};
414   test::mock::osi_fixed_queue::fixed_queue_get_list = {};
415   test::mock::osi_fixed_queue::fixed_queue_get_enqueue_fd = {};
416   test::mock::osi_fixed_queue::fixed_queue_get_dequeue_fd = {};
417   test::mock::osi_fixed_queue::fixed_queue_register_dequeue = {};
418   test::mock::osi_fixed_queue::fixed_queue_unregister_dequeue = {};
419 }
420 
421 }  // namespace fake
422 }  // namespace test
423