fmemopen2_test.c revision 274592
1185029Spjd/*- 2185029SpjdCopyright (C) 2013 Pietro Cerutti <gahr@FreeBSD.org> 3185029Spjd 4185029SpjdRedistribution and use in source and binary forms, with or without 5185029Spjdmodification, are permitted provided that the following conditions 6185029Spjdare met: 7185029Spjd1. Redistributions of source code must retain the above copyright 8185029Spjd notice, this list of conditions and the following disclaimer. 9185029Spjd2. Redistributions in binary form must reproduce the above copyright 10185029Spjd notice, this list of conditions and the following disclaimer in the 11185029Spjd documentation and/or other materials provided with the distribution. 12185029Spjd 13185029SpjdTHIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14185029SpjdANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15185029SpjdIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16185029SpjdARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17185029SpjdFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18185029SpjdDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19185029SpjdOR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20185029SpjdHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21185029SpjdLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22185029SpjdOUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23185029SpjdSUCH DAMAGE. 24185029Spjd*/ 25185029Spjd 26185029Spjd/* 27185029Spjd * Test basic FILE * functions (fread, fwrite, fseek, fclose) against 28185029Spjd * a FILE * retrieved using fmemopen() 29185029Spjd */ 30185029Spjd 31185029Spjd#include <sys/cdefs.h> 32185029Spjd__FBSDID("$FreeBSD: head/lib/libc/tests/stdio/fmemopen2_test.c 274592 2014-11-16 19:57:47Z ngie $"); 33185029Spjd 34185029Spjd#include <errno.h> 35185029Spjd#include <stdio.h> 36185029Spjd#include <string.h> 37185029Spjd#include <strings.h> 38185029Spjd#include <atf-c.h> 39185029Spjd 40185029SpjdATF_TC_WITHOUT_HEAD(test_preexisting); 41185029SpjdATF_TC_BODY(test_preexisting, tc) 42185029Spjd{ 43185029Spjd /* 44185029Spjd * Use a pre-existing buffer. 45185029Spjd */ 46185029Spjd 47185029Spjd char buf[512]; 48185029Spjd char buf2[512]; 49185029Spjd char str[] = "Test writing some stuff"; 50185029Spjd char str2[] = "AAAAAAAAA"; 51185029Spjd char str3[] = "AAAA writing some stuff"; 52185029Spjd FILE *fp; 53185029Spjd size_t nofw, nofr; 54185029Spjd int rc; 55185029Spjd 56185029Spjd /* Open a FILE * using fmemopen. */ 57185029Spjd fp = fmemopen(buf, sizeof(buf), "w"); 58185029Spjd ATF_REQUIRE(fp != NULL); 59185029Spjd 60185029Spjd /* Write to the buffer. */ 61185029Spjd nofw = fwrite(str, 1, sizeof(str), fp); 62185029Spjd ATF_REQUIRE(nofw == sizeof(str)); 63185029Spjd 64185029Spjd /* Close the FILE *. */ 65185029Spjd rc = fclose(fp); 66185029Spjd ATF_REQUIRE(rc == 0); 67185029Spjd 68185029Spjd /* Re-open the FILE * to read back the data. */ 69185029Spjd fp = fmemopen(buf, sizeof(buf), "r"); 70185029Spjd ATF_REQUIRE(fp != NULL); 71185029Spjd 72185029Spjd /* Read from the buffer. */ 73185029Spjd bzero(buf2, sizeof(buf2)); 74185029Spjd nofr = fread(buf2, 1, sizeof(buf2), fp); 75185029Spjd ATF_REQUIRE(nofr == sizeof(buf2)); 76185029Spjd 77185029Spjd /* 78185029Spjd * Since a write on a FILE * retrieved by fmemopen 79185029Spjd * will add a '\0' (if there's space), we can check 80185029Spjd * the strings for equality. 81185029Spjd */ 82185029Spjd ATF_REQUIRE(strcmp(str, buf2) == 0); 83185029Spjd 84185029Spjd /* Close the FILE *. */ 85185029Spjd rc = fclose(fp); 86185029Spjd ATF_REQUIRE(rc == 0); 87185029Spjd 88185029Spjd /* Now open a FILE * on the first 4 bytes of the string. */ 89185029Spjd fp = fmemopen(str, 4, "w"); 90185029Spjd ATF_REQUIRE(fp != NULL); 91185029Spjd 92185029Spjd /* 93185029Spjd * Try to write more bytes than we shoud, we'll get a short count (4). 94185029Spjd */ 95185029Spjd nofw = fwrite(str2, 1, sizeof(str2), fp); 96185029Spjd ATF_REQUIRE(nofw == 4); 97185029Spjd 98185029Spjd /* Close the FILE *. */ 99185029Spjd rc = fclose(fp); 100185029Spjd 101185029Spjd /* Check that the string was not modified after the first 4 bytes. */ 102185029Spjd ATF_REQUIRE(strcmp(str, str3) == 0); 103185029Spjd} 104185029Spjd 105185029SpjdATF_TC_WITHOUT_HEAD(test_autoalloc); 106185029SpjdATF_TC_BODY(test_autoalloc, tc) 107185029Spjd{ 108185029Spjd /* 109185029Spjd * Let fmemopen allocate the buffer. 110185029Spjd */ 111185029Spjd 112185029Spjd char str[] = "A quick test"; 113185029Spjd FILE *fp; 114185029Spjd long pos; 115185029Spjd size_t nofw, nofr, i; 116185029Spjd int rc; 117185029Spjd 118185029Spjd /* Open a FILE * using fmemopen. */ 119185029Spjd fp = fmemopen(NULL, 512, "w+"); 120185029Spjd ATF_REQUIRE(fp != NULL); 121185029Spjd 122185029Spjd /* fill the buffer */ 123185029Spjd for (i = 0; i < 512; i++) { 124185029Spjd nofw = fwrite("a", 1, 1, fp); 125185029Spjd ATF_REQUIRE(nofw == 1); 126185029Spjd } 127185029Spjd 128185029Spjd /* Get the current position into the stream. */ 129185029Spjd pos = ftell(fp); 130185029Spjd ATF_REQUIRE(pos == 512); 131185029Spjd 132185029Spjd /* 133185029Spjd * Try to write past the end, we should get a short object count (0) 134185029Spjd */ 135185029Spjd nofw = fwrite("a", 1, 1, fp); 136185029Spjd ATF_REQUIRE(nofw == 0); 137185029Spjd 138185029Spjd /* Close the FILE *. */ 139185029Spjd rc = fclose(fp); 140185029Spjd ATF_REQUIRE(rc == 0); 141185029Spjd 142185029Spjd /* Open a FILE * using a wrong mode */ 143185029Spjd fp = fmemopen(NULL, 512, "r"); 144185029Spjd ATF_REQUIRE(fp == NULL); 145185029Spjd 146185029Spjd fp = fmemopen(NULL, 512, "w"); 147185029Spjd ATF_REQUIRE(fp == NULL); 148185029Spjd} 149185029Spjd 150185029SpjdATF_TC_WITHOUT_HEAD(test_data_length); 151185029SpjdATF_TC_BODY(test_data_length, tc) 152185029Spjd{ 153185029Spjd /* 154185029Spjd * Here we test that a read operation doesn't go past the end of the 155185029Spjd * data actually written, and that a SEEK_END seeks from the end of the 156185029Spjd * data, not of the whole buffer. 157185029Spjd */ 158185029Spjd FILE *fp; 159185029Spjd char buf[512] = {'\0'}; 160185029Spjd char str[] = "Test data length. "; 161185029Spjd char str2[] = "Do we have two sentences?"; 162185029Spjd char str3[sizeof(str) + sizeof(str2) -1]; 163185029Spjd long pos; 164185029Spjd size_t nofw, nofr; 165185029Spjd int rc; 166185029Spjd 167185029Spjd /* Open a FILE * for updating our buffer. */ 168185029Spjd fp = fmemopen(buf, sizeof(buf), "w+"); 169185029Spjd ATF_REQUIRE(fp != NULL); 170185029Spjd 171185029Spjd /* Write our string into the buffer. */ 172185029Spjd nofw = fwrite(str, 1, sizeof(str), fp); 173185029Spjd ATF_REQUIRE(nofw == sizeof(str)); 174185029Spjd 175185029Spjd /* 176185029Spjd * Now seek to the end and check that ftell 177185029Spjd * gives us sizeof(str). 178185029Spjd */ 179185029Spjd rc = fseek(fp, 0, SEEK_END); 180185029Spjd ATF_REQUIRE(rc == 0); 181185029Spjd pos = ftell(fp); 182185029Spjd ATF_REQUIRE(pos == sizeof(str)); 183185029Spjd 184185029Spjd /* Close the FILE *. */ 185185029Spjd rc = fclose(fp); 186185029Spjd ATF_REQUIRE(rc == 0); 187185029Spjd 188185029Spjd /* Reopen the buffer for appending. */ 189185029Spjd fp = fmemopen(buf, sizeof(buf), "a+"); 190185029Spjd ATF_REQUIRE(fp != NULL); 191185029Spjd 192185029Spjd /* We should now be writing after the first string. */ 193185029Spjd nofw = fwrite(str2, 1, sizeof(str2), fp); 194185029Spjd ATF_REQUIRE(nofw == sizeof(str2)); 195185029Spjd 196185029Spjd /* Rewind the FILE *. */ 197185029Spjd rc = fseek(fp, 0, SEEK_SET); 198185029Spjd ATF_REQUIRE(rc == 0); 199185029Spjd 200185029Spjd /* Make sure we're at the beginning. */ 201185029Spjd pos = ftell(fp); 202185029Spjd ATF_REQUIRE(pos == 0); 203185029Spjd 204185029Spjd /* Read the whole buffer. */ 205185029Spjd nofr = fread(str3, 1, sizeof(buf), fp); 206185029Spjd ATF_REQUIRE(nofr == sizeof(str3)); 207185029Spjd 208185029Spjd /* Make sure the two strings are there. */ 209185029Spjd ATF_REQUIRE(strncmp(str3, str, sizeof(str) - 1) == 0); 210185029Spjd ATF_REQUIRE(strncmp(str3 + sizeof(str) - 1, str2, sizeof(str2)) == 0); 211185029Spjd 212185029Spjd /* Close the FILE *. */ 213185029Spjd rc = fclose(fp); 214185029Spjd ATF_REQUIRE(rc == 0); 215185029Spjd} 216185029Spjd 217185029SpjdATF_TC_WITHOUT_HEAD(test_binary); 218185029SpjdATF_TC_BODY(test_binary, tc) 219185029Spjd{ 220185029Spjd /* 221185029Spjd * Make sure that NULL bytes are never appended when opening a buffer 222185029Spjd * in binary mode. 223185029Spjd */ 224185029Spjd 225185029Spjd FILE *fp; 226185029Spjd char buf[20]; 227185029Spjd char str[] = "Test"; 228185029Spjd size_t nofw; 229185029Spjd int rc, i; 230185029Spjd 231185029Spjd /* Pre-fill the buffer. */ 232185029Spjd memset(buf, 'A', sizeof(buf)); 233185029Spjd 234185029Spjd /* Open a FILE * in binary mode. */ 235185029Spjd fp = fmemopen(buf, sizeof(buf), "w+b"); 236185029Spjd ATF_REQUIRE(fp != NULL); 237185029Spjd 238185029Spjd /* Write some data into it. */ 239185029Spjd nofw = fwrite(str, 1, strlen(str), fp); 240185029Spjd ATF_REQUIRE(nofw == strlen(str)); 241185029Spjd 242185029Spjd /* Make sure that the buffer doesn't contain any NULL bytes. */ 243185029Spjd for (i = 0; i < sizeof(buf); i++) 244185029Spjd ATF_REQUIRE(buf[i] != '\0'); 245185029Spjd 246185029Spjd /* Close the FILE *. */ 247185029Spjd rc = fclose(fp); 248185029Spjd ATF_REQUIRE(rc == 0); 249185029Spjd} 250185029Spjd 251185029SpjdATF_TC_WITHOUT_HEAD(test_append_binary_pos); 252185029SpjdATF_TC_BODY(test_append_binary_pos, tc) 253185029Spjd{ 254185029Spjd /* 255185029Spjd * For compatibility with other implementations (glibc), we set the 256185029Spjd * position to 0 when opening an automatically allocated binary stream 257185029Spjd * for appending. 258185029Spjd */ 259185029Spjd 260185029Spjd FILE *fp; 261185029Spjd 262185029Spjd fp = fmemopen(NULL, 16, "ab+"); 263185029Spjd ATF_REQUIRE(ftell(fp) == 0L); 264185029Spjd fclose(fp); 265185029Spjd 266185029Spjd /* 267185029Spjd * Make sure that a pre-allocated buffer behaves correctly. 268185029Spjd */ 269185029Spjd char buf[] = "Hello"; 270185029Spjd fp = fmemopen(buf, sizeof(buf), "ab+"); 271185029Spjd ATF_REQUIRE(ftell(fp) == strlen(buf)); 272185029Spjd fclose(fp); 273185029Spjd} 274185029Spjd 275185029SpjdATF_TC_WITHOUT_HEAD(test_size_0); 276185029SpjdATF_TC_BODY(test_size_0, tc) 277185029Spjd{ 278185029Spjd /* 279185029Spjd * POSIX mandates that we return EINVAL if size is 0. 280185029Spjd */ 281185029Spjd 282185029Spjd FILE *fp; 283185029Spjd 284185029Spjd fp = fmemopen(NULL, 0, "r+"); 285185029Spjd ATF_REQUIRE(fp == NULL); 286185029Spjd ATF_REQUIRE(errno == EINVAL); 287185029Spjd} 288185029Spjd 289185029SpjdATF_TP_ADD_TCS(tp) 290185029Spjd{ 291185029Spjd 292185029Spjd ATF_TP_ADD_TC(tp, test_autoalloc); 293185029Spjd ATF_TP_ADD_TC(tp, test_preexisting); 294185029Spjd ATF_TP_ADD_TC(tp, test_data_length); 295185029Spjd ATF_TP_ADD_TC(tp, test_binary); 296185029Spjd ATF_TP_ADD_TC(tp, test_append_binary_pos); 297185029Spjd ATF_TP_ADD_TC(tp, test_size_0); 298185029Spjd 299185029Spjd return (atf_no_error()); 300185029Spjd} 301185029Spjd