1 /*- 2 * Copyright (c) 2017 Enji Cooper <ngie@freebsd.org> 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 #include <sys/cdefs.h> 27 __FBSDID("$FreeBSD$"); 28 29 #include <sys/param.h> 30 #include <sys/sbuf.h> 31 #include <errno.h> 32 #include <stdarg.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <unistd.h> 37 38 #include <atf-c.h> 39 40 #include "sbuf_test_common.h" 41 42 static char test_string[] = "this is a test string"; 43 #define TEST_STRING_CHOP_COUNT 5 44 _Static_assert(nitems(test_string) > TEST_STRING_CHOP_COUNT, 45 "test_string is too short"); 46 47 ATF_TC_WITHOUT_HEAD(sbuf_clear_test); 48 ATF_TC_BODY(sbuf_clear_test, tc) 49 { 50 struct sbuf *sb; 51 ssize_t buf_len; 52 pid_t child_proc; 53 54 sb = sbuf_new_auto(); 55 ATF_REQUIRE_MSG(sb != NULL, "sbuf_new_auto failed: %s", 56 strerror(errno)); 57 58 ATF_REQUIRE_MSG(sbuf_cat(sb, test_string) == 0, "sbuf_cat failed"); 59 60 /* 61 * Cheat so we can get the contents of the buffer before calling 62 * sbuf_finish(3) below, making additional sbuf changes impossible. 63 */ 64 child_proc = atf_utils_fork(); 65 if (child_proc == 0) { 66 ATF_REQUIRE_EQ_MSG(0, sbuf_finish(sb), "sbuf_finish failed: %s", 67 strerror(errno)); 68 69 sbuf_putbuf(sb); 70 exit(0); 71 } 72 atf_utils_wait(child_proc, 0, test_string, ""); 73 74 sbuf_clear(sb); 75 76 ATF_REQUIRE_MSG(sbuf_finish(sb) == 0, "sbuf_finish failed: %s", 77 strerror(errno)); 78 79 buf_len = sbuf_len(sb); 80 ATF_REQUIRE_MSG(buf_len == 0, "sbuf_len (%zd) != 0", buf_len); 81 ATF_REQUIRE_STREQ_MSG(sbuf_data(sb), "", 82 "sbuf (\"%s\") was not empty", sbuf_data(sb)); 83 84 sbuf_delete(sb); 85 } 86 87 ATF_TC_WITHOUT_HEAD(sbuf_done_and_sbuf_finish_test); 88 ATF_TC_BODY(sbuf_done_and_sbuf_finish_test, tc) 89 { 90 struct sbuf *sb; 91 92 sb = sbuf_new_auto(); 93 ATF_REQUIRE_MSG(sb != NULL, "sbuf_new_auto failed: %s", 94 strerror(errno)); 95 96 ATF_CHECK(sbuf_done(sb) == 0); 97 98 ATF_REQUIRE_MSG(sbuf_finish(sb) == 0, "sbuf_finish failed: %s", 99 strerror(errno)); 100 101 ATF_CHECK(sbuf_done(sb) != 0); 102 103 sbuf_delete(sb); 104 } 105 106 static int 107 drain_ret0(void *arg, const char *data, int len) 108 { 109 110 (void)arg; 111 (void)data; 112 (void)len; 113 114 return (0); 115 } 116 117 ATF_TC_WITHOUT_HEAD(sbuf_drain_ret0_test); 118 ATF_TC_BODY(sbuf_drain_ret0_test, tc) 119 { 120 struct sbuf *sb; 121 122 sb = sbuf_new_auto(); 123 124 sbuf_set_drain(sb, drain_ret0, NULL); 125 126 sbuf_cat(sb, test_string); 127 128 ATF_CHECK_EQ_MSG(-1, sbuf_finish(sb), 129 "required to return error when drain func returns 0"); 130 ATF_CHECK_EQ_MSG(EDEADLK, errno, 131 "errno required to be EDEADLK when drain func returns 0"); 132 } 133 134 ATF_TC_WITHOUT_HEAD(sbuf_len_test); 135 ATF_TC_BODY(sbuf_len_test, tc) 136 { 137 struct sbuf *sb; 138 ssize_t buf_len, test_string_len; 139 int i; 140 141 sb = sbuf_new_auto(); 142 ATF_REQUIRE_MSG(sb != NULL, "sbuf_new_auto failed: %s", 143 strerror(errno)); 144 145 test_string_len = strlen(test_string); 146 for (i = 0; i < 20; i++) { 147 buf_len = sbuf_len(sb); 148 ATF_REQUIRE_MSG(buf_len == (ssize_t)(i * test_string_len), 149 "sbuf_len (%zd) != %zu", buf_len, i * test_string_len); 150 ATF_REQUIRE_MSG(sbuf_cat(sb, test_string) == 0, "sbuf_cat failed"); 151 } 152 153 #ifdef HAVE_SBUF_SET_FLAGS 154 sbuf_set_flags(sb, SBUF_INCLUDENUL); 155 ATF_REQUIRE_MSG((ssize_t)(i * test_string_len + 1) == sbuf_len(sb), 156 "sbuf_len(..) didn't report the NUL char"); 157 #endif 158 159 ATF_REQUIRE_MSG(sbuf_finish(sb) == 0, "sbuf_finish failed: %s", 160 strerror(errno)); 161 162 sbuf_delete(sb); 163 } 164 165 ATF_TC_WITHOUT_HEAD(sbuf_new_fixedlen); 166 ATF_TC_BODY(sbuf_new_fixedlen, tc) 167 { 168 char buf[strlen(test_string) + 1]; 169 struct sbuf sb; 170 pid_t child_proc; 171 172 sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN); 173 174 sbuf_cat(&sb, test_string); 175 176 child_proc = atf_utils_fork(); 177 if (child_proc == 0) { 178 ATF_REQUIRE_EQ_MSG(0, sbuf_finish(&sb), "sbuf_finish failed: %s", 179 strerror(errno)); 180 181 sbuf_putbuf(&sb); 182 exit(0); 183 } 184 atf_utils_wait(child_proc, 0, test_string, ""); 185 186 sbuf_putc(&sb, ' '); 187 188 ATF_CHECK_EQ_MSG(-1, sbuf_finish(&sb), "failed to return error on overflow"); 189 190 sbuf_delete(&sb); 191 } 192 193 ATF_TC_WITHOUT_HEAD(sbuf_setpos_test); 194 ATF_TC_BODY(sbuf_setpos_test, tc) 195 { 196 struct sbuf *sb; 197 size_t test_string_chopped_len, test_string_len; 198 ssize_t buf_len; 199 200 sb = sbuf_new_auto(); 201 ATF_REQUIRE_MSG(sb != NULL, "sbuf_new_auto failed: %s", 202 strerror(errno)); 203 204 /* 205 * An obvious sanity check -- if sbuf_len(..) lies, these invariants 206 * are impossible to test. 207 */ 208 ATF_REQUIRE(sbuf_len(sb) == 0); 209 210 ATF_CHECK(sbuf_setpos(sb, -1) == -1); 211 ATF_CHECK(sbuf_setpos(sb, 0) == 0); 212 ATF_CHECK(sbuf_setpos(sb, 1) == -1); 213 214 ATF_REQUIRE_MSG(sbuf_cat(sb, test_string) == 0, "sbuf_cat failed"); 215 216 buf_len = sbuf_len(sb); 217 test_string_len = strlen(test_string); 218 test_string_chopped_len = test_string_len - TEST_STRING_CHOP_COUNT; 219 ATF_REQUIRE_MSG(buf_len == (ssize_t)test_string_len, 220 "sbuf length (%zd) != test_string length (%zu)", buf_len, 221 test_string_len); 222 223 /* Out of bounds (under length) */ 224 ATF_CHECK(sbuf_setpos(sb, -1) == -1); 225 /* 226 * Out of bounds (over length) 227 * 228 * Note: SBUF_INCLUDENUL not set, so take '\0' into account. 229 */ 230 ATF_CHECK(sbuf_setpos(sb, test_string_len + 2) == -1); 231 /* Within bounds */ 232 ATF_CHECK(sbuf_setpos(sb, test_string_chopped_len) == 0); 233 234 ATF_REQUIRE_MSG(sbuf_finish(sb) == 0, "sbuf_finish failed: %s", 235 strerror(errno)); 236 237 buf_len = sbuf_len(sb); 238 ATF_REQUIRE_MSG(buf_len == (ssize_t)test_string_chopped_len, 239 "sbuf_setpos didn't truncate string as expected"); 240 ATF_REQUIRE_MSG(strncmp(sbuf_data(sb), test_string, buf_len) == 0, 241 "sbuf (\"%s\") != test string (\"%s\") for [0,%zd]", sbuf_data(sb), 242 test_string, buf_len); 243 244 sbuf_delete(sb); 245 } 246 247 ATF_TP_ADD_TCS(tp) 248 { 249 250 ATF_TP_ADD_TC(tp, sbuf_clear_test); 251 ATF_TP_ADD_TC(tp, sbuf_done_and_sbuf_finish_test); 252 ATF_TP_ADD_TC(tp, sbuf_drain_ret0_test); 253 ATF_TP_ADD_TC(tp, sbuf_len_test); 254 ATF_TP_ADD_TC(tp, sbuf_new_fixedlen); 255 #if 0 256 /* TODO */ 257 #ifdef HAVE_SBUF_CLEAR_FLAGS 258 ATF_TP_ADD_TC(tp, sbuf_clear_flags_test); 259 #endif 260 #ifdef HAVE_SBUF_GET_FLAGS 261 ATF_TP_ADD_TC(tp, sbuf_get_flags_test); 262 #endif 263 ATF_TP_ADD_TC(tp, sbuf_new_positive_test); 264 ATF_TP_ADD_TC(tp, sbuf_new_negative_test); 265 #ifdef HAVE_SBUF_SET_FLAGS 266 ATF_TP_ADD_TC(tp, sbuf_set_flags_test); 267 #endif 268 #endif 269 ATF_TP_ADD_TC(tp, sbuf_setpos_test); 270 271 return (atf_no_error()); 272 } 273