transfer_buffer.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
3  */
4 
5 #if __GNUC__
6 # pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
7 #endif
8 
9 #include <algorithm>
10 #include <gtest/gtest.h>
11 #include <memory>
13 
14 static const std::string TEST_DATA =
15  "It was like this: I asked myself one day this question - what if Napoleon, for instance, had happened to be in my "
16  "place, and if he had not had Toulon nor Egypt nor the passage of Mont Blanc to begin his career with, but "
17  "instead of all those picturesque and monumental things, there had simply been some ridiculous old hag, a "
18  "pawnbroker, who had to be murdered too to get money from her trunk (for his career, you understand). "
19  "Well, would he have brought himself to that if there had been no other means?";
20 
21 template <typename T, unsigned Size>
22 static bool allEqual(const T (&a)[Size])
23 {
24  unsigned n = Size;
25  while ((--n > 0) && (a[n] == a[0])) { }
26  return n == 0;
27 }
28 
29 template <typename T, unsigned Size, typename R>
30 static void fill(T (&a)[Size], R value)
31 {
32  for (unsigned i = 0; i < Size; i++)
33  {
34  a[i] = T(value);
35  }
36 }
37 
38 static bool matchAgainst(const std::string& data, const uavcan::ITransferBuffer& tbb,
39  unsigned offset = 0, int len = -1)
40 {
41  uint8_t local_buffer[1024];
42  fill(local_buffer, 0);
43  assert((len < 0) || (sizeof(local_buffer) >= static_cast<unsigned>(len)));
44 
45  if (len < 0)
46  {
47  const int res = tbb.read(offset, local_buffer, sizeof(local_buffer));
48  if (res < 0)
49  {
50  std::cout << "matchAgainst(): res " << res << std::endl;
51  return false;
52  }
53  len = res;
54  }
55  else
56  {
57  const int res = tbb.read(offset, local_buffer, unsigned(len));
58  if (res != len)
59  {
60  std::cout << "matchAgainst(): res " << res << " expected " << len << std::endl;
61  return false;
62  }
63  }
64  const bool equals = std::equal(local_buffer, local_buffer + len, data.begin() + offset);
65  if (!equals)
66  {
67  std::cout << "local_buffer:\n\t" << local_buffer << std::endl;
68  std::cout << "test_data:\n\t" << std::string(data.begin() + offset, data.begin() + offset + len) << std::endl;
69  }
70  return equals;
71 }
72 
73 static bool matchAgainstTestData(const uavcan::ITransferBuffer& tbb, unsigned offset, int len = -1)
74 {
75  return matchAgainst(TEST_DATA, tbb, offset, len);
76 }
77 
78 TEST(TransferBuffer, TestDataValidation)
79 {
80  ASSERT_LE(4, TEST_DATA.length() / uavcan::MemPoolBlockSize);
81  uint8_t local_buffer[50];
82  std::copy(TEST_DATA.begin(), TEST_DATA.begin() + sizeof(local_buffer), local_buffer);
83  ASSERT_FALSE(allEqual(local_buffer));
84 }
85 
86 static const int TEST_BUFFER_SIZE = 200;
87 
88 TEST(StaticTransferBuffer, Basic)
89 {
91  StaticTransferBuffer<TEST_BUFFER_SIZE> buf;
92 
93  uint8_t local_buffer[TEST_BUFFER_SIZE * 2];
94  const uint8_t* const test_data_ptr = reinterpret_cast<const uint8_t*>(TEST_DATA.c_str());
95 
96  // Empty reads
97  fill(local_buffer, 0xA5);
98  ASSERT_EQ(0, buf.read(0, local_buffer, 999));
99  ASSERT_EQ(0, buf.read(0, local_buffer, 0));
100  ASSERT_EQ(0, buf.read(999, local_buffer, 0));
101  ASSERT_TRUE(allEqual(local_buffer));
102 
103  // Bulk write
104  ASSERT_EQ(TEST_BUFFER_SIZE, buf.write(0, test_data_ptr, unsigned(TEST_DATA.length())));
105  ASSERT_TRUE(matchAgainstTestData(buf, 0));
106  ASSERT_TRUE(matchAgainstTestData(buf, TEST_BUFFER_SIZE));
107  ASSERT_TRUE(matchAgainstTestData(buf, TEST_BUFFER_SIZE / 2));
108  ASSERT_TRUE(matchAgainstTestData(buf, TEST_BUFFER_SIZE / 2, TEST_BUFFER_SIZE / 4));
109  ASSERT_TRUE(matchAgainstTestData(buf, TEST_BUFFER_SIZE / 4, TEST_BUFFER_SIZE / 2));
110  ASSERT_TRUE(matchAgainstTestData(buf, 0, TEST_BUFFER_SIZE / 4));
111 
112  // Reset
113  fill(local_buffer, 0xA5);
114  buf.reset();
115  ASSERT_EQ(0, buf.read(0, local_buffer, 0));
116  ASSERT_EQ(0, buf.read(0, local_buffer, 999));
117  ASSERT_TRUE(allEqual(local_buffer));
118 
119  // Random write
120  ASSERT_EQ(21, buf.write(12, test_data_ptr + 12, 21));
121  ASSERT_TRUE(matchAgainstTestData(buf, 12, 21));
122 
123  ASSERT_EQ(12, buf.write(0, test_data_ptr, 12));
124  ASSERT_TRUE(matchAgainstTestData(buf, 0));
125 
126  ASSERT_EQ(0, buf.write(21, test_data_ptr + 21, 0));
127  ASSERT_EQ(TEST_BUFFER_SIZE - 21, buf.write(21, test_data_ptr + 21, 999));
128  ASSERT_TRUE(matchAgainstTestData(buf, 21, TEST_BUFFER_SIZE - 21));
129  ASSERT_TRUE(matchAgainstTestData(buf, 0));
130 }
131 
132 
133 TEST(TransferBufferManagerEntry, Basic)
134 {
136 
137  static const int MAX_SIZE = TEST_BUFFER_SIZE;
138  static const int POOL_BLOCKS = 8;
140 
141  TransferBufferManagerEntry buf(pool, MAX_SIZE);
142 
143  uint8_t local_buffer[TEST_BUFFER_SIZE * 2];
144  const uint8_t* const test_data_ptr = reinterpret_cast<const uint8_t*>(TEST_DATA.c_str());
145 
146  // Empty reads
147  fill(local_buffer, 0xA5);
148  ASSERT_EQ(0, buf.read(0, local_buffer, 999));
149  ASSERT_EQ(0, buf.read(0, local_buffer, 0));
150  ASSERT_EQ(0, buf.read(999, local_buffer, 0));
151  ASSERT_TRUE(allEqual(local_buffer));
152 
153  // Bulk write
154  ASSERT_EQ(MAX_SIZE, buf.write(0, test_data_ptr, unsigned(TEST_DATA.length())));
155 
156  ASSERT_LT(0, pool.getNumUsedBlocks()); // Making sure some memory was used
157 
158  ASSERT_TRUE(matchAgainstTestData(buf, 0));
159  ASSERT_TRUE(matchAgainstTestData(buf, TEST_BUFFER_SIZE));
160  ASSERT_TRUE(matchAgainstTestData(buf, TEST_BUFFER_SIZE / 2));
161  ASSERT_TRUE(matchAgainstTestData(buf, TEST_BUFFER_SIZE / 2, TEST_BUFFER_SIZE / 4));
162  ASSERT_TRUE(matchAgainstTestData(buf, TEST_BUFFER_SIZE / 4, TEST_BUFFER_SIZE / 2));
163  ASSERT_TRUE(matchAgainstTestData(buf, 0, TEST_BUFFER_SIZE / 4));
164 
165  // Reset
166  fill(local_buffer, 0xA5);
167  buf.reset();
168  ASSERT_EQ(0, buf.read(0, local_buffer, 0));
169  ASSERT_EQ(0, buf.read(0, local_buffer, 999));
170  ASSERT_TRUE(allEqual(local_buffer));
171  ASSERT_EQ(0, pool.getNumUsedBlocks());
172 
173  // Random write
174  ASSERT_EQ(21, buf.write(12, test_data_ptr + 12, 21));
175  ASSERT_TRUE(matchAgainstTestData(buf, 12, 21));
176 
177  ASSERT_EQ(60, buf.write(TEST_BUFFER_SIZE - 60, test_data_ptr + TEST_BUFFER_SIZE - 60, 60));
178  ASSERT_TRUE(matchAgainstTestData(buf, TEST_BUFFER_SIZE - 60));
179 
180  // Now we have two empty regions: empty-data-empty-data
181 
182  ASSERT_EQ(0, buf.write(0, test_data_ptr, 0));
183  ASSERT_EQ(TEST_BUFFER_SIZE - 21, buf.write(21, test_data_ptr + 21, TEST_BUFFER_SIZE - 21));
184  ASSERT_TRUE(matchAgainstTestData(buf, 21, TEST_BUFFER_SIZE - 21));
185 
186  // Now: empty-data-data-data
187 
188  ASSERT_EQ(21, buf.write(0, test_data_ptr, 21));
189  ASSERT_TRUE(matchAgainstTestData(buf, 0));
190 
191  // Destroying the object; memory should be released
192  ASSERT_LT(0, pool.getNumUsedBlocks());
193  buf.~TransferBufferManagerEntry();
194  ASSERT_EQ(0, pool.getNumUsedBlocks());
195 }
196 
197 
198 static const std::string MGR_TEST_DATA[4] =
199 {
200  "I thought you would cry out again \'don\'t speak of it, leave off.\'\" Raskolnikov gave a laugh, but rather a "
201  "forced one. \"What, silence again?\" he asked a minute later. \"We must talk about something, you know. ",
202 
203  "It would be interesting for me to know how you would decide a certain \'problem\' as Lebeziatnikov would say.\" "
204  "(He was beginning to lose the thread.) \"No, really, I am serious. Imagine, Sonia, that you had known all ",
205 
206  "Luzhin\'s intentions beforehand. Known, that is, for a fact, that they would be the ruin of Katerina Ivanovna "
207  "and the children and yourself thrown in--since you don\'t count yourself for anything--Polenka too... for ",
208 
209  "she\'ll go the same way. Well, if suddenly it all depended on your decision whether he or they should go on "
210  "living, that is whether Luzhin should go on living and doing wicked things, or Katerina Ivanovna should die? "
211  "How would you decide which of them was to die? I ask you?"
212 };
213 
214 static const int MGR_MAX_BUFFER_SIZE = 100;
215 
216 TEST(TransferBufferManager, TestDataValidation)
217 {
218  for (unsigned i = 0; i < sizeof(MGR_TEST_DATA) / sizeof(MGR_TEST_DATA[0]); i++)
219  {
220  ASSERT_LT(MGR_MAX_BUFFER_SIZE, MGR_TEST_DATA[i].length());
221  }
222 }
223 
224 
225 static int fillTestData(const std::string& data, uavcan::ITransferBuffer* tbb)
226 {
227  return tbb->write(0, reinterpret_cast<const uint8_t*>(data.c_str()), unsigned(data.length()));
228 }
229 
230 TEST(TransferBufferManager, Basic)
231 {
235 
236  static const int POOL_BLOCKS = 100;
238 
239  std::unique_ptr<TransferBufferManager> mgr(new TransferBufferManager(MGR_MAX_BUFFER_SIZE, pool));
240 
241  // Empty
242  ASSERT_FALSE(mgr->access(TransferBufferManagerKey(0, uavcan::TransferTypeMessageBroadcast)));
243  ASSERT_FALSE(mgr->access(TransferBufferManagerKey(127, uavcan::TransferTypeServiceRequest)));
244 
245  ITransferBuffer* tbb = UAVCAN_NULLPTR;
246 
247  const TransferBufferManagerKey keys[5] =
248  {
249  TransferBufferManagerKey(0, uavcan::TransferTypeServiceRequest),
250  TransferBufferManagerKey(1, uavcan::TransferTypeMessageBroadcast),
251  TransferBufferManagerKey(2, uavcan::TransferTypeServiceRequest),
252  TransferBufferManagerKey(127, uavcan::TransferTypeServiceResponse),
253  TransferBufferManagerKey(64, uavcan::TransferTypeMessageBroadcast)
254  };
255 
256  ASSERT_TRUE((tbb = mgr->create(keys[0])));
257  ASSERT_EQ(MGR_MAX_BUFFER_SIZE, fillTestData(MGR_TEST_DATA[0], tbb));
258  ASSERT_EQ(1, mgr->getNumBuffers());
259 
260  ASSERT_TRUE((tbb = mgr->create(keys[1])));
261  ASSERT_EQ(MGR_MAX_BUFFER_SIZE, fillTestData(MGR_TEST_DATA[1], tbb));
262  ASSERT_EQ(2, mgr->getNumBuffers());
263  ASSERT_LT(2, pool.getNumUsedBlocks());
264 
265  ASSERT_TRUE((tbb = mgr->create(keys[2])));
266  ASSERT_EQ(MGR_MAX_BUFFER_SIZE, fillTestData(MGR_TEST_DATA[2], tbb));
267  ASSERT_EQ(3, mgr->getNumBuffers());
268 
269  std::cout << "TransferBufferManager - Basic: Pool usage: " << pool.getNumUsedBlocks() << std::endl;
270 
271  ASSERT_TRUE((tbb = mgr->create(keys[3])));
272 
273  ASSERT_LT(0, fillTestData(MGR_TEST_DATA[3], tbb));
274  ASSERT_EQ(4, mgr->getNumBuffers());
275 
276  // Making sure all buffers contain proper data
277  ASSERT_TRUE((tbb = mgr->access(keys[0])));
278  ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[0], *tbb));
279 
280  ASSERT_TRUE((tbb = mgr->access(keys[1])));
281  ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[1], *tbb));
282 
283  ASSERT_TRUE((tbb = mgr->access(keys[2])));
284  ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[2], *tbb));
285 
286  ASSERT_TRUE((tbb = mgr->access(keys[3])));
287  ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[3], *tbb));
288 
289  mgr->remove(keys[1]);
290  ASSERT_FALSE(mgr->access(keys[1]));
291  ASSERT_EQ(3, mgr->getNumBuffers());
292  ASSERT_LT(0, pool.getNumFreeBlocks());
293 
294  mgr->remove(keys[0]);
295  ASSERT_FALSE(mgr->access(keys[0]));
296  ASSERT_EQ(2, mgr->getNumBuffers());
297 
298  // At this time we have the following NodeID: 2, 127
299  ASSERT_TRUE((tbb = mgr->access(keys[2])));
300  ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[2], *tbb));
301 
302  ASSERT_TRUE((tbb = mgr->access(keys[3])));
303  ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[3], *tbb));
304 
305  // These were deleted: 0, 1; 3 is still there
306  ASSERT_FALSE(mgr->access(keys[1]));
307  ASSERT_FALSE(mgr->access(keys[0]));
308  ASSERT_TRUE(mgr->access(keys[3]));
309 
310  // Filling the memory again in order to check the destruction below
311  ASSERT_TRUE((tbb = mgr->create(keys[1])));
312  ASSERT_LT(0, fillTestData(MGR_TEST_DATA[1], tbb));
313 
314  // Deleting the object; all memory must be freed
315  ASSERT_NE(0, pool.getNumUsedBlocks());
316  mgr.reset();
317  ASSERT_EQ(0, pool.getNumUsedBlocks());
318 }
UAVCAN_NULLPTR
#define UAVCAN_NULLPTR
Definition: libuavcan/libuavcan/include/uavcan/build_config.hpp:51
TEST
TEST(TransferBuffer, TestDataValidation)
Definition: transfer_buffer.cpp:78
MGR_TEST_DATA
static const std::string MGR_TEST_DATA[4]
Definition: transfer_buffer.cpp:198
uavcan::ITransferBuffer
Definition: abstract_transfer_buffer.hpp:16
uavcan::TransferTypeServiceResponse
@ TransferTypeServiceResponse
Definition: transfer.hpp:20
uavcan::TransferTypeServiceRequest
@ TransferTypeServiceRequest
Definition: transfer.hpp:21
uavcan::PoolAllocator
Definition: dynamic_memory.hpp:51
uavcan::TransferBufferManagerKey
Definition: transfer_buffer.hpp:63
uavcan::TransferBufferManagerEntry
Definition: transfer_buffer.hpp:102
uavcan::PoolAllocator::getNumFreeBlocks
uint16_t getNumFreeBlocks() const
Definition: dynamic_memory.hpp:91
uavcan::uint8_t
std::uint8_t uint8_t
Definition: std.hpp:24
uavcan::TransferTypeMessageBroadcast
@ TransferTypeMessageBroadcast
Definition: transfer.hpp:22
TEST_BUFFER_SIZE
static const int TEST_BUFFER_SIZE
Definition: transfer_buffer.cpp:86
TEST_DATA
static const std::string TEST_DATA
Definition: transfer_buffer.cpp:14
uavcan::equal
UAVCAN_EXPORT bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2)
Definition: templates.hpp:324
uavcan::TransferBufferManager
Definition: transfer_buffer.hpp:153
MGR_MAX_BUFFER_SIZE
static const int MGR_MAX_BUFFER_SIZE
Definition: transfer_buffer.cpp:214
uavcan::ITransferBuffer::write
virtual int write(unsigned offset, const uint8_t *data, unsigned len)=0
uavcan::StaticTransferBuffer
Definition: transfer_buffer.hpp:50
uavcan::ITransferBuffer::read
virtual int read(unsigned offset, uint8_t *data, unsigned len) const =0
uavcan::MemPoolBlockSize
static const unsigned MemPoolBlockSize
Safe default that should be OK for any platform.
Definition: libuavcan/libuavcan/include/uavcan/build_config.hpp:228
matchAgainst
static bool matchAgainst(const std::string &data, const uavcan::ITransferBuffer &tbb, unsigned offset=0, int len=-1)
Definition: transfer_buffer.cpp:38
uavcan::PoolAllocator::getNumUsedBlocks
uint16_t getNumUsedBlocks() const
Definition: dynamic_memory.hpp:85
matchAgainstTestData
static bool matchAgainstTestData(const uavcan::ITransferBuffer &tbb, unsigned offset, int len=-1)
Definition: transfer_buffer.cpp:73
fill
static void fill(T(&a)[Size], R value)
Definition: transfer_buffer.cpp:30
allEqual
static bool allEqual(const T(&a)[Size])
Definition: transfer_buffer.cpp:22
uavcan::copy
UAVCAN_EXPORT OutputIt copy(InputIt first, InputIt last, OutputIt result)
Definition: templates.hpp:238
transfer_buffer.hpp
fillTestData
static int fillTestData(const std::string &data, uavcan::ITransferBuffer *tbb)
Definition: transfer_buffer.cpp:225


uavcan_communicator
Author(s):
autogenerated on Fri Dec 13 2024 03:10:03