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
39using namespace ns3;
40
41NS_LOG_COMPONENT_DEFINE("AttributeContainerTestSuite");
42
54{
55 public:
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
107TypeId
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
143void
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
152void
154{
155 m_intvec = vec;
156}
157
158std::vector<int>
160{
161 return m_intvec;
162}
163
164std::ostream&
165operator<<(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
190template <class A, class B, class C, class D>
191bool
192operator==(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
220void
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
325void
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>());
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
425void
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.
friend std::ostream & operator<<(std::ostream &os, const AttributeContainerObject &obj)
Stream insertion operator.
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
std::ostream & operator<<(std::ostream &os, TypeId tid)
Output streamer.
Definition: type-id.cc:1229
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:935
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()
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.
Ptr< AttributeChecker > MakeAttributeContainerChecker(const AttributeContainerValue< A, C > &value)
Make AttributeContainerChecker from AttributeContainerValue.
value
Definition: second.py:41