Руслан Урядинский / libuavcan

Dependents:   UAVCAN UAVCAN_Subscriber

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers transfer_buffer.cpp Source File

transfer_buffer.cpp

00001 /*
00002  * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
00003  */
00004 
00005 #if __GNUC__
00006 // We need auto_ptr for compatibility reasons
00007 # pragma GCC diagnostic ignored "-Wdeprecated-declarations"
00008 # pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
00009 #endif
00010 
00011 #include <algorithm>
00012 #include <gtest/gtest.h>
00013 #include <memory>
00014 #include <uavcan/transport/transfer_buffer.hpp>
00015 
00016 static const std::string TEST_DATA =
00017     "It was like this: I asked myself one day this question - what if Napoleon, for instance, had happened to be in my "
00018     "place, and if he had not had Toulon nor Egypt nor the passage of Mont Blanc to begin his career with, but "
00019     "instead of all those picturesque and monumental things, there had simply been some ridiculous old hag, a "
00020     "pawnbroker, who had to be murdered too to get money from her trunk (for his career, you understand). "
00021     "Well, would he have brought himself to that if there had been no other means?";
00022 
00023 template <typename T, unsigned Size>
00024 static bool allEqual(const T (&a)[Size])
00025 {
00026     unsigned n = Size;
00027     while ((--n > 0) && (a[n] == a[0])) { }
00028     return n == 0;
00029 }
00030 
00031 template <typename T, unsigned Size, typename R>
00032 static void fill(T (&a)[Size], R value)
00033 {
00034     for (unsigned i = 0; i < Size; i++)
00035     {
00036         a[i] = T(value);
00037     }
00038 }
00039 
00040 static bool matchAgainst(const std::string& data, const uavcan::ITransferBuffer& tbb,
00041                          unsigned offset = 0, int len = -1)
00042 {
00043     uint8_t local_buffer[1024];
00044     fill(local_buffer, 0);
00045     assert((len < 0) || (sizeof(local_buffer) >= static_cast<unsigned>(len)));
00046 
00047     if (len < 0)
00048     {
00049         const int res = tbb.read(offset, local_buffer, sizeof(local_buffer));
00050         if (res < 0)
00051         {
00052             std::cout << "matchAgainst(): res " << res << std::endl;
00053             return false;
00054         }
00055         len = res;
00056     }
00057     else
00058     {
00059         const int res = tbb.read(offset, local_buffer, unsigned(len));
00060         if (res != len)
00061         {
00062             std::cout << "matchAgainst(): res " << res << " expected " << len << std::endl;
00063             return false;
00064         }
00065     }
00066     const bool equals = std::equal(local_buffer, local_buffer + len, data.begin() + offset);
00067     if (!equals)
00068     {
00069         std::cout << "local_buffer:\n\t" << local_buffer << std::endl;
00070         std::cout << "test_data:\n\t" << std::string(data.begin() + offset, data.begin() + offset + len) << std::endl;
00071     }
00072     return equals;
00073 }
00074 
00075 static bool matchAgainstTestData(const uavcan::ITransferBuffer& tbb, unsigned offset, int len = -1)
00076 {
00077     return matchAgainst(TEST_DATA, tbb, offset, len);
00078 }
00079 
00080 TEST(TransferBuffer, TestDataValidation)
00081 {
00082     ASSERT_LE(4, TEST_DATA.length() / uavcan::MemPoolBlockSize);
00083     uint8_t local_buffer[50];
00084     std::copy(TEST_DATA.begin(), TEST_DATA.begin() + sizeof(local_buffer), local_buffer);
00085     ASSERT_FALSE(allEqual(local_buffer));
00086 }
00087 
00088 static const int TEST_BUFFER_SIZE = 200;
00089 
00090 TEST(StaticTransferBuffer, Basic)
00091 {
00092     using uavcan::StaticTransferBuffer;
00093     StaticTransferBuffer<TEST_BUFFER_SIZE> buf;
00094 
00095     uint8_t local_buffer[TEST_BUFFER_SIZE * 2];
00096     const uint8_t* const test_data_ptr = reinterpret_cast<const uint8_t*>(TEST_DATA.c_str());
00097 
00098     // Empty reads
00099     fill(local_buffer, 0xA5);
00100     ASSERT_EQ(0, buf.read(0, local_buffer, 999));
00101     ASSERT_EQ(0, buf.read(0, local_buffer, 0));
00102     ASSERT_EQ(0, buf.read(999, local_buffer, 0));
00103     ASSERT_TRUE(allEqual(local_buffer));
00104 
00105     // Bulk write
00106     ASSERT_EQ(TEST_BUFFER_SIZE, buf.write(0, test_data_ptr, unsigned(TEST_DATA.length())));
00107     ASSERT_TRUE(matchAgainstTestData(buf, 0));
00108     ASSERT_TRUE(matchAgainstTestData(buf, TEST_BUFFER_SIZE));
00109     ASSERT_TRUE(matchAgainstTestData(buf, TEST_BUFFER_SIZE / 2));
00110     ASSERT_TRUE(matchAgainstTestData(buf, TEST_BUFFER_SIZE / 2, TEST_BUFFER_SIZE / 4));
00111     ASSERT_TRUE(matchAgainstTestData(buf, TEST_BUFFER_SIZE / 4, TEST_BUFFER_SIZE / 2));
00112     ASSERT_TRUE(matchAgainstTestData(buf, 0, TEST_BUFFER_SIZE / 4));
00113 
00114     // Reset
00115     fill(local_buffer, 0xA5);
00116     buf.reset();
00117     ASSERT_EQ(0, buf.read(0, local_buffer, 0));
00118     ASSERT_EQ(0, buf.read(0, local_buffer, 999));
00119     ASSERT_TRUE(allEqual(local_buffer));
00120 
00121     // Random write
00122     ASSERT_EQ(21, buf.write(12, test_data_ptr + 12, 21));
00123     ASSERT_TRUE(matchAgainstTestData(buf, 12, 21));
00124 
00125     ASSERT_EQ(12, buf.write(0, test_data_ptr, 12));
00126     ASSERT_TRUE(matchAgainstTestData(buf, 0));
00127 
00128     ASSERT_EQ(0, buf.write(21, test_data_ptr + 21, 0));
00129     ASSERT_EQ(TEST_BUFFER_SIZE - 21, buf.write(21, test_data_ptr + 21, 999));
00130     ASSERT_TRUE(matchAgainstTestData(buf, 21, TEST_BUFFER_SIZE - 21));
00131     ASSERT_TRUE(matchAgainstTestData(buf, 0));
00132 }
00133 
00134 
00135 TEST(TransferBufferManagerEntry, Basic)
00136 {
00137     using uavcan::TransferBufferManagerEntry;
00138 
00139     static const int MAX_SIZE = TEST_BUFFER_SIZE;
00140     static const int POOL_BLOCKS = 8;
00141     uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool;
00142 
00143     TransferBufferManagerEntry buf(pool, MAX_SIZE);
00144 
00145     uint8_t local_buffer[TEST_BUFFER_SIZE * 2];
00146     const uint8_t* const test_data_ptr = reinterpret_cast<const uint8_t*>(TEST_DATA.c_str());
00147 
00148     // Empty reads
00149     fill(local_buffer, 0xA5);
00150     ASSERT_EQ(0, buf.read(0, local_buffer, 999));
00151     ASSERT_EQ(0, buf.read(0, local_buffer, 0));
00152     ASSERT_EQ(0, buf.read(999, local_buffer, 0));
00153     ASSERT_TRUE(allEqual(local_buffer));
00154 
00155     // Bulk write
00156     ASSERT_EQ(MAX_SIZE, buf.write(0, test_data_ptr, unsigned(TEST_DATA.length())));
00157 
00158     ASSERT_LT(0, pool.getNumUsedBlocks());      // Making sure some memory was used
00159 
00160     ASSERT_TRUE(matchAgainstTestData(buf, 0));
00161     ASSERT_TRUE(matchAgainstTestData(buf, TEST_BUFFER_SIZE));
00162     ASSERT_TRUE(matchAgainstTestData(buf, TEST_BUFFER_SIZE / 2));
00163     ASSERT_TRUE(matchAgainstTestData(buf, TEST_BUFFER_SIZE / 2, TEST_BUFFER_SIZE / 4));
00164     ASSERT_TRUE(matchAgainstTestData(buf, TEST_BUFFER_SIZE / 4, TEST_BUFFER_SIZE / 2));
00165     ASSERT_TRUE(matchAgainstTestData(buf, 0, TEST_BUFFER_SIZE / 4));
00166 
00167     // Reset
00168     fill(local_buffer, 0xA5);
00169     buf.reset();
00170     ASSERT_EQ(0, buf.read(0, local_buffer, 0));
00171     ASSERT_EQ(0, buf.read(0, local_buffer, 999));
00172     ASSERT_TRUE(allEqual(local_buffer));
00173     ASSERT_EQ(0, pool.getNumUsedBlocks());
00174 
00175     // Random write
00176     ASSERT_EQ(21, buf.write(12, test_data_ptr + 12, 21));
00177     ASSERT_TRUE(matchAgainstTestData(buf, 12, 21));
00178 
00179     ASSERT_EQ(60, buf.write(TEST_BUFFER_SIZE - 60, test_data_ptr + TEST_BUFFER_SIZE - 60, 60));
00180     ASSERT_TRUE(matchAgainstTestData(buf, TEST_BUFFER_SIZE - 60));
00181 
00182     // Now we have two empty regions: empty-data-empty-data
00183 
00184     ASSERT_EQ(0, buf.write(0, test_data_ptr, 0));
00185     ASSERT_EQ(TEST_BUFFER_SIZE - 21, buf.write(21, test_data_ptr + 21, TEST_BUFFER_SIZE - 21));
00186     ASSERT_TRUE(matchAgainstTestData(buf, 21, TEST_BUFFER_SIZE - 21));
00187 
00188     // Now: empty-data-data-data
00189 
00190     ASSERT_EQ(21, buf.write(0, test_data_ptr, 21));
00191     ASSERT_TRUE(matchAgainstTestData(buf, 0));
00192 
00193     // Destroying the object; memory should be released
00194     ASSERT_LT(0, pool.getNumUsedBlocks());
00195     buf.~TransferBufferManagerEntry();
00196     ASSERT_EQ(0, pool.getNumUsedBlocks());
00197 }
00198 
00199 
00200 static const std::string MGR_TEST_DATA[4] =
00201 {
00202     "I thought you would cry out again \'don\'t speak of it, leave off.\'\" Raskolnikov gave a laugh, but rather a "
00203     "forced one. \"What, silence again?\" he asked a minute later. \"We must talk about something, you know. ",
00204 
00205     "It would be interesting for me to know how you would decide a certain \'problem\' as Lebeziatnikov would say.\" "
00206     "(He was beginning to lose the thread.) \"No, really, I am serious. Imagine, Sonia, that you had known all ",
00207 
00208     "Luzhin\'s intentions beforehand. Known, that is, for a fact, that they would be the ruin of Katerina Ivanovna "
00209     "and the children and yourself thrown in--since you don\'t count yourself for anything--Polenka too... for ",
00210 
00211     "she\'ll go the same way. Well, if suddenly it all depended on your decision whether he or they should go on "
00212     "living, that is whether Luzhin should go on living and doing wicked things, or Katerina Ivanovna should die? "
00213     "How would you decide which of them was to die? I ask you?"
00214 };
00215 
00216 static const int MGR_MAX_BUFFER_SIZE = 100;
00217 
00218 TEST(TransferBufferManager, TestDataValidation)
00219 {
00220     for (unsigned i = 0; i < sizeof(MGR_TEST_DATA) / sizeof(MGR_TEST_DATA[0]); i++)
00221     {
00222         ASSERT_LT(MGR_MAX_BUFFER_SIZE, MGR_TEST_DATA[i].length());
00223     }
00224 }
00225 
00226 
00227 static int fillTestData(const std::string& data, uavcan::ITransferBuffer* tbb)
00228 {
00229     return tbb->write(0, reinterpret_cast<const uint8_t*>(data.c_str()), unsigned(data.length()));
00230 }
00231 
00232 TEST(TransferBufferManager, Basic)
00233 {
00234     using uavcan::TransferBufferManager;
00235     using uavcan::TransferBufferManagerKey;
00236     using uavcan::ITransferBuffer;
00237 
00238     static const int POOL_BLOCKS = 100;
00239     uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool;
00240 
00241     std::auto_ptr<TransferBufferManager> mgr(new TransferBufferManager(MGR_MAX_BUFFER_SIZE, pool));
00242 
00243     // Empty
00244     ASSERT_FALSE(mgr->access(TransferBufferManagerKey(0, uavcan::TransferTypeMessageBroadcast)));
00245     ASSERT_FALSE(mgr->access(TransferBufferManagerKey(127, uavcan::TransferTypeServiceRequest)));
00246 
00247     ITransferBuffer* tbb = UAVCAN_NULLPTR;
00248 
00249     const TransferBufferManagerKey keys[5] =
00250     {
00251         TransferBufferManagerKey(0, uavcan::TransferTypeServiceRequest),
00252         TransferBufferManagerKey(1, uavcan::TransferTypeMessageBroadcast),
00253         TransferBufferManagerKey(2, uavcan::TransferTypeServiceRequest),
00254         TransferBufferManagerKey(127, uavcan::TransferTypeServiceResponse),
00255         TransferBufferManagerKey(64, uavcan::TransferTypeMessageBroadcast)
00256     };
00257 
00258     ASSERT_TRUE((tbb = mgr->create(keys[0])));
00259     ASSERT_EQ(MGR_MAX_BUFFER_SIZE, fillTestData(MGR_TEST_DATA[0], tbb));
00260     ASSERT_EQ(1, mgr->getNumBuffers());
00261 
00262     ASSERT_TRUE((tbb = mgr->create(keys[1])));
00263     ASSERT_EQ(MGR_MAX_BUFFER_SIZE, fillTestData(MGR_TEST_DATA[1], tbb));
00264     ASSERT_EQ(2, mgr->getNumBuffers());
00265     ASSERT_LT(2, pool.getNumUsedBlocks());
00266 
00267     ASSERT_TRUE((tbb = mgr->create(keys[2])));
00268     ASSERT_EQ(MGR_MAX_BUFFER_SIZE, fillTestData(MGR_TEST_DATA[2], tbb));
00269     ASSERT_EQ(3, mgr->getNumBuffers());
00270 
00271     std::cout << "TransferBufferManager - Basic: Pool usage: " << pool.getNumUsedBlocks() << std::endl;
00272 
00273     ASSERT_TRUE((tbb = mgr->create(keys[3])));
00274 
00275     ASSERT_LT(0, fillTestData(MGR_TEST_DATA[3], tbb));
00276     ASSERT_EQ(4, mgr->getNumBuffers());
00277 
00278     // Making sure all buffers contain proper data
00279     ASSERT_TRUE((tbb = mgr->access(keys[0])));
00280     ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[0], *tbb));
00281 
00282     ASSERT_TRUE((tbb = mgr->access(keys[1])));
00283     ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[1], *tbb));
00284 
00285     ASSERT_TRUE((tbb = mgr->access(keys[2])));
00286     ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[2], *tbb));
00287 
00288     ASSERT_TRUE((tbb = mgr->access(keys[3])));
00289     ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[3], *tbb));
00290 
00291     mgr->remove(keys[1]);
00292     ASSERT_FALSE(mgr->access(keys[1]));
00293     ASSERT_EQ(3, mgr->getNumBuffers());
00294     ASSERT_LT(0, pool.getNumFreeBlocks());
00295 
00296     mgr->remove(keys[0]);
00297     ASSERT_FALSE(mgr->access(keys[0]));
00298     ASSERT_EQ(2, mgr->getNumBuffers());
00299 
00300     // At this time we have the following NodeID: 2, 127
00301     ASSERT_TRUE((tbb = mgr->access(keys[2])));
00302     ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[2], *tbb));
00303 
00304     ASSERT_TRUE((tbb = mgr->access(keys[3])));
00305     ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[3], *tbb));
00306 
00307     // These were deleted: 0, 1; 3 is still there
00308     ASSERT_FALSE(mgr->access(keys[1]));
00309     ASSERT_FALSE(mgr->access(keys[0]));
00310     ASSERT_TRUE(mgr->access(keys[3]));
00311 
00312     // Filling the memory again in order to check the destruction below
00313     ASSERT_TRUE((tbb = mgr->create(keys[1])));
00314     ASSERT_LT(0, fillTestData(MGR_TEST_DATA[1], tbb));
00315 
00316     // Deleting the object; all memory must be freed
00317     ASSERT_NE(0, pool.getNumUsedBlocks());
00318     mgr.reset();
00319     ASSERT_EQ(0, pool.getNumUsedBlocks());
00320 }