1 | /* |
2 | * Copyright (c) 2020 Apple Inc. All rights reserved. |
3 | * |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
5 | * |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License |
8 | * Version 2.0 (the 'License'). You may not use this file except in |
9 | * compliance with the License. The rights granted to you under the License |
10 | * may not be used to create, or enable the creation or redistribution of, |
11 | * unlawful or unlicensed copies of an Apple operating system, or to |
12 | * circumvent, violate, or enable the circumvention or violation of, any |
13 | * terms of an Apple operating system software license agreement. |
14 | * |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. |
17 | * |
18 | * The Original Code and all software distributed under the License are |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
23 | * Please see the License for the specific language governing rights and |
24 | * limitations under the License. |
25 | * |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
27 | */ |
28 | #include <kern/kalloc.h> |
29 | #include <libkern/libkern.h> |
30 | #include <os/base.h> |
31 | #include <os/overflow.h> |
32 | #include <sys/param.h> |
33 | #include <sys/sbuf.h> |
34 | #include <sys/uio.h> |
35 | |
36 | #if DEBUG || DEVELOPMENT |
37 | #include <kern/macro_help.h> |
38 | #include <sys/errno.h> |
39 | #include <sys/sysctl.h> |
40 | #endif /* DEBUG || DEVELOPMENT */ |
41 | |
42 | #define SBUF_ISSET(s, f) ((s)->s_flags & (f)) |
43 | #define SBUF_SETFLAG(s, f) do { (s)->s_flags |= (f); } while (0) |
44 | #define SBUF_CLEARFLAG(s, f) do { (s)->s_flags &= ~(f); } while (0) |
45 | |
46 | #define SBUF_CANEXTEND(s) SBUF_ISSET(s, SBUF_AUTOEXTEND) |
47 | #define SBUF_HASOVERFLOWED(s) SBUF_ISSET(s, SBUF_OVERFLOWED) |
48 | #define SBUF_ISDYNAMIC(s) SBUF_ISSET(s, SBUF_DYNAMIC) |
49 | #define SBUF_ISDYNSTRUCT(s) SBUF_ISSET(s, SBUF_DYNSTRUCT) |
50 | #define SBUF_ISFINISHED(s) SBUF_ISSET(s, SBUF_FINISHED) |
51 | |
52 | #define SBUF_MINEXTENDSIZE 16 |
53 | #define SBUF_MAXEXTENDSIZE PAGE_SIZE |
54 | #define SBUF_MAXEXTENDINCR PAGE_SIZE |
55 | |
56 | /*! |
57 | * @function sbuf_delete |
58 | * |
59 | * @brief |
60 | * Destroys an sbuf. Frees the underlying buffer if it's allocated on the heap |
61 | * (indicated by SBUF_ISDYNAMIC) and frees the sbuf if it itself is allocated |
62 | * on the heap (SBUF_ISDYNSTRUCT). |
63 | * |
64 | * @param s |
65 | * The sbuf to destroy. |
66 | */ |
67 | void |
68 | sbuf_delete(struct sbuf *s) |
69 | { |
70 | if (SBUF_ISDYNAMIC(s) && s->s_buf) { |
71 | kfree_data(s->s_buf, s->s_size); |
72 | s->s_buf = NULL; |
73 | } |
74 | |
75 | if (SBUF_ISDYNSTRUCT(s)) { |
76 | kfree_type(struct sbuf, s); |
77 | } |
78 | } |
79 | |
80 | /*! |
81 | * @function sbuf_extendsize |
82 | * |
83 | * @brief |
84 | * Attempts to extend the size of an sbuf to the value pointed to by size. |
85 | * |
86 | * @param size |
87 | * Points to a size_t containing the desired size for input and receives the |
88 | * actual new size on success (which will be greater than or equal to the |
89 | * requested size). |
90 | * |
91 | * @returns |
92 | * 0 on success, -1 on failure. |
93 | */ |
94 | static int |
95 | sbuf_extendsize(size_t *size) |
96 | { |
97 | size_t target_size = *size; |
98 | size_t new_size; |
99 | |
100 | if (target_size > INT_MAX) { |
101 | return -1; |
102 | } |
103 | |
104 | if (target_size < SBUF_MAXEXTENDSIZE) { |
105 | new_size = SBUF_MINEXTENDSIZE; |
106 | while (new_size < target_size) { |
107 | new_size *= 2; |
108 | } |
109 | } else { |
110 | /* round up to nearest page: */ |
111 | new_size = (target_size + PAGE_SIZE - 1) & ~PAGE_MASK; |
112 | } |
113 | |
114 | if (new_size > INT_MAX) { |
115 | return -1; |
116 | } |
117 | |
118 | *size = new_size; |
119 | return 0; |
120 | } |
121 | |
122 | /*! |
123 | * @function sbuf_new |
124 | * |
125 | * @brief |
126 | * Allocates and/or initializes an sbuf. |
127 | * |
128 | * @param s |
129 | * An optional existing sbuf to initialize. If NULL, a new one is allocated on |
130 | * the heap. |
131 | * |
132 | * @param buf |
133 | * An optional existing backing buffer to assign to the sbuf. If NULL, a new |
134 | * one is allocated on the heap. |
135 | * |
136 | * @param length_ |
137 | * The initial size of the sbuf. The actual size may be greater than this |
138 | * value. |
139 | * |
140 | * @param flags |
141 | * The flags to set on the sbuf. Accepted values are: |
142 | * |
143 | * - SBUF_FIXEDLEN: Do not allow the backing buffer to dynamically expand |
144 | * to accommodate appended data. |
145 | * - SBUF_AUTOEXPAND: Automatically reallocate the backing buffer using the |
146 | * heap if required. |
147 | * |
148 | * @returns |
149 | * The new and/or initialized sbuf on success, or NULL on failure. |
150 | */ |
151 | struct sbuf * |
152 | sbuf_new(struct sbuf *s, char *buf, int length_, int flags) |
153 | { |
154 | size_t length = (size_t)length_; |
155 | |
156 | if (length > INT_MAX || flags & ~SBUF_USRFLAGMSK) { |
157 | return NULL; |
158 | } |
159 | |
160 | if (s == NULL) { |
161 | s = (struct sbuf *)kalloc_type(struct sbuf, Z_WAITOK | Z_ZERO); |
162 | if (NULL == s) { |
163 | return NULL; |
164 | } |
165 | |
166 | s->s_flags = flags; |
167 | SBUF_SETFLAG(s, SBUF_DYNSTRUCT); |
168 | } else { |
169 | bzero(s, n: sizeof(*s)); |
170 | s->s_flags = flags; |
171 | } |
172 | |
173 | if (buf) { |
174 | s->s_size = (int)length; |
175 | s->s_buf = buf; |
176 | return s; |
177 | } |
178 | |
179 | if (SBUF_CANEXTEND(s) && (-1 == sbuf_extendsize(size: &length))) { |
180 | goto fail; |
181 | } |
182 | |
183 | /* |
184 | * we always need at least 1 byte for \0, so s_size of 0 will cause an |
185 | * underflow in sbuf_capacity. |
186 | */ |
187 | if (length == 0) { |
188 | goto fail; |
189 | } |
190 | |
191 | s->s_buf = kalloc_data(length, Z_WAITOK | Z_ZERO); |
192 | if (NULL == s->s_buf) { |
193 | goto fail; |
194 | } |
195 | s->s_size = (int)length; |
196 | |
197 | SBUF_SETFLAG(s, SBUF_DYNAMIC); |
198 | return s; |
199 | |
200 | fail: |
201 | sbuf_delete(s); |
202 | return NULL; |
203 | } |
204 | |
205 | /*! |
206 | * @function sbuf_setpos |
207 | * |
208 | * @brief |
209 | * Set the current position of the sbuf. |
210 | * |
211 | * @param s |
212 | * The sbuf to modify. |
213 | * |
214 | * @param pos |
215 | * The new position to set. Must be less than or equal to the current position. |
216 | * |
217 | * @returns |
218 | * 0 on success, -1 on failure. |
219 | */ |
220 | int |
221 | sbuf_setpos(struct sbuf *s, int pos) |
222 | { |
223 | if (pos < 0 || pos > s->s_len) { |
224 | return -1; |
225 | } |
226 | |
227 | s->s_len = pos; |
228 | return 0; |
229 | } |
230 | |
231 | /*! |
232 | * @function sbuf_clear |
233 | * |
234 | * @brief |
235 | * Resets the position/length of the sbuf data to zero and clears the finished |
236 | * and overflow flags. |
237 | * |
238 | * @param s |
239 | * The sbuf to clear. |
240 | */ |
241 | void |
242 | sbuf_clear(struct sbuf *s) |
243 | { |
244 | SBUF_CLEARFLAG(s, SBUF_FINISHED); |
245 | SBUF_CLEARFLAG(s, SBUF_OVERFLOWED); |
246 | sbuf_setpos(s, pos: 0); |
247 | } |
248 | |
249 | /*! |
250 | * @function sbuf_extend |
251 | * |
252 | * @brief |
253 | * Attempt to extend the size of an sbuf's backing buffer by @a addlen bytes. |
254 | * |
255 | * @param s |
256 | * The sbuf to extend. |
257 | * |
258 | * @param addlen |
259 | * How many bytes to increase the size by. |
260 | * |
261 | * @returns |
262 | * 0 on success, -1 on failure. |
263 | */ |
264 | static int OS_WARN_RESULT |
265 | sbuf_extend(struct sbuf *s, size_t addlen) |
266 | { |
267 | char *new_buf; |
268 | size_t new_size; |
269 | |
270 | if (addlen == 0) { |
271 | return 0; |
272 | } |
273 | |
274 | if (!SBUF_CANEXTEND(s)) { |
275 | return -1; |
276 | } |
277 | |
278 | if (os_add_overflow((size_t)s->s_size, addlen, &new_size)) { |
279 | return -1; |
280 | } |
281 | |
282 | if (-1 == sbuf_extendsize(size: &new_size)) { |
283 | return -1; |
284 | } |
285 | |
286 | new_buf = (char *) kalloc_data(new_size, Z_WAITOK); |
287 | if (NULL == new_buf) { |
288 | return -1; |
289 | } |
290 | |
291 | bcopy(src: s->s_buf, dst: new_buf, n: (size_t)s->s_size); |
292 | if (SBUF_ISDYNAMIC(s)) { |
293 | kfree_data(s->s_buf, (size_t)s->s_size); |
294 | } else { |
295 | SBUF_SETFLAG(s, SBUF_DYNAMIC); |
296 | } |
297 | |
298 | s->s_buf = new_buf; |
299 | s->s_size = (int)new_size; |
300 | return 0; |
301 | } |
302 | |
303 | /*! |
304 | * @function sbuf_capacity |
305 | * |
306 | * @brief |
307 | * Get the current capacity of an sbuf: how many more bytes we can append given |
308 | * the current size and position. |
309 | * |
310 | * @param s |
311 | * The sbuf to get the capacity of. |
312 | * |
313 | * @returns |
314 | * The current sbuf capacity. |
315 | */ |
316 | static size_t |
317 | sbuf_capacity(const struct sbuf *s) |
318 | { |
319 | /* 1 byte reserved for \0: */ |
320 | return (size_t)(s->s_size - s->s_len - 1); |
321 | } |
322 | |
323 | /*! |
324 | * @function sbuf_ensure_capacity |
325 | * |
326 | * @brief |
327 | * Ensure that an sbuf can accommodate @a add_len bytes, reallocating the |
328 | * backing buffer if necessary. |
329 | * |
330 | * @param s |
331 | * The sbuf. |
332 | * |
333 | * @param wanted |
334 | * The minimum capacity to ensure @a s has. |
335 | * |
336 | * @returns |
337 | * 0 if the minimum capacity is met by @a s, or -1 on error. |
338 | */ |
339 | static int |
340 | sbuf_ensure_capacity(struct sbuf *s, size_t wanted) |
341 | { |
342 | size_t size; |
343 | |
344 | size = sbuf_capacity(s); |
345 | if (size >= wanted) { |
346 | return 0; |
347 | } |
348 | |
349 | return sbuf_extend(s, addlen: wanted - size); |
350 | } |
351 | |
352 | /*! |
353 | * @function sbuf_bcat |
354 | * |
355 | * @brief |
356 | * Append data to an sbuf. |
357 | * |
358 | * @param s |
359 | * The sbuf. |
360 | * |
361 | * @param data |
362 | * The data to append. |
363 | * |
364 | * @param len |
365 | * The length of the data. |
366 | * |
367 | * @returns |
368 | * 0 on success, -1 on failure. Will always fail if the sbuf is marked as |
369 | * overflowed. |
370 | */ |
371 | int |
372 | sbuf_bcat(struct sbuf *s, const void *data, size_t len) |
373 | { |
374 | if (SBUF_HASOVERFLOWED(s)) { |
375 | return -1; |
376 | } |
377 | |
378 | if (-1 == sbuf_ensure_capacity(s, wanted: len)) { |
379 | SBUF_SETFLAG(s, SBUF_OVERFLOWED); |
380 | return -1; |
381 | } |
382 | |
383 | bcopy(src: data, dst: s->s_buf + s->s_len, n: len); |
384 | s->s_len += (int)len; /* safe */ |
385 | |
386 | return 0; |
387 | } |
388 | |
389 | /*! |
390 | * @function sbuf_bcpy |
391 | * |
392 | * @brief |
393 | * Set the entire sbuf data, possibly reallocating the backing buffer to |
394 | * accommodate. |
395 | * |
396 | * @param s |
397 | * The sbuf. |
398 | * |
399 | * @param data |
400 | * The data to set. |
401 | * |
402 | * @param len |
403 | * The length of the data to set. |
404 | * |
405 | * @returns |
406 | * 0 on success or -1 on failure. Will clear the finished/overflowed flags. |
407 | */ |
408 | int |
409 | sbuf_bcpy(struct sbuf *s, const void *data, size_t len) |
410 | { |
411 | sbuf_clear(s); |
412 | return sbuf_bcat(s, data, len); |
413 | } |
414 | |
415 | /*! |
416 | * @function sbuf_cat |
417 | * |
418 | * @brief |
419 | * Append a string to an sbuf, possibly expanding the backing buffer to |
420 | * accommodate. |
421 | * |
422 | * @param s |
423 | * The sbuf. |
424 | * |
425 | * @param str |
426 | * The string to append. |
427 | * |
428 | * @returns |
429 | * 0 on success, -1 on failure. Always fails if the sbuf is marked as |
430 | * overflowed. |
431 | */ |
432 | int |
433 | sbuf_cat(struct sbuf *s, const char *str) |
434 | { |
435 | return sbuf_bcat(s, data: str, len: strlen(s: str)); |
436 | } |
437 | |
438 | /*! |
439 | * @function sbuf_cpy |
440 | * |
441 | * @brief |
442 | * Set the entire sbuf data to the given nul-terminated string, possibly |
443 | * expanding the backing buffer to accommodate it if necessary. |
444 | * |
445 | * @param s |
446 | * The sbuf. |
447 | * |
448 | * @param str |
449 | * The string to set the sbuf data to. |
450 | * |
451 | * @returns |
452 | * 0 on success, -1 on failure. Clears and resets the sbuf first. |
453 | */ |
454 | int |
455 | sbuf_cpy(struct sbuf *s, const char *str) |
456 | { |
457 | sbuf_clear(s); |
458 | return sbuf_cat(s, str); |
459 | } |
460 | |
461 | /*! |
462 | * @function sbuf_vprintf |
463 | * |
464 | * @brief |
465 | * Formatted-print into an sbuf using a va_list. |
466 | * |
467 | * @param s |
468 | * The sbuf. |
469 | * |
470 | * @param fmt |
471 | * The format string. |
472 | * |
473 | * @param ap |
474 | * The format string argument data. |
475 | * |
476 | * @returns |
477 | * 0 on success, -1 on failure. Always fails if the sbuf is marked as |
478 | * overflowed. |
479 | */ |
480 | int |
481 | sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap) |
482 | { |
483 | va_list ap_copy; |
484 | int result; |
485 | size_t capacity; |
486 | size_t len; |
487 | |
488 | if (SBUF_HASOVERFLOWED(s)) { |
489 | return -1; |
490 | } |
491 | |
492 | do { |
493 | capacity = sbuf_capacity(s); |
494 | |
495 | va_copy(ap_copy, ap); |
496 | /* +1 for \0. safe because we already accommodate this. */ |
497 | result = vsnprintf(&s->s_buf[s->s_len], capacity + 1, fmt, ap_copy); |
498 | va_end(ap_copy); |
499 | |
500 | if (result < 0) { |
501 | return -1; |
502 | } |
503 | |
504 | len = (size_t)result; |
505 | if (len <= capacity) { |
506 | s->s_len += (int)len; |
507 | return 0; |
508 | } |
509 | } while (-1 != sbuf_ensure_capacity(s, wanted: len)); |
510 | |
511 | SBUF_SETFLAG(s, SBUF_OVERFLOWED); |
512 | return -1; |
513 | } |
514 | |
515 | /*! |
516 | * @function sbuf_printf |
517 | * |
518 | * @brief |
519 | * Formatted-print into an sbuf using variadic arguments. |
520 | * |
521 | * @param s |
522 | * The sbuf. |
523 | * |
524 | * @param fmt |
525 | * The format string. |
526 | * |
527 | * @returns |
528 | * 0 on success, -1 on failure. Always fails if the sbuf is marked as |
529 | * overflowed. |
530 | */ |
531 | int |
532 | sbuf_printf(struct sbuf *s, const char *fmt, ...) |
533 | { |
534 | va_list ap; |
535 | int result; |
536 | |
537 | va_start(ap, fmt); |
538 | result = sbuf_vprintf(s, fmt, ap); |
539 | va_end(ap); |
540 | return result; |
541 | } |
542 | |
543 | /*! |
544 | * @function sbuf_putc |
545 | * |
546 | * @brief |
547 | * Append a single character to an sbuf. Ignores '\0'. |
548 | * |
549 | * @param s |
550 | * The sbuf. |
551 | * |
552 | * @param c_ |
553 | * The character to append. |
554 | * |
555 | * @returns |
556 | * 0 on success, -1 on failure. This function will always fail if the sbuf is |
557 | * marked as overflowed. |
558 | */ |
559 | int |
560 | sbuf_putc(struct sbuf *s, int c_) |
561 | { |
562 | char c = (char)c_; |
563 | |
564 | if (SBUF_HASOVERFLOWED(s)) { |
565 | return -1; |
566 | } |
567 | |
568 | if (-1 == sbuf_ensure_capacity(s, wanted: 1)) { |
569 | SBUF_SETFLAG(s, SBUF_OVERFLOWED); |
570 | return -1; |
571 | } |
572 | |
573 | if (c != '\0') { |
574 | s->s_buf[s->s_len++] = c; |
575 | } |
576 | |
577 | return 0; |
578 | } |
579 | |
580 | static inline int |
581 | isspace(char ch) |
582 | { |
583 | return ch == ' ' || ch == '\n' || ch == '\t'; |
584 | } |
585 | |
586 | /*! |
587 | * @function sbuf_trim |
588 | * |
589 | * @brief |
590 | * Removes whitespace from the end of an sbuf. |
591 | * |
592 | * @param s |
593 | * The sbuf. |
594 | * |
595 | * @returns |
596 | * 0 on success or -1 if the sbuf is marked as overflowed. |
597 | */ |
598 | int |
599 | sbuf_trim(struct sbuf *s) |
600 | { |
601 | if (SBUF_HASOVERFLOWED(s)) { |
602 | return -1; |
603 | } |
604 | |
605 | while (s->s_len > 0 && isspace(ch: s->s_buf[s->s_len - 1])) { |
606 | --s->s_len; |
607 | } |
608 | |
609 | return 0; |
610 | } |
611 | |
612 | /*! |
613 | * @function sbuf_overflowed |
614 | * |
615 | * @brief |
616 | * Indicates whether the sbuf is marked as overflowed. |
617 | * |
618 | * @param s |
619 | * The sbuf. |
620 | * |
621 | * @returns |
622 | * 1 if the sbuf has overflowed or 0 otherwise. |
623 | */ |
624 | int |
625 | sbuf_overflowed(struct sbuf *s) |
626 | { |
627 | return !!SBUF_HASOVERFLOWED(s); |
628 | } |
629 | |
630 | /*! |
631 | * @function sbuf_finish |
632 | * |
633 | * @brief |
634 | * Puts a trailing nul byte onto the sbuf data. |
635 | * |
636 | * @param s |
637 | * The sbuf. |
638 | */ |
639 | void |
640 | sbuf_finish(struct sbuf *s) |
641 | { |
642 | /* safe because we always reserve a byte at the end for \0: */ |
643 | s->s_buf[s->s_len] = '\0'; |
644 | SBUF_CLEARFLAG(s, SBUF_OVERFLOWED); |
645 | SBUF_SETFLAG(s, SBUF_FINISHED); |
646 | } |
647 | |
648 | /*! |
649 | * @function sbuf_data |
650 | * |
651 | * @brief |
652 | * Gets a pointer to the sbuf backing data. |
653 | * |
654 | * @param s |
655 | * The sbuf. |
656 | * |
657 | * @returns |
658 | * A pointer to the sbuf data. |
659 | */ |
660 | char * |
661 | sbuf_data(struct sbuf *s) |
662 | { |
663 | return s->s_buf; |
664 | } |
665 | |
666 | /*! |
667 | * @function sbuf_len |
668 | * |
669 | * @brief |
670 | * Retrieves the current length of the sbuf data. |
671 | * |
672 | * @param s |
673 | * The sbuf |
674 | * |
675 | * @returns |
676 | * The length of the sbuf data or -1 if the sbuf is marked as overflowed. |
677 | */ |
678 | int |
679 | sbuf_len(struct sbuf *s) |
680 | { |
681 | if (SBUF_HASOVERFLOWED(s)) { |
682 | return -1; |
683 | } |
684 | |
685 | return s->s_len; |
686 | } |
687 | |
688 | /*! |
689 | * @function sbuf_done |
690 | * |
691 | * @brief |
692 | * Tests if the sbuf is marked as finished. |
693 | * |
694 | * @param s |
695 | * The sbuf. |
696 | * |
697 | * @returns |
698 | * 1 if the sbuf is marked as finished or 0 if not. |
699 | */ |
700 | int |
701 | sbuf_done(struct sbuf *s) |
702 | { |
703 | return !!SBUF_ISFINISHED(s); |
704 | } |
705 | |
706 | #if DEBUG || DEVELOPMENT |
707 | |
708 | /* |
709 | * a = assertion string |
710 | */ |
711 | #define SBUF_FAIL(a) \ |
712 | MACRO_BEGIN \ |
713 | printf("sbuf_tests: failed assertion: %s\n", a); \ |
714 | if (what != NULL && should != NULL) { \ |
715 | printf("sbuf_tests: while testing: %s should %s\n", what, should); \ |
716 | } \ |
717 | goto fail; \ |
718 | MACRO_END |
719 | |
720 | #define SBUF_PASS \ |
721 | ++passed |
722 | |
723 | /* |
724 | * x = expression |
725 | */ |
726 | #define SBUF_ASSERT(x) \ |
727 | MACRO_BEGIN \ |
728 | if (x) { \ |
729 | SBUF_PASS; \ |
730 | } else { \ |
731 | SBUF_FAIL(#x); \ |
732 | } \ |
733 | MACRO_END |
734 | |
735 | #define SBUF_ASSERT_NOT(x) \ |
736 | SBUF_ASSERT(!(x)) |
737 | |
738 | /* |
739 | * e = expected |
740 | * a = actual |
741 | * c = comparator |
742 | */ |
743 | #define SBUF_ASSERT_CMP(e, a, c) \ |
744 | MACRO_BEGIN \ |
745 | if ((a) c (e)) { \ |
746 | SBUF_PASS; \ |
747 | } else { \ |
748 | SBUF_FAIL(#a " " #c " " #e); \ |
749 | } \ |
750 | MACRO_END |
751 | |
752 | #define SBUF_ASSERT_EQ(e, a) SBUF_ASSERT_CMP(e, a, ==) |
753 | #define SBUF_ASSERT_NE(e, a) SBUF_ASSERT_CMP(e, a, !=) |
754 | #define SBUF_ASSERT_GT(e, a) SBUF_ASSERT_CMP(e, a, >) |
755 | #define SBUF_ASSERT_GTE(e, a) SBUF_ASSERT_CMP(e, a, >=) |
756 | #define SBUF_ASSERT_LT(e, a) SBUF_ASSERT_CMP(e, a, <) |
757 | #define SBUF_ASSERT_LTE(e, a) SBUF_ASSERT_CMP(e, a, <=) |
758 | |
759 | #define SBUF_TEST_BEGIN \ |
760 | size_t passed = 0; \ |
761 | const char *what = NULL; \ |
762 | const char *should = NULL; |
763 | |
764 | /* |
765 | * include the trailing semi-colons here intentionally to allow for block-like |
766 | * appearance: |
767 | */ |
768 | #define SBUF_TESTING(f) \ |
769 | MACRO_BEGIN \ |
770 | what = (f); \ |
771 | MACRO_END; |
772 | |
773 | #define SBUF_SHOULD(s) \ |
774 | MACRO_BEGIN \ |
775 | should = (s); \ |
776 | MACRO_END; |
777 | |
778 | #define SBUF_TEST_END \ |
779 | printf("sbuf_tests: %zu assertions passed\n", passed); \ |
780 | return 0; \ |
781 | fail: \ |
782 | return ENOTRECOVERABLE; |
783 | |
784 | static int |
785 | sysctl_sbuf_tests SYSCTL_HANDLER_ARGS |
786 | { |
787 | #pragma unused(arg1, arg2) |
788 | int rval = 0; |
789 | char str[32] = { 'o', 'k', 0 }; |
790 | |
791 | rval = sysctl_handle_string(oidp, str, sizeof(str), req); |
792 | if (rval != 0 || req->newptr == 0 || req->newlen < 1) { |
793 | return rval; |
794 | } |
795 | |
796 | SBUF_TEST_BEGIN; |
797 | |
798 | SBUF_TESTING("sbuf_new" ) |
799 | { |
800 | SBUF_SHOULD("fail to allocate >INT_MAX" ) |
801 | { |
802 | struct sbuf *s = NULL; |
803 | |
804 | s = sbuf_new(NULL, NULL, INT_MIN, 0); |
805 | SBUF_ASSERT_EQ(NULL, s); |
806 | } |
807 | |
808 | SBUF_SHOULD("fail when claiming a backing buffer >INT_MAX" ) |
809 | { |
810 | struct sbuf *s = NULL; |
811 | char buf[4] = { 0 }; |
812 | |
813 | s = sbuf_new(NULL, buf, INT_MIN, 0); |
814 | SBUF_ASSERT_EQ(NULL, s); |
815 | } |
816 | |
817 | SBUF_SHOULD("fail to allocate a zero-length sbuf" ) |
818 | { |
819 | struct sbuf *s = NULL; |
820 | |
821 | s = sbuf_new(NULL, NULL, 0, 0); |
822 | SBUF_ASSERT_EQ(NULL, s); |
823 | } |
824 | |
825 | SBUF_SHOULD("not accept invalid flags" ) |
826 | { |
827 | struct sbuf *s = NULL; |
828 | |
829 | s = sbuf_new(NULL, NULL, 16, 0x10000); |
830 | SBUF_ASSERT_EQ(NULL, s); |
831 | } |
832 | |
833 | SBUF_SHOULD("succeed when passed an existing sbuf" ) |
834 | { |
835 | struct sbuf *s = NULL; |
836 | struct sbuf existing; |
837 | |
838 | memset(&existing, 0x41, sizeof(existing)); |
839 | s = sbuf_new(&existing, NULL, 16, SBUF_AUTOEXTEND); |
840 | SBUF_ASSERT_EQ(&existing, s); |
841 | SBUF_ASSERT(SBUF_ISSET(s, SBUF_AUTOEXTEND)); |
842 | SBUF_ASSERT(SBUF_ISSET(s, SBUF_DYNAMIC)); |
843 | SBUF_ASSERT_NE(NULL, s->s_buf); |
844 | SBUF_ASSERT_NE(0, s->s_size); |
845 | SBUF_ASSERT_EQ(0, s->s_len); |
846 | |
847 | sbuf_delete(s); |
848 | } |
849 | |
850 | SBUF_SHOULD("succeed when passed an existing sbuf and buffer" ) |
851 | { |
852 | struct sbuf *s = NULL; |
853 | struct sbuf existing; |
854 | char buf[4] = { 0 }; |
855 | |
856 | memset(&existing, 0x41, sizeof(existing)); |
857 | s = sbuf_new(&existing, buf, sizeof(buf), 0); |
858 | SBUF_ASSERT_EQ(&existing, s); |
859 | SBUF_ASSERT_EQ(buf, s->s_buf); |
860 | SBUF_ASSERT_EQ(4, s->s_size); |
861 | SBUF_ASSERT_EQ(0, s->s_len); |
862 | |
863 | sbuf_delete(s); |
864 | } |
865 | |
866 | SBUF_SHOULD("succeed without an existing sbuf or buffer" ) |
867 | { |
868 | struct sbuf *s = NULL; |
869 | |
870 | s = sbuf_new(NULL, NULL, 16, 0); |
871 | SBUF_ASSERT_NE(NULL, s); |
872 | SBUF_ASSERT(SBUF_ISSET(s, SBUF_DYNAMIC)); |
873 | SBUF_ASSERT(SBUF_ISSET(s, SBUF_DYNSTRUCT)); |
874 | SBUF_ASSERT_NE(NULL, s->s_buf); |
875 | SBUF_ASSERT_NE(0, s->s_size); |
876 | SBUF_ASSERT_EQ(0, s->s_len); |
877 | |
878 | sbuf_delete(s); |
879 | } |
880 | |
881 | SBUF_SHOULD("succeed without an existing sbuf, but with a buffer" ) |
882 | { |
883 | struct sbuf *s = NULL; |
884 | char buf[4] = { 0 }; |
885 | |
886 | s = sbuf_new(NULL, buf, sizeof(buf), 0); |
887 | SBUF_ASSERT_NE(NULL, s); |
888 | SBUF_ASSERT(SBUF_ISSET(s, SBUF_DYNSTRUCT)); |
889 | SBUF_ASSERT_EQ(buf, s->s_buf); |
890 | SBUF_ASSERT_EQ(4, s->s_size); |
891 | SBUF_ASSERT_EQ(0, s->s_len); |
892 | |
893 | sbuf_delete(s); |
894 | } |
895 | |
896 | SBUF_SHOULD("round up the requested size if SBUF_AUTOEXTEND" ) |
897 | { |
898 | struct sbuf *s = NULL; |
899 | |
900 | s = sbuf_new(NULL, NULL, 1, SBUF_AUTOEXTEND); |
901 | SBUF_ASSERT_GT(1, s->s_size); |
902 | |
903 | sbuf_delete(s); |
904 | } |
905 | } |
906 | |
907 | SBUF_TESTING("sbuf_clear" ) |
908 | { |
909 | SBUF_SHOULD("clear the overflowed and finished flags" ) |
910 | { |
911 | struct sbuf *s = NULL; |
912 | |
913 | s = sbuf_new(NULL, NULL, 16, 0); |
914 | |
915 | SBUF_SETFLAG(s, SBUF_OVERFLOWED); |
916 | SBUF_ASSERT(SBUF_ISSET(s, SBUF_OVERFLOWED)); |
917 | SBUF_SETFLAG(s, SBUF_FINISHED); |
918 | SBUF_ASSERT(SBUF_ISSET(s, SBUF_FINISHED)); |
919 | sbuf_clear(s); |
920 | SBUF_ASSERT_NOT(SBUF_ISSET(s, SBUF_OVERFLOWED)); |
921 | SBUF_ASSERT_NOT(SBUF_ISSET(s, SBUF_FINISHED)); |
922 | |
923 | sbuf_delete(s); |
924 | } |
925 | |
926 | SBUF_SHOULD("reset the position to zero" ) |
927 | { |
928 | struct sbuf *s = NULL; |
929 | |
930 | s = sbuf_new(NULL, NULL, 16, 0); |
931 | |
932 | s->s_len = 1; |
933 | sbuf_clear(s); |
934 | SBUF_ASSERT_EQ(0, s->s_len); |
935 | |
936 | sbuf_delete(s); |
937 | } |
938 | } |
939 | |
940 | SBUF_TESTING("sbuf_extend" ) |
941 | { |
942 | SBUF_SHOULD("allow zero" ) |
943 | { |
944 | struct sbuf *s = NULL; |
945 | int size_before; |
946 | |
947 | s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND); |
948 | size_before = s->s_size; |
949 | SBUF_ASSERT_EQ(0, sbuf_extend(s, 0)); |
950 | SBUF_ASSERT_EQ(size_before, s->s_size); |
951 | |
952 | sbuf_delete(s); |
953 | } |
954 | |
955 | SBUF_SHOULD("fail for sbuf not marked as SBUF_AUTOEXTEND" ) |
956 | { |
957 | struct sbuf *s = NULL; |
958 | |
959 | s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN); |
960 | SBUF_ASSERT_EQ(-1, sbuf_extend(s, 10)); |
961 | |
962 | sbuf_delete(s); |
963 | } |
964 | |
965 | SBUF_SHOULD("accommodate reasonable requests" ) |
966 | { |
967 | struct sbuf *s = NULL; |
968 | int size_before; |
969 | |
970 | s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND); |
971 | size_before = s->s_size; |
972 | |
973 | SBUF_ASSERT_EQ(0, sbuf_extend(s, 10)); |
974 | SBUF_ASSERT_GTE(10, s->s_size - size_before); |
975 | |
976 | sbuf_delete(s); |
977 | } |
978 | |
979 | SBUF_SHOULD("reject requests that cause overflows" ) |
980 | { |
981 | struct sbuf *s = NULL; |
982 | |
983 | s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND); |
984 | SBUF_ASSERT_EQ(-1, sbuf_extend(s, SIZE_MAX)); |
985 | SBUF_ASSERT_EQ(-1, sbuf_extend(s, INT_MAX)); |
986 | |
987 | sbuf_delete(s); |
988 | } |
989 | |
990 | SBUF_SHOULD("transform the sbuf into an SBUF_DYNAMIC one" ) |
991 | { |
992 | struct sbuf *s = NULL; |
993 | char buf[4] = { 0 }; |
994 | |
995 | s = sbuf_new(NULL, buf, sizeof(buf), SBUF_AUTOEXTEND); |
996 | SBUF_ASSERT_NOT(SBUF_ISSET(s, SBUF_DYNAMIC)); |
997 | SBUF_ASSERT_EQ(0, sbuf_extend(s, 10)); |
998 | SBUF_ASSERT(SBUF_ISSET(s, SBUF_DYNAMIC)); |
999 | |
1000 | sbuf_delete(s); |
1001 | } |
1002 | } |
1003 | |
1004 | SBUF_TESTING("sbuf_capacity" ) |
1005 | { |
1006 | SBUF_SHOULD("account for the trailing nul byte" ) |
1007 | { |
1008 | struct sbuf *s = NULL; |
1009 | |
1010 | s = sbuf_new(NULL, NULL, 16, 0); |
1011 | SBUF_ASSERT_EQ(s->s_size - s->s_len - 1, sbuf_capacity(s)); |
1012 | |
1013 | sbuf_delete(s); |
1014 | } |
1015 | } |
1016 | |
1017 | SBUF_TESTING("sbuf_ensure_capacity" ) |
1018 | { |
1019 | SBUF_SHOULD("return 0 if the sbuf already has enough capacity" ) |
1020 | { |
1021 | struct sbuf *s = NULL; |
1022 | int size_before; |
1023 | |
1024 | s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND); |
1025 | size_before = s->s_size; |
1026 | SBUF_ASSERT_EQ(0, sbuf_ensure_capacity(s, 5)); |
1027 | SBUF_ASSERT_EQ(size_before, s->s_size); |
1028 | |
1029 | sbuf_delete(s); |
1030 | } |
1031 | |
1032 | SBUF_SHOULD("extend the buffer as needed" ) |
1033 | { |
1034 | struct sbuf *s = NULL; |
1035 | int size_before; |
1036 | |
1037 | s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND); |
1038 | size_before = s->s_size; |
1039 | SBUF_ASSERT_EQ(0, sbuf_ensure_capacity(s, 30)); |
1040 | SBUF_ASSERT_GT(size_before, s->s_size); |
1041 | |
1042 | sbuf_delete(s); |
1043 | } |
1044 | } |
1045 | |
1046 | SBUF_TESTING("sbuf_bcat" ) |
1047 | { |
1048 | SBUF_SHOULD("fail if the sbuf is marked as overflowed" ) |
1049 | { |
1050 | struct sbuf *s = NULL; |
1051 | |
1052 | s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND); |
1053 | SBUF_SETFLAG(s, SBUF_OVERFLOWED); |
1054 | SBUF_ASSERT_EQ(-1, sbuf_bcat(s, "A" , 1)); |
1055 | |
1056 | sbuf_delete(s); |
1057 | } |
1058 | |
1059 | SBUF_SHOULD("fail if len is too big" ) |
1060 | { |
1061 | struct sbuf *s = NULL; |
1062 | |
1063 | s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND); |
1064 | SBUF_ASSERT_EQ(-1, sbuf_bcat(s, "A" , INT_MAX)); |
1065 | SBUF_ASSERT(SBUF_ISSET(s, SBUF_OVERFLOWED)); |
1066 | |
1067 | sbuf_delete(s); |
1068 | } |
1069 | |
1070 | SBUF_SHOULD("succeed for a fixed buf within limits" ) |
1071 | { |
1072 | struct sbuf *s = NULL; |
1073 | |
1074 | s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN); |
1075 | SBUF_ASSERT_EQ(0, sbuf_bcat(s, "ABC" , 3)); |
1076 | SBUF_ASSERT_EQ(3, s->s_len); |
1077 | SBUF_ASSERT_EQ('A', s->s_buf[0]); |
1078 | SBUF_ASSERT_EQ('B', s->s_buf[1]); |
1079 | SBUF_ASSERT_EQ('C', s->s_buf[2]); |
1080 | |
1081 | sbuf_delete(s); |
1082 | } |
1083 | |
1084 | SBUF_SHOULD("succeed for binary data, even with nul bytes" ) |
1085 | { |
1086 | struct sbuf *s = NULL; |
1087 | |
1088 | s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN); |
1089 | SBUF_ASSERT_EQ(0, sbuf_bcat(s, "A\0C" , 3)); |
1090 | SBUF_ASSERT_EQ(3, s->s_len); |
1091 | SBUF_ASSERT_EQ('A', s->s_buf[0]); |
1092 | SBUF_ASSERT_EQ('\0', s->s_buf[1]); |
1093 | SBUF_ASSERT_EQ('C', s->s_buf[2]); |
1094 | |
1095 | sbuf_delete(s); |
1096 | } |
1097 | |
1098 | SBUF_SHOULD("append to existing data" ) |
1099 | { |
1100 | struct sbuf *s = NULL; |
1101 | |
1102 | s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN); |
1103 | SBUF_ASSERT_EQ(0, sbuf_bcat(s, "ABC" , 3)); |
1104 | SBUF_ASSERT_EQ(3, s->s_len); |
1105 | SBUF_ASSERT_EQ('A', s->s_buf[0]); |
1106 | SBUF_ASSERT_EQ('B', s->s_buf[1]); |
1107 | SBUF_ASSERT_EQ('C', s->s_buf[2]); |
1108 | |
1109 | SBUF_ASSERT_EQ(0, sbuf_bcat(s, "DEF" , 3)); |
1110 | SBUF_ASSERT_EQ(6, s->s_len); |
1111 | SBUF_ASSERT_EQ('D', s->s_buf[3]); |
1112 | SBUF_ASSERT_EQ('E', s->s_buf[4]); |
1113 | SBUF_ASSERT_EQ('F', s->s_buf[5]); |
1114 | |
1115 | sbuf_delete(s); |
1116 | } |
1117 | |
1118 | SBUF_SHOULD("succeed for a fixed buf right up to the limit" ) |
1119 | { |
1120 | struct sbuf *s = NULL; |
1121 | |
1122 | s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN); |
1123 | SBUF_ASSERT_EQ(0, sbuf_bcat(s, "0123456789abcde" , 15)); |
1124 | SBUF_ASSERT_EQ(15, s->s_len); |
1125 | |
1126 | sbuf_delete(s); |
1127 | } |
1128 | |
1129 | SBUF_SHOULD("fail for a fixed buf if too big" ) |
1130 | { |
1131 | struct sbuf *s = NULL; |
1132 | |
1133 | s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN); |
1134 | SBUF_ASSERT_EQ(-1, sbuf_bcat(s, "0123456789abcdef" , 16)); |
1135 | SBUF_ASSERT(SBUF_ISSET(s, SBUF_OVERFLOWED)); |
1136 | |
1137 | sbuf_delete(s); |
1138 | } |
1139 | |
1140 | SBUF_SHOULD("expand the backing buffer as needed" ) |
1141 | { |
1142 | struct sbuf *s = NULL; |
1143 | int size_before; |
1144 | |
1145 | s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND); |
1146 | size_before = s->s_size; |
1147 | SBUF_ASSERT_EQ(0, sbuf_bcat(s, "0123456789abcdef" , 16)); |
1148 | SBUF_ASSERT_GT(size_before, s->s_size); |
1149 | SBUF_ASSERT_EQ(16, s->s_len); |
1150 | |
1151 | sbuf_delete(s); |
1152 | } |
1153 | } |
1154 | |
1155 | SBUF_TESTING("sbuf_bcpy" ) |
1156 | { |
1157 | SBUF_SHOULD("overwrite any existing data" ) |
1158 | { |
1159 | struct sbuf *s = NULL; |
1160 | |
1161 | s = sbuf_new(NULL, NULL, 16, 0); |
1162 | SBUF_ASSERT_EQ(0, sbuf_bcpy(s, "ABC" , 3)); |
1163 | SBUF_ASSERT_EQ(3, s->s_len); |
1164 | SBUF_ASSERT_EQ('A', s->s_buf[0]); |
1165 | SBUF_ASSERT_EQ('B', s->s_buf[1]); |
1166 | SBUF_ASSERT_EQ('C', s->s_buf[2]); |
1167 | |
1168 | SBUF_ASSERT_EQ(0, sbuf_bcpy(s, "XYZ123" , 6)); |
1169 | SBUF_ASSERT_EQ(6, s->s_len); |
1170 | SBUF_ASSERT_EQ('X', s->s_buf[0]); |
1171 | SBUF_ASSERT_EQ('Y', s->s_buf[1]); |
1172 | SBUF_ASSERT_EQ('Z', s->s_buf[2]); |
1173 | SBUF_ASSERT_EQ('1', s->s_buf[3]); |
1174 | SBUF_ASSERT_EQ('2', s->s_buf[4]); |
1175 | SBUF_ASSERT_EQ('3', s->s_buf[5]); |
1176 | |
1177 | sbuf_delete(s); |
1178 | } |
1179 | |
1180 | SBUF_SHOULD("succeed if the sbuf is marked as overflowed, but there is space" ) |
1181 | { |
1182 | struct sbuf *s = NULL; |
1183 | |
1184 | s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND); |
1185 | SBUF_SETFLAG(s, SBUF_OVERFLOWED); |
1186 | SBUF_ASSERT_EQ(0, sbuf_bcpy(s, "A" , 1)); |
1187 | |
1188 | sbuf_delete(s); |
1189 | } |
1190 | |
1191 | SBUF_SHOULD("fail if len is too big" ) |
1192 | { |
1193 | struct sbuf *s = NULL; |
1194 | |
1195 | s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND); |
1196 | SBUF_ASSERT_EQ(-1, sbuf_bcpy(s, "A" , INT_MAX)); |
1197 | SBUF_ASSERT(SBUF_ISSET(s, SBUF_OVERFLOWED)); |
1198 | |
1199 | sbuf_delete(s); |
1200 | } |
1201 | |
1202 | SBUF_SHOULD("succeed for a fixed buf within limits" ) |
1203 | { |
1204 | struct sbuf *s = NULL; |
1205 | |
1206 | s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN); |
1207 | SBUF_ASSERT_EQ(0, sbuf_bcpy(s, "ABC" , 3)); |
1208 | SBUF_ASSERT_EQ(3, s->s_len); |
1209 | SBUF_ASSERT_EQ('A', s->s_buf[0]); |
1210 | SBUF_ASSERT_EQ('B', s->s_buf[1]); |
1211 | SBUF_ASSERT_EQ('C', s->s_buf[2]); |
1212 | |
1213 | sbuf_delete(s); |
1214 | } |
1215 | |
1216 | SBUF_SHOULD("succeed for a fixed buf right up to the limit" ) |
1217 | { |
1218 | struct sbuf *s = NULL; |
1219 | |
1220 | s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN); |
1221 | SBUF_ASSERT_EQ(0, sbuf_bcpy(s, "0123456789abcde" , 15)); |
1222 | SBUF_ASSERT_EQ(15, s->s_len); |
1223 | |
1224 | sbuf_delete(s); |
1225 | } |
1226 | |
1227 | SBUF_SHOULD("fail for a fixed buf if too big" ) |
1228 | { |
1229 | struct sbuf *s = NULL; |
1230 | |
1231 | s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN); |
1232 | SBUF_ASSERT_EQ(-1, sbuf_bcpy(s, "0123456789abcdef" , 16)); |
1233 | SBUF_ASSERT(SBUF_ISSET(s, SBUF_OVERFLOWED)); |
1234 | |
1235 | sbuf_delete(s); |
1236 | } |
1237 | |
1238 | SBUF_SHOULD("expand the backing buffer as needed" ) |
1239 | { |
1240 | struct sbuf *s = NULL; |
1241 | int size_before; |
1242 | |
1243 | s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND); |
1244 | size_before = s->s_size; |
1245 | SBUF_ASSERT_EQ(0, sbuf_bcpy(s, "0123456789abcdef" , 16)); |
1246 | SBUF_ASSERT_GT(size_before, s->s_size); |
1247 | SBUF_ASSERT_EQ(16, s->s_len); |
1248 | |
1249 | sbuf_delete(s); |
1250 | } |
1251 | } |
1252 | |
1253 | SBUF_TESTING("sbuf_cat" ) |
1254 | { |
1255 | SBUF_SHOULD("fail if the sbuf is marked as overflowed" ) |
1256 | { |
1257 | struct sbuf *s = NULL; |
1258 | |
1259 | s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND); |
1260 | SBUF_SETFLAG(s, SBUF_OVERFLOWED); |
1261 | SBUF_ASSERT_EQ(-1, sbuf_cat(s, "A" )); |
1262 | |
1263 | sbuf_delete(s); |
1264 | } |
1265 | |
1266 | SBUF_SHOULD("succeed for a fixed buf within limits" ) |
1267 | { |
1268 | struct sbuf *s = NULL; |
1269 | |
1270 | s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN); |
1271 | SBUF_ASSERT_EQ(0, sbuf_cat(s, "ABC" )); |
1272 | SBUF_ASSERT_EQ(3, s->s_len); |
1273 | SBUF_ASSERT_EQ('A', s->s_buf[0]); |
1274 | SBUF_ASSERT_EQ('B', s->s_buf[1]); |
1275 | SBUF_ASSERT_EQ('C', s->s_buf[2]); |
1276 | |
1277 | sbuf_delete(s); |
1278 | } |
1279 | |
1280 | SBUF_SHOULD("only copy up to a nul byte" ) |
1281 | { |
1282 | struct sbuf *s = NULL; |
1283 | |
1284 | s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN); |
1285 | SBUF_ASSERT_EQ(0, sbuf_cat(s, "A\0C" )); |
1286 | SBUF_ASSERT_EQ(1, s->s_len); |
1287 | SBUF_ASSERT_EQ('A', s->s_buf[0]); |
1288 | |
1289 | sbuf_delete(s); |
1290 | } |
1291 | |
1292 | SBUF_SHOULD("append to existing data" ) |
1293 | { |
1294 | struct sbuf *s = NULL; |
1295 | |
1296 | s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN); |
1297 | SBUF_ASSERT_EQ(0, sbuf_cat(s, "ABC" )); |
1298 | SBUF_ASSERT_EQ(3, s->s_len); |
1299 | SBUF_ASSERT_EQ('A', s->s_buf[0]); |
1300 | SBUF_ASSERT_EQ('B', s->s_buf[1]); |
1301 | SBUF_ASSERT_EQ('C', s->s_buf[2]); |
1302 | |
1303 | SBUF_ASSERT_EQ(0, sbuf_cat(s, "DEF" )); |
1304 | SBUF_ASSERT_EQ(6, s->s_len); |
1305 | SBUF_ASSERT_EQ('D', s->s_buf[3]); |
1306 | SBUF_ASSERT_EQ('E', s->s_buf[4]); |
1307 | SBUF_ASSERT_EQ('F', s->s_buf[5]); |
1308 | |
1309 | sbuf_delete(s); |
1310 | } |
1311 | |
1312 | SBUF_SHOULD("succeed for a fixed buf right up to the limit" ) |
1313 | { |
1314 | struct sbuf *s = NULL; |
1315 | |
1316 | s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN); |
1317 | SBUF_ASSERT_EQ(0, sbuf_cat(s, "0123456789abcde" )); |
1318 | SBUF_ASSERT_EQ(15, s->s_len); |
1319 | |
1320 | sbuf_delete(s); |
1321 | } |
1322 | |
1323 | SBUF_SHOULD("fail for a fixed buf if too big" ) |
1324 | { |
1325 | struct sbuf *s = NULL; |
1326 | |
1327 | s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN); |
1328 | SBUF_ASSERT_EQ(-1, sbuf_cat(s, "0123456789abcdef" )); |
1329 | SBUF_ASSERT(SBUF_ISSET(s, SBUF_OVERFLOWED)); |
1330 | |
1331 | sbuf_delete(s); |
1332 | } |
1333 | |
1334 | SBUF_SHOULD("expand the backing buffer as needed" ) |
1335 | { |
1336 | struct sbuf *s = NULL; |
1337 | int size_before; |
1338 | |
1339 | s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND); |
1340 | size_before = s->s_size; |
1341 | SBUF_ASSERT_EQ(0, sbuf_cat(s, "0123456789abcdef" )); |
1342 | SBUF_ASSERT_GT(size_before, s->s_size); |
1343 | SBUF_ASSERT_EQ(16, s->s_len); |
1344 | |
1345 | sbuf_delete(s); |
1346 | } |
1347 | } |
1348 | |
1349 | SBUF_TESTING("sbuf_cpy" ) |
1350 | { |
1351 | SBUF_SHOULD("overwrite any existing data" ) |
1352 | { |
1353 | struct sbuf *s = NULL; |
1354 | |
1355 | s = sbuf_new(NULL, NULL, 16, 0); |
1356 | SBUF_ASSERT_EQ(0, sbuf_cpy(s, "ABC" )); |
1357 | SBUF_ASSERT_EQ(3, s->s_len); |
1358 | SBUF_ASSERT_EQ('A', s->s_buf[0]); |
1359 | SBUF_ASSERT_EQ('B', s->s_buf[1]); |
1360 | SBUF_ASSERT_EQ('C', s->s_buf[2]); |
1361 | |
1362 | SBUF_ASSERT_EQ(0, sbuf_cpy(s, "XYZ123" )); |
1363 | SBUF_ASSERT_EQ(6, s->s_len); |
1364 | SBUF_ASSERT_EQ('X', s->s_buf[0]); |
1365 | SBUF_ASSERT_EQ('Y', s->s_buf[1]); |
1366 | SBUF_ASSERT_EQ('Z', s->s_buf[2]); |
1367 | SBUF_ASSERT_EQ('1', s->s_buf[3]); |
1368 | SBUF_ASSERT_EQ('2', s->s_buf[4]); |
1369 | SBUF_ASSERT_EQ('3', s->s_buf[5]); |
1370 | |
1371 | sbuf_delete(s); |
1372 | } |
1373 | |
1374 | SBUF_SHOULD("succeed if the sbuf is marked as overflowed, but there is space" ) |
1375 | { |
1376 | struct sbuf *s = NULL; |
1377 | |
1378 | s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND); |
1379 | SBUF_SETFLAG(s, SBUF_OVERFLOWED); |
1380 | SBUF_ASSERT_EQ(0, sbuf_bcpy(s, "A" , 1)); |
1381 | |
1382 | sbuf_delete(s); |
1383 | } |
1384 | |
1385 | SBUF_SHOULD("succeed for a fixed buf within limits" ) |
1386 | { |
1387 | struct sbuf *s = NULL; |
1388 | |
1389 | s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN); |
1390 | SBUF_ASSERT_EQ(0, sbuf_cpy(s, "ABC" )); |
1391 | SBUF_ASSERT_EQ(3, s->s_len); |
1392 | SBUF_ASSERT_EQ('A', s->s_buf[0]); |
1393 | SBUF_ASSERT_EQ('B', s->s_buf[1]); |
1394 | SBUF_ASSERT_EQ('C', s->s_buf[2]); |
1395 | |
1396 | sbuf_delete(s); |
1397 | } |
1398 | |
1399 | SBUF_SHOULD("succeed for a fixed buf right up to the limit" ) |
1400 | { |
1401 | struct sbuf *s = NULL; |
1402 | |
1403 | s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN); |
1404 | SBUF_ASSERT_EQ(0, sbuf_cpy(s, "0123456789abcde" )); |
1405 | SBUF_ASSERT_EQ(15, s->s_len); |
1406 | |
1407 | sbuf_delete(s); |
1408 | } |
1409 | |
1410 | SBUF_SHOULD("fail for a fixed buf if too big" ) |
1411 | { |
1412 | struct sbuf *s = NULL; |
1413 | |
1414 | s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN); |
1415 | SBUF_ASSERT_EQ(-1, sbuf_cpy(s, "0123456789abcdef" )); |
1416 | SBUF_ASSERT(SBUF_ISSET(s, SBUF_OVERFLOWED)); |
1417 | |
1418 | sbuf_delete(s); |
1419 | } |
1420 | |
1421 | SBUF_SHOULD("expand the backing buffer as needed" ) |
1422 | { |
1423 | struct sbuf *s = NULL; |
1424 | int size_before; |
1425 | |
1426 | s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND); |
1427 | size_before = s->s_size; |
1428 | SBUF_ASSERT_EQ(0, sbuf_cpy(s, "0123456789abcdef" )); |
1429 | SBUF_ASSERT_GT(size_before, s->s_size); |
1430 | SBUF_ASSERT_EQ(16, s->s_len); |
1431 | |
1432 | sbuf_delete(s); |
1433 | } |
1434 | } |
1435 | |
1436 | /* also tests sbuf_vprintf: */ |
1437 | SBUF_TESTING("sbuf_printf" ) |
1438 | { |
1439 | SBUF_SHOULD("support simple printing" ) |
1440 | { |
1441 | struct sbuf *s = NULL; |
1442 | |
1443 | s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND); |
1444 | SBUF_ASSERT_EQ(0, sbuf_printf(s, "hello" )); |
1445 | SBUF_ASSERT_EQ(5, s->s_len); |
1446 | SBUF_ASSERT_EQ('h', s->s_buf[0]); |
1447 | SBUF_ASSERT_EQ('e', s->s_buf[1]); |
1448 | SBUF_ASSERT_EQ('l', s->s_buf[2]); |
1449 | SBUF_ASSERT_EQ('l', s->s_buf[3]); |
1450 | SBUF_ASSERT_EQ('o', s->s_buf[4]); |
1451 | |
1452 | sbuf_delete(s); |
1453 | } |
1454 | |
1455 | SBUF_SHOULD("support format strings" ) |
1456 | { |
1457 | struct sbuf *s = NULL; |
1458 | char data1 = 'A'; |
1459 | int data2 = 123; |
1460 | const char *data3 = "foo" ; |
1461 | |
1462 | s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND); |
1463 | SBUF_ASSERT_EQ(0, sbuf_printf(s, "%c %d %s" , data1, data2, data3)); |
1464 | SBUF_ASSERT_EQ(9, s->s_len); |
1465 | SBUF_ASSERT_EQ('A', s->s_buf[0]); |
1466 | SBUF_ASSERT_EQ(' ', s->s_buf[1]); |
1467 | SBUF_ASSERT_EQ('1', s->s_buf[2]); |
1468 | SBUF_ASSERT_EQ('2', s->s_buf[3]); |
1469 | SBUF_ASSERT_EQ('3', s->s_buf[4]); |
1470 | SBUF_ASSERT_EQ(' ', s->s_buf[5]); |
1471 | SBUF_ASSERT_EQ('f', s->s_buf[6]); |
1472 | SBUF_ASSERT_EQ('o', s->s_buf[7]); |
1473 | SBUF_ASSERT_EQ('o', s->s_buf[8]); |
1474 | |
1475 | sbuf_delete(s); |
1476 | } |
1477 | |
1478 | SBUF_SHOULD("work with the fact we reserve a nul byte at the end" ) |
1479 | { |
1480 | struct sbuf *s = NULL; |
1481 | |
1482 | s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN); |
1483 | SBUF_ASSERT_EQ(0, sbuf_printf(s, "0123456789abcde" )); |
1484 | SBUF_ASSERT_NOT(SBUF_ISSET(s, SBUF_OVERFLOWED)); |
1485 | |
1486 | sbuf_delete(s); |
1487 | } |
1488 | |
1489 | SBUF_SHOULD("mark the sbuf as overflowed if we try to write too much" ) |
1490 | { |
1491 | struct sbuf *s = NULL; |
1492 | |
1493 | s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN); |
1494 | SBUF_ASSERT_EQ(-1, sbuf_printf(s, "0123456789abcdef" )); |
1495 | SBUF_ASSERT(SBUF_ISSET(s, SBUF_OVERFLOWED)); |
1496 | |
1497 | sbuf_delete(s); |
1498 | } |
1499 | |
1500 | SBUF_SHOULD("auto-extend as necessary" ) |
1501 | { |
1502 | struct sbuf *s = NULL; |
1503 | const char *data = "0123456789abcdef" ; |
1504 | int size_before; |
1505 | size_t n; |
1506 | |
1507 | s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND); |
1508 | size_before = s->s_size; |
1509 | SBUF_ASSERT_EQ(0, sbuf_printf(s, "%s" , data)); |
1510 | SBUF_ASSERT_GT(size_before, s->s_size); |
1511 | |
1512 | for (n = 0; n < strlen(data); ++n) { |
1513 | SBUF_ASSERT_EQ(data[n], s->s_buf[n]); |
1514 | } |
1515 | |
1516 | sbuf_delete(s); |
1517 | } |
1518 | |
1519 | SBUF_SHOULD("fail if the sbuf is marked as overflowed" ) |
1520 | { |
1521 | struct sbuf *s = NULL; |
1522 | |
1523 | s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN); |
1524 | SBUF_SETFLAG(s, SBUF_OVERFLOWED); |
1525 | SBUF_ASSERT_EQ(-1, sbuf_printf(s, "A" )); |
1526 | |
1527 | sbuf_delete(s); |
1528 | } |
1529 | } |
1530 | |
1531 | SBUF_TESTING("sbuf_putc" ) |
1532 | { |
1533 | SBUF_SHOULD("work where we have capacity" ) |
1534 | { |
1535 | struct sbuf *s = NULL; |
1536 | |
1537 | s = sbuf_new(NULL, NULL, 16, 0); |
1538 | SBUF_ASSERT_EQ(0, sbuf_putc(s, 'a')); |
1539 | SBUF_ASSERT_EQ(1, s->s_len); |
1540 | SBUF_ASSERT_EQ('a', s->s_buf[0]); |
1541 | |
1542 | sbuf_delete(s); |
1543 | } |
1544 | |
1545 | SBUF_SHOULD("fail if we have a full, fixedlen sbuf" ) |
1546 | { |
1547 | struct sbuf *s = NULL; |
1548 | |
1549 | s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN); |
1550 | SBUF_ASSERT_EQ(0, sbuf_cpy(s, "0123456789abcd" )); |
1551 | SBUF_ASSERT_EQ(0, sbuf_putc(s, 'e')); |
1552 | SBUF_ASSERT_EQ(-1, sbuf_putc(s, 'f')); |
1553 | SBUF_ASSERT(SBUF_ISSET(s, SBUF_OVERFLOWED)); |
1554 | |
1555 | sbuf_delete(s); |
1556 | } |
1557 | |
1558 | SBUF_SHOULD("ignore nul" ) |
1559 | { |
1560 | struct sbuf *s = NULL; |
1561 | |
1562 | s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND); |
1563 | SBUF_ASSERT_EQ(0, sbuf_putc(s, '\0')); |
1564 | SBUF_ASSERT_EQ(0, s->s_len); |
1565 | |
1566 | sbuf_delete(s); |
1567 | } |
1568 | |
1569 | SBUF_SHOULD("auto-extend if necessary" ) |
1570 | { |
1571 | struct sbuf *s = NULL; |
1572 | int len_before; |
1573 | int size_before; |
1574 | |
1575 | s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND); |
1576 | SBUF_ASSERT_EQ(0, sbuf_cpy(s, "0123456789abcde" )); |
1577 | len_before = s->s_len; |
1578 | size_before = s->s_size; |
1579 | SBUF_ASSERT_EQ(0, sbuf_putc(s, 'f')); |
1580 | SBUF_ASSERT_EQ(len_before + 1, s->s_len); |
1581 | SBUF_ASSERT_GT(size_before, s->s_size); |
1582 | SBUF_ASSERT_EQ('f', s->s_buf[s->s_len - 1]); |
1583 | |
1584 | sbuf_delete(s); |
1585 | } |
1586 | |
1587 | SBUF_SHOULD("fail if the sbuf is overflowed" ) |
1588 | { |
1589 | struct sbuf *s = NULL; |
1590 | |
1591 | s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND); |
1592 | SBUF_SETFLAG(s, SBUF_OVERFLOWED); |
1593 | SBUF_ASSERT_EQ(-1, sbuf_putc(s, 'a')); |
1594 | |
1595 | sbuf_delete(s); |
1596 | } |
1597 | } |
1598 | |
1599 | SBUF_TESTING("sbuf_trim" ) |
1600 | { |
1601 | SBUF_SHOULD("remove trailing spaces, tabs and newlines" ) |
1602 | { |
1603 | struct sbuf *s = NULL; |
1604 | const char *test = "foo \t\t\n\t" ; |
1605 | |
1606 | s = sbuf_new(NULL, NULL, 16, 0); |
1607 | SBUF_ASSERT_EQ(0, sbuf_cpy(s, test)); |
1608 | SBUF_ASSERT_EQ(strlen(test), s->s_len); |
1609 | SBUF_ASSERT_EQ(0, sbuf_trim(s)); |
1610 | SBUF_ASSERT_EQ(3, s->s_len); |
1611 | |
1612 | sbuf_delete(s); |
1613 | } |
1614 | |
1615 | SBUF_SHOULD("do nothing if there is no trailing whitespace" ) |
1616 | { |
1617 | struct sbuf *s = NULL; |
1618 | const char *test = "foo" ; |
1619 | |
1620 | s = sbuf_new(NULL, NULL, 16, 0); |
1621 | SBUF_ASSERT_EQ(0, sbuf_cpy(s, test)); |
1622 | SBUF_ASSERT_EQ(strlen(test), s->s_len); |
1623 | SBUF_ASSERT_EQ(0, sbuf_trim(s)); |
1624 | SBUF_ASSERT_EQ(strlen(test), s->s_len); |
1625 | |
1626 | sbuf_delete(s); |
1627 | } |
1628 | |
1629 | SBUF_SHOULD("fail if the sbuf is overflowed" ) |
1630 | { |
1631 | struct sbuf *s = NULL; |
1632 | const char *test = "foo " ; |
1633 | |
1634 | s = sbuf_new(NULL, NULL, 16, 0); |
1635 | SBUF_ASSERT_EQ(0, sbuf_cpy(s, test)); |
1636 | SBUF_SETFLAG(s, SBUF_OVERFLOWED); |
1637 | SBUF_ASSERT_EQ(-1, sbuf_trim(s)); |
1638 | SBUF_ASSERT_EQ(strlen(test), s->s_len); |
1639 | |
1640 | sbuf_delete(s); |
1641 | } |
1642 | |
1643 | SBUF_SHOULD("work on empty strings" ) |
1644 | { |
1645 | struct sbuf *s = NULL; |
1646 | |
1647 | s = sbuf_new(NULL, NULL, 16, 0); |
1648 | SBUF_ASSERT_EQ(0, sbuf_trim(s)); |
1649 | SBUF_ASSERT_EQ(0, s->s_len); |
1650 | |
1651 | sbuf_delete(s); |
1652 | } |
1653 | } |
1654 | |
1655 | SBUF_TESTING("sbuf_overflowed" ) |
1656 | { |
1657 | SBUF_SHOULD("return false if it hasn't overflowed" ) |
1658 | { |
1659 | struct sbuf *s = NULL; |
1660 | |
1661 | s = sbuf_new(NULL, NULL, 16, 0); |
1662 | SBUF_ASSERT_NOT(sbuf_overflowed(s)); |
1663 | |
1664 | sbuf_delete(s); |
1665 | } |
1666 | |
1667 | SBUF_SHOULD("return true if it has overflowed" ) |
1668 | { |
1669 | struct sbuf *s = NULL; |
1670 | |
1671 | s = sbuf_new(NULL, NULL, 16, 0); |
1672 | SBUF_SETFLAG(s, SBUF_OVERFLOWED); |
1673 | SBUF_ASSERT(sbuf_overflowed(s)); |
1674 | |
1675 | sbuf_delete(s); |
1676 | } |
1677 | } |
1678 | |
1679 | SBUF_TESTING("sbuf_finish" ) |
1680 | { |
1681 | SBUF_SHOULD("insert a nul byte, clear the overflowed flag and set the finished flag" ) |
1682 | { |
1683 | struct sbuf *s = NULL; |
1684 | |
1685 | s = sbuf_new(NULL, NULL, 16, 0); |
1686 | SBUF_ASSERT_EQ(0, sbuf_putc(s, 'A')); |
1687 | s->s_buf[s->s_len] = 'x'; |
1688 | SBUF_SETFLAG(s, SBUF_OVERFLOWED); |
1689 | SBUF_ASSERT_NOT(SBUF_ISSET(s, SBUF_FINISHED)); |
1690 | |
1691 | sbuf_finish(s); |
1692 | |
1693 | SBUF_ASSERT_EQ(0, s->s_buf[s->s_len]); |
1694 | SBUF_ASSERT_NOT(SBUF_ISSET(s, SBUF_OVERFLOWED)); |
1695 | SBUF_ASSERT(SBUF_ISSET(s, SBUF_FINISHED)); |
1696 | |
1697 | sbuf_delete(s); |
1698 | } |
1699 | } |
1700 | |
1701 | SBUF_TESTING("sbuf_data" ) |
1702 | { |
1703 | SBUF_SHOULD("return the s_buf pointer" ) |
1704 | { |
1705 | struct sbuf *s = NULL; |
1706 | |
1707 | s = sbuf_new(NULL, NULL, 16, 0); |
1708 | SBUF_ASSERT_EQ(s->s_buf, sbuf_data(s)); |
1709 | |
1710 | sbuf_delete(s); |
1711 | } |
1712 | |
1713 | SBUF_SHOULD("return the buffer we gave it" ) |
1714 | { |
1715 | struct sbuf *s = NULL; |
1716 | char buf[4] = { 0 }; |
1717 | |
1718 | s = sbuf_new(NULL, buf, sizeof(buf), 0); |
1719 | SBUF_ASSERT_EQ(buf, sbuf_data(s)); |
1720 | |
1721 | sbuf_delete(s); |
1722 | } |
1723 | } |
1724 | |
1725 | SBUF_TESTING("sbuf_len" ) |
1726 | { |
1727 | SBUF_SHOULD("return the length of the sbuf data" ) |
1728 | { |
1729 | struct sbuf *s = NULL; |
1730 | |
1731 | s = sbuf_new(NULL, NULL, 16, 0); |
1732 | SBUF_ASSERT_EQ(0, sbuf_cpy(s, "hello" )); |
1733 | SBUF_ASSERT_EQ(5, sbuf_len(s)); |
1734 | |
1735 | sbuf_delete(s); |
1736 | } |
1737 | |
1738 | SBUF_SHOULD("return -1 if the sbuf is overflowed" ) |
1739 | { |
1740 | struct sbuf *s = NULL; |
1741 | |
1742 | s = sbuf_new(NULL, NULL, 16, 0); |
1743 | SBUF_ASSERT_EQ(0, sbuf_cpy(s, "hello" )); |
1744 | SBUF_ASSERT_EQ(5, sbuf_len(s)); |
1745 | SBUF_SETFLAG(s, SBUF_OVERFLOWED); |
1746 | SBUF_ASSERT_EQ(-1, sbuf_len(s)); |
1747 | |
1748 | sbuf_delete(s); |
1749 | } |
1750 | } |
1751 | |
1752 | SBUF_TESTING("sbuf_done" ) |
1753 | { |
1754 | SBUF_SHOULD("return false if the sbuf isn't finished" ) |
1755 | { |
1756 | struct sbuf *s = NULL; |
1757 | |
1758 | s = sbuf_new(NULL, NULL, 16, 0); |
1759 | SBUF_ASSERT_NOT(sbuf_done(s)); |
1760 | |
1761 | sbuf_delete(s); |
1762 | } |
1763 | |
1764 | SBUF_SHOULD("return true if the sbuf has finished" ) |
1765 | { |
1766 | struct sbuf *s = NULL; |
1767 | |
1768 | s = sbuf_new(NULL, NULL, 16, 0); |
1769 | SBUF_ASSERT_NOT(sbuf_done(s)); |
1770 | SBUF_SETFLAG(s, SBUF_FINISHED); |
1771 | SBUF_ASSERT(sbuf_done(s)); |
1772 | |
1773 | sbuf_delete(s); |
1774 | } |
1775 | } |
1776 | |
1777 | SBUF_TESTING("sbuf_delete" ) |
1778 | { |
1779 | SBUF_SHOULD("just free the backing buffer if we supplied an sbuf" ) |
1780 | { |
1781 | struct sbuf *s = NULL; |
1782 | struct sbuf existing = {}; |
1783 | |
1784 | s = sbuf_new(&existing, NULL, 16, 0); |
1785 | SBUF_ASSERT_NE(NULL, s->s_buf); |
1786 | |
1787 | sbuf_delete(s); |
1788 | SBUF_ASSERT_EQ(NULL, s->s_buf); |
1789 | } |
1790 | } |
1791 | |
1792 | SBUF_TEST_END; |
1793 | } |
1794 | |
1795 | SYSCTL_PROC(_kern, OID_AUTO, sbuf_test, CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_MASKED, 0, 0, sysctl_sbuf_tests, "A" , "sbuf tests" ); |
1796 | |
1797 | #endif /* DEBUG || DEVELOPMENT */ |
1798 | |