Convert gr-audio-portaudio to Boost via gruel
[debian/gnuradio] / mblock / src / lib / qa_mblock_prims.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2006,2007,2008 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 3, 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 <mblock/mblock.h>
30 #include <mblock/runtime.h>
31 #include <mblock/protocol_class.h>
32 #include <mblock/exception.h>
33 #include <mblock/msg_queue.h>
34 #include <mblock/message.h>
35 #include <mb_mblock_impl.h>
36 #include <mblock/msg_accepter.h>
37 #include <mblock/class_registry.h>
38 #include <stdio.h>
39
40 using namespace pmt;
41
42 static pmt_t s_cs = pmt_intern("cs");
43 static pmt_t s_debug = pmt_intern("debug");
44 static pmt_t s_in = pmt_intern("in");
45 static pmt_t s_out = pmt_intern("out");
46   
47
48 // ================================================================
49
50 class dp_1 : public mb_mblock
51 {
52 public:
53   dp_1(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
54   ~dp_1();
55 };
56
57 dp_1::dp_1(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
58   : mb_mblock(runtime, instance_name, user_arg)
59 {
60 }
61
62 dp_1::~dp_1(){}
63
64 REGISTER_MBLOCK_CLASS(dp_1);
65
66 // ----------------------------------------------------------------
67
68 class dp_2 : public mb_mblock
69 {
70 public:
71   dp_2(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
72   ~dp_2();
73 };
74
75 dp_2::dp_2(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
76   : mb_mblock(runtime, instance_name, user_arg)
77 {
78   define_port("cs", "cs-protocol", false, mb_port::EXTERNAL);
79 }
80
81 dp_2::~dp_2(){}
82
83 REGISTER_MBLOCK_CLASS(dp_2);
84
85 // ----------------------------------------------------------------
86
87 class dp_3 : public mb_mblock
88 {
89 public:
90   dp_3(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
91   ~dp_3();
92 };
93
94 dp_3::dp_3(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
95   : mb_mblock(runtime, instance_name, user_arg)
96 {
97   define_port("cs", "cs-protocol", false, mb_port::EXTERNAL);
98   define_port("cs", "cs-protocol", false, mb_port::EXTERNAL);   // duplicate def
99 }
100
101 dp_3::~dp_3(){}
102
103 REGISTER_MBLOCK_CLASS(dp_3);
104
105 // ----------------------------------------------------------------
106
107 void
108 qa_mblock_prims::test_define_ports()
109 {
110   
111   mb_runtime_sptr rts = mb_make_runtime();
112   mb_runtime *rt = rts.get();
113   
114   // Should work
115   mb_mblock_sptr  mb1 = mb_mblock_sptr(new dp_1(rt, "top", PMT_F));
116
117   // raises runtime_error because of unknown protocol "cs-protocol"
118   CPPUNIT_ASSERT_THROW(mb_mblock_sptr(new dp_2(rt, "top", PMT_F)),
119                        std::runtime_error);
120
121   // define the protocol class
122   pmt_t pc = mb_make_protocol_class(pmt_intern("cs-protocol"),
123                                     pmt_list2(pmt_intern("start"),
124                                               pmt_intern("stop")),
125                                     PMT_NIL);
126
127   // std::cout << "pc = " << pc << '\n';
128
129   mb_mblock_sptr mb2 = mb_mblock_sptr(new dp_2(rt, "top", PMT_F));
130
131   // raises pmt_exception because of duplicate port definition of "cs"
132   CPPUNIT_ASSERT_THROW(mb_mblock_sptr(new dp_3(rt, "top", PMT_F)),
133                        mbe_duplicate_port);
134 }
135
136 // ================================================================
137
138 class dc_0 : public mb_mblock
139 {
140 public:
141   dc_0(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
142   ~dc_0();
143 };
144
145 dc_0::dc_0(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
146   : mb_mblock(runtime, instance_name, user_arg)
147 {
148 }
149
150 dc_0::~dc_0() {}
151
152 REGISTER_MBLOCK_CLASS(dc_0);
153
154 // ----------------------------------------------------------------
155
156 class dc_ok : public mb_mblock
157 {
158 public:
159   dc_ok(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
160   ~dc_ok();
161 };
162
163 dc_ok::dc_ok(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
164   : mb_mblock(runtime, instance_name, user_arg)
165 {
166   define_component("c0", "dc_0");
167   define_component("c1", "dc_0");
168   define_component("c2", "dc_0");
169 }
170
171 dc_ok::~dc_ok(){}
172
173 REGISTER_MBLOCK_CLASS(dc_ok);
174
175 // ----------------------------------------------------------------
176
177 class dc_not_ok : public mb_mblock
178 {
179 public:
180   dc_not_ok(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg);
181   ~dc_not_ok();
182 };
183
184 dc_not_ok::dc_not_ok(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
185   : mb_mblock(runtime, instance_name, user_arg)
186 {
187   define_component("c0", "dc_0");
188   define_component("c0", "dc_0");       // duplicate name
189 }
190
191 dc_not_ok::~dc_not_ok(){}
192
193 REGISTER_MBLOCK_CLASS(dc_not_ok);
194
195 // ----------------------------------------------------------------
196
197 void
198 qa_mblock_prims::test_define_components()
199 {
200   mb_runtime_sptr rts = mb_make_runtime();
201   mb_runtime *rt = rts.get();
202   
203   // Should work
204   mb_mblock_sptr  mb1 = mb_mblock_sptr(new dc_ok(rt, "top", PMT_F));
205
206   // raises pmt_exception because of duplicate component definition of "c0"
207   CPPUNIT_ASSERT_THROW(mb_mblock_sptr(new dc_not_ok(rt, "top", PMT_F)),
208                        mbe_duplicate_component);
209 }
210
211 // ================================================================
212
213 class tc_norm : public mb_mblock
214 {
215 public:
216   tc_norm(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
217     : mb_mblock(runtime, instance_name, user_arg)
218   {
219     define_port("data", "i/o", false, mb_port::EXTERNAL);
220     define_port("norm", "i/o", false, mb_port::EXTERNAL);
221     define_port("conj", "i/o", true,  mb_port::EXTERNAL);
222     define_port("int",  "i/o", false, mb_port::INTERNAL);
223   }
224
225   ~tc_norm();
226 };
227
228 tc_norm::~tc_norm(){}
229
230 REGISTER_MBLOCK_CLASS(tc_norm);
231
232 ////////////////////////////////////////////////////////////////
233
234 class tc_0 : public mb_mblock
235 {
236 public:
237   tc_0(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
238     : mb_mblock(runtime, instance_name, user_arg)
239   {
240     define_port("norm", "i/o", false, mb_port::EXTERNAL);
241     define_port("conj", "i/o", true,  mb_port::EXTERNAL);
242     define_port("int",  "i/o", false, mb_port::INTERNAL);
243
244     define_component("c0", "tc_norm");
245     define_component("c1", "tc_norm");
246     define_component("c2", "tc_norm");
247     define_component("c3", "tc_norm");
248     define_component("c4", "tc_norm");
249     define_component("c5", "tc_norm");
250
251     // OK
252     connect("c0", "norm", "c1", "conj");
253
254     // No:  No such component name
255     CPPUNIT_ASSERT_THROW(connect("foo", "data", "c1", "norm"), mbe_no_such_component);
256
257     // No:  No such port name
258     CPPUNIT_ASSERT_THROW(connect("c0", "data", "c1", "foo"), mbe_no_such_port);
259
260     // No:  already connected
261     CPPUNIT_ASSERT_THROW(connect("c0", "norm", "c2", "data"), mbe_already_connected);
262
263     // No:  already connected
264     CPPUNIT_ASSERT_THROW(connect("c2", "data", "c0", "norm"), mbe_already_connected);
265
266     // No: incompatible ports
267     CPPUNIT_ASSERT_THROW(connect("c1", "norm", "c2", "norm"), mbe_incompatible_ports);
268
269     // OK
270     connect("c1", "norm", "c2", "conj");
271
272     // No: No such port name
273     CPPUNIT_ASSERT_THROW(connect("c2", "norm", "self", "foo"), mbe_no_such_port);
274
275     // No: can't connect to child's internal port
276     CPPUNIT_ASSERT_THROW(connect("c0", "conj", "c2", "int"), mbe_no_such_port);
277
278     // No: can't connect to our own external port
279     CPPUNIT_ASSERT_THROW(connect("self", "norm", "c0", "conj"), mbe_invalid_port_type);
280
281     // OK:  connecting to one of our internal ports
282     connect("self", "int", "c3", "conj");
283
284     // =====  Now test disconnecting some stuff =====
285
286     // Confirm we're already connected
287     CPPUNIT_ASSERT_THROW(connect("self", "int", "c3", "conj"), mbe_already_connected);
288
289     int nc = nconnections();
290     disconnect("self", "int", "c3", "conj");    // disconnect
291     CPPUNIT_ASSERT_EQUAL(nc-1, nconnections());
292     
293     connect("self", "int", "c3", "conj");       // reconnect
294     CPPUNIT_ASSERT_EQUAL(nc, nconnections());
295
296     // confirm we're already connected
297     CPPUNIT_ASSERT_THROW(connect("self", "int", "c3", "conj"), mbe_already_connected);
298
299
300     connect("c0", "conj", "c5", "data");
301     connect("c4", "norm", "c5", "conj");
302     connect("c4", "conj", "c5", "norm");
303
304     nc = nconnections();
305     disconnect_component("c4");
306     CPPUNIT_ASSERT_EQUAL(nc-2, nconnections());
307
308     disconnect_component("c5");
309     CPPUNIT_ASSERT_EQUAL(nc-3, nconnections());
310
311     disconnect_all();
312     CPPUNIT_ASSERT_EQUAL(0, nconnections());
313
314   }
315
316   ~tc_0();
317 };
318
319 tc_0::~tc_0(){}
320
321 REGISTER_MBLOCK_CLASS(tc_0);
322
323 ////////////////////////////////////////////////////////////////
324
325 class tc_1 : public mb_mblock
326 {
327 public:
328   tc_1(mb_runtime *runtime, const std::string &instance_name, pmt_t user_arg)
329     : mb_mblock(runtime, instance_name, user_arg)
330   {
331     define_component("c0", "tc_norm");
332     define_component("c1", "tc_norm");
333
334     connect("c0", "norm", "c1", "conj");
335   }
336
337   ~tc_1();
338 };
339
340 tc_1::~tc_1(){}
341
342 REGISTER_MBLOCK_CLASS(tc_1);
343
344 ////////////////////////////////////////////////////////////////
345
346 void
347 qa_mblock_prims::test_connect()
348 {
349   // define the protocol class
350   mb_make_protocol_class(pmt_intern("data"),                    // name of class
351                          pmt_list1(pmt_intern("data")),         // in
352                          PMT_NIL);                              // out
353
354   mb_make_protocol_class(pmt_intern("i/o"),                     // name of class
355                          pmt_list1(pmt_intern("in")),           // in
356                          pmt_list1(pmt_intern("out")));         // out
357
358   mb_runtime_sptr rts = mb_make_runtime();
359   mb_runtime *rt = rts.get();
360
361   mb_mblock_sptr        mb0 = mb_mblock_sptr(new tc_0(rt, "top", PMT_F));
362 }
363
364 ////////////////////////////////////////////////////////////////
365
366 void
367 qa_mblock_prims::test_msg_queue()
368 {
369   mb_msg_queue  q;
370
371   // check initial state
372   CPPUNIT_ASSERT(q.get_highest_pri_msg_nowait() == 0);
373
374   CPPUNIT_ASSERT(MB_NPRI >= 5); // sanity check for this test
375
376   // insert three messages at the same pri and ensure that they come out in order
377   //                       signal       data          metadata     pri
378   q.insert(mb_make_message(PMT_NIL, pmt_from_long(0), PMT_NIL, MB_PRI_BEST + 2));
379   q.insert(mb_make_message(PMT_NIL, pmt_from_long(1), PMT_NIL, MB_PRI_BEST + 2));
380   q.insert(mb_make_message(PMT_NIL, pmt_from_long(2), PMT_NIL, MB_PRI_BEST + 2));
381   
382   CPPUNIT_ASSERT_EQUAL(0L, pmt_to_long(q.get_highest_pri_msg_nowait()->data()));
383   CPPUNIT_ASSERT_EQUAL(1L, pmt_to_long(q.get_highest_pri_msg_nowait()->data()));
384   CPPUNIT_ASSERT_EQUAL(2L, pmt_to_long(q.get_highest_pri_msg_nowait()->data()));
385
386   CPPUNIT_ASSERT(q.get_highest_pri_msg_nowait() == 0);
387
388
389   // insert messages of different priorities in pseudo-random order
390   //                       signal   data     metadata     pri
391   q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 3));
392   q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 2));
393   q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 4));
394   q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 0));
395   q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 1));
396   q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 3));
397   q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 2));
398   q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 4));
399   q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 0));
400   q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 1));
401
402   // confirm that they come out in order
403   CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 0, q.get_highest_pri_msg_nowait()->priority());
404   CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 0, q.get_highest_pri_msg_nowait()->priority());
405   CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 1, q.get_highest_pri_msg_nowait()->priority());
406   CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 1, q.get_highest_pri_msg_nowait()->priority());
407   CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 2, q.get_highest_pri_msg_nowait()->priority());
408   CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 2, q.get_highest_pri_msg_nowait()->priority());
409   CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 3, q.get_highest_pri_msg_nowait()->priority());
410   CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 3, q.get_highest_pri_msg_nowait()->priority());
411   CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 4, q.get_highest_pri_msg_nowait()->priority());
412   CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 4, q.get_highest_pri_msg_nowait()->priority());
413   
414   // check final state
415   CPPUNIT_ASSERT(q.get_highest_pri_msg_nowait() == 0);
416 }
417
418 ////////////////////////////////////////////////////////////////
419
420 void
421 qa_mblock_prims::test_make_accepter()
422 {
423   mb_runtime_sptr rts = mb_make_runtime();
424   mb_runtime *rt = rts.get();
425
426   // create a block
427   mb_mblock_sptr mb = mb_mblock_sptr(new dp_2(rt, "top", PMT_F));
428
429   // use "internal use only" method...
430   mb_msg_accepter_sptr accepter = mb->impl()->make_accepter(pmt_intern("cs"));
431
432   // Now push a few messages into it...
433   //          signal       data          metadata     pri
434   (*accepter)(PMT_NIL, pmt_from_long(0), PMT_NIL, MB_PRI_BEST + 2);
435   (*accepter)(PMT_NIL, pmt_from_long(1), PMT_NIL, MB_PRI_BEST + 2);
436   (*accepter)(PMT_NIL, pmt_from_long(2), PMT_NIL, MB_PRI_BEST + 2);
437
438   // try to pull them out
439
440   pmt_t cs = pmt_intern("cs");
441
442   mb_message_sptr msg = mb->impl()->msgq().get_highest_pri_msg_nowait();
443   CPPUNIT_ASSERT(pmt_eq(cs, msg->port_id()));         // confirm that port_id is set
444   CPPUNIT_ASSERT_EQUAL(0L, pmt_to_long(msg->data())); // and that data is correct
445
446   CPPUNIT_ASSERT_EQUAL(1L, pmt_to_long(mb->impl()->msgq().get_highest_pri_msg_nowait()->data()));
447   CPPUNIT_ASSERT_EQUAL(2L, pmt_to_long(mb->impl()->msgq().get_highest_pri_msg_nowait()->data()));
448 }