79ed5a21e278339c829911c131d41635d249a614
[debian/gnuradio] / mblock / src / lib / qa_mblock_prims.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2006,2007 Free Software Foundation, Inc.
4  * 
5  * This file is part of GNU Radio
6  * 
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  * 
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Radio; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <qa_mblock_prims.h>
28 #include <cppunit/TestAssert.h>
29 #include <mb_mblock.h>
30 #include <mb_runtime.h>
31 #include <mb_protocol_class.h>
32 #include <mb_exception.h>
33 #include <mb_msg_queue.h>
34 #include <mb_message.h>
35 #include <mb_mblock_impl.h>
36 #include <mb_msg_accepter.h>
37 #include <stdio.h>
38
39 static pmt_t s_cs = pmt_intern("cs");
40 static pmt_t s_debug = pmt_intern("debug");
41 static pmt_t s_in = pmt_intern("in");
42 static pmt_t s_out = pmt_intern("out");
43   
44
45 // ================================================================
46
47 class dp_1 : public mb_mblock
48 {
49 public:
50   dp_1();
51   ~dp_1();
52 };
53
54 dp_1::dp_1()
55 {
56 }
57
58 dp_1::~dp_1(){}
59
60 // ----------------------------------------------------------------
61
62 class dp_2 : public mb_mblock
63 {
64 public:
65   dp_2();
66   ~dp_2();
67 };
68
69 dp_2::dp_2()
70 {
71   define_port("cs", "cs-protocol", false, mb_port::EXTERNAL);
72 }
73
74 dp_2::~dp_2(){}
75
76 // ----------------------------------------------------------------
77
78 class dp_3 : public mb_mblock
79 {
80 public:
81   dp_3();
82   ~dp_3();
83 };
84
85 dp_3::dp_3()
86 {
87   define_port("cs", "cs-protocol", false, mb_port::EXTERNAL);
88   define_port("cs", "cs-protocol", false, mb_port::EXTERNAL);   // duplicate def
89 }
90
91 dp_3::~dp_3(){}
92
93 // ----------------------------------------------------------------
94
95 void
96 qa_mblock_prims::test_define_ports()
97 {
98   // std::vector<mb_port_sptr>  intf;
99
100   mb_mblock_sptr        mb1 = mb_mblock_sptr(new dp_1());
101   // intf = mb1->peer_interface();
102   // CPPUNIT_ASSERT_EQUAL(size_t(0), intf.size());
103
104   // raises runtime_error because of unknown protocol "cs-protocol"
105   CPPUNIT_ASSERT_THROW(mb_mblock_sptr(new dp_2()), std::runtime_error);
106
107   // define the protocol class
108   pmt_t pc = mb_make_protocol_class(pmt_intern("cs-protocol"),
109                                     pmt_list2(pmt_intern("start"),
110                                               pmt_intern("stop")),
111                                     PMT_NIL);
112
113   // std::cout << "pc = " << pc << '\n';
114
115   mb_mblock_sptr mb2 = mb_mblock_sptr(new dp_2());
116
117   // raises pmt_exception because of duplicate port definition of "cs"
118   CPPUNIT_ASSERT_THROW(mb_mblock_sptr(new dp_3()), mbe_duplicate_port);
119 }
120
121 // ================================================================
122
123 class dc_0 : public mb_mblock
124 {
125 public:
126   dc_0();
127   ~dc_0();
128 };
129
130 dc_0::dc_0()
131 {
132 }
133
134 dc_0::~dc_0() {}
135
136 // ----------------------------------------------------------------
137
138 class dc_ok : public mb_mblock
139 {
140 public:
141   dc_ok();
142   ~dc_ok();
143 };
144
145 dc_ok::dc_ok()
146 {
147   define_component("c0", mb_mblock_sptr(new dc_0()));
148   define_component("c1", mb_mblock_sptr(new dc_0()));
149   define_component("c2", mb_mblock_sptr(new dc_0()));
150 }
151
152 dc_ok::~dc_ok(){}
153
154 // ----------------------------------------------------------------
155
156 class dc_not_ok : public mb_mblock
157 {
158 public:
159   dc_not_ok();
160   ~dc_not_ok();
161 };
162
163 dc_not_ok::dc_not_ok()
164   : mb_mblock()
165 {
166   define_component("c0", mb_mblock_sptr(new dc_0()));
167   define_component("c0", mb_mblock_sptr(new dc_0()));   // duplicate name
168 }
169
170 dc_not_ok::~dc_not_ok(){}
171
172 // ----------------------------------------------------------------
173
174 void
175 qa_mblock_prims::test_define_components()
176 {
177   mb_mblock_sptr        mb1 = mb_mblock_sptr(new dc_ok());      // OK
178
179   // raises pmt_exception because of duplicate component definition of "c0"
180   CPPUNIT_ASSERT_THROW(mb_mblock_sptr(new dc_not_ok()), mbe_duplicate_component);
181 }
182
183 // ================================================================
184
185 class tc_norm : public mb_mblock
186 {
187 public:
188   tc_norm(){
189     define_port("data", "i/o", false, mb_port::EXTERNAL);
190     define_port("norm", "i/o", false, mb_port::EXTERNAL);
191     define_port("conj", "i/o", true,  mb_port::EXTERNAL);
192     define_port("int",  "i/o", false, mb_port::INTERNAL);
193   }
194
195   ~tc_norm();
196 };
197
198 tc_norm::~tc_norm(){}
199
200 ////////////////////////////////////////////////////////////////
201
202 class tc_0 : public mb_mblock
203 {
204 public:
205   tc_0(){
206     define_port("norm", "i/o", false, mb_port::EXTERNAL);
207     define_port("conj", "i/o", true,  mb_port::EXTERNAL);
208     define_port("int",  "i/o", false, mb_port::INTERNAL);
209
210     define_component("c0", mb_mblock_sptr(new tc_norm()));
211     define_component("c1", mb_mblock_sptr(new tc_norm()));
212     define_component("c2", mb_mblock_sptr(new tc_norm()));
213     define_component("c3", mb_mblock_sptr(new tc_norm()));
214     define_component("c4", mb_mblock_sptr(new tc_norm()));
215     define_component("c5", mb_mblock_sptr(new tc_norm()));
216
217     // OK
218     connect("c0", "norm", "c1", "conj");
219
220     // No:  No such component name
221     CPPUNIT_ASSERT_THROW(connect("foo", "data", "c1", "norm"), mbe_no_such_component);
222
223     // No:  No such port name
224     CPPUNIT_ASSERT_THROW(connect("c0", "data", "c1", "foo"), mbe_no_such_port);
225
226     // No:  already connected
227     CPPUNIT_ASSERT_THROW(connect("c0", "norm", "c2", "data"), mbe_already_connected);
228
229     // No:  already connected
230     CPPUNIT_ASSERT_THROW(connect("c2", "data", "c0", "norm"), mbe_already_connected);
231
232     // No: incompatible ports
233     CPPUNIT_ASSERT_THROW(connect("c1", "norm", "c2", "norm"), mbe_incompatible_ports);
234
235     // OK
236     connect("c1", "norm", "c2", "conj");
237
238     // No: No such port name
239     CPPUNIT_ASSERT_THROW(connect("c2", "norm", "self", "foo"), mbe_no_such_port);
240
241     // No: can't connect to child's internal port
242     CPPUNIT_ASSERT_THROW(connect("c0", "conj", "c2", "int"), mbe_no_such_port);
243
244     // No: can't connect to our own external port
245     CPPUNIT_ASSERT_THROW(connect("self", "norm", "c0", "conj"), mbe_invalid_port_type);
246
247     // OK:  connecting to one of our internal ports
248     connect("self", "int", "c3", "conj");
249
250     // =====  Now test disconnecting some stuff =====
251
252     // Confirm we're already connected
253     CPPUNIT_ASSERT_THROW(connect("self", "int", "c3", "conj"), mbe_already_connected);
254
255     int nc = nconnections();
256     disconnect("self", "int", "c3", "conj");    // disconnect
257     CPPUNIT_ASSERT_EQUAL(nc-1, nconnections());
258     
259     connect("self", "int", "c3", "conj");       // reconnect
260     CPPUNIT_ASSERT_EQUAL(nc, nconnections());
261
262     // confirm we're already connected
263     CPPUNIT_ASSERT_THROW(connect("self", "int", "c3", "conj"), mbe_already_connected);
264
265
266     connect("c0", "conj", "c5", "data");
267     connect("c4", "norm", "c5", "conj");
268     connect("c4", "conj", "c5", "norm");
269
270     nc = nconnections();
271     disconnect_component("c4");
272     CPPUNIT_ASSERT_EQUAL(nc-2, nconnections());
273
274     disconnect_component("c5");
275     CPPUNIT_ASSERT_EQUAL(nc-3, nconnections());
276
277     disconnect_all();
278     CPPUNIT_ASSERT_EQUAL(0, nconnections());
279
280   }
281
282   ~tc_0();
283 };
284
285 tc_0::~tc_0(){}
286
287 ////////////////////////////////////////////////////////////////
288
289 class tc_1 : public mb_mblock
290 {
291 public:
292   tc_1(){
293     define_component("c0", mb_mblock_sptr(new tc_norm()));
294     define_component("c1", mb_mblock_sptr(new tc_norm()));
295
296     connect("c0", "norm", "c1", "conj");
297   }
298
299   ~tc_1();
300 };
301
302 tc_1::~tc_1(){}
303
304 ////////////////////////////////////////////////////////////////
305
306 void
307 qa_mblock_prims::test_connect()
308 {
309   // define the protocol class
310   mb_make_protocol_class(pmt_intern("data"),                    // name of class
311                          pmt_list1(pmt_intern("data")),         // in
312                          PMT_NIL);                              // out
313
314   mb_make_protocol_class(pmt_intern("i/o"),                     // name of class
315                          pmt_list1(pmt_intern("in")),           // in
316                          pmt_list1(pmt_intern("out")));         // out
317
318   mb_mblock_sptr        mb0 = mb_mblock_sptr(new tc_0());
319 }
320
321 ////////////////////////////////////////////////////////////////
322
323 void
324 qa_mblock_prims::test_msg_queue()
325 {
326   mb_msg_queue  q;
327
328   // check initial state
329   CPPUNIT_ASSERT(q.get_highest_pri_msg_nowait() == 0);
330
331   CPPUNIT_ASSERT(MB_NPRI >= 5); // sanity check for this test
332
333   // insert three messages at the same pri and ensure that they come out in order
334   //                       signal       data          metadata     pri
335   q.insert(mb_make_message(PMT_NIL, pmt_from_long(0), PMT_NIL, MB_PRI_BEST + 2));
336   q.insert(mb_make_message(PMT_NIL, pmt_from_long(1), PMT_NIL, MB_PRI_BEST + 2));
337   q.insert(mb_make_message(PMT_NIL, pmt_from_long(2), PMT_NIL, MB_PRI_BEST + 2));
338   
339   CPPUNIT_ASSERT_EQUAL(0L, pmt_to_long(q.get_highest_pri_msg_nowait()->data()));
340   CPPUNIT_ASSERT_EQUAL(1L, pmt_to_long(q.get_highest_pri_msg_nowait()->data()));
341   CPPUNIT_ASSERT_EQUAL(2L, pmt_to_long(q.get_highest_pri_msg_nowait()->data()));
342
343   CPPUNIT_ASSERT(q.get_highest_pri_msg_nowait() == 0);
344
345
346   // insert messages of different priorities in pseudo-random order
347   //                       signal   data     metadata     pri
348   q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 3));
349   q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 2));
350   q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 4));
351   q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 0));
352   q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 1));
353   q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 3));
354   q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 2));
355   q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 4));
356   q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 0));
357   q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 1));
358
359   // confirm that they come out in order
360   CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 0, q.get_highest_pri_msg_nowait()->priority());
361   CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 0, q.get_highest_pri_msg_nowait()->priority());
362   CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 1, q.get_highest_pri_msg_nowait()->priority());
363   CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 1, q.get_highest_pri_msg_nowait()->priority());
364   CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 2, q.get_highest_pri_msg_nowait()->priority());
365   CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 2, q.get_highest_pri_msg_nowait()->priority());
366   CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 3, q.get_highest_pri_msg_nowait()->priority());
367   CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 3, q.get_highest_pri_msg_nowait()->priority());
368   CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 4, q.get_highest_pri_msg_nowait()->priority());
369   CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 4, q.get_highest_pri_msg_nowait()->priority());
370   
371   // check final state
372   CPPUNIT_ASSERT(q.get_highest_pri_msg_nowait() == 0);
373 }
374
375 ////////////////////////////////////////////////////////////////
376
377 void
378 qa_mblock_prims::test_make_accepter()
379 {
380   // create a block
381   mb_mblock_sptr mb = mb_mblock_sptr(new dp_2());
382
383   // use "internal use only" method...
384   mb_msg_accepter_sptr accepter = mb->impl()->make_accepter("cs");
385
386   // Now push a few messages into it...
387   //          signal       data          metadata     pri
388   (*accepter)(PMT_NIL, pmt_from_long(0), PMT_NIL, MB_PRI_BEST + 2);
389   (*accepter)(PMT_NIL, pmt_from_long(1), PMT_NIL, MB_PRI_BEST + 2);
390   (*accepter)(PMT_NIL, pmt_from_long(2), PMT_NIL, MB_PRI_BEST + 2);
391
392   // try to pull them out
393
394   pmt_t cs = pmt_intern("cs");
395
396   mb_message_sptr msg = mb->impl()->msgq().get_highest_pri_msg_nowait();
397   CPPUNIT_ASSERT(pmt_eq(cs, msg->port_id()));         // confirm that port_id is set
398   CPPUNIT_ASSERT_EQUAL(0L, pmt_to_long(msg->data())); // and that data is correct
399
400   CPPUNIT_ASSERT_EQUAL(1L, pmt_to_long(mb->impl()->msgq().get_highest_pri_msg_nowait()->data()));
401   CPPUNIT_ASSERT_EQUAL(2L, pmt_to_long(mb->impl()->msgq().get_highest_pri_msg_nowait()->data()));
402 }