A Discrete-Event Network Simulator
API
attribute-container-test-suite.cc
Go to the documentation of this file.
1 /* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2018 Caliola Engineering, LLC.
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: Jared Dulmage <jared.dulmage@caliola.com>
19  */
20 
21 #include <ns3/test.h>
22 #include <ns3/log.h>
23 #include <ns3/attribute-container.h>
24 #include <ns3/attribute-container-accessor-helper.h>
25 #include <ns3/pair.h>
26 #include <ns3/double.h>
27 #include <ns3/integer.h>
28 #include <ns3/string.h>
29 #include <ns3/ptr.h>
30 #include <ns3/object.h>
31 #include <ns3/type-id.h>
32 
33 #include <list>
34 #include <vector>
35 #include <map>
36 #include <algorithm>
37 #include <iterator>
38 #include <sstream>
39 #include <utility>
40 
41 using namespace ns3;
42 
43 NS_LOG_COMPONENT_DEFINE ("AttributeContainerTestSuite");
44 
56 {
57 public:
59  virtual ~AttributeContainerObject ();
60 
64  void ReverseList ();
65 
70  static
71  TypeId GetTypeId ();
72 
80  friend std::ostream &operator <<(std::ostream &os, const AttributeContainerObject &obj);
81 
82 private:
83  std::list<double> m_doublelist;
84  std::vector<int> m_intvec;
85  // TODO(jared): need PairValue attributevalue to handle std::pair elements
86  std::map<std::string, int> m_map;
87 };
88 
90 {
91 
92 }
93 
95 {
96 
97 }
98 
99 TypeId
101 {
102  static TypeId tid = TypeId ("ns3::AttributeContainerObject")
103  .SetParent<Object> ()
104  .SetGroupName("Test")
105  .AddConstructor<AttributeContainerObject> ()
106  .AddAttribute ("DoubleList", "List of doubles",
108  MakeAttributeContainerAccessor <DoubleValue> (&AttributeContainerObject::m_doublelist),
109  MakeAttributeContainerChecker<DoubleValue> (MakeDoubleChecker<double> ()))
110  .AddAttribute ("IntegerVector", "Vector of integers",
111  // the container value container differs from the underlying object
113  MakeAttributeContainerAccessor <IntegerValue> (&AttributeContainerObject::m_intvec),
114  MakeAttributeContainerChecker<IntegerValue> (MakeIntegerChecker<int> ()))
115  .AddAttribute ("MapStringInt", "Map of strings to ints",
116  // the container value container differs from the underlying object
118  MakeAttributeContainerAccessor <PairValue <StringValue, IntegerValue> > (&AttributeContainerObject::m_map),
120  MakePairChecker<StringValue, IntegerValue> (MakeStringChecker (), MakeIntegerChecker<int> ())))
121  ;
122  return tid;
123 }
124 
125 void
127 {
128  m_doublelist.reverse ();
129  std::vector<int> tmp;
130  std::copy_backward (m_intvec.begin (), m_intvec.end (), tmp.begin ());
131  m_intvec = tmp;
132 }
133 
134 std::ostream &
135 operator << (std::ostream &os, const AttributeContainerObject &obj)
136 {
137  os << "AttributeContainerObject: ";
138  bool first = true;
139  for (auto d: obj.m_doublelist)
140  {
141  if (!first) os << ", ";
142  os << d;
143  first = false;
144  }
145  return os;
146 }
147 
157 template <class A, class B, class C, class D>
158 bool
159 operator ==(const std::pair<A, B> &x, const std::pair<C, D> &y)
160 {
161  return x.first == y.first && x.second == y.second;
162 }
163 
170 {
171 public:
174 
175 private:
176  virtual void DoRun ();
177 };
178 
180  : TestCase ("test instantiation, initialization, access")
181 {
182 
183 }
184 
185 void
187 {
188  {
189  std::list<double> ref = {1.0, 2.1, 3.145269};
190 
192 
193  NS_TEST_ASSERT_MSG_EQ (ref.size (), ac.GetN (), "Container size mismatch");
194  auto aciter = ac.Begin ();
195  for (auto rend = ref.end (),
196  riter= ref.begin (); riter != rend; ++riter)
197  {
198  NS_TEST_ASSERT_MSG_NE (true, (aciter == ac.End ()), "AC iterator reached end");
199  NS_TEST_ASSERT_MSG_EQ (*riter, (*aciter)->Get (), "Incorrect value");
200  ++aciter;
201  }
202  NS_TEST_ASSERT_MSG_EQ (true, (aciter == ac.End ()), "AC iterator did not reach end");
203  }
204 
205  {
206  std::vector<int> ref = {-2, 3, 10, -1042};
207 
208  AttributeContainerValue<IntegerValue> ac (ref.begin (), ref.end ());
209 
210  NS_TEST_ASSERT_MSG_EQ (ref.size (), ac.GetN (), "Container size mismatch");
211  auto aciter = ac.Begin ();
212  for (auto rend = ref.end (),
213  riter= ref.begin (); riter != rend; ++riter)
214  {
215  NS_TEST_ASSERT_MSG_NE (true, (aciter == ac.End ()), "AC iterator reached end");
216  NS_TEST_ASSERT_MSG_EQ (*riter, (*aciter)->Get (), "Incorrect value");
217  ++aciter;
218  }
219  NS_TEST_ASSERT_MSG_EQ (true, (aciter == ac.End ()), "AC iterator did not reach end");
220  }
221 
222  {
223  auto ref = {"one", "two", "three"};
224  AttributeContainerValue<StringValue> ac (ref.begin (), ref.end ());
225 
226  NS_TEST_ASSERT_MSG_EQ (3, ac.GetN (), "Container size mismatch");
227  auto aciter = ac.Begin ();
228  for (auto v: ref)
229  {
230  NS_TEST_ASSERT_MSG_NE (true, (aciter == ac.End ()), "AC iterator reached end");
231  NS_TEST_ASSERT_MSG_EQ (v, (*aciter)->Get (), "Incorrect value");
232  ++aciter;
233  }
234  NS_TEST_ASSERT_MSG_EQ (true, (aciter == ac.End ()), "AC iterator did not reach end");
235  }
236 
237  {
238  auto ref = {"one", "two", "three"};
240 
241  NS_TEST_ASSERT_MSG_EQ (3, ac.GetN (), "Container size mismatch");
242  auto aciter = ac.Begin ();
243  for (auto v: ref)
244  {
245  NS_TEST_ASSERT_MSG_NE (true, (aciter == ac.End ()), "AC iterator reached end");
246  NS_TEST_ASSERT_MSG_EQ (v, (*aciter)->Get (), "Incorrect value");
247  ++aciter;
248  }
249  NS_TEST_ASSERT_MSG_EQ (true, (aciter == ac.End ()), "AC iterator did not reach end");
250  }
251 
252  {
253  // use int64_t which is default for IntegerValue
254  std::map<std::string, int64_t> ref = { {"one", 1}, {"two", 2}, {"three", 3}};
256 
257  NS_TEST_ASSERT_MSG_EQ (3, ac.GetN (), "Container size mismatch");
258  auto aciter = ac.Begin ();
259  for (auto v: ref)
260  {
261  NS_TEST_ASSERT_MSG_NE (true, (aciter == ac.End ()), "AC iterator reached end");
262  NS_TEST_ASSERT_MSG_EQ (v, (*aciter)->Get (), "Incorrect value");
263  ++aciter;
264  }
265  NS_TEST_ASSERT_MSG_EQ (true, (aciter == ac.End ()), "AC iterator did not reach end");
266 
267  }
268 }
269 
276 {
277 public:
280 
281 private:
282  virtual void DoRun (void);
283 };
284 
286  : TestCase ("test serialization and deserialization")
287 {
288 
289 }
290 
291 void
293 {
294  {
295  // notice embedded spaces
296  std::string doubles = "1.0001, 20.53, -102.3";
297 
299  auto checker = MakeAttributeContainerChecker (attr);
300  auto acchecker = DynamicCast<AttributeContainerChecker> (checker);
301  acchecker->SetItemChecker (MakeDoubleChecker<double> ());
302  NS_TEST_ASSERT_MSG_EQ (attr.DeserializeFromString (doubles, checker), true, "Deserialize failed");
303  NS_TEST_ASSERT_MSG_EQ (attr.GetN (), 3, "Incorrect container size");
304 
305  std::string reserialized = attr.SerializeToString (checker);
306  std::string canonical = doubles;
307  canonical.erase (std::remove (canonical.begin (), canonical.end (), ' '), canonical.end ());
308  NS_TEST_ASSERT_MSG_EQ (reserialized, canonical, "Reserialization failed");
309  }
310 
311  {
312  // notice embedded spaces
313  std::string ints = "1, 2, -3, -4";
314 
316  auto checker = MakeAttributeContainerChecker (attr);
317  auto acchecker = DynamicCast<AttributeContainerChecker> (checker);
318  acchecker->SetItemChecker (MakeIntegerChecker<int> ());
319  NS_TEST_ASSERT_MSG_EQ (attr.DeserializeFromString (ints, checker), true, "Deserialize failed");
320  NS_TEST_ASSERT_MSG_EQ (attr.GetN (), 4, "Incorrect container size");
321 
322  std::string reserialized = attr.SerializeToString (checker);
323  std::string canonical = ints;
324  canonical.erase (std::remove (canonical.begin (), canonical.end (), ' '), canonical.end ());
325  NS_TEST_ASSERT_MSG_EQ (reserialized, canonical, "Reserialization failed");
326  }
327 
328  {
329  std::string strings = "this is a sentence with words";
330 
332  auto checker = MakeAttributeContainerChecker (attr);
333  auto acchecker = DynamicCast<AttributeContainerChecker> (checker);
334  acchecker->SetItemChecker (MakeStringChecker ());
335  NS_TEST_ASSERT_MSG_EQ (attr.DeserializeFromString (strings, checker), true, "Deserialize failed");
336  NS_TEST_ASSERT_MSG_EQ (attr.GetN (), 6, "Incorrect container size");
337 
338  std::string reserialized = attr.SerializeToString (checker);
339  std::string canonical = strings;
340  NS_TEST_ASSERT_MSG_EQ (reserialized, canonical, "Reserialization failed");
341  }
342 
343  {
344  std::string pairs = "one 1,two 2,three 3";
346  auto checker = MakeAttributeContainerChecker (attr);
347  auto acchecker = DynamicCast<AttributeContainerChecker> (checker);
348  acchecker->SetItemChecker (MakePairChecker <StringValue, IntegerValue> (
349  MakeStringChecker (), MakeIntegerChecker<int> ()));
350  NS_TEST_ASSERT_MSG_EQ (attr.DeserializeFromString (pairs, checker), true, "Deserialization failed");
351  NS_TEST_ASSERT_MSG_EQ (attr.GetN (), 3, "Incorrect container size");
352 
353  std::string reserialized = attr.SerializeToString (checker);
354  std::string canonical = pairs;
355  NS_TEST_ASSERT_MSG_EQ (reserialized, canonical, "Reserealization failed");
356 
357  }
358 }
359 
366 {
367 public:
370 
371 private:
372  virtual void DoRun (void);
373 };
374 
376  : TestCase ("test attribute set and get")
377 {
378 
379 }
380 
381 void
383 {
384  Ptr<AttributeContainerObject> obj = CreateObject<AttributeContainerObject> ();
385  {
386  std::ostringstream oss;
387  oss << *obj;
388  NS_TEST_ASSERT_MSG_EQ (oss.str (), "AttributeContainerObject: ", "DoubleList initialized incorrectly");
389  }
390 
391  std::list<double> doubles = {1.1, 2.22, 3.333};
392  obj->SetAttribute ("DoubleList", AttributeContainerValue<DoubleValue> (doubles));
393  {
394  std::ostringstream oss;
395  oss << *obj;
396  NS_TEST_ASSERT_MSG_EQ (oss.str (), "AttributeContainerObject: 1.1, 2.22, 3.333", "DoubleList incorrectly set");
397  }
398 
399  obj->ReverseList ();
400  {
401  std::ostringstream oss;
402  oss << *obj;
403  NS_TEST_ASSERT_MSG_EQ (oss.str (), "AttributeContainerObject: 3.333, 2.22, 1.1", "DoubleList incorrectly reversed");
404 
405  // NOTE: changing the return container here too!
407  obj->GetAttribute ("DoubleList", value);
408  NS_TEST_ASSERT_MSG_EQ (doubles.size (), value.GetN (), "AttributeContainerValue wrong size");
409 
410  AttributeContainerValue<DoubleValue>::result_type doublevec = value.Get ();
411  NS_TEST_ASSERT_MSG_EQ (doubles.size (), doublevec.size (), "DoublesVec wrong size");
412  auto iter = doubles.rbegin ();
413  for (auto d: doublevec)
414  {
415  NS_TEST_ASSERT_MSG_EQ (d, *iter, "Incorrect value in doublesvec");
416  ++iter;
417  }
418  }
419 
420  std::vector<int> ints = {-1, 0, 1, 2, 3};
421  // NOTE: here the underlying attribute container type differs from the actual container
422  obj->SetAttribute ("IntegerVector", AttributeContainerValue<IntegerValue> (ints));
423 
424  {
425  // NOTE: changing the container here too!
427  obj->GetAttribute ("IntegerVector", value);
428  NS_TEST_ASSERT_MSG_EQ (ints.size (), value.GetN (), "AttributeContainerValue wrong size");
429 
431  NS_TEST_ASSERT_MSG_EQ (ints.size (), intlist.size (), "Intvec wrong size");
432  auto iter = ints.begin ();
433  for (auto d: intlist)
434  {
435  NS_TEST_ASSERT_MSG_EQ (d, *iter, "Incorrect value in intvec");
436  ++iter;
437  }
438  }
439 
440  std::map<std::string, int> map = { {"one", 1}, {"two", 2}, {"three", 3}};
441  obj->SetAttribute ("MapStringInt", AttributeContainerValue<PairValue <StringValue, IntegerValue> > (map));
442 
443  {
445  obj->GetAttribute ("MapStringInt", value);
446  NS_TEST_ASSERT_MSG_EQ (map.size (), value.GetN (), "AttributeContainerValue wrong size");
447 
448  // could possibly make custom assignment operator to make assignment statement work
449  std::map<std::string, int> mapstrint;
450  auto lst = value.Get ();
451  for (auto l: lst) mapstrint[l.first] = l.second;
452 
453  NS_TEST_ASSERT_MSG_EQ (map.size (), mapstrint.size (), "mapstrint wrong size");
454  auto iter = map.begin ();
455  for (auto v: mapstrint)
456  {
457  NS_TEST_ASSERT_MSG_EQ (v, *iter, "Incorrect value in mapstrint");
458  ++iter;
459  }
460  }
461 }
462 
469 {
470  public:
472 };
473 
475  : TestSuite ("attribute-container-test-suite", UNIT)
476 {
477  AddTestCase (new AttributeContainerTestCase (), TestCase::QUICK);
478  AddTestCase (new AttributeContainerSerializationTestCase (), TestCase::QUICK);
479  AddTestCase (new AttributeContainerSetGetTestCase (), TestCase::QUICK);
480 }
481 
static AttributeContainerTestSuite g_attributeContainerTestSuite
Static variable for test initialization.
std::vector< int > m_intvec
Vector of ints.
std::list< double > m_doublelist
List of doubles.
std::map< std::string, int > m_map
Map of <std::string, int>.
void ReverseList()
Reverses the list of doubles.
static TypeId GetTypeId()
Get the type ID.
Attribute serialization and deserialization TestCase.
virtual void DoRun(void)
Implementation to actually run this TestCase.
virtual void DoRun(void)
Implementation to actually run this TestCase.
Test AttributeContainer instantiation, initialization, access.
virtual void DoRun()
Implementation to actually run this TestCase.
Attribute attribute container TestCase.
A container for one type of attribute.
std::string SerializeToString(Ptr< const AttributeChecker > checker) const
Iterator End(void)
NS3-style ending of container.
bool DeserializeFromString(std::string value, Ptr< const AttributeChecker > checker)
size_type GetN(void) const
NS3-style Number of items.
size_type size(void) const
STL-style number of items in container.
Iterator Begin(void)
NS3-style beginning of container.
C< item_type > result_type
Type of container returned.
A base class which provides memory management and object aggregation.
Definition: object.h:88
Hold objects of type std::pair<A, B>.
Definition: pair.h:56
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:74
encapsulates test code
Definition: test.h:994
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:299
A suite of tests to run.
Definition: test.h:1188
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:922
Ptr< const AttributeChecker > MakeStringChecker(void)
Definition: string.cc:30
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition: test.h:141
#define NS_TEST_ASSERT_MSG_NE(actual, limit, msg)
Test that an actual and expected (limit) value are not equal and report and abort if not.
Definition: test.h:542
Definition: first.py:1
Every class exported by the ns3 library is enclosed in the ns3 namespace.
bool operator==(const EventId &a, const EventId &b)
Definition: event-id.h:158
Ptr< AttributeChecker > MakeAttributeContainerChecker(const AttributeContainerValue< A, C > &value)
Make AttributeContainerChecker from AttributeContainerValue.
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition: angles.cc:139
list x
Random number samples.