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 
46 {
47 public:
49  virtual ~AttributeContainerObject ();
50 
51  void ReverseList ();
52 
53  static
54  TypeId GetTypeId ();
55 
56  friend std::ostream &operator <<(std::ostream &os, const AttributeContainerObject &obj);
57 
58 private:
59  std::list<double> m_doublelist;
60  std::vector<int> m_intvec;
61  // TODO(jared): need PairValue attributevalue to handle std::pair elements
62  std::map<std::string, int> m_map;
63 };
64 
66 {
67 
68 }
69 
71 {
72 
73 }
74 
75 TypeId
77 {
78  static TypeId tid = TypeId ("ns3::AttributeContainerObject")
79  .SetParent<Object> ()
80  .SetGroupName("Test")
81  .AddConstructor<AttributeContainerObject> ()
82  .AddAttribute ("DoubleList", "List of doubles",
84  MakeAttributeContainerAccessor <DoubleValue> (&AttributeContainerObject::m_doublelist),
85  MakeAttributeContainerChecker<DoubleValue> (MakeDoubleChecker<double> ()))
86  .AddAttribute ("IntegerVector", "Vector of integers",
87  // the container value container differs from the underlying object
89  MakeAttributeContainerAccessor <IntegerValue> (&AttributeContainerObject::m_intvec),
90  MakeAttributeContainerChecker<IntegerValue> (MakeIntegerChecker<int> ()))
91  .AddAttribute ("MapStringInt", "Map of strings to ints",
92  // the container value container differs from the underlying object
96  MakePairChecker<StringValue, IntegerValue> (MakeStringChecker (), MakeIntegerChecker<int> ())))
97  ;
98  return tid;
99 }
100 
101 void
103 {
104  m_doublelist.reverse ();
105  std::vector<int> tmp;
106  std::copy_backward (m_intvec.begin (), m_intvec.end (), tmp.begin ());
107  m_intvec = tmp;
108 }
109 
110 std::ostream &
111 operator << (std::ostream &os, const AttributeContainerObject &obj)
112 {
113  os << "AttributeContainerObject: ";
114  bool first = true;
115  for (auto d: obj.m_doublelist)
116  {
117  if (!first) os << ", ";
118  os << d;
119  first = false;
120  }
121  return os;
122 }
123 
124 // this handles mixed constness and compatible, yet
125 // distinct numerical classes (like int and long)
126 template <class A, class B, class C, class D>
127 bool
128 operator ==(const std::pair<A, B> &x, const std::pair<C, D> &y)
129 {
130  return x.first == y.first && x.second == y.second;
131 }
132 
133 /* Test instantiation, initialization, access */
135 {
136 public:
139 
140 private:
141  virtual void DoRun ();
142 };
143 
145  : TestCase ("test instantiation, initialization, access")
146 {
147 
148 }
149 
150 void
152 {
153  {
154  std::list<double> ref = {1.0, 2.1, 3.145269};
155 
157 
158  NS_TEST_ASSERT_MSG_EQ (ref.size (), ac.GetN (), "Container size mismatch");
159  auto aciter = ac.Begin ();
160  for (auto rend = ref.end (),
161  riter= ref.begin (); riter != rend; ++riter)
162  {
163  NS_TEST_ASSERT_MSG_NE (true, (aciter == ac.End ()), "AC iterator reached end");
164  NS_TEST_ASSERT_MSG_EQ (*riter, (*aciter)->Get (), "Incorrect value");
165  ++aciter;
166  }
167  NS_TEST_ASSERT_MSG_EQ (true, (aciter == ac.End ()), "AC iterator did not reach end");
168  }
169 
170  {
171  std::vector<int> ref = {-2, 3, 10, -1042};
172 
173  AttributeContainerValue<IntegerValue> ac (ref.begin (), ref.end ());
174 
175  NS_TEST_ASSERT_MSG_EQ (ref.size (), ac.GetN (), "Container size mismatch");
176  auto aciter = ac.Begin ();
177  for (auto rend = ref.end (),
178  riter= ref.begin (); riter != rend; ++riter)
179  {
180  NS_TEST_ASSERT_MSG_NE (true, (aciter == ac.End ()), "AC iterator reached end");
181  NS_TEST_ASSERT_MSG_EQ (*riter, (*aciter)->Get (), "Incorrect value");
182  ++aciter;
183  }
184  NS_TEST_ASSERT_MSG_EQ (true, (aciter == ac.End ()), "AC iterator did not reach end");
185  }
186 
187  {
188  auto ref = {"one", "two", "three"};
189  AttributeContainerValue<StringValue> ac (ref.begin (), ref.end ());
190 
191  NS_TEST_ASSERT_MSG_EQ (3, ac.GetN (), "Container size mismatch");
192  auto aciter = ac.Begin ();
193  for (auto v: ref)
194  {
195  NS_TEST_ASSERT_MSG_NE (true, (aciter == ac.End ()), "AC iterator reached end");
196  NS_TEST_ASSERT_MSG_EQ (v, (*aciter)->Get (), "Incorrect value");
197  ++aciter;
198  }
199  NS_TEST_ASSERT_MSG_EQ (true, (aciter == ac.End ()), "AC iterator did not reach end");
200  }
201 
202  {
203  auto ref = {"one", "two", "three"};
205 
206  NS_TEST_ASSERT_MSG_EQ (3, ac.GetN (), "Container size mismatch");
207  auto aciter = ac.Begin ();
208  for (auto v: ref)
209  {
210  NS_TEST_ASSERT_MSG_NE (true, (aciter == ac.End ()), "AC iterator reached end");
211  NS_TEST_ASSERT_MSG_EQ (v, (*aciter)->Get (), "Incorrect value");
212  ++aciter;
213  }
214  NS_TEST_ASSERT_MSG_EQ (true, (aciter == ac.End ()), "AC iterator did not reach end");
215  }
216 
217  {
218  // use int64_t which is default for IntegerValue
219  std::map<std::string, int64_t> ref = { {"one", 1}, {"two", 2}, {"three", 3}};
221 
222  NS_TEST_ASSERT_MSG_EQ (3, ac.GetN (), "Container size mismatch");
223  auto aciter = ac.Begin ();
224  for (auto v: ref)
225  {
226  NS_TEST_ASSERT_MSG_NE (true, (aciter == ac.End ()), "AC iterator reached end");
227  NS_TEST_ASSERT_MSG_EQ (v, (*aciter)->Get (), "Incorrect value");
228  ++aciter;
229  }
230  NS_TEST_ASSERT_MSG_EQ (true, (aciter == ac.End ()), "AC iterator did not reach end");
231 
232  }
233 }
234 
235 // test serdes functions
237 {
238 public:
241 
242 private:
243  virtual void DoRun (void);
244 };
245 
247  : TestCase ("test serialization and deserialization")
248 {
249 
250 }
251 
252 void
254 {
255  {
256  // notice embedded spaces
257  std::string doubles = "1.0001, 20.53, -102.3";
258 
260  auto checker = MakeAttributeContainerChecker (attr);
261  auto acchecker = DynamicCast<AttributeContainerChecker> (checker);
262  acchecker->SetItemChecker (MakeDoubleChecker<double> ());
263  NS_TEST_ASSERT_MSG_EQ (attr.DeserializeFromString (doubles, checker), true, "Deserialize failed");
264  NS_TEST_ASSERT_MSG_EQ (attr.GetN (), 3, "Incorrect container size");
265 
266  std::string reserialized = attr.SerializeToString (checker);
267  std::string canonical = doubles;
268  canonical.erase (std::remove (canonical.begin (), canonical.end (), ' '), canonical.end ());
269  NS_TEST_ASSERT_MSG_EQ (reserialized, canonical, "Reserialization failed");
270  }
271 
272  {
273  // notice embedded spaces
274  std::string ints = "1, 2, -3, -4";
275 
277  auto checker = MakeAttributeContainerChecker (attr);
278  auto acchecker = DynamicCast<AttributeContainerChecker> (checker);
279  acchecker->SetItemChecker (MakeIntegerChecker<int> ());
280  NS_TEST_ASSERT_MSG_EQ (attr.DeserializeFromString (ints, checker), true, "Deserialize failed");
281  NS_TEST_ASSERT_MSG_EQ (attr.GetN (), 4, "Incorrect container size");
282 
283  std::string reserialized = attr.SerializeToString (checker);
284  std::string canonical = ints;
285  canonical.erase (std::remove (canonical.begin (), canonical.end (), ' '), canonical.end ());
286  NS_TEST_ASSERT_MSG_EQ (reserialized, canonical, "Reserialization failed");
287  }
288 
289  {
290  std::string strings = "this is a sentence with words";
291 
293  auto checker = MakeAttributeContainerChecker (attr);
294  auto acchecker = DynamicCast<AttributeContainerChecker> (checker);
295  acchecker->SetItemChecker (MakeStringChecker ());
296  NS_TEST_ASSERT_MSG_EQ (attr.DeserializeFromString (strings, checker), true, "Deserialize failed");
297  NS_TEST_ASSERT_MSG_EQ (attr.GetN (), 6, "Incorrect container size");
298 
299  std::string reserialized = attr.SerializeToString (checker);
300  std::string canonical = strings;
301  NS_TEST_ASSERT_MSG_EQ (reserialized, canonical, "Reserialization failed");
302  }
303 
304  {
305  std::string pairs = "one 1,two 2,three 3";
307  auto checker = MakeAttributeContainerChecker (attr);
308  auto acchecker = DynamicCast<AttributeContainerChecker> (checker);
309  acchecker->SetItemChecker (MakePairChecker <StringValue, IntegerValue> (
310  MakeStringChecker (), MakeIntegerChecker<int> ()));
311  NS_TEST_ASSERT_MSG_EQ (attr.DeserializeFromString (pairs, checker), true, "Deserialization failed");
312  NS_TEST_ASSERT_MSG_EQ (attr.GetN (), 3, "Incorrect container size");
313 
314  std::string reserialized = attr.SerializeToString (checker);
315  std::string canonical = pairs;
316  NS_TEST_ASSERT_MSG_EQ (reserialized, canonical, "Reserealization failed");
317 
318  }
319 }
320 
322 {
323 public:
326 
327 private:
328  virtual void DoRun (void);
329 };
330 
332  : TestCase ("test attribute set and get")
333 {
334 
335 }
336 
337 void
339 {
340  Ptr<AttributeContainerObject> obj = CreateObject<AttributeContainerObject> ();
341  {
342  std::ostringstream oss;
343  oss << *obj;
344  NS_TEST_ASSERT_MSG_EQ (oss.str (), "AttributeContainerObject: ", "DoubleList initialized incorrectly");
345  }
346 
347  std::list<double> doubles = {1.1, 2.22, 3.333};
348  obj->SetAttribute ("DoubleList", AttributeContainerValue<DoubleValue> (doubles));
349  {
350  std::ostringstream oss;
351  oss << *obj;
352  NS_TEST_ASSERT_MSG_EQ (oss.str (), "AttributeContainerObject: 1.1, 2.22, 3.333", "DoubleList incorrectly set");
353  }
354 
355  obj->ReverseList ();
356  {
357  std::ostringstream oss;
358  oss << *obj;
359  NS_TEST_ASSERT_MSG_EQ (oss.str (), "AttributeContainerObject: 3.333, 2.22, 1.1", "DoubleList incorrectly reversed");
360 
361  // NOTE: changing the return container here too!
363  obj->GetAttribute ("DoubleList", value);
364  NS_TEST_ASSERT_MSG_EQ (doubles.size (), value.GetN (), "AttributeContainerValue wrong size");
365 
366  AttributeContainerValue<DoubleValue>::result_type doublevec = value.Get ();
367  NS_TEST_ASSERT_MSG_EQ (doubles.size (), doublevec.size (), "DoublesVec wrong size");
368  auto iter = doubles.rbegin ();
369  for (auto d: doublevec)
370  {
371  NS_TEST_ASSERT_MSG_EQ (d, *iter, "Incorrect value in doublesvec");
372  ++iter;
373  }
374  }
375 
376  std::vector<int> ints = {-1, 0, 1, 2, 3};
377  // NOTE: here the underlying attribute container type differs from the actual container
378  obj->SetAttribute ("IntegerVector", AttributeContainerValue<IntegerValue> (ints));
379 
380  {
381  // NOTE: changing the container here too!
383  obj->GetAttribute ("IntegerVector", value);
384  NS_TEST_ASSERT_MSG_EQ (ints.size (), value.GetN (), "AttributeContainerValue wrong size");
385 
387  NS_TEST_ASSERT_MSG_EQ (ints.size (), intlist.size (), "Intvec wrong size");
388  auto iter = ints.begin ();
389  for (auto d: intlist)
390  {
391  NS_TEST_ASSERT_MSG_EQ (d, *iter, "Incorrect value in intvec");
392  ++iter;
393  }
394  }
395 
396  std::map<std::string, int> map = { {"one", 1}, {"two", 2}, {"three", 3}};
398 
399  {
401  obj->GetAttribute ("MapStringInt", value);
402  NS_TEST_ASSERT_MSG_EQ (map.size (), value.GetN (), "AttributeContainerValue wrong size");
403 
404  // could possibly make custom assignment operator to make assignment statement work
405  std::map<std::string, int> mapstrint;
406  auto lst = value.Get ();
407  for (auto l: lst) mapstrint[l.first] = l.second;
408 
409  NS_TEST_ASSERT_MSG_EQ (map.size (), mapstrint.size (), "mapstrint wrong size");
410  auto iter = map.begin ();
411  for (auto v: mapstrint)
412  {
413  NS_TEST_ASSERT_MSG_EQ (v, *iter, "Incorrect value in mapstrint");
414  ++iter;
415  }
416  }
417 }
418 
420 {
421  public:
423 };
424 
426  : TestSuite ("attribute-container-test-suite", UNIT)
427 {
428  AddTestCase (new AttributeContainerTestCase (), TestCase::QUICK);
429  AddTestCase (new AttributeContainerSerializationTestCase (), TestCase::QUICK);
430  AddTestCase (new AttributeContainerSetGetTestCase (), TestCase::QUICK);
431 }
432 
Iterator Begin(void)
NS3-style beginning of container.
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:73
result_type Get(void) const
Return a container of items.
Ptr< const AttributeAccessor > MakeAttributeContainerAccessor(T1 a1)
bool DeserializeFromString(std::string value, Ptr< const AttributeChecker > checker)
A suite of tests to run.
Definition: test.h:1343
size_type GetN(void) const
NS3-style Number of items.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
encapsulates test code
Definition: test.h:1153
Ptr< const AttributeChecker > MakeStringChecker(void)
Definition: string.cc:30
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:299
#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:166
virtual void DoRun()
Implementation to actually run this TestCase.
A container for one type of attribute.
std::map< std::string, int > m_map
virtual void DoRun(void)
Implementation to actually run this TestCase.
std::ostream & operator<<(std::ostream &os, const Angles &a)
print a struct Angles to output
Definition: angles.cc:42
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< AttributeChecker > MakeAttributeContainerChecker(const AttributeContainerValue< A, C > &value)
Make AttributeContainerChecker from AttributeContainerValue.
Iterator End(void)
NS3-style ending of container.
std::string SerializeToString(Ptr< const AttributeChecker > checker) const
#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:622
C< item_type > result_type
Type of container returned.
virtual void DoRun(void)
Implementation to actually run this TestCase.
bool operator==(const EventId &a, const EventId &b)
Definition: event-id.h:142
A base class which provides memory management and object aggregation.
Definition: object.h:87
Hold objects of type std::pair<A, B>.
Definition: pair.h:47
static AttributeContainerTestSuite AttributeContainerTestSuite
Static variable for test initialization.
Definition: first.py:1
void SetAttribute(std::string name, const AttributeValue &value)
Set a single attribute, raising fatal errors if unsuccessful.
Definition: object-base.cc:185
a unique identifier for an interface.
Definition: type-id.h:58
void GetAttribute(std::string name, AttributeValue &value) const
Get the value of an attribute, raising fatal errors if unsuccessful.
Definition: object-base.cc:223
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:923