A Discrete-Event Network Simulator
API
attribute-container-test-suite.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018 Caliola Engineering, LLC.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Author: Jared Dulmage <jared.dulmage@caliola.com>
18  */
19 
20 #include <ns3/attribute-container.h>
21 #include <ns3/double.h>
22 #include <ns3/integer.h>
23 #include <ns3/log.h>
24 #include <ns3/object.h>
25 #include <ns3/pair.h>
26 #include <ns3/ptr.h>
27 #include <ns3/string.h>
28 #include <ns3/test.h>
29 #include <ns3/type-id.h>
30 
31 #include <algorithm>
32 #include <iterator>
33 #include <list>
34 #include <map>
35 #include <utility>
36 #include <vector>
37 
38 using namespace ns3;
39 
40 NS_LOG_COMPONENT_DEFINE("AttributeContainerTestSuite");
41 
53 {
54  public:
56  ~AttributeContainerObject() override;
57 
61  void ReverseDoubleList();
62 
67  static TypeId GetTypeId();
68 
74  void SetDoubleList(const std::list<double>& doubleList);
80  std::list<double> GetDoubleList() const;
81 
87  void SetIntVec(std::vector<int> vec);
93  std::vector<int> GetIntVec() const;
94 
95  private:
96  std::list<double> m_doublelist;
97  std::vector<int> m_intvec;
98  // TODO(jared): need PairValue attributevalue to handle std::pair elements
99  std::map<std::string, int> m_map;
100  std::map<int64_t, std::list<int64_t>> m_intVecIntMapping;
101 };
102 
104 {
105 }
106 
108 {
109 }
110 
111 TypeId
113 {
115 
116  static TypeId tid =
117  TypeId("ns3::AttributeContainerObject")
118  .SetParent<Object>()
119  .SetGroupName("Test")
120  .AddConstructor<AttributeContainerObject>()
121  .AddAttribute("DoubleList",
122  "List of doubles",
124  MakeAttributeContainerAccessor<DoubleValue>(
126  MakeAttributeContainerChecker<DoubleValue>(MakeDoubleChecker<double>()))
127  .AddAttribute(
128  "IntegerVector",
129  "Vector of integers",
130  // the container value container differs from the underlying object
132  // the type of the underlying container cannot be deduced
133  MakeAttributeContainerAccessor<IntegerValue, ';', std::list>(
136  MakeAttributeContainerChecker<IntegerValue, ';'>(MakeIntegerChecker<int>()))
137  .AddAttribute(
138  "MapStringInt",
139  "Map of strings to ints",
140  // the container value container differs from the underlying object
142  MakeAttributeContainerAccessor<PairValue<StringValue, IntegerValue>>(
145  MakePairChecker<StringValue, IntegerValue>(MakeStringChecker(),
146  MakeIntegerChecker<int>())))
147  .AddAttribute(
148  "IntVecPairVec",
149  "An example of complex attribute that is defined by a vector of pairs consisting "
150  "of an integer value and a vector of integers. In case a string is used to set "
151  "this attribute, the string shall contain the pairs separated by a semicolon (;); "
152  "in every pair, the integer value and the vector of integers are separated by a "
153  "blank space, and the elements of the vectors are separated by a comma (,) "
154  "without spaces. E.g. \"0 1,2,3; 1 0; 2 0,1\" consists of three pairs containing "
155  "vectors of 3, 1 and 2 elements, respectively.",
156  StringValue(""),
157  MakeAttributeContainerAccessor<IntVecMapValue, ';'>(
159  MakeAttributeContainerChecker<IntVecMapValue, ';'>(
161  MakeIntegerChecker<int>(),
162  MakeAttributeContainerChecker<IntegerValue>(MakeIntegerChecker<int>()))));
163  return tid;
164 }
165 
166 void
168 {
169  m_doublelist.reverse();
170 }
171 
172 void
173 AttributeContainerObject::SetDoubleList(const std::list<double>& doubleList)
174 {
175  m_doublelist = doubleList;
176 }
177 
178 std::list<double>
180 {
181  return m_doublelist;
182 }
183 
184 void
186 {
187  m_intvec = vec;
188 }
189 
190 std::vector<int>
192 {
193  return m_intvec;
194 }
195 
205 template <class A, class B, class C, class D>
206 bool
207 operator==(const std::pair<A, B>& x, const std::pair<C, D>& y)
208 {
209  return x.first == y.first && x.second == y.second;
210 }
211 
218 {
219  public:
221 
223  {
224  }
225 
226  private:
227  void DoRun() override;
228 };
229 
231  : TestCase("test instantiation, initialization, access")
232 {
233 }
234 
235 void
237 {
238  {
239  std::list<double> ref = {1.0, 2.1, 3.145269};
240 
242 
243  NS_TEST_ASSERT_MSG_EQ(ref.size(), ac.GetN(), "Container size mismatch");
244  auto aciter = ac.Begin();
245  for (auto rend = ref.end(), riter = ref.begin(); riter != rend; ++riter)
246  {
247  NS_TEST_ASSERT_MSG_NE(true, (aciter == ac.End()), "AC iterator reached end");
248  NS_TEST_ASSERT_MSG_EQ(*riter, (*aciter)->Get(), "Incorrect value");
249  ++aciter;
250  }
251  NS_TEST_ASSERT_MSG_EQ(true, (aciter == ac.End()), "AC iterator did not reach end");
252  }
253 
254  {
255  std::vector<int> ref = {-2, 3, 10, -1042};
256 
257  AttributeContainerValue<IntegerValue> ac(ref.begin(), ref.end());
258 
259  NS_TEST_ASSERT_MSG_EQ(ref.size(), ac.GetN(), "Container size mismatch");
260  auto aciter = ac.Begin();
261  for (auto rend = ref.end(), riter = ref.begin(); riter != rend; ++riter)
262  {
263  NS_TEST_ASSERT_MSG_NE(true, (aciter == ac.End()), "AC iterator reached end");
264  NS_TEST_ASSERT_MSG_EQ(*riter, (*aciter)->Get(), "Incorrect value");
265  ++aciter;
266  }
267  NS_TEST_ASSERT_MSG_EQ(true, (aciter == ac.End()), "AC iterator did not reach end");
268  }
269 
270  {
271  auto ref = {"one", "two", "three"};
272  AttributeContainerValue<StringValue> ac(ref.begin(), ref.end());
273 
274  NS_TEST_ASSERT_MSG_EQ(ref.size(), ac.GetN(), "Container size mismatch");
275  auto aciter = ac.Begin();
276  for (auto v : ref)
277  {
278  NS_TEST_ASSERT_MSG_NE(true, (aciter == ac.End()), "AC iterator reached end");
279  NS_TEST_ASSERT_MSG_EQ(v, (*aciter)->Get(), "Incorrect value");
280  ++aciter;
281  }
282  NS_TEST_ASSERT_MSG_EQ(true, (aciter == ac.End()), "AC iterator did not reach end");
283  }
284 
285  {
286  auto ref = {"one", "two", "three"};
288 
289  NS_TEST_ASSERT_MSG_EQ(ref.size(), ac.GetN(), "Container size mismatch");
290  auto aciter = ac.Begin();
291  for (auto v : ref)
292  {
293  NS_TEST_ASSERT_MSG_NE(true, (aciter == ac.End()), "AC iterator reached end");
294  NS_TEST_ASSERT_MSG_EQ(v, (*aciter)->Get(), "Incorrect value");
295  ++aciter;
296  }
297  NS_TEST_ASSERT_MSG_EQ(true, (aciter == ac.End()), "AC iterator did not reach end");
298  }
299 
300  {
301  // use int64_t which is default for IntegerValue
302  std::map<std::string, int64_t> ref = {{"one", 1}, {"two", 2}, {"three", 3}};
304 
305  NS_TEST_ASSERT_MSG_EQ(ref.size(), ac.GetN(), "Container size mismatch");
306  auto aciter = ac.Begin();
307  for (const auto& v : ref)
308  {
309  NS_TEST_ASSERT_MSG_NE(true, (aciter == ac.End()), "AC iterator reached end");
310  NS_TEST_ASSERT_MSG_EQ(v, (*aciter)->Get(), "Incorrect value");
311  ++aciter;
312  }
313  NS_TEST_ASSERT_MSG_EQ(true, (aciter == ac.End()), "AC iterator did not reach end");
314  }
315 }
316 
323 {
324  public:
326 
328  {
329  }
330 
331  private:
332  void DoRun() override;
333 };
334 
336  : TestCase("test serialization and deserialization")
337 {
338 }
339 
340 void
342 {
343  {
344  // notice embedded spaces
345  std::string doubles = "1.0001, 20.53, -102.3";
346 
348  auto checker = MakeAttributeContainerChecker(attr);
349  auto acchecker = DynamicCast<AttributeContainerChecker>(checker);
350  acchecker->SetItemChecker(MakeDoubleChecker<double>());
351  NS_TEST_ASSERT_MSG_EQ(attr.DeserializeFromString(doubles, checker),
352  true,
353  "Deserialize failed");
354  NS_TEST_ASSERT_MSG_EQ(attr.GetN(), 3, "Incorrect container size");
355 
356  std::string reserialized = attr.SerializeToString(checker);
357  std::string canonical = doubles;
358  canonical.erase(std::remove(canonical.begin(), canonical.end(), ' '), canonical.end());
359  NS_TEST_ASSERT_MSG_EQ(reserialized, canonical, "Reserialization failed");
360  }
361 
362  {
363  // notice embedded spaces
364  std::string ints = "1, 2, -3, -4";
365 
367  auto checker = MakeAttributeContainerChecker(attr);
368  auto acchecker = DynamicCast<AttributeContainerChecker>(checker);
369  acchecker->SetItemChecker(MakeIntegerChecker<int>());
370  NS_TEST_ASSERT_MSG_EQ(attr.DeserializeFromString(ints, checker),
371  true,
372  "Deserialize failed");
373  NS_TEST_ASSERT_MSG_EQ(attr.GetN(), 4, "Incorrect container size");
374 
375  std::string reserialized = attr.SerializeToString(checker);
376  std::string canonical = ints;
377  canonical.erase(std::remove(canonical.begin(), canonical.end(), ' '), canonical.end());
378  NS_TEST_ASSERT_MSG_EQ(reserialized, canonical, "Reserialization failed");
379  }
380 
381  {
382  std::string strings = "this is a sentence with words";
383 
385  auto checker = MakeAttributeContainerChecker(attr);
386  auto acchecker = DynamicCast<AttributeContainerChecker>(checker);
387  acchecker->SetItemChecker(MakeStringChecker());
388  NS_TEST_ASSERT_MSG_EQ(attr.DeserializeFromString(strings, checker),
389  true,
390  "Deserialize failed");
391  NS_TEST_ASSERT_MSG_EQ(attr.GetN(), 6, "Incorrect container size");
392 
393  std::string reserialized = attr.SerializeToString(checker);
394  NS_TEST_ASSERT_MSG_EQ(reserialized, strings, "Reserialization failed");
395  }
396 
397  {
398  std::string pairs = "one 1,two 2,three 3";
400  auto checker = MakeAttributeContainerChecker(attr);
401  auto acchecker = DynamicCast<AttributeContainerChecker>(checker);
402  acchecker->SetItemChecker(
403  MakePairChecker<StringValue, IntegerValue>(MakeStringChecker(),
404  MakeIntegerChecker<int>()));
405  NS_TEST_ASSERT_MSG_EQ(attr.DeserializeFromString(pairs, checker),
406  true,
407  "Deserialization failed");
408  NS_TEST_ASSERT_MSG_EQ(attr.GetN(), 3, "Incorrect container size");
409 
410  std::string reserialized = attr.SerializeToString(checker);
411  NS_TEST_ASSERT_MSG_EQ(reserialized, pairs, "Reserealization failed");
412  }
413 }
414 
421 {
422  public:
424 
426  {
427  }
428 
429  private:
430  void DoRun() override;
431 };
432 
434  : TestCase("test attribute set and get")
435 {
436 }
437 
438 void
440 {
441  Ptr<AttributeContainerObject> obj = CreateObject<AttributeContainerObject>();
442  {
443  auto doubleList = obj->GetDoubleList();
444  NS_TEST_ASSERT_MSG_EQ(doubleList.empty(), true, "DoubleList initialized incorrectly");
445  }
446 
447  const std::list<double> doubles = {1.1, 2.22, 3.333};
448  obj->SetAttribute("DoubleList", AttributeContainerValue<DoubleValue>(doubles));
449  {
450  auto doubleList = obj->GetDoubleList();
451  NS_TEST_ASSERT_MSG_EQ(std::equal(doubles.begin(), doubles.end(), doubleList.begin()),
452  true,
453  "DoubleList incorrectly set");
454  }
455 
456  obj->ReverseDoubleList();
457  {
458  auto doubleList = obj->GetDoubleList();
459  NS_TEST_ASSERT_MSG_EQ(std::equal(doubles.rbegin(), doubles.rend(), doubleList.begin()),
460  true,
461  "DoubleList incorrectly reversed");
462 
463  // NOTE: changing the return container here too!
465  obj->GetAttribute("DoubleList", value);
466  NS_TEST_ASSERT_MSG_EQ(doubles.size(), value.GetN(), "AttributeContainerValue wrong size");
467 
469  NS_TEST_ASSERT_MSG_EQ(doubles.size(), doublevec.size(), "DoublesVec wrong size");
470  NS_TEST_ASSERT_MSG_EQ(std::equal(doubles.rbegin(), doubles.rend(), doublevec.begin()),
471  true,
472  "Incorrect value in doublesvec");
473  }
474 
475  const std::vector<int> ints = {-1, 0, 1, 2, 3};
476  // NOTE: here the underlying attribute container type differs from the actual container
477  obj->SetAttribute("IntegerVector", AttributeContainerValue<IntegerValue, ';'>(ints));
478 
479  {
480  // NOTE: changing the container here too!
482  obj->GetAttribute("IntegerVector", value);
483  NS_TEST_ASSERT_MSG_EQ(ints.size(), value.GetN(), "AttributeContainerValue wrong size");
484 
486  NS_TEST_ASSERT_MSG_EQ(ints.size(), intlist.size(), "Intvec wrong size");
487 
488  NS_TEST_ASSERT_MSG_EQ(std::equal(ints.begin(), ints.end(), intlist.begin()),
489  true,
490  "Incorrect value in intvec");
491  }
492 
493  std::string intVecPairString("0 1,2,3; 1 0; 2 0,1");
494  // NOTE: here the underlying attribute container type differs from the actual container
495  obj->SetAttribute("IntVecPairVec", StringValue(intVecPairString));
496 
497  {
499 
500  // NOTE: changing the container here too!
502  obj->GetAttribute("IntVecPairVec", value);
503  NS_TEST_ASSERT_MSG_EQ(3, value.GetN(), "AttributeContainerValue wrong size"); // 3 pairs
504 
506  NS_TEST_ASSERT_MSG_EQ(3, reslist.size(), "IntVecMapValue wrong size");
507  auto reslistIt = reslist.begin();
508  NS_TEST_ASSERT_MSG_EQ(reslistIt->first, 0, "Incorrect integer value in first pair");
509  NS_TEST_ASSERT_MSG_EQ(reslistIt->second.size(),
510  3,
511  "Incorrect number of integer values in first pair");
512  ++reslistIt;
513  NS_TEST_ASSERT_MSG_EQ(reslistIt->first, 1, "Incorrect integer value in second pair");
514  NS_TEST_ASSERT_MSG_EQ(reslistIt->second.size(),
515  1,
516  "Incorrect number of integer values in second pair");
517  ++reslistIt;
518  NS_TEST_ASSERT_MSG_EQ(reslistIt->first, 2, "Incorrect integer value in third pair");
519  NS_TEST_ASSERT_MSG_EQ(reslistIt->second.size(),
520  2,
521  "Incorrect number of integer values in third pair");
522  }
523 
524  std::map<std::string, int> map = {{"one", 1}, {"two", 2}, {"three", 3}};
525  obj->SetAttribute("MapStringInt",
527 
528  {
530  obj->GetAttribute("MapStringInt", value);
531  NS_TEST_ASSERT_MSG_EQ(map.size(), value.GetN(), "AttributeContainerValue wrong size");
532 
533  // could possibly make custom assignment operator to make assignment statement work
534  std::map<std::string, int> mapstrint;
535  auto lst = value.Get();
536  for (const auto& l : lst)
537  {
538  mapstrint[l.first] = l.second;
539  }
540 
541  NS_TEST_ASSERT_MSG_EQ(map.size(), mapstrint.size(), "mapstrint wrong size");
542  auto iter = map.begin();
543  for (const auto& v : mapstrint)
544  {
545  NS_TEST_ASSERT_MSG_EQ(v, *iter, "Incorrect value in mapstrint");
546  ++iter;
547  }
548  }
549 }
550 
557 {
558  public:
560 };
561 
563  : TestSuite("attribute-container-test-suite", UNIT)
564 {
565  AddTestCase(new AttributeContainerTestCase(), TestCase::QUICK);
567  AddTestCase(new AttributeContainerSetGetTestCase(), TestCase::QUICK);
568 }
569 
static AttributeContainerTestSuite g_attributeContainerTestSuite
Static variable for test initialization.
std::vector< int > GetIntVec() const
Get the vector of ints.
std::vector< int > m_intvec
Vector of ints.
void ReverseDoubleList()
Reverses the list of doubles.
std::list< double > m_doublelist
List of doubles.
std::list< double > GetDoubleList() const
Get the list of doubles.
std::map< std::string, int > m_map
Map of <std::string, int>.
static TypeId GetTypeId()
Get the type ID.
void SetIntVec(std::vector< int > vec)
Set the vector of ints to the given vector.
void SetDoubleList(const std::list< double > &doubleList)
Set the list of doubles to the given list.
std::map< int64_t, std::list< int64_t > > m_intVecIntMapping
Mapping integers to vectors.
Attribute serialization and deserialization TestCase.
void DoRun() override
Implementation to actually run this TestCase.
void DoRun() override
Implementation to actually run this TestCase.
Test AttributeContainer instantiation, initialization, access.
void DoRun() override
Implementation to actually run this TestCase.
Attribute attribute container TestCase.
A container for one type of attribute.
Iterator End()
NS3-style ending of container.
size_type GetN() const
NS3-style Number of items.
std::string SerializeToString(Ptr< const AttributeChecker > checker) const override
C< item_type > result_type
Type of container returned.
Iterator Begin()
NS3-style beginning of container.
size_type size() const
STL-style number of items in container.
iterator begin()
STL-style beginning of container.
bool DeserializeFromString(std::string value, Ptr< const AttributeChecker > checker) override
Hold a signed integer type.
Definition: integer.h:45
A base class which provides memory management and object aggregation.
Definition: object.h:89
Hold objects of type std::pair<A, B>.
Definition: pair.h:56
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
Hold variables of type string.
Definition: string.h:56
encapsulates test code
Definition: test.h:1060
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:301
A suite of tests to run.
Definition: test.h:1256
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:931
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#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:144
#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:564
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:157
Ptr< AttributeChecker > MakeAttributeContainerChecker(const AttributeContainerValue< A, Sep, C > &value)
Make AttributeContainerChecker from AttributeContainerValue.
Ptr< const AttributeChecker > MakeStringChecker()
Definition: string.cc:30
Ptr< AttributeChecker > MakePairChecker(const PairValue< A, B > &value)
Make a PairChecker from a PairValue.
Definition: pair.h:236
value
Definition: second.py:48