1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #pragma once
16 #include <cpp-string/string_printf.h>
17 
18 #include <algorithm>
19 #include <array>
20 #include <iostream>
21 #include <type_traits>
22 
23 #include "gmock/gmock.h"
24 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
25 
26 // Run |statement| and return if a fatal test error occurred. Include the file
27 // name and line number in the output.
28 //
29 // This is useful for running test helpers in subroutines. For example, if a
30 // test helper posted ASSERTs checks inside of a dispatcher task:
31 //
32 //   RETURN_IF_FATAL(RunLoopUntilIdle());
33 //
34 // would return if any of the tasks had an ASSERT failure.
35 //
36 // Fatal failures in Google Test such as ASSERT_* failures and calls to FAIL()
37 // set a global flag for the failure (see testing::Test::HasFatalFailure) and
38 // return from the function where they occur. However, the change in flow
39 // control is limited to that subroutine scope. Test code higher up the stack
40 // must propagate the failure in order to exit the test.
41 //
42 // Note in the above example, if a task in the test loop has a fatal failure, it
43 // does not prevent the remaining due tasks in the loop from running. The test
44 // case would not exit until RunLoopFromIdle returns.
45 #define RETURN_IF_FATAL(statement)      \
46   do {                                  \
47     SCOPED_TRACE("");                   \
48     ASSERT_NO_FATAL_FAILURE(statement); \
49   } while (false)
50 
51 namespace bt {
52 
53 template <class InputIt>
ByteContainerToString(InputIt begin,InputIt end)54 std::string ByteContainerToString(InputIt begin, InputIt end) {
55   std::string bytes_string;
56   for (InputIt iter = begin; iter != end; ++iter) {
57     bytes_string += bt_lib_cpp_string::StringPrintf("0x%.2x ", *iter);
58   }
59   return bytes_string;
60 }
61 
62 template <class Container>
ByteContainerToString(const Container & c)63 std::string ByteContainerToString(const Container& c) {
64   return ByteContainerToString(c.begin(), c.end());
65 }
66 
67 template <class InputIt>
PrintByteContainer(InputIt begin,InputIt end)68 void PrintByteContainer(InputIt begin, InputIt end) {
69   std::cout << ByteContainerToString(begin, end);
70 }
71 
72 // Prints the contents of a container as a string.
73 template <class Container>
PrintByteContainer(const Container & c)74 void PrintByteContainer(const Container& c) {
75   PrintByteContainer(c.begin(), c.end());
76 }
77 
78 // Function-template for comparing contents of two iterable byte containers for
79 // equality. If the contents are not equal, this logs a GTEST-style error
80 // message to stdout. Meant to be used from unit tests.
81 template <class InputIt1, class InputIt2>
ContainersEqual(InputIt1 expected_begin,InputIt1 expected_end,InputIt2 actual_begin,InputIt2 actual_end)82 bool ContainersEqual(InputIt1 expected_begin,
83                      InputIt1 expected_end,
84                      InputIt2 actual_begin,
85                      InputIt2 actual_end) {
86   if (std::equal(expected_begin, expected_end, actual_begin, actual_end))
87     return true;
88   std::cout << "Expected: (" << (expected_end - expected_begin) << " bytes) { ";
89   PrintByteContainer(expected_begin, expected_end);
90   std::cout << "}\n   Found: (" << (actual_end - actual_begin) << " bytes) { ";
91   PrintByteContainer(actual_begin, actual_end);
92   std::cout << "}" << std::endl;
93   return false;
94 }
95 
96 template <class Container1, class Container2>
ContainersEqual(const Container1 & expected,const Container2 & actual)97 bool ContainersEqual(const Container1& expected, const Container2& actual) {
98   return ContainersEqual(
99       expected.begin(), expected.end(), actual.begin(), actual.end());
100 }
101 
102 template <class Container1>
ContainersEqual(const Container1 & expected,const uint8_t * actual_bytes,size_t actual_num_bytes)103 bool ContainersEqual(const Container1& expected,
104                      const uint8_t* actual_bytes,
105                      size_t actual_num_bytes) {
106   return ContainersEqual(expected.begin(),
107                          expected.end(),
108                          actual_bytes,
109                          actual_bytes + actual_num_bytes);
110 }
111 
112 // Returns a managed pointer to a heap allocated MutableByteBuffer.
113 template <typename... T>
NewBuffer(T...bytes)114 MutableByteBufferPtr NewBuffer(T... bytes) {
115   return std::make_unique<StaticByteBuffer<sizeof...(T)>>(
116       std::forward<T>(bytes)...);
117 }
118 
119 // Returns the value of |x| as a little-endian array, i.e. the first byte of the
120 // array has the value of the least significant byte of |x|.
121 template <typename T>
ToBytes(T x)122 constexpr std::array<uint8_t, sizeof(T)> ToBytes(T x) {
123   static_assert(std::is_integral_v<T>,
124                 "Must use integral types for safe bytewise access");
125   std::array<uint8_t, sizeof(T)> bytes;
126   for (auto& byte : bytes) {
127     byte = static_cast<uint8_t>(x);
128     x >>= 8;
129   }
130   return bytes;
131 }
132 
133 // Returns the Upper/Lower bits of a uint16_t
UpperBits(const uint16_t x)134 constexpr uint8_t UpperBits(const uint16_t x) { return ToBytes(x).back(); }
LowerBits(const uint16_t x)135 constexpr uint8_t LowerBits(const uint16_t x) { return ToBytes(x).front(); }
136 
137 // Wraps ContainerEq, which doesn't support comparing different ByteBuffer types
138 MATCHER_P(BufferEq, b, "") {
139   return ::testing::ExplainMatchResult(
140       ::testing::ContainerEq(bt::BufferView(b)),
141       bt::BufferView(arg),
142       result_listener);
143 }
144 
145 }  // namespace bt
146