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