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