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 <sstream>
36 #include <utility>
37 #include <vector>
38 
39 using namespace ns3;
40 
41 NS_LOG_COMPONENT_DEFINE("AttributeContainerTestSuite");
42 
54 {
55  public:
57  ~AttributeContainerObject() override;
58 
62  void ReverseList();
63 
68  static TypeId GetTypeId();
69 
75  void SetIntVec(std::vector<int> vec);
81  std::vector<int> GetIntVec() const;
82 
90  friend std::ostream& operator<<(std::ostream& os, const AttributeContainerObject& obj);
91 
92  private:
93  std::list<double> m_doublelist;
94  std::vector<int> m_intvec;
95  // TODO(jared): need PairValue attributevalue to handle std::pair elements
96  std::map<std::string, int> m_map;
97 };
98 
100 {
101 }
102 
104 {
105 }
106 
107 TypeId
109 {
110  static TypeId tid =
111  TypeId("ns3::AttributeContainerObject")
112  .SetParent<Object>()
113  .SetGroupName("Test")
114  .AddConstructor<AttributeContainerObject>()
115  .AddAttribute("DoubleList",
116  "List of doubles",
118  MakeAttributeContainerAccessor<DoubleValue>(
120  MakeAttributeContainerChecker<DoubleValue>(MakeDoubleChecker<double>()))
121  .AddAttribute("IntegerVector",
122  "Vector of integers",
123  // the container value container differs from the underlying object
125  // the type of the underlying container cannot be deduced
126  MakeAttributeContainerAccessor<IntegerValue, std::list>(
129  MakeAttributeContainerChecker<IntegerValue>(MakeIntegerChecker<int>()))
130  .AddAttribute(
131  "MapStringInt",
132  "Map of strings to ints",
133  // the container value container differs from the underlying object
135  MakeAttributeContainerAccessor<PairValue<StringValue, IntegerValue>>(
138  MakePairChecker<StringValue, IntegerValue>(MakeStringChecker(),
139  MakeIntegerChecker<int>())));
140  return tid;
141 }
142 
143 void
145 {
146  m_doublelist.reverse();
147  std::vector<int> tmp;
148  std::copy_backward(m_intvec.begin(), m_intvec.end(), tmp.begin());
149  m_intvec = tmp;
150 }
151 
152 void
154 {
155  m_intvec = vec;
156 }
157 
158 std::vector<int>
160 {
161  return m_intvec;
162 }
163 
164 std::ostream&
165 operator<<(std::ostream& os, const AttributeContainerObject& obj)
166 {
167  os << "AttributeContainerObject: ";
168  bool first = true;
169  for (auto d : obj.m_doublelist)
170  {
171  if (!first)
172  {
173  os << ", ";
174  }
175  os << d;
176  first = false;
177  }
178  return os;
179 }
180 
190 template <class A, class B, class C, class D>
191 bool
192 operator==(const std::pair<A, B>& x, const std::pair<C, D>& y)
193 {
194  return x.first == y.first && x.second == y.second;
195 }
196 
203 {
204  public:
206 
208  {
209  }
210 
211  private:
212  void DoRun() override;
213 };
214 
216  : TestCase("test instantiation, initialization, access")
217 {
218 }
219 
220 void
222 {
223  {
224  std::list<double> ref = {1.0, 2.1, 3.145269};
225 
227 
228  NS_TEST_ASSERT_MSG_EQ(ref.size(), ac.GetN(), "Container size mismatch");
229  auto aciter = ac.Begin();
230  for (auto rend = ref.end(), riter = ref.begin(); riter != rend; ++riter)
231  {
232  NS_TEST_ASSERT_MSG_NE(true, (aciter == ac.End()), "AC iterator reached end");
233  NS_TEST_ASSERT_MSG_EQ(*riter, (*aciter)->Get(), "Incorrect value");
234  ++aciter;
235  }
236  NS_TEST_ASSERT_MSG_EQ(true, (aciter == ac.End()), "AC iterator did not reach end");
237  }
238 
239  {
240  std::vector<int> ref = {-2, 3, 10, -1042};
241 
242  AttributeContainerValue<IntegerValue> ac(ref.begin(), ref.end());
243 
244  NS_TEST_ASSERT_MSG_EQ(ref.size(), ac.GetN(), "Container size mismatch");
245  auto aciter = ac.Begin();
246  for (auto rend = ref.end(), riter = ref.begin(); riter != rend; ++riter)
247  {
248  NS_TEST_ASSERT_MSG_NE(true, (aciter == ac.End()), "AC iterator reached end");
249  NS_TEST_ASSERT_MSG_EQ(*riter, (*aciter)->Get(), "Incorrect value");
250  ++aciter;
251  }
252  NS_TEST_ASSERT_MSG_EQ(true, (aciter == ac.End()), "AC iterator did not reach end");
253  }
254 
255  {
256  auto ref = {"one", "two", "three"};
257  AttributeContainerValue<StringValue> ac(ref.begin(), ref.end());
258 
259  NS_TEST_ASSERT_MSG_EQ(3, ac.GetN(), "Container size mismatch");
260  auto aciter = ac.Begin();
261  for (auto v : ref)
262  {
263  NS_TEST_ASSERT_MSG_NE(true, (aciter == ac.End()), "AC iterator reached end");
264  NS_TEST_ASSERT_MSG_EQ(v, (*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"};
273 
274  NS_TEST_ASSERT_MSG_EQ(3, 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  // use int64_t which is default for IntegerValue
287  std::map<std::string, int64_t> ref = {{"one", 1}, {"two", 2}, {"three", 3}};
289 
290  NS_TEST_ASSERT_MSG_EQ(3, ac.GetN(), "Container size mismatch");
291  auto aciter = ac.Begin();
292  for (const auto& v : ref)
293  {
294  NS_TEST_ASSERT_MSG_NE(true, (aciter == ac.End()), "AC iterator reached end");
295  NS_TEST_ASSERT_MSG_EQ(v, (*aciter)->Get(), "Incorrect value");
296  ++aciter;
297  }
298  NS_TEST_ASSERT_MSG_EQ(true, (aciter == ac.End()), "AC iterator did not reach end");
299  }
300 }
301 
308 {
309  public:
311 
313  {
314  }
315 
316  private:
317  void DoRun() override;
318 };
319 
321  : TestCase("test serialization and deserialization")
322 {
323 }
324 
325 void
327 {
328  {
329  // notice embedded spaces
330  std::string doubles = "1.0001, 20.53, -102.3";
331 
333  auto checker = MakeAttributeContainerChecker(attr);
334  auto acchecker = DynamicCast<AttributeContainerChecker>(checker);
335  acchecker->SetItemChecker(MakeDoubleChecker<double>());
336  NS_TEST_ASSERT_MSG_EQ(attr.DeserializeFromString(doubles, checker),
337  true,
338  "Deserialize failed");
339  NS_TEST_ASSERT_MSG_EQ(attr.GetN(), 3, "Incorrect container size");
340 
341  std::string reserialized = attr.SerializeToString(checker);
342  std::string canonical = doubles;
343  canonical.erase(std::remove(canonical.begin(), canonical.end(), ' '), canonical.end());
344  NS_TEST_ASSERT_MSG_EQ(reserialized, canonical, "Reserialization failed");
345  }
346 
347  {
348  // notice embedded spaces
349  std::string ints = "1, 2, -3, -4";
350 
352  auto checker = MakeAttributeContainerChecker(attr);
353  auto acchecker = DynamicCast<AttributeContainerChecker>(checker);
354  acchecker->SetItemChecker(MakeIntegerChecker<int>());
355  NS_TEST_ASSERT_MSG_EQ(attr.DeserializeFromString(ints, checker),
356  true,
357  "Deserialize failed");
358  NS_TEST_ASSERT_MSG_EQ(attr.GetN(), 4, "Incorrect container size");
359 
360  std::string reserialized = attr.SerializeToString(checker);
361  std::string canonical = ints;
362  canonical.erase(std::remove(canonical.begin(), canonical.end(), ' '), canonical.end());
363  NS_TEST_ASSERT_MSG_EQ(reserialized, canonical, "Reserialization failed");
364  }
365 
366  {
367  std::string strings = "this is a sentence with words";
368 
370  auto checker = MakeAttributeContainerChecker(attr);
371  auto acchecker = DynamicCast<AttributeContainerChecker>(checker);
372  acchecker->SetItemChecker(MakeStringChecker());
373  NS_TEST_ASSERT_MSG_EQ(attr.DeserializeFromString(strings, checker),
374  true,
375  "Deserialize failed");
376  NS_TEST_ASSERT_MSG_EQ(attr.GetN(), 6, "Incorrect container size");
377 
378  std::string reserialized = attr.SerializeToString(checker);
379  std::string canonical = strings;
380  NS_TEST_ASSERT_MSG_EQ(reserialized, canonical, "Reserialization failed");
381  }
382 
383  {
384  std::string pairs = "one 1,two 2,three 3";
386  auto checker = MakeAttributeContainerChecker(attr);
387  auto acchecker = DynamicCast<AttributeContainerChecker>(checker);
388  acchecker->SetItemChecker(
389  MakePairChecker<StringValue, IntegerValue>(MakeStringChecker(),
390  MakeIntegerChecker<int>()));
391  NS_TEST_ASSERT_MSG_EQ(attr.DeserializeFromString(pairs, checker),
392  true,
393  "Deserialization failed");
394  NS_TEST_ASSERT_MSG_EQ(attr.GetN(), 3, "Incorrect container size");
395 
396  std::string reserialized = attr.SerializeToString(checker);
397  std::string canonical = pairs;
398  NS_TEST_ASSERT_MSG_EQ(reserialized, canonical, "Reserealization failed");
399  }
400 }
401 
408 {
409  public:
411 
413  {
414  }
415 
416  private:
417  void DoRun() override;
418 };
419 
421  : TestCase("test attribute set and get")
422 {
423 }
424 
425 void
427 {
428  Ptr<AttributeContainerObject> obj = CreateObject<AttributeContainerObject>();
429  {
430  std::ostringstream oss;
431  oss << *obj;
432  NS_TEST_ASSERT_MSG_EQ(oss.str(),
433  "AttributeContainerObject: ",
434  "DoubleList initialized incorrectly");
435  }
436 
437  std::list<double> doubles = {1.1, 2.22, 3.333};
438  obj->SetAttribute("DoubleList", AttributeContainerValue<DoubleValue>(doubles));
439  {
440  std::ostringstream oss;
441  oss << *obj;
442  NS_TEST_ASSERT_MSG_EQ(oss.str(),
443  "AttributeContainerObject: 1.1, 2.22, 3.333",
444  "DoubleList incorrectly set");
445  }
446 
447  obj->ReverseList();
448  {
449  std::ostringstream oss;
450  oss << *obj;
451  NS_TEST_ASSERT_MSG_EQ(oss.str(),
452  "AttributeContainerObject: 3.333, 2.22, 1.1",
453  "DoubleList incorrectly reversed");
454 
455  // NOTE: changing the return container here too!
457  obj->GetAttribute("DoubleList", value);
458  NS_TEST_ASSERT_MSG_EQ(doubles.size(), value.GetN(), "AttributeContainerValue wrong size");
459 
461  NS_TEST_ASSERT_MSG_EQ(doubles.size(), doublevec.size(), "DoublesVec wrong size");
462  auto iter = doubles.rbegin();
463  for (auto d : doublevec)
464  {
465  NS_TEST_ASSERT_MSG_EQ(d, *iter, "Incorrect value in doublesvec");
466  ++iter;
467  }
468  }
469 
470  std::vector<int> ints = {-1, 0, 1, 2, 3};
471  // NOTE: here the underlying attribute container type differs from the actual container
472  obj->SetAttribute("IntegerVector", AttributeContainerValue<IntegerValue>(ints));
473 
474  {
475  // NOTE: changing the container here too!
477  obj->GetAttribute("IntegerVector", value);
478  NS_TEST_ASSERT_MSG_EQ(ints.size(), value.GetN(), "AttributeContainerValue wrong size");
479 
481  NS_TEST_ASSERT_MSG_EQ(ints.size(), intlist.size(), "Intvec wrong size");
482  auto iter = ints.begin();
483  for (auto d : intlist)
484  {
485  NS_TEST_ASSERT_MSG_EQ(d, *iter, "Incorrect value in intvec");
486  ++iter;
487  }
488  }
489 
490  std::map<std::string, int> map = {{"one", 1}, {"two", 2}, {"three", 3}};
491  obj->SetAttribute("MapStringInt",
493 
494  {
496  obj->GetAttribute("MapStringInt", value);
497  NS_TEST_ASSERT_MSG_EQ(map.size(), value.GetN(), "AttributeContainerValue wrong size");
498 
499  // could possibly make custom assignment operator to make assignment statement work
500  std::map<std::string, int> mapstrint;
501  auto lst = value.Get();
502  for (const auto& l : lst)
503  {
504  mapstrint[l.first] = l.second;
505  }
506 
507  NS_TEST_ASSERT_MSG_EQ(map.size(), mapstrint.size(), "mapstrint wrong size");
508  auto iter = map.begin();
509  for (const auto& v : mapstrint)
510  {
511  NS_TEST_ASSERT_MSG_EQ(v, *iter, "Incorrect value in mapstrint");
512  ++iter;
513  }
514  }
515 }
516 
523 {
524  public:
526 };
527 
529  : TestSuite("attribute-container-test-suite", UNIT)
530 {
531  AddTestCase(new AttributeContainerTestCase(), TestCase::QUICK);
533  AddTestCase(new AttributeContainerSetGetTestCase(), TestCase::QUICK);
534 }
535 
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.
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.
void SetIntVec(std::vector< int > vec)
Set the vector of ints to the given vector.
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 Begin()
NS3-style beginning of container.
std::string SerializeToString(Ptr< const AttributeChecker > checker) const override
bool DeserializeFromString(std::string value, Ptr< const AttributeChecker > checker) override
C< item_type > result_type
Type of container returned.
size_type GetN() const
NS3-style Number of items.
Iterator End()
NS3-style ending of container.
size_type size() const
STL-style number of items in container.
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:78
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:305
A suite of tests to run.
Definition: test.h:1256
a unique identifier for an interface.
Definition: type-id.h:60
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:935
Ptr< const AttributeChecker > MakeStringChecker()
Definition: string.cc:30
#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
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:157
Ptr< AttributeChecker > MakeAttributeContainerChecker(const AttributeContainerValue< A, C > &value)
Make AttributeContainerChecker from AttributeContainerValue.
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition: angles.cc:129
value
Definition: second.py:41