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
41using namespace ns3;
42
43NS_LOG_COMPONENT_DEFINE ("AttributeContainerTestSuite");
44
56{
57public:
60
64 void ReverseList ();
65
70 static
72
80 friend std::ostream &operator <<(std::ostream &os, const AttributeContainerObject &obj);
81
82private:
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
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
125void
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
134std::ostream &
135operator << (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
157template <class A, class B, class C, class D>
158bool
159operator ==(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{
171public:
174
175private:
176 virtual void DoRun ();
177};
178
180 : TestCase ("test instantiation, initialization, access")
181{
182
183}
184
185void
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{
277public:
280
281private:
282 virtual void DoRun (void);
283};
284
286 : TestCase ("test serialization and deserialization")
287{
288
289}
290
291void
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{
367public:
370
371private:
372 virtual void DoRun (void);
373};
374
376 : TestCase ("test attribute set and get")
377{
378
379}
380
381void
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
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);
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.
friend std::ostream & operator<<(std::ostream &os, const AttributeContainerObject &obj)
Stream insertion operator.
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
result_type Get(void) const
Return a container of items.
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
std::ostream & operator<<(std::ostream &os, TypeId tid)
Output streamer.
Definition: type-id.cc:1202
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:922
bool operator==(const std::pair< A, B > &x, const std::pair< C, D > &y)
This function handles mixed constness and compatible, yet distinct numerical classes (like int and lo...
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.
Ptr< AttributeChecker > MakeAttributeContainerChecker(const AttributeContainerValue< A, C > &value)
Make AttributeContainerChecker from AttributeContainerValue.
list x
Random number samples.