1 /*
2 * Copyright 2018 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
17 #pragma once
18
19 #include <list>
20 #include <memory>
21
22 #include "avrcp_common.h"
23 #include "packet.h"
24 namespace bluetooth {
25
26 // A helper templated class to access the protected members of Packet to make
27 // testing easier
28 template <class PacketType>
29 class TestPacketType : public PacketType {
30 public:
31 using PacketType::PacketType;
32
Make()33 static std::shared_ptr<TestPacketType<PacketType>> Make() {
34 return std::shared_ptr<TestPacketType<PacketType>>(
35 new TestPacketType<PacketType>());
36 }
37
Make(std::shared_ptr<Packet> packet)38 static std::shared_ptr<TestPacketType<PacketType>> Make(
39 std::shared_ptr<Packet> packet) {
40 return std::shared_ptr<TestPacketType<PacketType>>(
41 new TestPacketType<PacketType>(packet));
42 }
43
Make(std::vector<uint8_t> payload)44 static std::shared_ptr<TestPacketType<PacketType>> Make(
45 std::vector<uint8_t> payload) {
46 size_t end = payload.size();
47 return Make(std::move(payload), 0, end);
48 }
49
Make(std::vector<uint8_t> payload,size_t start,size_t end)50 static std::shared_ptr<TestPacketType<PacketType>> Make(
51 std::vector<uint8_t> payload, size_t start, size_t end) {
52 auto pkt = std::shared_ptr<TestPacketType<PacketType>>(
53 new TestPacketType<PacketType>());
54 pkt->packet_start_index_ = start;
55 pkt->packet_end_index_ = end;
56 pkt->data_ = std::make_shared<std::vector<uint8_t>>(std::move(payload));
57 return pkt;
58 }
59
GetData()60 const std::vector<uint8_t>& GetData() { return *PacketType::data_; }
61
GetDataPointer()62 std::shared_ptr<std::vector<uint8_t>> GetDataPointer() {
63 return PacketType::data_;
64 }
65 };
66
67 namespace avrcp {
68
to_string(const Attribute & a)69 inline std::string to_string(const Attribute& a) {
70 switch (a) {
71 case Attribute::TITLE:
72 return "TITLE";
73 case Attribute::ARTIST_NAME:
74 return "ARTIST_NAME";
75 case Attribute::ALBUM_NAME:
76 return "ALBUM_NAME";
77 case Attribute::TRACK_NUMBER:
78 return "TRACK_NUMBER";
79 case Attribute::TOTAL_NUMBER_OF_TRACKS:
80 return "TOTAL_NUMBER_OF_TRACKS";
81 case Attribute::GENRE:
82 return "GENRE";
83 case Attribute::PLAYING_TIME:
84 return "PLAYING_TIME";
85 case Attribute::DEFAULT_COVER_ART:
86 return "DEFAULT_COVER_ART";
87 default:
88 return "UNKNOWN ATTRIBUTE";
89 };
90 }
91
to_string(const AttributeEntry & entry)92 inline std::string to_string(const AttributeEntry& entry) {
93 std::stringstream ss;
94 ss << to_string(entry.attribute()) << ": " << entry.value();
95 return ss.str();
96 }
97
98 template <class Container>
to_string(const Container & entries)99 std::string to_string(const Container& entries) {
100 std::stringstream ss;
101 for (const auto& el : entries) {
102 ss << to_string(el) << std::endl;
103 }
104 return ss.str();
105 }
106
107 inline bool operator==(const AttributeEntry& a, const AttributeEntry& b) {
108 return (a.attribute() == b.attribute()) && (a.value() == b.value());
109 }
110
111 inline bool operator!=(const AttributeEntry& a, const AttributeEntry& b) {
112 return !(a == b);
113 }
114
115 template <class AttributesResponseBuilder>
116 class AttributesResponseBuilderTestUser {
117 public:
118 using Builder = AttributesResponseBuilder;
119 using Maker = std::function<typename Builder::Builder(size_t)>;
120
121 private:
122 Maker maker;
123 typename Builder::Builder _builder;
124 size_t _mtu;
125 size_t _current_size = 0;
126 size_t _entry_counter = 0;
127 std::set<AttributeEntry> _control_set;
128 std::list<AttributeEntry> _order_control;
129 std::list<AttributeEntry> _sended_order;
130 std::stringstream _report;
131 bool _test_result = true;
132 bool _order_test_result = true;
133
reset()134 void reset() {
135 for (const auto& en : _builder->entries_) {
136 _sended_order.push_back(en);
137 }
138 _current_size = 0, _entry_counter = 0;
139 _control_set.clear();
140 _builder->clear();
141 }
142
expected_size()143 size_t expected_size() { return Builder::kHeaderSize() + _current_size; }
144
145 public:
getReport()146 std::string getReport() const { return _report.str(); }
147
AttributesResponseBuilderTestUser(size_t m_size,Maker maker)148 AttributesResponseBuilderTestUser(size_t m_size, Maker maker)
149 : maker(maker), _builder(maker(m_size)), _mtu(m_size) {
150 _report << __func__ << ": mtu \"" << _mtu << "\"\n";
151 }
152
startTest(size_t m_size)153 void startTest(size_t m_size) {
154 _builder = maker(m_size);
155 _mtu = m_size;
156 reset();
157 _report.str("");
158 _report.clear();
159 _order_control.clear();
160 _sended_order.clear();
161 _report << __func__ << ": mtu \"" << _mtu << "\"\n";
162 _order_test_result = true;
163 _test_result = true;
164 }
165
testResult()166 bool testResult() const { return _test_result; }
167
testOrder()168 bool testOrder() { return _order_test_result; }
169
finishTest()170 void finishTest() {
171 reset();
172 if (_order_control.size() != _sended_order.size()) {
173 _report << __func__ << ": testOrder FAIL: "
174 << "the count of entries which should send ("
175 << _order_control.size() << ") is not equal to sended entries("
176 << _sended_order.size() << ")) \n input:\n "
177 << to_string(_order_control) << "\n sended:\n"
178 << to_string(_sended_order) << "\n";
179 _order_test_result = false;
180 return;
181 }
182 auto e = _order_control.begin();
183 auto s = _sended_order.begin();
184 for (; e != _order_control.end(); ++e, ++s) {
185 if (*e != *s) {
186 _report << __func__ << "testOrder FAIL: order of entries was changed\n";
187 _order_test_result = false;
188 break;
189 }
190 }
191 _report << __func__ << ": mtu \"" << _mtu << "\"\n";
192 }
193
AddAttributeEntry(AttributeEntry entry)194 void AddAttributeEntry(AttributeEntry entry) {
195 auto f = _builder->AddAttributeEntry(entry);
196 if (f != 0) {
197 _current_size += f;
198 ++_entry_counter;
199 }
200 if (f == entry.size()) {
201 wholeEntry(f, std::move(entry));
202 } else {
203 fractionEntry(f, std::move(entry));
204 }
205 }
206
207 private:
wholeEntry(size_t f,AttributeEntry && entry)208 void wholeEntry(size_t f, AttributeEntry&& entry) {
209 _control_set.insert(entry);
210 _order_control.push_back(entry);
211 if (_builder->size() != expected_size()) {
212 _report << __func__ << "FAIL for \"" << to_string(entry)
213 << "\": not allowed to add.\n";
214 _test_result = false;
215 }
216 }
217
fractionEntry(size_t f,AttributeEntry && entry)218 void fractionEntry(size_t f, AttributeEntry&& entry) {
219 auto l_value = entry.value().size() - (entry.size() - f);
220 if (f != 0) {
221 auto pushed_entry = AttributeEntry(
222 entry.attribute(), std::string(entry.value(), 0, l_value));
223 _control_set.insert(pushed_entry);
224 _order_control.push_back(pushed_entry);
225 }
226
227 if (expected_size() != _builder->size()) {
228 _test_result = false;
229 _report << __func__ << "FAIL for \"" << to_string(entry)
230 << "\": not allowed to add.\n";
231 }
232
233 if (_builder->size() != expected_size() ||
234 _builder->entries_.size() != _entry_counter) {
235 _report << __func__ << "FAIL for \"" << to_string(entry)
236 << "\": unexpected size of packet\n";
237 _test_result = false;
238 }
239 for (auto dat = _builder->entries_.begin(), ex = _control_set.begin();
240 ex != _control_set.end(); ++dat, ++ex) {
241 if (*dat != *ex) {
242 _report << __func__ << "FAIL for \"" << to_string(entry)
243 << "\": unexpected entry order\n";
244 _test_result = false;
245 }
246 }
247 auto tail = (f == 0) ? entry
248 : AttributeEntry(entry.attribute(),
249 std::string(entry.value(), l_value));
250 if (_builder->entries_.size() != 0) {
251 reset();
252 AddAttributeEntry(tail);
253 }
254 if (_builder->entries_.size() == 0) {
255 _report << __func__ << "FAIL: MTU " << _mtu << " too small\n";
256 _test_result = false;
257 _order_control.push_back(entry);
258 reset();
259 }
260 }
261 };
262
263 template <class AttributesBuilder>
264 class FragmentationBuilderHelper {
265 public:
266 using Builder = AttributesBuilder;
267 using Helper = AttributesResponseBuilderTestUser<Builder>;
268 using Maker = typename Helper::Maker;
269
FragmentationBuilderHelper(size_t mtu,Maker m)270 FragmentationBuilderHelper(size_t mtu, Maker m) : _helper(mtu, m) {}
271
272 template <class TestCollection>
273 void runTest(const TestCollection& test_data, size_t mtu,
274 bool expect_fragmentation = true, bool expect_ordering = true) {
275 _helper.startTest(mtu);
276
277 for (auto& i : test_data) {
278 _helper.AddAttributeEntry(i);
279 }
280 _helper.finishTest();
281
282 EXPECT_EQ(expect_fragmentation, _helper.testResult())
283 << "Report: " << _helper.getReport();
284 EXPECT_EQ(expect_ordering, _helper.testOrder())
285 << "Report: " << _helper.getReport();
286 }
287
288 private:
289 Helper _helper;
290 };
291 } // namespace avrcp
292 } // namespace bluetooth
293