1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2010 INRIA
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  * Author: Mathieu Lacage <mathieu.lacage@cutebugs.net>
19  */
20 
21 #include "ns3/buffer.h"
22 #include "ns3/random-variable-stream.h"
23 #include "ns3/double.h"
24 #include "ns3/test.h"
25 
26 using namespace ns3;
27 
28 /**
29  * \ingroup network
30  * \defgroup network-test Network module unit tests
31  */
32 
33 /**
34  * \ingroup network-test
35  * \ingroup tests
36  *
37  * Buffer unit tests.
38  */
39 class BufferTest : public TestCase {
40 private:
41   /**
42    * Checks the buffer content
43    * \param b The buffer to check
44    * \param n The number of bytes to check
45    * \param array The array of bytes that should be in the buffer
46    * \param file The file name
47    * \param line The line number
48    */
49   void EnsureWrittenBytes (Buffer b, uint32_t n, uint8_t array[], const char *file, int line);
50 public:
51   virtual void DoRun (void);
52   BufferTest ();
53 };
54 
55 
BufferTest()56 BufferTest::BufferTest ()
57   : TestCase ("Buffer") {
58 }
59 
60 void
EnsureWrittenBytes(Buffer b,uint32_t n,uint8_t array[],const char * file,int line)61 BufferTest::EnsureWrittenBytes (Buffer b, uint32_t n, uint8_t array[], const char *file, int line)
62 {
63   bool success = true;
64   uint8_t *expected = array;
65   uint8_t const*got;
66   got = b.PeekData ();
67   for (uint32_t j = 0; j < n; j++)
68     {
69       if (got[j] != expected[j])
70         {
71           success = false;
72         }
73     }
74   if (!success)
75     {
76       std::ostringstream failure;
77       failure << "Buffer -- ";
78       failure << "expected: n=";
79       failure << n << ", ";
80       failure.setf (std::ios::hex, std::ios::basefield);
81       for (uint32_t j = 0; j < n; j++)
82         {
83           failure << (uint16_t)expected[j] << " ";
84         }
85       failure.setf (std::ios::dec, std::ios::basefield);
86       failure << "got: ";
87       failure.setf (std::ios::hex, std::ios::basefield);
88       for (uint32_t j = 0; j < n; j++)
89         {
90           failure << (uint16_t)got[j] << " ";
91         }
92       failure << std::endl;
93       NS_TEST_ASSERT_MSG_EQ_INTERNAL (true, false, failure.str (), file, line);
94     }
95 }
96 
97 /*
98  * Works only when variadic macros are
99  * available which is the case for gcc.
100  */
101 #define ENSURE_WRITTEN_BYTES(buffer, n, ...)                    \
102   {                                                             \
103     uint8_t bytes[] = { __VA_ARGS__};                            \
104     EnsureWrittenBytes (buffer, n, bytes, __FILE__, __LINE__);  \
105   }
106 
107 void
DoRun(void)108 BufferTest::DoRun (void)
109 {
110   Buffer buffer;
111   Buffer::Iterator i;
112   buffer.AddAtStart (6);
113   i = buffer.Begin ();
114   i.WriteU8 (0x66);
115   ENSURE_WRITTEN_BYTES (buffer, 1, 0x66);
116   i = buffer.Begin ();
117   i.WriteU8 (0x67);
118   ENSURE_WRITTEN_BYTES (buffer, 1, 0x67);
119   i.WriteHtonU16 (0x6568);
120   i = buffer.Begin ();
121   ENSURE_WRITTEN_BYTES (buffer, 3, 0x67, 0x65, 0x68);
122   i.WriteHtonU16 (0x6369);
123   ENSURE_WRITTEN_BYTES (buffer, 3, 0x63, 0x69, 0x68);
124   i.WriteHtonU32 (0xdeadbeaf);
125   ENSURE_WRITTEN_BYTES (buffer, 6, 0x63, 0x69, 0xde, 0xad, 0xbe, 0xaf);
126   buffer.AddAtStart (2);
127   i = buffer.Begin ();
128   i.WriteU16 (0);
129   ENSURE_WRITTEN_BYTES (buffer, 8, 0, 0, 0x63, 0x69, 0xde, 0xad, 0xbe, 0xaf);
130   buffer.AddAtEnd (2);
131   i = buffer.Begin ();
132   i.Next (8);
133   i.WriteU16 (0);
134   ENSURE_WRITTEN_BYTES (buffer, 10, 0, 0, 0x63, 0x69, 0xde, 0xad, 0xbe, 0xaf, 0, 0);
135   buffer.RemoveAtStart (3);
136   i = buffer.Begin ();
137   ENSURE_WRITTEN_BYTES (buffer, 7, 0x69, 0xde, 0xad, 0xbe, 0xaf, 0, 0);
138   buffer.RemoveAtEnd (4);
139   i = buffer.Begin ();
140   ENSURE_WRITTEN_BYTES (buffer, 3, 0x69, 0xde, 0xad);
141   buffer.AddAtStart (1);
142   i = buffer.Begin ();
143   i.WriteU8 (0xff);
144   ENSURE_WRITTEN_BYTES (buffer, 4, 0xff, 0x69, 0xde, 0xad);
145   buffer.AddAtEnd (1);
146   i = buffer.Begin ();
147   i.Next (4);
148   i.WriteU8 (0xff);
149   i.Prev (2);
150   uint16_t saved = i.ReadU16 ();
151   i.Prev (2);
152   i.WriteHtonU16 (0xff00);
153   i.Prev (2);
154   NS_TEST_ASSERT_MSG_EQ (i.ReadNtohU16 (), 0xff00, "Could not read expected value");
155   i.Prev (2);
156   i.WriteU16 (saved);
157   ENSURE_WRITTEN_BYTES (buffer, 5, 0xff, 0x69, 0xde, 0xad, 0xff);
158   Buffer o = buffer;
159   ENSURE_WRITTEN_BYTES (o, 5, 0xff, 0x69, 0xde, 0xad, 0xff);
160   o.AddAtStart (1);
161   i = o.Begin ();
162   i.WriteU8 (0xfe);
163   ENSURE_WRITTEN_BYTES (o, 6, 0xfe, 0xff, 0x69, 0xde, 0xad, 0xff);
164   buffer.AddAtStart (2);
165   i = buffer.Begin ();
166   i.WriteU8 (0xfd);
167   i.WriteU8 (0xfd);
168   ENSURE_WRITTEN_BYTES (o, 6, 0xfe, 0xff, 0x69, 0xde, 0xad, 0xff);
169   ENSURE_WRITTEN_BYTES (buffer, 7, 0xfd, 0xfd, 0xff, 0x69, 0xde, 0xad, 0xff);
170 
171   // test 64-bit read/write
172   Buffer buff64;
173   buff64.AddAtStart (8);
174   i = buff64.Begin ();
175   i.WriteU64 (0x0123456789ABCDEFllu);
176   i = buff64.Begin ();
177   NS_TEST_ASSERT_MSG_EQ (i.ReadU64 (), 0x0123456789abcdefllu, "Could not read expected value");
178   i = buff64.Begin ();
179   i.WriteHtolsbU64 (0x0123456789ABCDEFllu);
180   ENSURE_WRITTEN_BYTES (buff64, 8, 0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01);
181   i = buff64.Begin ();
182   NS_TEST_ASSERT_MSG_EQ (i.ReadLsbtohU64 (), 0x0123456789abcdefllu, "Could not read expected value");
183   i = buff64.Begin ();
184   i.WriteHtonU64 (0x0123456789ABCDEFllu);
185   ENSURE_WRITTEN_BYTES (buff64, 8, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef);
186   i = buff64.Begin ();
187   NS_TEST_ASSERT_MSG_EQ (i.ReadNtohU64 (), 0x0123456789abcdefllu, "could not read expected value");
188 
189   // test self-assignment
190   {
191     Buffer a = o;
192 #if defined(__clang__)
193   #if __has_warning("-Wself-assign-overloaded")
194     #pragma clang diagnostic push
195     #pragma clang diagnostic ignored "-Wself-assign-overloaded"
196   #endif
197 #endif
198     a = a;
199 #if defined(__clang__)
200   #if __has_warning("-Wself-assign-overloaded")
201     #pragma clang diagnostic pop
202   #endif
203 #endif
204   }
205 
206   // test Remove start.
207   buffer = Buffer (5);
208   ENSURE_WRITTEN_BYTES (buffer, 5, 0, 0, 0, 0, 0);
209   buffer.RemoveAtStart (1);
210   ENSURE_WRITTEN_BYTES (buffer, 4, 0, 0, 0, 0);
211   buffer.AddAtStart (1);
212   buffer.Begin ().WriteU8 (0xff);
213   ENSURE_WRITTEN_BYTES (buffer, 5, 0xff, 0, 0, 0, 0);
214   buffer.RemoveAtStart (3);
215   ENSURE_WRITTEN_BYTES (buffer, 2, 0, 0);
216   buffer.AddAtStart (4);
217   buffer.Begin ().WriteHtonU32 (0xdeadbeaf);
218   ENSURE_WRITTEN_BYTES (buffer, 6,  0xde, 0xad, 0xbe, 0xaf, 0, 0);
219   buffer.RemoveAtStart (2);
220   ENSURE_WRITTEN_BYTES (buffer, 4,  0xbe, 0xaf, 0, 0);
221   buffer.AddAtEnd (4);
222   i = buffer.Begin ();
223   i.Next (4);
224   i.WriteHtonU32 (0xdeadbeaf);
225   ENSURE_WRITTEN_BYTES (buffer, 8,  0xbe, 0xaf, 0, 0, 0xde, 0xad, 0xbe, 0xaf);
226   buffer.RemoveAtStart (5);
227   ENSURE_WRITTEN_BYTES (buffer, 3,  0xad, 0xbe, 0xaf);
228   // test Remove end
229   buffer = Buffer (5);
230   ENSURE_WRITTEN_BYTES (buffer, 5, 0, 0, 0, 0, 0);
231   buffer.RemoveAtEnd (1);
232   ENSURE_WRITTEN_BYTES (buffer, 4, 0, 0, 0, 0);
233   buffer.AddAtEnd (2);
234   i = buffer.Begin ();
235   i.Next (4);
236   i.WriteU8 (0xab);
237   i.WriteU8 (0xac);
238   ENSURE_WRITTEN_BYTES (buffer, 6, 0, 0, 0, 0, 0xab, 0xac);
239   buffer.RemoveAtEnd (1);
240   ENSURE_WRITTEN_BYTES (buffer, 5, 0, 0, 0, 0, 0xab);
241   buffer.RemoveAtEnd (3);
242   ENSURE_WRITTEN_BYTES (buffer, 2, 0, 0);
243   buffer.AddAtEnd (6);
244   i = buffer.Begin ();
245   i.Next (2);
246   i.WriteU8 (0xac);
247   i.WriteU8 (0xad);
248   i.WriteU8 (0xae);
249   i.WriteU8 (0xaf);
250   i.WriteU8 (0xba);
251   i.WriteU8 (0xbb);
252   ENSURE_WRITTEN_BYTES (buffer, 8, 0, 0, 0xac, 0xad, 0xae, 0xaf, 0xba, 0xbb);
253   buffer.AddAtStart (3);
254   i = buffer.Begin ();
255   i.WriteU8 (0x30);
256   i.WriteU8 (0x31);
257   i.WriteU8 (0x32);
258   ENSURE_WRITTEN_BYTES (buffer, 11, 0x30, 0x31, 0x32, 0, 0, 0xac, 0xad, 0xae, 0xaf, 0xba, 0xbb);
259   buffer.RemoveAtEnd (9);
260   ENSURE_WRITTEN_BYTES (buffer, 2, 0x30, 0x31);
261   buffer = Buffer (3);
262   buffer.AddAtEnd (2);
263   i = buffer.Begin ();
264   i.Next (3);
265   i.WriteHtonU16 (0xabcd);
266   buffer.AddAtStart (1);
267   buffer.Begin ().WriteU8 (0x21);
268   ENSURE_WRITTEN_BYTES (buffer, 6, 0x21, 0, 0, 0, 0xab, 0xcd);
269   buffer.RemoveAtEnd (8);
270   NS_TEST_ASSERT_MSG_EQ (buffer.GetSize (), 0, "Buffer size not zero");
271 
272   buffer = Buffer (6);
273   buffer.AddAtStart (9);
274   buffer.AddAtEnd (3);
275   i = buffer.End ();
276   i.Prev (1);
277   i.WriteU8 (1, 1);
278 
279   buffer = Buffer (6);
280   buffer.AddAtStart (3);
281   buffer.RemoveAtEnd (8);
282   buffer.AddAtEnd (4);
283   i = buffer.End ();
284   i.Prev (4);
285   i.WriteU8 (1, 4);
286 
287   buffer = Buffer (1);
288   buffer.AddAtEnd (100);
289   i = buffer.End ();
290   i.Prev (100);
291   i.WriteU8 (1, 100);
292 
293   /// \internal
294   /// See \bugid{54}
295   {
296     const uint32_t actualSize = 72602;
297     const uint32_t chunkSize = 67624;
298     Ptr<UniformRandomVariable> bytesRng = CreateObject<UniformRandomVariable> ();
299     bytesRng->SetAttribute ("Min", DoubleValue (0));
300     bytesRng->SetAttribute ("Max", DoubleValue (256));
301 
302     Buffer inputBuffer;
303     Buffer outputBuffer;
304 
305     inputBuffer.AddAtEnd (actualSize);
306     {
307       Buffer::Iterator iter = inputBuffer.Begin ();
308       for (uint32_t i = 0; i < actualSize; i++)
309         iter.WriteU8 (static_cast<uint8_t> (bytesRng->GetValue ()));
310     }
311 
312     outputBuffer.AddAtEnd (chunkSize);
313     Buffer::Iterator iter = outputBuffer.End ();
314     iter.Prev (chunkSize);
315     iter.Write (inputBuffer.PeekData (), chunkSize);
316 
317     NS_TEST_EXPECT_MSG_EQ (memcmp (inputBuffer.PeekData (), outputBuffer.PeekData (), chunkSize), 0, "memcp works");
318   }
319 
320   buffer = Buffer (5);
321   buffer.AddAtEnd (2);
322   i = buffer.End ();
323   i.Prev (2);
324   i.WriteU8 (0);
325   i.WriteU8 (0x66);
326   ENSURE_WRITTEN_BYTES (buffer, 7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66);
327   Buffer frag0 = buffer.CreateFragment (0, 2);
328   ENSURE_WRITTEN_BYTES (frag0, 2, 0x00, 0x00);
329   Buffer frag1 = buffer.CreateFragment (2, 5);
330   ENSURE_WRITTEN_BYTES (frag1, 5, 0x00, 0x00, 0x00, 0x00, 0x66);
331   frag0.AddAtEnd (frag1);
332   ENSURE_WRITTEN_BYTES (buffer, 7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66);
333   ENSURE_WRITTEN_BYTES (frag0, 7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66);
334 
335   buffer = Buffer (5);
336   buffer.AddAtStart (2);
337   i = buffer.Begin ();
338   i.WriteU8 (0x1);
339   i.WriteU8 (0x2);
340   buffer.AddAtEnd (2);
341   i = buffer.End ();
342   i.Prev (2);
343   i.WriteU8 (0x3);
344   i.WriteU8 (0x4);
345   ENSURE_WRITTEN_BYTES (buffer, 9, 0x1, 0x2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3, 0x4);
346   Buffer other;
347   other.AddAtStart (9);
348   i = other.Begin ();
349   i.Write (buffer.Begin (), buffer.End ());
350   ENSURE_WRITTEN_BYTES (other, 9, 0x1, 0x2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3, 0x4);
351 
352   /// \internal See \bugid{1001}
353   std::string ct ("This is the next content of the buffer.");
354   buffer = Buffer ();
355   buffer.AddAtStart (ct.size ());
356   i = buffer.Begin ();
357   i.Write ((const uint8_t*)ct.c_str (), ct.size ());
358   uint32_t sizeBuffer = buffer.GetSize ();
359   NS_TEST_ASSERT_MSG_EQ (sizeBuffer, ct.size(), "Buffer bad size");
360   uint8_t const* evilBuffer = buffer.PeekData ();
361   NS_TEST_ASSERT_MSG_NE( evilBuffer, 0, "Buffer PeekData failed");
362   uint8_t *cBuf = (uint8_t*) malloc ( sizeBuffer );
363   uint32_t copyLen = buffer.CopyData (cBuf, sizeBuffer);
364   NS_TEST_ASSERT_MSG_EQ (copyLen, sizeBuffer, "CopyData return bad size");
365   for (uint8_t i=0; i < sizeBuffer ; i++ )
366     {
367       NS_TEST_ASSERT_MSG_EQ ( cBuf [i], *(((const uint8_t*)ct.c_str ()) + i), "Bad buffer copied data");
368       NS_TEST_ASSERT_MSG_EQ ( evilBuffer [i], cBuf [i] , "Bad buffer peeked");
369     }
370   free (cBuf);
371 
372   /// \internal See \bugid{2044}  Will not pass without bug2044 fix.
373   buffer = Buffer (1);
374   buffer.AddAtEnd (2);
375   i = buffer.Begin ();
376   i.Next (1);
377   i.WriteU8 (0x77);
378   i.WriteU8 (0x66);
379   ENSURE_WRITTEN_BYTES (buffer, 3, 0x00, 0x77, 0x66);
380   i = buffer.Begin ();
381   i.ReadU8 ();
382   uint16_t val1 = i.ReadNtohU16 ();
383   i = buffer.Begin ();
384   i.ReadU8 ();
385   uint16_t val2 = 0;
386   val2 |= i.ReadU8 ();
387   val2 <<= 8;
388   val2 |= i.ReadU8 ();
389   NS_TEST_ASSERT_MSG_EQ (val1, val2, "Bad ReadNtohU16()");
390 }
391 
392 /**
393  * \ingroup network-test
394  * \ingroup tests
395  *
396  * \brief Buffer TestSuite
397  */
398 class BufferTestSuite : public TestSuite
399 {
400 public:
401   BufferTestSuite ();
402 };
403 
BufferTestSuite()404 BufferTestSuite::BufferTestSuite ()
405   : TestSuite ("buffer", UNIT)
406 {
407   AddTestCase (new BufferTest, TestCase::QUICK);
408 }
409 
410 static BufferTestSuite g_bufferTestSuite; //!< Static variable for test initialization
411