4dbe32925f11dee96155ecf917dbca2f01c81b16
[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 "Packets.hh"
33
34 #include <senf/Utils/auto_unit_test.hh>
35 #include <boost/test/test_tools.hpp>
36
37 #define prefix_
38 ///////////////////////////////cc.p////////////////////////////////////////
39
40 namespace {
41
42     struct RegTag {
43         typedef unsigned key_t;
44     };
45
46     struct FooPacketType 
47         : public senf::PacketTypeBase,
48           public senf::PacketTypeMixin<FooPacketType>
49     {
50         using senf::PacketTypeMixin<FooPacketType>::nextPacketRange;
51         using senf::PacketTypeMixin<FooPacketType>::initSize;
52         using senf::PacketTypeMixin<FooPacketType>::init;
53         static size_type initSize()
54             { return 4u; }
55
56         // We need to implement initHeadSize() to force the mixin to switch into 'fixed-size'
57         // mode. Otherwise, mixin::nextPacketRange() would query the parser for it's size to find
58         // the header size. Since the parser is VoidPacketParser, the header size would therefore be
59         // 0
60         static size_type initHeadSize() 
61             { return initSize(); }
62     };
63     typedef senf::ConcretePacket<FooPacketType> FooPacket;
64
65     struct BarPacketParser : public senf::PacketParserBase
66     {
67 #       include SENF_FIXED_PARSER()
68         
69         SENF_PARSER_FIELD( type,     senf::UInt16Parser );
70         SENF_PARSER_FIELD( length,   senf::Int32Parser  );
71         SENF_PARSER_FIELD( reserved, senf::UInt16Parser );
72
73         SENF_PARSER_INIT() {
74             reserved() << 0xA0A0u;
75         }
76
77         SENF_PARSER_FINALIZE(BarPacketParser);
78     };
79
80     struct BarPacketType 
81         : public senf::PacketTypeBase,
82           public senf::PacketTypeMixin<BarPacketType,RegTag>
83     {
84         typedef senf::PacketTypeMixin<BarPacketType,RegTag> mixin;
85         typedef senf::ConcretePacket<BarPacketType> packet;
86         typedef BarPacketParser parser;
87         using mixin::nextPacketRange;
88         using mixin::nextPacketType;
89         using mixin::initSize;
90         using mixin::init;
91         static void dump(packet p, std::ostream & os) {
92             os << "BarPacket:\n"
93                << "  type: " << p->type() << "\n"
94                << "  length: " << p->length() << "\n";
95         }
96         static void finalize(packet p) {
97             if (p.next(senf::nothrow))
98                 p->type() = senf::PacketRegistry<RegTag>::key(p.next());
99             else
100                 p->type() = -1;
101         }
102         static key_t nextPacketKey(packet p) {
103             return p->type();
104         }
105     };
106     typedef BarPacketType::packet BarPacket;
107
108     namespace reg {
109         senf::PacketRegistry<RegTag>::RegistrationProxy<FooPacket> registerFoo(1u);
110         senf::PacketRegistry<RegTag>::RegistrationProxy<BarPacket> registerBar(2u);
111     }
112
113     struct IntAnnotation {
114         unsigned value;
115     };
116
117     std::ostream & operator<<(std::ostream & os, IntAnnotation const & v)
118     { os << v.value; return os; }
119     
120     struct LargeAnnotation {
121         char value[32];
122     };
123
124     std::ostream & operator<<(std::ostream & os, LargeAnnotation const & v)
125     { os << v.value; return os; }
126
127     struct ComplexAnnotation : senf::ComplexAnnotation
128     {
129         ComplexAnnotation() : s(), i() {}
130         std::string s;
131         int i;
132     };
133
134     std::ostream & operator<<(std::ostream & os, ComplexAnnotation const & v)
135     { os << "('" << v.s << "' " << v.i << ')'; return os; }
136
137     struct ComplexEmptyAnnotation : senf::ComplexAnnotation
138     {};
139
140     std::ostream & operator<<(std::ostream & os, ComplexEmptyAnnotation const & v)
141     { os << "(empty)"; return os; }
142
143     struct InvalidAnnotation
144     {
145         std::string value;
146     };
147
148     std::ostream & operator<<(std::ostream & os, InvalidAnnotation const & v)
149     { os << v.value; return os; }
150
151 }
152
153 BOOST_AUTO_UNIT_TEST(packet)
154 {
155     senf::Packet packet (FooPacket::create());    
156     BarPacket::createAfter(packet);
157
158     BOOST_REQUIRE( packet );
159     BOOST_CHECK( packet.next() );
160     BOOST_CHECK( ! packet.next().next(senf::nothrow) );
161     BOOST_CHECK( ! packet.prev(senf::nothrow) );
162     BOOST_CHECK( packet.next().prev() == packet );
163     BOOST_CHECK( packet.next() != packet );
164     BOOST_CHECK_EQUAL( std::distance(packet.data().begin(), packet.next().data().begin()), 4 );
165     BOOST_CHECK_EQUAL( std::distance(packet.data().begin(), packet.data().end()), 12 );
166     BOOST_CHECK_EQUAL( std::distance(packet.next().data().begin(), packet.next().data().end()), 8 );
167     BOOST_CHECK( packet.data().end() == packet.next().data().end() );
168     BOOST_CHECK_EQUAL( packet.size(), 12u );
169     BOOST_CHECK_EQUAL( packet.next().size(), 8u );
170     BOOST_CHECK( packet.is<FooPacket>() );
171     BOOST_CHECK( packet.next().is<BarPacket>() );
172     BOOST_CHECK( packet.first() == packet );
173     BOOST_CHECK( packet.last() == packet.next() );
174     
175     senf::Packet p2 (packet.next());
176     BOOST_CHECK( p2 );
177     packet.parseNextAs<FooPacket>();
178     BOOST_CHECK_EQUAL( packet.size(), 12u );
179     BOOST_CHECK_EQUAL( packet.next().size(), 8u );
180     BOOST_CHECK( packet.next().is<FooPacket>() );
181     BOOST_CHECK( ! p2 );
182     BOOST_CHECK( packet.next().as<FooPacket>() );
183     
184     p2 = packet.next().clone();
185     BOOST_REQUIRE( p2 );
186     packet.next().append( p2 );
187     BOOST_REQUIRE( packet.next().next() );
188     BOOST_CHECK( packet.next().next().next() );
189     BOOST_CHECK( packet.next().next().next().is<senf::DataPacket>() );
190     BOOST_CHECK_EQUAL( packet.size(), 16u );
191
192     // This calls and checks typeId()
193     BOOST_CHECK_EQUAL( senf::PacketRegistry<RegTag>::key(packet), 1u );
194     packet.next().parseNextAs( senf::PacketRegistry<RegTag>::lookup(2u).factory() );
195     BOOST_CHECK( packet.next().next().is<BarPacket>() );
196     
197     std::stringstream s;
198     packet.dump(s);
199     BOOST_CHECK_EQUAL( s.str(), 
200                        "Annotations:\n"
201                        "  (anonymous namespace)::ComplexAnnotation: no value\n"
202                        "  (anonymous namespace)::IntAnnotation: 0\n"
203                        "BarPacket:\n"
204                        "  type: 0\n"
205                        "  length: 0\n" );
206     
207     packet.finalizeAll();
208     BOOST_CHECK_EQUAL( packet.last().as<BarPacket>()->type(), 
209                        BarPacket::Parser::type_t::value_type(-1) );
210     packet.last().append(FooPacket::create());
211     packet.finalizeThis();
212     packet.finalizeTo<BarPacket>();
213     packet.finalizeTo(packet.find<BarPacket>());
214     packet.finalizeAll();
215     BOOST_CHECK_EQUAL( packet.find<BarPacket>()->type(), 1u );
216
217     BOOST_CHECK( packet.factory() == FooPacket::factory() );
218
219     senf::PacketData::byte data[] = { 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
220                                       0x81, 0x82, 0x83 };
221
222     BarPacket::createAfter(packet, data);
223     BOOST_REQUIRE( packet.next() );
224     BOOST_REQUIRE( packet.next().is<BarPacket>() );
225     BOOST_CHECK( packet.last().is<FooPacket>() );
226     BOOST_CHECK_EQUAL( packet.last().rfind<BarPacket>()->type(), 1u );
227     BOOST_CHECK_EQUAL( packet.next().size(), 11u );
228     BOOST_REQUIRE( packet.next().next() );
229     BOOST_CHECK( packet.next().next().is<FooPacket>() );
230     BOOST_CHECK( ! packet.next().next().next(senf::nothrow) );
231     BOOST_CHECK_EQUAL( packet.next().next().data()[0], 0x81u );
232
233     BOOST_CHECK( packet.first().find<FooPacket>() == packet );
234     BOOST_CHECK( packet.last().rfind<BarPacket>() == packet.last().prev() );
235     BOOST_CHECK( packet.find<FooPacket>() == packet );
236     BOOST_CHECK( packet.last().rfind<FooPacket>() == packet.last() );
237     BOOST_CHECK( packet.next<BarPacket>() == packet.next() );
238     BOOST_CHECK( packet.last().prev().prev<FooPacket>() == packet );
239     
240     senf::DataPacket::createAfter(packet);
241     BOOST_CHECK_THROW( packet.next().next().next().parseNextAs<BarPacket>(),
242             senf::InvalidPacketChainException );
243
244     SENF_CHECK_NO_THROW( BarPacket::create(senf::noinit).dump(s));
245 }
246
247 BOOST_AUTO_UNIT_TEST(concretePacket)
248 {
249     senf::PacketData::byte data[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
250
251     BOOST_CHECK_EQUAL( FooPacket::create().size(), 4u );
252     BOOST_CHECK_EQUAL( FooPacket::create(senf::noinit).size(), 0u );
253     BOOST_CHECK_THROW( FooPacket::create(2u), senf::TruncatedPacketException );
254     // No 'u' suffix here to check, that the disable_if works ...
255     BOOST_CHECK_EQUAL( FooPacket::create(10).size(), 10u );
256     BOOST_CHECK_EQUAL( FooPacket::create(2u,senf::noinit).size(), 2u );
257     BOOST_CHECK_EQUAL( FooPacket::create(data).size(), 6u );
258
259     senf::Packet packet (FooPacket::create());
260
261     BOOST_CHECK_EQUAL( FooPacket::createAfter(packet).size(), 4u );
262     BOOST_CHECK_EQUAL( packet.size(), 8u );
263
264     BOOST_CHECK_EQUAL( FooPacket::createAfter(packet,senf::noinit).size(), 0u );
265     BOOST_CHECK_EQUAL( packet.size(), 4u );
266
267     BOOST_CHECK_THROW( FooPacket::createAfter(packet,2u), senf::TruncatedPacketException );
268     // No 'u' suffix here to check, that the disable_if works ...
269     BOOST_CHECK_EQUAL( FooPacket::createAfter(packet,10).size(), 10u );
270     BOOST_CHECK_EQUAL( packet.size(), 14u );
271     
272     BOOST_CHECK_EQUAL( FooPacket::createAfter(packet,2u,senf::noinit).size(), 2u );
273     BOOST_CHECK_EQUAL( packet.size(), 6u );
274     
275     BOOST_CHECK_EQUAL( FooPacket::createAfter(packet,data).size(), 6u );
276     BOOST_CHECK_EQUAL( packet.size(), 10u );
277     
278     BOOST_CHECK_EQUAL( FooPacket::createBefore(packet).size(), 14u );
279     BOOST_CHECK_EQUAL( packet.size(), 10u );
280
281     BOOST_CHECK_EQUAL( FooPacket::createBefore(packet,senf::noinit).size(), 10u );
282     BOOST_CHECK_EQUAL( packet.size(), 10u );
283
284     BOOST_CHECK( packet.clone() != packet );
285     BOOST_CHECK_EQUAL( BarPacket::create()->reserved(), 0xA0A0u );
286 }
287
288 BOOST_AUTO_UNIT_TEST(packetAssign)
289 {
290     BarPacket bar1 (BarPacket::create());
291     BarPacket bar2 (BarPacket::create());
292
293     bar2->type() << 0x2A2Bu;
294     bar1.parser() << bar2;
295     
296     BOOST_CHECK_EQUAL( bar1->type(), 0x2A2Bu );
297 }
298
299 BOOST_AUTO_UNIT_TEST(packetAnnotation)
300 {
301     senf::Packet packet (FooPacket::create());
302     BarPacket::createAfter(packet);
303
304     ComplexAnnotation & ca (packet.annotation<ComplexAnnotation>());
305     ca.s = "dead beef";
306     ca.i = 0x12345678;
307     SENF_CHECK_NO_THROW( packet.annotation<IntAnnotation>().value = 0xDEADBEEF );
308
309     senf::Packet p2 (packet.next());
310
311     BOOST_CHECK_EQUAL( p2.annotation<IntAnnotation>().value, 0xDEADBEEFu );
312     BOOST_CHECK_EQUAL( p2.annotation<ComplexAnnotation>().s, "dead beef" );
313     BOOST_CHECK_EQUAL( p2.annotation<ComplexAnnotation>().i, 0x12345678 );
314
315     BOOST_CHECK( senf::detail::AnnotationIndexer<IntAnnotation>::Small );
316     BOOST_CHECK( ! senf::detail::AnnotationIndexer<LargeAnnotation>::Small );
317     BOOST_CHECK( ! senf::detail::AnnotationIndexer<ComplexAnnotation>::Small );
318     BOOST_CHECK( ! senf::detail::AnnotationIndexer<ComplexEmptyAnnotation>::Small );
319 }
320
321 #ifdef COMPILE_CHECK
322
323 COMPILE_FAIL(invalidAnnotation)
324 {
325 #if 0 // The traits check fails for user defined but trivial constructors so ...
326 #   ifdef BOOST_HAS_TYPE_TRAITS_INTRINSICS
327
328     senf::Packet packet (FooPacket::create());
329     (void) packet.annotation<InvalidAnnotation>();
330
331 #   else
332 #   endif
333 #endif
334
335     invalid_annotation_check_disabled();
336
337 }
338
339 #endif
340
341 ///////////////////////////////cc.e////////////////////////////////////////
342 #undef prefix_
343
344 \f
345 // Local Variables:
346 // mode: c++
347 // fill-column: 100
348 // c-file-style: "senf"
349 // indent-tabs-mode: nil
350 // ispell-local-dictionary: "american"
351 // compile-command: "scons -u test"
352 // comment-column: 40
353 // End: