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 #include <sys/param.h> 28 #include <sys/sbuf.h> 29 #include <errno.h> 30 #include <stdarg.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <unistd.h> 35 36 #include <atf-c.h> 37 38 #include "sbuf_test_common.h" 39 40 static char test_string[] = "this is a test string"; 41 #define TEST_STRING_CHOP_COUNT 5 42 _Static_assert(nitems(test_string) > TEST_STRING_CHOP_COUNT, 43 "test_string is too short"); 44 45 ATF_TC_WITHOUT_HEAD(sbuf_clear_test); 46 ATF_TC_BODY(sbuf_clear_test, tc) 47 { 48 struct sbuf *sb; 49 ssize_t buf_len; 50 pid_t child_proc; 51 52 sb = sbuf_new_auto(); 53 ATF_REQUIRE_MSG(sb != NULL, "sbuf_new_auto failed: %s", 54 strerror(errno)); 55 56 ATF_REQUIRE_MSG(sbuf_cat(sb, test_string) == 0, "sbuf_cat failed"); 57 58 /* 59 * Cheat so we can get the contents of the buffer before calling 60 * sbuf_finish(3) below, making additional sbuf changes impossible. 61 */ 62 child_proc = atf_utils_fork(); 63 if (child_proc == 0) { 64 ATF_REQUIRE_EQ_MSG(0, sbuf_finish(sb), "sbuf_finish failed: %s", 65 strerror(errno)); 66 67 sbuf_putbuf(sb); 68 exit(0); 69 } 70 atf_utils_wait(child_proc, 0, test_string, ""); 71 72 sbuf_clear(sb); 73 74 ATF_REQUIRE_MSG(sbuf_finish(sb) == 0, "sbuf_finish failed: %s", 75 strerror(errno)); 76 77 buf_len = sbuf_len(sb); 78 ATF_REQUIRE_MSG(buf_len == 0, "sbuf_len (%zd) != 0", buf_len); 79 ATF_REQUIRE_STREQ_MSG(sbuf_data(sb), "", 80 "sbuf (\"%s\") was not empty", sbuf_data(sb)); 81 82 sbuf_delete(sb); 83 } 84 85 ATF_TC_WITHOUT_HEAD(sbuf_done_and_sbuf_finish_test); 86 ATF_TC_BODY(sbuf_done_and_sbuf_finish_test, tc) 87 { 88 struct sbuf *sb; 89 90 sb = sbuf_new_auto(); 91 ATF_REQUIRE_MSG(sb != NULL, "sbuf_new_auto failed: %s", 92 strerror(errno)); 93 94 ATF_CHECK(sbuf_done(sb) == 0); 95 96 ATF_REQUIRE_MSG(sbuf_finish(sb) == 0, "sbuf_finish failed: %s", 97 strerror(errno)); 98 99 ATF_CHECK(sbuf_done(sb) != 0); 100 101 sbuf_delete(sb); 102 } 103 104 static int 105 drain_ret0(void *arg, const char *data, int len) 106 { 107 108 (void)arg; 109 (void)data; 110 (void)len; 111 112 return (0); 113 } 114 115 ATF_TC_WITHOUT_HEAD(sbuf_drain_ret0_test); 116 ATF_TC_BODY(sbuf_drain_ret0_test, tc) 117 { 118 struct sbuf *sb; 119 120 sb = sbuf_new_auto(); 121 122 sbuf_set_drain(sb, drain_ret0, NULL); 123 124 sbuf_cat(sb, test_string); 125 126 ATF_CHECK_EQ_MSG(-1, sbuf_finish(sb), 127 "required to return error when drain func returns 0"); 128 ATF_CHECK_EQ_MSG(EDEADLK, errno, 129 "errno required to be EDEADLK when drain func returns 0"); 130 } 131 132 ATF_TC_WITHOUT_HEAD(sbuf_len_test); 133 ATF_TC_BODY(sbuf_len_test, tc) 134 { 135 struct sbuf *sb; 136 ssize_t buf_len, test_string_len; 137 int i; 138 139 sb = sbuf_new_auto(); 140 ATF_REQUIRE_MSG(sb != NULL, "sbuf_new_auto failed: %s", 141 strerror(errno)); 142 143 test_string_len = strlen(test_string); 144 for (i = 0; i < 20; i++) { 145 buf_len = sbuf_len(sb); 146 ATF_REQUIRE_MSG(buf_len == (ssize_t)(i * test_string_len), 147 "sbuf_len (%zd) != %zu", buf_len, i * test_string_len); 148 ATF_REQUIRE_MSG(sbuf_cat(sb, test_string) == 0, "sbuf_cat failed"); 149 } 150 151 #ifdef HAVE_SBUF_SET_FLAGS 152 sbuf_set_flags(sb, SBUF_INCLUDENUL); 153 ATF_REQUIRE_MSG((ssize_t)(i * test_string_len + 1) == sbuf_len(sb), 154 "sbuf_len(..) didn't report the NUL char"); 155 #endif 156 157 ATF_REQUIRE_MSG(sbuf_finish(sb) == 0, "sbuf_finish failed: %s", 158 strerror(errno)); 159 160 sbuf_delete(sb); 161 } 162 163 ATF_TC_WITHOUT_HEAD(sbuf_new_fixedlen); 164 ATF_TC_BODY(sbuf_new_fixedlen, tc) 165 { 166 char buf[strlen(test_string) + 1]; 167 struct sbuf sb; 168 pid_t child_proc; 169 170 sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN); 171 172 sbuf_cat(&sb, test_string); 173 174 child_proc = atf_utils_fork(); 175 if (child_proc == 0) { 176 ATF_REQUIRE_EQ_MSG(0, sbuf_finish(&sb), "sbuf_finish failed: %s", 177 strerror(errno)); 178 179 sbuf_putbuf(&sb); 180 exit(0); 181 } 182 atf_utils_wait(child_proc, 0, test_string, ""); 183 184 sbuf_putc(&sb, ' '); 185 186 ATF_CHECK_EQ_MSG(-1, sbuf_finish(&sb), "failed to return error on overflow"); 187 188 sbuf_delete(&sb); 189 } 190 191 ATF_TC_WITHOUT_HEAD(sbuf_setpos_test); 192 ATF_TC_BODY(sbuf_setpos_test, tc) 193 { 194 struct sbuf *sb; 195 size_t test_string_chopped_len, test_string_len; 196 ssize_t buf_len; 197 198 sb = sbuf_new_auto(); 199 ATF_REQUIRE_MSG(sb != NULL, "sbuf_new_auto failed: %s", 200 strerror(errno)); 201 202 /* 203 * An obvious sanity check -- if sbuf_len(..) lies, these invariants 204 * are impossible to test. 205 */ 206 ATF_REQUIRE(sbuf_len(sb) == 0); 207 208 ATF_CHECK(sbuf_setpos(sb, -1) == -1); 209 ATF_CHECK(sbuf_setpos(sb, 0) == 0); 210 ATF_CHECK(sbuf_setpos(sb, 1) == -1); 211 212 ATF_REQUIRE_MSG(sbuf_cat(sb, test_string) == 0, "sbuf_cat failed"); 213 214 buf_len = sbuf_len(sb); 215 test_string_len = strlen(test_string); 216 test_string_chopped_len = test_string_len - TEST_STRING_CHOP_COUNT; 217 ATF_REQUIRE_MSG(buf_len == (ssize_t)test_string_len, 218 "sbuf length (%zd) != test_string length (%zu)", buf_len, 219 test_string_len); 220 221 /* Out of bounds (under length) */ 222 ATF_CHECK(sbuf_setpos(sb, -1) == -1); 223 /* 224 * Out of bounds (over length) 225 * 226 * Note: SBUF_INCLUDENUL not set, so take '\0' into account. 227 */ 228 ATF_CHECK(sbuf_setpos(sb, test_string_len + 2) == -1); 229 /* Within bounds */ 230 ATF_CHECK(sbuf_setpos(sb, test_string_chopped_len) == 0); 231 232 ATF_REQUIRE_MSG(sbuf_finish(sb) == 0, "sbuf_finish failed: %s", 233 strerror(errno)); 234 235 buf_len = sbuf_len(sb); 236 ATF_REQUIRE_MSG(buf_len == (ssize_t)test_string_chopped_len, 237 "sbuf_setpos didn't truncate string as expected"); 238 ATF_REQUIRE_MSG(strncmp(sbuf_data(sb), test_string, buf_len) == 0, 239 "sbuf (\"%s\") != test string (\"%s\") for [0,%zd]", sbuf_data(sb), 240 test_string, buf_len); 241 242 sbuf_delete(sb); 243 } 244 245 ATF_TP_ADD_TCS(tp) 246 { 247 248 ATF_TP_ADD_TC(tp, sbuf_clear_test); 249 ATF_TP_ADD_TC(tp, sbuf_done_and_sbuf_finish_test); 250 ATF_TP_ADD_TC(tp, sbuf_drain_ret0_test); 251 ATF_TP_ADD_TC(tp, sbuf_len_test); 252 ATF_TP_ADD_TC(tp, sbuf_new_fixedlen); 253 #if 0 254 /* TODO */ 255 #ifdef HAVE_SBUF_CLEAR_FLAGS 256 ATF_TP_ADD_TC(tp, sbuf_clear_flags_test); 257 #endif 258 #ifdef HAVE_SBUF_GET_FLAGS 259 ATF_TP_ADD_TC(tp, sbuf_get_flags_test); 260 #endif 261 ATF_TP_ADD_TC(tp, sbuf_new_positive_test); 262 ATF_TP_ADD_TC(tp, sbuf_new_negative_test); 263 #ifdef HAVE_SBUF_SET_FLAGS 264 ATF_TP_ADD_TC(tp, sbuf_set_flags_test); 265 #endif 266 #endif 267 ATF_TP_ADD_TC(tp, sbuf_setpos_test); 268 269 return (atf_no_error()); 270 } 271