c714924ebc938501466d004ce92094e4ec04daad
[senf.git] / senf / Packets / Packet.test.cc
1 // $Id$
2 //
3 // Copyright (C) 2007
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 //
6 // The contents of this file are subject to the Fraunhofer FOKUS Public License
7 // Version 1.0 (the "License"); you may not use this file except in compliance
8 // with the License. You may obtain a copy of the License at 
9 // http://senf.berlios.de/license.html
10 //
11 // The Fraunhofer FOKUS Public License Version 1.0 is based on, 
12 // but modifies the Mozilla Public License Version 1.1.
13 // See the full license text for the amendments.
14 //
15 // Software distributed under the License is distributed on an "AS IS" basis, 
16 // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
17 // for the specific language governing rights and limitations under the License.
18 //
19 // The Original Code is Fraunhofer FOKUS code.
20 //
21 // The Initial Developer of the Original Code is Fraunhofer-Gesellschaft e.V. 
22 // (registered association), Hansastraße 27 c, 80686 Munich, Germany.
23 // All Rights Reserved.
24 //
25 // Contributor(s):
26 //   Stefan Bund <g0dil@berlios.de>
27
28 /** \file
29     \brief Packet unit tests */
30
31 //#include "Packet.test.hh"
32 //#include "Packet.test.ih"
33
34 // Custom includes
35 #include <sstream>
36 #include <boost/static_assert.hpp>
37 #include <boost/cstdint.hpp>
38 #include "Packets.hh"
39
40 #include <senf/Utils/auto_unit_test.hh>
41 #include <boost/test/test_tools.hpp>
42
43 #define prefix_
44 //-/////////////////////////////////////////////////////////////////////////////////////////////////
45
46 namespace {
47
48     struct RegTag {
49         typedef unsigned key_t;
50     };
51
52     struct FooPacketType
53         : public senf::PacketTypeBase,
54           public senf::PacketTypeMixin<FooPacketType>
55     {
56         using senf::PacketTypeMixin<FooPacketType>::nextPacketRange;
57         using senf::PacketTypeMixin<FooPacketType>::initSize;
58         using senf::PacketTypeMixin<FooPacketType>::init;
59         static size_type initSize()
60             { return 4u; }
61
62         // We need to implement initHeadSize() to force the mixin to switch into 'fixed-size'
63         // mode. Otherwise, mixin::nextPacketRange() would query the parser for it's size to find
64         // the header size. Since the parser is VoidPacketParser, the header size would therefore be
65         // 0
66         static size_type initHeadSize()
67             { return initSize(); }
68     };
69     typedef senf::ConcretePacket<FooPacketType> FooPacket;
70
71     struct BarPacketParser : public senf::PacketParserBase
72     {
73 #       include SENF_FIXED_PARSER()
74
75         SENF_PARSER_FIELD( type,     senf::UInt16Parser );
76         SENF_PARSER_FIELD( length,   senf::Int32Parser  );
77         SENF_PARSER_FIELD( reserved, senf::UInt16Parser );
78
79         SENF_PARSER_INIT() {
80             reserved() << 0xA0A0u;
81         }
82
83         SENF_PARSER_FINALIZE(BarPacketParser);
84     };
85
86     struct BarPacketType
87         : public senf::PacketTypeBase,
88           public senf::PacketTypeMixin<BarPacketType,RegTag>
89     {
90         typedef senf::PacketTypeMixin<BarPacketType,RegTag> mixin;
91         typedef senf::ConcretePacket<BarPacketType> packet;
92         typedef BarPacketParser parser;
93         using mixin::nextPacketRange;
94         using mixin::nextPacketType;
95         using mixin::initSize;
96         using mixin::init;
97         static void dump(packet p, std::ostream & os) {
98             os << "BarPacket:\n"
99                << senf::fieldName("type") << p->type() << "\n"
100                << senf::fieldName("length") << p->length() << "\n";
101         }
102         static void finalize(packet p) {
103             if (p.next(senf::nothrow))
104                 p->type() = senf::PacketRegistry<RegTag>::key(p.next());
105             else
106                 p->type() = -1;
107         }
108         static key_t nextPacketKey(packet p) {
109             return p->type();
110         }
111     };
112     typedef BarPacketType::packet BarPacket;
113
114     namespace reg {
115         senf::PacketRegistry<RegTag>::ScopedRegistrationProxy<FooPacket> registerFoo(1u);
116         senf::PacketRegistry<RegTag>::ScopedRegistrationProxy<BarPacket> registerBar(2u);
117     }
118
119     struct IntAnnotation {
120         boost::uint32_t value;
121     };
122
123     std::ostream & operator<<(std::ostream & os, IntAnnotation const & v)
124     { os << v.value; return os; }
125
126     struct LargeAnnotation {
127         char value[32];
128     };
129
130     std::ostream & operator<<(std::ostream & os, LargeAnnotation const & v)
131     { os << v.value; return os; }
132
133     struct ComplexAnnotation : senf::ComplexAnnotation
134     {
135         ComplexAnnotation() : s("empty"), i(-1) {}
136         std::string s;
137         boost::int32_t i;
138         // padding so the size does not depend on the platform ...
139         struct _ {std::string s;boost::int32_t i;};
140         char __ [32-sizeof(_)];
141     };
142
143     std::ostream & operator<<(std::ostream & os, ComplexAnnotation const & v)
144     { os << "('" << v.s << "' " << v.i << ')'; return os; }
145
146     struct ComplexEmptyAnnotation : senf::ComplexAnnotation
147     {};
148
149     std::ostream & operator<<(std::ostream & os, ComplexEmptyAnnotation const & v)
150     { os << "(empty)"; return os; }
151
152     struct InvalidAnnotation
153     {
154         std::string value;
155     };
156
157     std::ostream & operator<<(std::ostream & os, InvalidAnnotation const & v)
158     { os << v.value; return os; }
159
160 }
161
162 SENF_AUTO_UNIT_TEST(packet)
163 {
164     BOOST_CHECK(! senf::Packet().is<BarPacket>() );
165     senf::Packet packet (FooPacket::create());
166     BarPacket::createAfter(packet);
167
168     BOOST_CHECK_THROW( senf::Packet().as<BarPacket>(), senf::WrapException<std::bad_cast> );
169     BOOST_CHECK_THROW( packet.as<BarPacket>(), senf::WrapException<std::bad_cast> );
170
171     BOOST_REQUIRE( packet );
172     BOOST_CHECK( packet.next() );
173     BOOST_CHECK( ! packet.next().next(senf::nothrow) );
174     BOOST_CHECK( ! packet.next().next(senf::nothrow).is<BarPacket>() );
175     BOOST_CHECK( ! packet.prev(senf::nothrow) );
176     BOOST_CHECK( packet.next().prev() == packet );
177     SENF_CHECK_NOT_EQUAL( packet.next(), packet );
178     BOOST_CHECK_EQUAL( std::distance(packet.data().begin(), packet.next().data().begin()), 4 );
179     BOOST_CHECK_EQUAL( std::distance(packet.data().begin(), packet.data().end()), 12 );
180     BOOST_CHECK_EQUAL( std::distance(packet.next().data().begin(), packet.next().data().end()), 8 );
181     BOOST_CHECK( packet.data().end() == packet.next().data().end() );
182     BOOST_CHECK_EQUAL( packet.size(), 12u );
183     BOOST_CHECK_EQUAL( packet.next().size(), 8u );
184     BOOST_CHECK( packet.is<FooPacket>() );
185     BOOST_CHECK( packet.next().is<BarPacket>() );
186     BOOST_CHECK( packet.first() == packet );
187     BOOST_CHECK( packet.last() == packet.next() );
188
189     BOOST_CHECK( ! packet.is_shared() );
190     {
191         senf::Packet p2 (packet);
192         BOOST_CHECK( packet.is_shared() );
193         BOOST_CHECK( p2.is_shared() );
194     }
195     BOOST_CHECK( ! packet.is_shared() );
196
197     senf::Packet p2 (packet.next());
198     BOOST_CHECK( p2 );
199     BOOST_CHECK( packet.is_shared() );
200     BOOST_CHECK( p2.is_shared() );
201     packet.parseNextAs<FooPacket>();
202     BOOST_CHECK_EQUAL( packet.size(), 12u );
203     BOOST_CHECK_EQUAL( packet.next().size(), 8u );
204     BOOST_CHECK( packet.next().is<FooPacket>() );
205     BOOST_CHECK( ! p2 );
206     BOOST_CHECK( packet.next().as<FooPacket>() );
207
208     p2 = packet.next().clone();
209     BOOST_CHECK( ! packet.is_shared() );
210     BOOST_REQUIRE( p2 );
211     packet.next().append( p2 );
212     BOOST_REQUIRE( packet.next().next() );
213     BOOST_CHECK( packet.next().next().next() );
214     BOOST_CHECK( packet.next().next().next().is<senf::DataPacket>() );
215     BOOST_CHECK_EQUAL( packet.size(), 16u );
216
217     // This calls and checks typeId()
218     BOOST_CHECK_EQUAL( senf::PacketRegistry<RegTag>::key(packet), 1u );
219     packet.next().parseNextAs( senf::PacketRegistry<RegTag>::lookup(2u).factory() );
220     BOOST_CHECK( packet.next().next().is<BarPacket>() );
221
222     std::stringstream s;
223     packet.dump(s);
224     BOOST_CHECK_EQUAL( s.str(),
225                        "Annotations:\n"
226                        "  (anonymous namespace)::IntAnnotation : 0\n"
227                        "BarPacket:\n"
228                        "  type                    : 0\n"
229                        "  length                  : 0\n" );
230
231     packet.finalizeAll();
232     BOOST_CHECK_EQUAL( packet.last().as<BarPacket>()->type(),
233                        BarPacket::Parser::type_t::value_type(-1) );
234     packet.last().append(FooPacket::create());
235     packet.finalizeThis();
236     packet.finalizeTo<BarPacket>();
237     packet.finalizeTo(packet.find<BarPacket>());
238     packet.finalizeAll();
239     BOOST_CHECK_EQUAL( packet.find<BarPacket>()->type(), 1u );
240
241     BOOST_CHECK( packet.factory() == FooPacket::factory() );
242
243     senf::PacketData::byte data[] = { 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
244                                       0x81, 0x82, 0x83 };
245
246     BarPacket::createAfter(packet, data);
247     BOOST_REQUIRE( packet.next() );
248     BOOST_REQUIRE( packet.next().is<BarPacket>() );
249     BOOST_CHECK( packet.last().is<FooPacket>() );
250     BOOST_CHECK_EQUAL( packet.last().rfind<BarPacket>()->type(), 1u );
251     BOOST_CHECK_EQUAL( packet.next().size(), 11u );
252     BOOST_REQUIRE( packet.next().next() );
253     BOOST_CHECK( packet.next().next().is<FooPacket>() );
254     BOOST_CHECK( ! packet.next().next().next(senf::nothrow) );
255     BOOST_CHECK_EQUAL( packet.next().next().data()[0], 0x81u );
256
257     BOOST_CHECK( packet.first().find<FooPacket>() == packet );
258     BOOST_CHECK( packet.last().rfind<BarPacket>() == packet.last().prev() );
259     BOOST_CHECK( packet.find<FooPacket>() == packet );
260     BOOST_CHECK( packet.last().rfind<FooPacket>() == packet.last() );
261     BOOST_CHECK( packet.next<BarPacket>() == packet.next() );
262     BOOST_CHECK( packet.last().prev().prev<FooPacket>() == packet );
263
264     senf::DataPacket::createAfter(packet);
265     BOOST_CHECK_THROW( packet.next().next().next().parseNextAs<BarPacket>(),
266             senf::InvalidPacketChainException );
267
268     SENF_CHECK_NO_THROW( BarPacket::create(senf::noinit).dump(s));
269 }
270
271 SENF_AUTO_UNIT_TEST(concretePacket)
272 {
273     senf::PacketData::byte data[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
274
275     BOOST_CHECK_EQUAL( FooPacket::create().size(), 4u );
276     BOOST_CHECK_EQUAL( FooPacket::create(senf::noinit).size(), 0u );
277     BOOST_CHECK_THROW( FooPacket::create(2u), senf::TruncatedPacketException );
278     // No 'u' suffix here to check, that the disable_if works ...
279     BOOST_CHECK_EQUAL( FooPacket::create(10).size(), 10u );
280     BOOST_CHECK_EQUAL( FooPacket::create(2u,senf::noinit).size(), 2u );
281     BOOST_CHECK_EQUAL( FooPacket::create(data).size(), 6u );
282
283     senf::Packet packet (FooPacket::create());
284
285     BOOST_CHECK_EQUAL( FooPacket::createAfter(packet).size(), 4u );
286     BOOST_CHECK_EQUAL( packet.size(), 8u );
287
288     BOOST_CHECK_EQUAL( FooPacket::createAfter(packet,senf::noinit).size(), 0u );
289     BOOST_CHECK_EQUAL( packet.size(), 4u );
290
291     BOOST_CHECK_THROW( FooPacket::createAfter(packet,2u), senf::TruncatedPacketException );
292     // No 'u' suffix here to check, that the disable_if works ...
293     BOOST_CHECK_EQUAL( FooPacket::createAfter(packet,10).size(), 10u );
294     BOOST_CHECK_EQUAL( packet.size(), 14u );
295
296     BOOST_CHECK_EQUAL( FooPacket::createAfter(packet,2u,senf::noinit).size(), 2u );
297     BOOST_CHECK_EQUAL( packet.size(), 6u );
298
299     BOOST_CHECK_EQUAL( FooPacket::createAfter(packet,data).size(), 6u );
300     BOOST_CHECK_EQUAL( packet.size(), 10u );
301
302     BOOST_CHECK_EQUAL( FooPacket::createBefore(packet).size(), 14u );
303     BOOST_CHECK_EQUAL( packet.size(), 10u );
304
305     BOOST_CHECK_EQUAL( FooPacket::createBefore(packet,senf::noinit).size(), 10u );
306     BOOST_CHECK_EQUAL( packet.size(), 10u );
307
308     BOOST_CHECK_EQUAL( FooPacket::createInsertBefore(packet).size(), 14u );
309     BOOST_CHECK_EQUAL( packet.size(), 10u );
310     BOOST_REQUIRE( packet.prev() );
311     BOOST_CHECK_EQUAL( packet.prev().size(), 14u );
312     BOOST_REQUIRE( packet.prev().prev() );
313     BOOST_CHECK_EQUAL( packet.prev().prev().size(), 14u );
314
315     BOOST_CHECK_EQUAL( FooPacket::createInsertBefore(packet,senf::noinit).size(), 10u );
316     BOOST_CHECK_EQUAL( packet.size(), 10u );
317     BOOST_REQUIRE_NO_THROW( packet.prev().prev().prev() );
318     BOOST_CHECK_THROW( packet.prev().prev().prev().prev(), senf::InvalidPacketChainException );
319     BOOST_CHECK_EQUAL( packet.prev().size(), 10u );
320     BOOST_CHECK_EQUAL( packet.prev().prev().size(), 14u );
321     BOOST_CHECK_EQUAL( packet.prev().prev().prev().size(), 14u );
322
323     SENF_CHECK_NOT_EQUAL( packet.clone(), packet );
324     BOOST_CHECK_EQUAL( BarPacket::create()->reserved(), 0xA0A0u );
325 }
326
327 SENF_AUTO_UNIT_TEST(packetAssign)
328 {
329     BarPacket bar1 (BarPacket::create());
330     BarPacket bar2 (BarPacket::create());
331
332     bar2->type() << 0x2A2Bu;
333     bar1.parser() << bar2;
334
335     BOOST_CHECK_EQUAL( bar1->type(), 0x2A2Bu );
336 }
337
338 SENF_AUTO_UNIT_TEST(packetAnnotation)
339 {
340     typedef senf::detail::AnnotationRegistry Reg;
341
342     senf::Packet packet (FooPacket::create());
343     BarPacket::createAfter(packet);
344
345     ComplexAnnotation & ca (packet.annotation<ComplexAnnotation>());
346
347     BOOST_CHECK_EQUAL( ca.s, "empty" );
348     BOOST_CHECK_EQUAL( ca.i, -1 );
349
350     ca.s = "dead beef";
351     ca.i = 0x12345678;
352     SENF_CHECK_NO_THROW( packet.annotation<IntAnnotation>().value = 0xDEADBEEF );
353
354     senf::Packet p2 (packet.next());
355
356     BOOST_CHECK_EQUAL( p2.annotation<IntAnnotation>().value, 0xDEADBEEFu );
357     BOOST_CHECK_EQUAL( p2.annotation<ComplexAnnotation>().s, "dead beef" );
358     BOOST_CHECK_EQUAL( p2.annotation<ComplexAnnotation>().i, 0x12345678 );
359
360     senf::Packet pClone (packet.clone());
361
362     p2.clearAnnotations();
363     BOOST_CHECK_EQUAL( p2.annotation<ComplexAnnotation>().s, "empty" );
364     BOOST_CHECK_EQUAL( p2.annotation<ComplexAnnotation>().i, -1 );
365     BOOST_CHECK_EQUAL( p2.annotation<IntAnnotation>().value, 0 );
366
367     BOOST_CHECK_EQUAL( pClone.annotation<IntAnnotation>().value, 0xDEADBEEFu );
368     BOOST_CHECK_EQUAL( pClone.annotation<ComplexAnnotation>().s, "dead beef" );
369     BOOST_CHECK_EQUAL( pClone.annotation<ComplexAnnotation>().i, 0x12345678 );
370
371     BOOST_CHECK( Reg::lookup<IntAnnotation>() >= 0 );
372     BOOST_CHECK( Reg::lookup<LargeAnnotation>() < 0 );
373     BOOST_CHECK( Reg::lookup<ComplexAnnotation>() < 0 );
374     BOOST_CHECK( Reg::lookup<ComplexEmptyAnnotation>() < 0 );
375
376     std::stringstream ss;
377     senf::dumpPacketAnnotationRegistry(ss);
378     BOOST_CHECK_EQUAL(
379         ss.str(),
380         "SENF_PACKET_ANNOTATION_SLOTS = 8\n"
381         "SENF_PACKET_ANNOTATION_SLOTSIZE = 16\n"
382         "TYPE                                                      FAST  COMPLEX   SIZE\n"
383         "(anonymous namespace)::ComplexAnnotation                  no    yes         32\n"
384         "(anonymous namespace)::ComplexEmptyAnnotation             no    yes          1\n"
385         "(anonymous namespace)::IntAnnotation                      yes   no           4\n"
386         "(anonymous namespace)::LargeAnnotation                    no    no          32\n" );
387 }
388
389 #ifdef COMPILE_CHECK
390
391 COMPILE_FAIL(invalidAnnotation)
392 {
393 #if 0 // The traits check fails for user defined but trivial constructors so ...
394 #   ifdef BOOST_HAS_TYPE_TRAITS_INTRINSICS
395
396     senf::Packet packet (FooPacket::create());
397     senf::IGNORE( packet.annotation<InvalidAnnotation>() );
398
399 #   else
400 #   endif
401 #endif
402
403     invalid_annotation_check_disabled();
404
405 }
406
407 #endif
408
409 //-/////////////////////////////////////////////////////////////////////////////////////////////////
410 #undef prefix_
411
412 \f
413 // Local Variables:
414 // mode: c++
415 // fill-column: 100
416 // c-file-style: "senf"
417 // indent-tabs-mode: nil
418 // ispell-local-dictionary: "american"
419 // compile-command: "scons -u test"
420 // comment-column: 40
421 // End: