• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***
2   This file is part of PulseAudio.
3 
4   PulseAudio is free software; you can redistribute it and/or modify
5   it under the terms of the GNU Lesser General Public License as published
6   by the Free Software Foundation; either version 2.1 of the License,
7   or (at your option) any later version.
8 
9   PulseAudio is distributed in the hope that it will be useful, but
10   WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12   General Public License for more details.
13 
14   You should have received a copy of the GNU Lesser General Public License
15   along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
16 ***/
17 
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif
21 
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <signal.h>
25 
26 #include <check.h>
27 
28 #include <pulsecore/memblockq.h>
29 #include <pulsecore/log.h>
30 #include <pulsecore/macro.h>
31 #include <pulsecore/strbuf.h>
32 #include <pulsecore/core-util.h>
33 
34 #include <pulse/xmalloc.h>
35 
36 static const char *fixed[] = {
37     "1122444411441144__22__11______3333______________________________",
38     "__________________3333__________________________________________"
39 };
40 static const char *manual[] = {
41     "1122444411441144__22__11______3333______________________________",
42     "__________________3333______________________________"
43 };
44 
45 /*
46  * utility function to create a memchunk
47  */
memchunk_from_str(pa_mempool * p,const char * data)48 static pa_memchunk memchunk_from_str(pa_mempool *p, const char* data)
49 {
50     pa_memchunk res;
51     size_t size = strlen(data);
52 
53     res.memblock = pa_memblock_new_fixed(p, (void*)data, size, true);
54     ck_assert_ptr_ne(res.memblock, NULL);
55 
56     res.index = 0;
57     res.length = pa_memblock_get_length(res.memblock);
58 
59     return res;
60 }
61 
dump_chunk(const pa_memchunk * chunk,pa_strbuf * buf)62 static void dump_chunk(const pa_memchunk *chunk, pa_strbuf *buf) {
63     size_t n;
64     void *q;
65     char *e;
66 
67     fail_unless(chunk != NULL);
68 
69     q = pa_memblock_acquire(chunk->memblock);
70     for (e = (char*) q + chunk->index, n = 0; n < chunk->length; n++, e++) {
71         fprintf(stderr, "%c", *e);
72         pa_strbuf_putc(buf, *e);
73     }
74     pa_memblock_release(chunk->memblock);
75 }
76 
dump(pa_memblockq * bq,int n)77 static void dump(pa_memblockq *bq, int n) {
78     pa_memchunk out;
79     pa_strbuf *buf;
80     char *str;
81 
82     pa_assert(bq);
83 
84     /* First let's dump this as fixed block */
85     fprintf(stderr, "FIXED >");
86     pa_memblockq_peek_fixed_size(bq, 64, &out);
87     buf = pa_strbuf_new();
88     dump_chunk(&out, buf);
89     pa_memblock_unref(out.memblock);
90     str = pa_strbuf_to_string_free(buf);
91     fail_unless(pa_streq(str, fixed[n]));
92     pa_xfree(str);
93     fprintf(stderr, "<\n");
94 
95     /* Then let's dump the queue manually */
96     fprintf(stderr, "MANUAL>");
97 
98     buf = pa_strbuf_new();
99     for (;;) {
100         if (pa_memblockq_peek(bq, &out) < 0)
101             break;
102 
103         dump_chunk(&out, buf);
104         pa_memblock_unref(out.memblock);
105         pa_memblockq_drop(bq, out.length);
106     }
107     str = pa_strbuf_to_string_free(buf);
108     fail_unless(pa_streq(str, manual[n]));
109     pa_xfree(str);
110     fprintf(stderr, "<\n");
111 }
112 
113 /*
114  * utility function to validate invariants
115  *
116  * The different values like base, maxlength etc follow certain rules.
117  * This convenience function makes sure that changes don't violate
118  * these rules.
119  */
check_queue_invariants(pa_memblockq * bq)120 static void check_queue_invariants(pa_memblockq *bq) {
121     size_t base = pa_memblockq_get_base(bq);
122     size_t maxlength = pa_memblockq_get_maxlength(bq);
123     size_t tlength = pa_memblockq_get_tlength(bq);
124     size_t minreq = pa_memblockq_get_minreq(bq);
125     size_t prebuf = pa_memblockq_get_prebuf(bq);
126     size_t length = pa_memblockq_get_length(bq);
127 
128     /* base > zero */
129     ck_assert_int_gt(base, 0);
130 
131     /* maxlength multiple of base
132      * maxlength >= base */
133     ck_assert_int_eq(maxlength % base, 0);
134     ck_assert_int_ge(maxlength, base);
135 
136     /* tlength multiple of base
137      * tlength >= base
138      * tlength <= maxlength */
139     ck_assert_int_eq(tlength % base, 0);
140     ck_assert_int_ge(tlength, base);
141     ck_assert_int_le(tlength, maxlength);
142 
143     /* minreq multiple of base
144      * minreq >= base
145      * minreq <= tlength */
146     ck_assert_int_eq(minreq % base, 0);
147     ck_assert_int_ge(minreq, base);
148     ck_assert_int_le(minreq, tlength);
149 
150     /* prebuf multiple of base
151      * prebuf >= 0
152      * prebuf <= tlength + base - minreq
153      * prebuf <= tlength (because minreq >= base) */
154     ck_assert_int_eq(prebuf % base, 0);
155     ck_assert_int_ge(prebuf, 0);
156     ck_assert_int_le(prebuf, tlength + base - minreq);
157     ck_assert_int_le(prebuf, tlength);
158 
159     /* length >= 0
160      * length <= maxlength */
161     ck_assert_int_ge(length, 0);
162     ck_assert_int_le(length, maxlength);
163 }
164 
START_TEST(memchunk_from_str_test)165 START_TEST (memchunk_from_str_test) {
166     pa_mempool *p;
167     pa_memchunk chunk;
168 
169     p = pa_mempool_new(PA_MEM_TYPE_PRIVATE, 0, true);
170     ck_assert_ptr_ne(p, NULL);
171 
172     /* allocate memchunk and check default settings */
173     chunk = memchunk_from_str(p, "abcd");
174     ck_assert_ptr_ne(chunk.memblock, NULL);
175     ck_assert_int_eq(chunk.index, 0);
176     ck_assert_int_eq(chunk.length, 4);
177 
178     /* cleanup */
179     pa_memblock_unref(chunk.memblock);
180     pa_mempool_unref(p);
181 }
182 END_TEST
183 
START_TEST(memblockq_test_initial_properties)184 START_TEST (memblockq_test_initial_properties) {
185     pa_mempool *p;
186     pa_memblockq *bq;
187     pa_memchunk silence;
188     pa_sample_spec ss = {
189         .format = PA_SAMPLE_S32BE,
190         .rate = 48000,
191         .channels = 1
192     };
193     int64_t idx = 0;
194     size_t maxlength = 100;
195     size_t tlength = 20;
196     size_t prebuf = 16;
197     size_t minreq = 8;
198     size_t maxrewind = 40;
199 
200     p = pa_mempool_new(PA_MEM_TYPE_PRIVATE, 0, true);
201     ck_assert_ptr_ne(p, NULL);
202 
203     silence = memchunk_from_str(p, "__");
204 
205     bq = pa_memblockq_new("test memblockq", idx, maxlength, tlength, &ss, prebuf, minreq, maxrewind, &silence);
206     fail_unless(bq != NULL);
207 
208     /* check initial properties */
209     ck_assert_int_eq(pa_memblockq_is_readable(bq), false);
210     ck_assert_int_eq(pa_memblockq_get_length(bq), 0);
211     ck_assert_int_eq(pa_memblockq_get_maxlength(bq), maxlength);
212     ck_assert_int_eq(pa_memblockq_get_tlength(bq), tlength);
213     ck_assert_int_eq(pa_memblockq_get_prebuf(bq), prebuf);
214     ck_assert_int_eq(pa_memblockq_get_minreq(bq), minreq);
215     ck_assert_int_eq(pa_memblockq_get_maxrewind(bq), maxrewind);
216     ck_assert_int_eq(pa_memblockq_get_base(bq), pa_frame_size(&ss));
217     ck_assert_int_eq(pa_memblockq_get_read_index(bq), 0);
218     ck_assert_int_eq(pa_memblockq_get_write_index(bq), 0);
219 
220     check_queue_invariants(bq);
221 
222     /* Check reporting of missing bytes:
223      * Initially, tlength bytes are missing. The second call doesn't
224      * report additional missing data since the first call. */
225     ck_assert_int_eq(pa_memblockq_pop_missing(bq), tlength);
226     ck_assert_int_eq(pa_memblockq_pop_missing(bq), 0);
227 
228     /* cleanup */
229     pa_memblockq_free(bq);
230     pa_memblock_unref(silence.memblock);
231     pa_mempool_unref(p);
232 }
233 END_TEST
234 
START_TEST(memblockq_test)235 START_TEST (memblockq_test) {
236     int ret;
237 
238     pa_mempool *p;
239     pa_memblockq *bq;
240     pa_memchunk chunk1, chunk2, chunk3, chunk4;
241     pa_memchunk silence;
242     pa_sample_spec ss = {
243         .format = PA_SAMPLE_S16LE,
244         .rate = 48000,
245         .channels = 1
246     };
247 
248     p = pa_mempool_new(PA_MEM_TYPE_PRIVATE, 0, true);
249     ck_assert_ptr_ne(p, NULL);
250 
251     silence = memchunk_from_str(p, "__");
252 
253     bq = pa_memblockq_new("test memblockq", 0, 200, 10, &ss, 4, 4, 40, &silence);
254     fail_unless(bq != NULL);
255     check_queue_invariants(bq);
256 
257     chunk1 = memchunk_from_str(p, "11");
258     chunk2 = memchunk_from_str(p, "XX22");
259     chunk2.index += 2;
260     chunk2.length -= 2;
261     chunk3 = memchunk_from_str(p, "3333");
262     chunk4 = memchunk_from_str(p, "44444444");
263 
264     ret = pa_memblockq_push(bq, &chunk1);
265     fail_unless(ret == 0);
266 
267     ret = pa_memblockq_push(bq, &chunk2);
268     fail_unless(ret == 0);
269 
270     ret = pa_memblockq_push(bq, &chunk3);
271     fail_unless(ret == 0);
272 
273     ret = pa_memblockq_push(bq, &chunk4);
274     fail_unless(ret == 0);
275 
276     check_queue_invariants(bq);
277 
278     pa_memblockq_seek(bq, -6, 0, true);
279     ret = pa_memblockq_push(bq, &chunk3);
280     fail_unless(ret == 0);
281 
282     pa_memblockq_seek(bq, -2, 0, true);
283     ret = pa_memblockq_push(bq, &chunk1);
284     fail_unless(ret == 0);
285 
286     pa_memblockq_seek(bq, -10, 0, true);
287     ret = pa_memblockq_push(bq, &chunk4);
288     fail_unless(ret == 0);
289 
290     pa_memblockq_seek(bq, 10, 0, true);
291 
292     ret = pa_memblockq_push(bq, &chunk1);
293     fail_unless(ret == 0);
294 
295     pa_memblockq_seek(bq, -6, 0, true);
296     ret = pa_memblockq_push(bq, &chunk2);
297     fail_unless(ret == 0);
298 
299     /* Test splitting */
300     pa_memblockq_seek(bq, -12, 0, true);
301     ret = pa_memblockq_push(bq, &chunk1);
302     fail_unless(ret == 0);
303 
304     pa_memblockq_seek(bq, 20, 0, true);
305 
306     /* Test merging */
307     ret = pa_memblockq_push(bq, &chunk3);
308     fail_unless(ret == 0);
309     pa_memblockq_seek(bq, -2, 0, true);
310 
311     chunk3.index += 2;
312     chunk3.length -= 2;
313     ret = pa_memblockq_push(bq, &chunk3);
314     fail_unless(ret == 0);
315 
316     pa_memblockq_seek(bq, 30, PA_SEEK_RELATIVE, true);
317 
318     dump(bq, 0);
319 
320     pa_memblockq_rewind(bq, 52);
321 
322     dump(bq, 1);
323 
324     check_queue_invariants(bq);
325 
326     pa_memblockq_free(bq);
327     pa_memblock_unref(silence.memblock);
328     pa_memblock_unref(chunk1.memblock);
329     pa_memblock_unref(chunk2.memblock);
330     pa_memblock_unref(chunk3.memblock);
331     pa_memblock_unref(chunk4.memblock);
332 
333     pa_mempool_unref(p);
334 }
335 END_TEST
336 
START_TEST(memblockq_test_length_changes)337 START_TEST (memblockq_test_length_changes) {
338     pa_mempool *p;
339     pa_memblockq *bq;
340     pa_memchunk silence, data;
341     pa_sample_spec ss = {
342         .format = PA_SAMPLE_S32BE,
343         .rate = 48000,
344         .channels = 1
345     };
346     int64_t idx = 0;
347     size_t maxlength = 60;
348     size_t tlength = 40;
349     size_t prebuf = 16;
350     size_t minreq = 20;
351     size_t maxrewind = 40;
352 
353     p = pa_mempool_new(PA_MEM_TYPE_PRIVATE, 0, true);
354     ck_assert_ptr_ne(p, NULL);
355 
356     silence = memchunk_from_str(p, "____");
357 
358     bq = pa_memblockq_new("test memblockq", idx, maxlength, tlength, &ss, prebuf, minreq, maxrewind, &silence);
359     fail_unless(bq != NULL);
360 
361     data = memchunk_from_str(p, "12345678");
362 
363     /* insert some data */
364     ck_assert_int_eq(pa_memblockq_push(bq, &data), 0);
365     ck_assert_int_eq(pa_memblockq_push(bq, &data), 0);
366     ck_assert_int_eq(pa_memblockq_push(bq, &data), 0);
367     ck_assert_int_eq(pa_memblockq_push(bq, &data), 0);
368 
369     /* check state */
370     ck_assert_int_eq(pa_memblockq_get_length(bq), 32);
371 
372     /* adjust maximum length
373      * This might modify tlength, prebuf, minreq, too. */
374     pa_memblockq_set_maxlength(bq, maxlength/2);
375     check_queue_invariants(bq);
376 
377     /* adjust target length
378      * This might modify minreq, too. */
379     pa_memblockq_set_tlength(bq, tlength/2);
380     check_queue_invariants(bq);
381 
382     /* adjust minimum requested length
383      * This might modify prebuf, too. */
384     pa_memblockq_set_minreq(bq, minreq/2);
385     check_queue_invariants(bq);
386 
387     /* adjust prebuffer length */
388     pa_memblockq_set_prebuf(bq, prebuf/2);
389     check_queue_invariants(bq);
390 
391     /* cleanup */
392     pa_memblockq_free(bq);
393     pa_memblock_unref(silence.memblock);
394     pa_memblock_unref(data.memblock);
395     pa_mempool_unref(p);
396 }
397 END_TEST
398 
START_TEST(memblockq_test_pop_missing)399 START_TEST (memblockq_test_pop_missing) {
400     pa_mempool *p;
401     pa_memblockq *bq;
402     pa_memchunk silence, data, chunk;
403     pa_sample_spec ss = {
404         .format = PA_SAMPLE_S16BE,
405         .rate = 48000,
406         .channels = 1
407     };
408     int64_t idx = 0;
409     size_t maxlength = 200;
410     size_t tlength = 100;
411     size_t prebuf = 0;
412     size_t minreq = 80;
413     size_t maxrewind = 0;
414 
415     p = pa_mempool_new(PA_MEM_TYPE_PRIVATE, 0, true);
416     ck_assert_ptr_ne(p, NULL);
417 
418     silence = memchunk_from_str(p, "____");
419     data = memchunk_from_str(p, "1234567890");
420 
421     bq = pa_memblockq_new("test memblockq", idx, maxlength, tlength, &ss, prebuf, minreq, maxrewind, &silence);
422     fail_unless(bq != NULL);
423 
424     /* The following equation regarding the internal variables of a memblockq
425      * is always true:
426      *
427      *   length + missing + requested = tlength
428      *
429      * "length" is the current memblockq length (write index minus read index)
430      * and "tlength" is the target length. The intuitive meaning of "missing"
431      * would be the difference between tlength and length, but actually
432      * "missing" and "requested" together constitute the amount that is missing
433      * from the queue. Writing to the queue decrements "requested" and reading
434      * from the queue increments "missing". pa_memblockq_pop_missing() resets
435      * "missing" to zero, returns the old "missing" value and adds the
436      * equivalent amount to "requested".
437      *
438      * This test has comments between each step documenting the assumed state
439      * of those internal variables. */
440 
441     /* length + missing + requested = tlength
442      * 0      + 100     + 0         = 100 */
443 
444     ck_assert_int_eq(pa_memblockq_pop_missing(bq), tlength);
445 
446     /* length + missing + requested = tlength
447      * 0      + 0       + 100       = 100 */
448 
449     for (int i = 0; i != 2; ++i)
450         ck_assert_int_eq(pa_memblockq_push(bq, &data), 0);
451     check_queue_invariants(bq);
452 
453     /* length + missing + requested = tlength
454      * 20     + 0       + 80        = 100 */
455 
456     ck_assert_int_eq(pa_memblockq_pop_missing(bq), 0);
457 
458     /* length + missing + requested = tlength
459      * 20     + 0       + 80        = 100 */
460 
461     for (int i = 0; i != 8; ++i)
462         ck_assert_int_eq(pa_memblockq_push(bq, &data), 0);
463     check_queue_invariants(bq);
464 
465     /* length + missing + requested = tlength
466      * 100    + 0       + 0         = 100 */
467 
468     ck_assert_int_eq(pa_memblockq_pop_missing(bq), 0);
469 
470     /* length + missing + requested = tlength
471      * 100    + 0       + 0         = 100 */
472 
473     ck_assert_int_eq(pa_memblockq_peek_fixed_size(bq, 40, &chunk), 0);
474     pa_memblockq_drop(bq, 40);
475     ck_assert_int_eq(chunk.length - chunk.index, 40);
476     pa_memblock_unref(chunk.memblock);
477     check_queue_invariants(bq);
478 
479     /* length + missing + requested = tlength
480      * 60     + 40      + 0         = 100 */
481 
482     /* 40 bytes are missing, but that's less than minreq, so 0 is reported */
483     ck_assert_int_eq(pa_memblockq_pop_missing(bq), 0);
484 
485     /* length + missing + requested = tlength
486      * 60     + 40      + 0         = 100 */
487 
488     /* Now we push 30 bytes even though it was not requested, so the requested
489      * counter goes negative! */
490     for (int i = 0; i != 3; ++i)
491         ck_assert_int_eq(pa_memblockq_push(bq, &data), 0);
492     check_queue_invariants(bq);
493 
494     /* length + missing + requested = tlength
495      * 90     + 40      + -30       = 100 */
496 
497     /* missing < minreq, so nothing is reported missing. */
498     ck_assert_int_eq(pa_memblockq_pop_missing(bq), 0);
499 
500     /* length + missing + requested = tlength
501      * 90     + 40      + -30       = 100 */
502 
503     ck_assert_int_eq(pa_memblockq_peek_fixed_size(bq, 20, &chunk), 0);
504     pa_memblockq_drop(bq, 20);
505     ck_assert_int_eq(chunk.length - chunk.index, 20);
506     pa_memblock_unref(chunk.memblock);
507     check_queue_invariants(bq);
508 
509     /* length + missing + requested = tlength
510      * 70     + 60      + -30       = 100 */
511 
512     /* missing < minreq, so nothing is reported missing. */
513     ck_assert_int_eq(pa_memblockq_pop_missing(bq), 0);
514 
515     /* length + missing + requested = tlength
516      * 70     + 60      + -30       = 100 */
517 
518     /* We push more data again even though it was not requested, so the
519      * requested counter goes further into the negative range. */
520     for (int i = 0; i != 5; ++i)
521         ck_assert_int_eq(pa_memblockq_push(bq, &data), 0);
522     check_queue_invariants(bq);
523 
524     /* length + missing + requested = tlength
525      * 120    + 60      + -80       = 100 */
526 
527     /* missing < minreq, so nothing is reported missing. */
528     ck_assert_int_eq(pa_memblockq_pop_missing(bq), 0);
529 
530     /* length + missing + requested = tlength
531      * 120    + 60      + -80       = 100 */
532 
533     ck_assert_int_eq(pa_memblockq_peek_fixed_size(bq, 20, &chunk), 0);
534     pa_memblockq_drop(bq, 20);
535     ck_assert_int_eq(chunk.length - chunk.index, 20);
536     pa_memblock_unref(chunk.memblock);
537     check_queue_invariants(bq);
538 
539     /* length + missing + requested = tlength
540      * 100    + 80      + -80       = 100 */
541 
542     /* missing has now reached the minreq threshold */
543     ck_assert_int_eq(pa_memblockq_pop_missing(bq), 80);
544 
545     /* length + missing + requested = tlength
546      * 100    + 0       + 0         = 100 */
547 
548     /* cleanup */
549     pa_memblockq_free(bq);
550     pa_memblock_unref(silence.memblock);
551     pa_memblock_unref(data.memblock);
552     pa_mempool_unref(p);
553 }
554 END_TEST
555 
START_TEST(memblockq_test_tlength_change)556 START_TEST (memblockq_test_tlength_change) {
557     int ret;
558     size_t missing;
559 
560     pa_mempool *p;
561     pa_memblockq *bq;
562     pa_memchunk chunk;
563     char buffer[2048];
564     pa_sample_spec ss = {
565         .format = PA_SAMPLE_S16LE,
566         .rate = 48000,
567         .channels = 1
568     };
569 
570     pa_log_set_level(PA_LOG_DEBUG);
571 
572     bq = pa_memblockq_new("test memblockq", 0, 4096, 2048, &ss, 0, 512, 512, NULL);
573     fail_unless(bq != NULL);
574 
575     /* Empty buffer, so expect tlength */
576     missing = pa_memblockq_pop_missing(bq);
577     fail_unless(missing == 2048);
578 
579     /* Everything requested, so should be satisfied */
580     missing = pa_memblockq_pop_missing(bq);
581     fail_unless(missing == 0);
582 
583     p = pa_mempool_new(PA_MEM_TYPE_PRIVATE, 0, true);
584 
585     chunk.memblock = pa_memblock_new_fixed(p, buffer, sizeof(buffer), 1);
586     fail_unless(chunk.memblock != NULL);
587 
588     chunk.index = 0;
589     chunk.length = sizeof(buffer);
590 
591     /* Fill buffer (i.e. satisfy earlier request) */
592     ret = pa_memblockq_push(bq, &chunk);
593     fail_unless(ret == 0);
594 
595     /* Should still be happy */
596     missing = pa_memblockq_pop_missing(bq);
597     fail_unless(missing == 0);
598 
599     /* Check that we don't request less than minreq */
600     pa_memblockq_drop(bq, 400);
601     missing = pa_memblockq_pop_missing(bq);
602     ck_assert_int_eq(missing, 0);
603 
604     missing = pa_memblockq_pop_missing(bq);
605     fail_unless(missing == 0);
606 
607     /* Reduce tlength under what's dropped and under previous minreq */
608     pa_memblockq_set_tlength(bq, 256);
609     pa_memblockq_set_minreq(bq, 64);
610 
611     /* We are now overbuffered and should not request more */
612     missing = pa_memblockq_pop_missing(bq);
613     fail_unless(missing == 0);
614 
615     /* Drop more data so we are below tlength again, but just barely */
616     pa_memblockq_drop(bq, 1400);
617 
618     /* Should still honour minreq */
619     missing = pa_memblockq_pop_missing(bq);
620     fail_unless(missing == 0);
621 
622     /* Finally drop enough to fall below minreq */
623     pa_memblockq_drop(bq, 80);
624 
625     /* And expect a request */
626     missing = pa_memblockq_pop_missing(bq);
627     fail_unless(missing == 88);
628 
629     pa_memblockq_free(bq);
630     pa_memblock_unref(chunk.memblock);
631     pa_mempool_unref(p);
632 }
633 END_TEST
634 
635 
main(int argc,char * argv[])636 int main(int argc, char *argv[]) {
637     int failed = 0;
638     Suite *s;
639     TCase *tc;
640     SRunner *sr;
641 
642     if (!getenv("MAKE_CHECK"))
643         pa_log_set_level(PA_LOG_DEBUG);
644 
645     s = suite_create("Memblock Queue");
646     tc = tcase_create("memblockq");
647     tcase_add_test(tc, memchunk_from_str_test);
648     tcase_add_test(tc, memblockq_test_initial_properties);
649     tcase_add_test(tc, memblockq_test);
650     tcase_add_test(tc, memblockq_test_length_changes);
651     tcase_add_test(tc, memblockq_test_pop_missing);
652     tcase_add_test(tc, memblockq_test_tlength_change);
653     suite_add_tcase(s, tc);
654 
655     sr = srunner_create(s);
656     srunner_run_all(sr, CK_NORMAL);
657     failed = srunner_ntests_failed(sr);
658     srunner_free(sr);
659 
660     return (failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
661 }
662