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