transfer_buffer.cpp 12 KB

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