getdelim_test.c revision 291870
1180237Sdas/*- 2180237Sdas * Copyright (c) 2009 David Schultz <das@FreeBSD.org> 3180237Sdas * All rights reserved. 4180237Sdas * 5180237Sdas * Redistribution and use in source and binary forms, with or without 6180237Sdas * modification, are permitted provided that the following conditions 7180237Sdas * are met: 8180237Sdas * 1. Redistributions of source code must retain the above copyright 9180237Sdas * notice, this list of conditions and the following disclaimer. 10180237Sdas * 2. Redistributions in binary form must reproduce the above copyright 11180237Sdas * notice, this list of conditions and the following disclaimer in the 12180237Sdas * documentation and/or other materials provided with the distribution. 13180237Sdas * 14180237Sdas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15180237Sdas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16180237Sdas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17180237Sdas * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18180237Sdas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19180237Sdas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20180237Sdas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21180237Sdas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22180237Sdas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23180237Sdas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24180237Sdas * SUCH DAMAGE. 25180237Sdas */ 26180237Sdas 27180237Sdas#include <sys/cdefs.h> 28180237Sdas__FBSDID("$FreeBSD: stable/10/lib/libc/tests/stdio/getdelim_test.c 291870 2015-12-05 21:49:35Z ngie $"); 29180237Sdas 30180237Sdas#define _WITH_GETLINE 31180237Sdas#include <errno.h> 32180237Sdas#include <stdio.h> 33180237Sdas#include <stdlib.h> 34180237Sdas#include <string.h> 35180237Sdas 36180237Sdas#include <atf-c.h> 37180237Sdas 38180237Sdas#define CHUNK_MAX 10 39251241Sdas 40180237Sdas/* The assertions depend on this string. */ 41180237Sdaschar apothegm[] = "All work and no play\0 makes Jack a dull boy.\n"; 42180237Sdas 43180237Sdas/* 44180237Sdas * This is a neurotic reader function designed to give getdelim() a 45180237Sdas * hard time. It reads through the string `apothegm' and returns a 46180237Sdas * random number of bytes up to the requested length. 47180237Sdas */ 48180237Sdasstatic int 49180237Sdas_reader(void *cookie, char *buf, int len) 50180237Sdas{ 51180237Sdas size_t *offp = cookie; 52180237Sdas size_t r; 53216221Sdas 54180237Sdas r = random() % CHUNK_MAX + 1; 55180237Sdas if (len > r) 56180237Sdas len = r; 57180237Sdas if (len > sizeof(apothegm) - *offp) 58180237Sdas len = sizeof(apothegm) - *offp; 59180237Sdas memcpy(buf, apothegm + *offp, len); 60180237Sdas *offp += len; 61180237Sdas return (len); 62180237Sdas} 63180237Sdas 64180237Sdasstatic FILE * 65180237Sdasmkfilebuf(void) 66180237Sdas{ 67180237Sdas size_t *offp; 68180237Sdas 69180237Sdas offp = malloc(sizeof(*offp)); /* XXX leak */ 70180237Sdas *offp = 0; 71180237Sdas return (fropen(offp, _reader)); 72180237Sdas} 73180237Sdas 74180237SdasATF_TC_WITHOUT_HEAD(getline_basic); 75180237SdasATF_TC_BODY(getline_basic, tc) 76180237Sdas{ 77180237Sdas FILE *fp; 78180237Sdas char *line; 79180237Sdas size_t linecap; 80180237Sdas int i; 81180237Sdas 82180237Sdas srandom(0); 83180237Sdas 84180237Sdas /* 85180237Sdas * Test multiple times with different buffer sizes 86180237Sdas * and different _reader() return values. 87180237Sdas */ 88180237Sdas errno = 0; 89314023Sngie for (i = 0; i < 8; i++) { 90314023Sngie fp = mkfilebuf(); 91180237Sdas linecap = i; 92180237Sdas line = malloc(i); 93180237Sdas /* First line: the full apothegm */ 94180237Sdas ATF_REQUIRE(getline(&line, &linecap, fp) == sizeof(apothegm) - 1); 95180237Sdas ATF_REQUIRE(memcmp(line, apothegm, sizeof(apothegm)) == 0); 96216221Sdas ATF_REQUIRE(linecap >= sizeof(apothegm)); 97180237Sdas /* Second line: the NUL terminator following the newline */ 98180237Sdas ATF_REQUIRE(getline(&line, &linecap, fp) == 1); 99180237Sdas ATF_REQUIRE(line[0] == '\0' && line[1] == '\0'); 100180237Sdas /* Third line: EOF */ 101180237Sdas line[0] = 'X'; 102180237Sdas ATF_REQUIRE(getline(&line, &linecap, fp) == -1); 103180237Sdas ATF_REQUIRE(line[0] == '\0'); 104180237Sdas free(line); 105180237Sdas line = NULL; 106180237Sdas ATF_REQUIRE(feof(fp)); 107180237Sdas ATF_REQUIRE(!ferror(fp)); 108180237Sdas fclose(fp); 109180237Sdas } 110180237Sdas ATF_REQUIRE(errno == 0); 111180237Sdas} 112314023Sngie 113314023SngieATF_TC_WITHOUT_HEAD(stream_error); 114314023SngieATF_TC_BODY(stream_error, tc) 115180237Sdas{ 116180237Sdas char *line; 117314023Sngie size_t linecap; 118314023Sngie 119314023Sngie /* Make sure read errors are handled properly. */ 120314023Sngie line = NULL; 121314023Sngie linecap = 0; 122314023Sngie errno = 0; 123314023Sngie ATF_REQUIRE(getline(&line, &linecap, stdout) == -1); 124180237Sdas ATF_REQUIRE(errno == EBADF); 125180237Sdas errno = 0; 126180237Sdas ATF_REQUIRE(getdelim(&line, &linecap, 'X', stdout) == -1); 127180237Sdas ATF_REQUIRE(errno == EBADF); 128180237Sdas ATF_REQUIRE(ferror(stdout)); 129180237Sdas} 130180237Sdas 131180237SdasATF_TC_WITHOUT_HEAD(invalid_params); 132180237SdasATF_TC_BODY(invalid_params, tc) 133180237Sdas{ 134180237Sdas FILE *fp; 135314023Sngie char *line; 136314023Sngie size_t linecap; 137314023Sngie 138180237Sdas /* Make sure NULL linep or linecapp pointers are handled. */ 139180237Sdas fp = mkfilebuf(); 140314023Sngie ATF_REQUIRE(getline(NULL, &linecap, fp) == -1); 141180237Sdas ATF_REQUIRE(errno == EINVAL); 142180237Sdas ATF_REQUIRE(getline(&line, NULL, fp) == -1); 143180237Sdas ATF_REQUIRE(errno == EINVAL); 144314023Sngie ATF_REQUIRE(ferror(fp)); 145314023Sngie fclose(fp); 146314023Sngie} 147180237Sdas 148180237SdasATF_TC_WITHOUT_HEAD(eof); 149180237SdasATF_TC_BODY(eof, tc) 150180237Sdas{ 151314023Sngie FILE *fp; 152180237Sdas char *line; 153180237Sdas size_t linecap; 154180237Sdas 155 /* Make sure getline() allocates memory as needed if fp is at EOF. */ 156 errno = 0; 157 fp = mkfilebuf(); 158 while (!feof(fp)) /* advance to EOF; can't fseek this stream */ 159 getc(fp); 160 line = NULL; 161 linecap = 0; 162 printf("getline\n"); 163 ATF_REQUIRE(getline(&line, &linecap, fp) == -1); 164 ATF_REQUIRE(line[0] == '\0'); 165 ATF_REQUIRE(linecap > 0); 166 ATF_REQUIRE(errno == 0); 167 printf("feof\n"); 168 errno = 0; 169 ATF_REQUIRE(feof(fp)); 170 ATF_REQUIRE(!ferror(fp)); 171 fclose(fp); 172} 173 174ATF_TC_WITHOUT_HEAD(nul); 175ATF_TC_BODY(nul, tc) 176{ 177 FILE *fp; 178 char *line; 179 size_t linecap, n; 180 181 errno = 0; 182 line = NULL; 183 linecap = 0; 184 /* Make sure a NUL delimiter works. */ 185 fp = mkfilebuf(); 186 n = strlen(apothegm); 187 printf("getdelim\n"); 188 ATF_REQUIRE(getdelim(&line, &linecap, '\0', fp) == n + 1); 189 ATF_REQUIRE(strcmp(line, apothegm) == 0); 190 ATF_REQUIRE(line[n + 1] == '\0'); 191 ATF_REQUIRE(linecap > n + 1); 192 n = strlen(apothegm + n + 1); 193 printf("getdelim 2\n"); 194 ATF_REQUIRE(getdelim(&line, &linecap, '\0', fp) == n + 1); 195 ATF_REQUIRE(line[n + 1] == '\0'); 196 ATF_REQUIRE(linecap > n + 1); 197 ATF_REQUIRE(errno == 0); 198 ATF_REQUIRE(!ferror(fp)); 199 fclose(fp); 200} 201 202ATF_TC_WITHOUT_HEAD(empty_NULL_buffer); 203ATF_TC_BODY(empty_NULL_buffer, tc) 204{ 205 FILE *fp; 206 char *line; 207 size_t linecap; 208 209 /* Make sure NULL *linep and zero *linecapp are handled. */ 210 fp = mkfilebuf(); 211 free(line); 212 line = NULL; 213 linecap = 42; 214 ATF_REQUIRE(getline(&line, &linecap, fp) == sizeof(apothegm) - 1); 215 ATF_REQUIRE(memcmp(line, apothegm, sizeof(apothegm)) == 0); 216 fp = mkfilebuf(); 217 free(line); 218 line = malloc(100); 219 linecap = 0; 220 ATF_REQUIRE(getline(&line, &linecap, fp) == sizeof(apothegm) - 1); 221 ATF_REQUIRE(memcmp(line, apothegm, sizeof(apothegm)) == 0); 222 free(line); 223 ATF_REQUIRE(!ferror(fp)); 224 fclose(fp); 225} 226 227ATF_TP_ADD_TCS(tp) 228{ 229 230 ATF_TP_ADD_TC(tp, getline_basic); 231 ATF_TP_ADD_TC(tp, stream_error); 232 ATF_TP_ADD_TC(tp, eof); 233 ATF_TP_ADD_TC(tp, invalid_params); 234 ATF_TP_ADD_TC(tp, nul); 235 ATF_TP_ADD_TC(tp, empty_NULL_buffer); 236 237 return (atf_no_error()); 238} 239