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