diff options
author | Guillem Jover <guillem@hadrons.org> | 2013-05-23 02:05:19 +0200 |
---|---|---|
committer | Guillem Jover <guillem@hadrons.org> | 2013-05-27 02:49:28 +0200 |
commit | 7196b4dccaaa796dd96358162fdf143393162a8d (patch) | |
tree | 02ea4f8c01aa5ae63963c84544ce9f36df63aea9 /test | |
parent | a97ce513e031b29a47965b740be14fb9a84277fc (diff) |
test: Add new fgetln() and fgetwln() unit test
Diffstat (limited to 'test')
-rw-r--r-- | test/.gitignore | 1 | ||||
-rw-r--r-- | test/Makefile.am | 3 | ||||
-rw-r--r-- | test/fgetln.c | 263 |
3 files changed, 267 insertions, 0 deletions
diff --git a/test/.gitignore b/test/.gitignore index 1c5d1f8..8fda062 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -1,3 +1,4 @@ endian +fgetln headers overlay diff --git a/test/Makefile.am b/test/Makefile.am index 1d41b86..f36b408 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -11,6 +11,9 @@ check_PROGRAMS = \ headers \ overlay \ endian \ + fgetln \ $(nil) +fgetln_LDFLAGS = $(top_builddir)/src/libbsd.la + TESTS = $(check_PROGRAMS) diff --git a/test/fgetln.c b/test/fgetln.c new file mode 100644 index 0000000..83d120c --- /dev/null +++ b/test/fgetln.c @@ -0,0 +1,263 @@ +/* + * Copyright © 2013 Guillem Jover <guillem@hadrons.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/wait.h> +#include <assert.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <locale.h> +#include <wchar.h> + +#define skip(msg) \ + do { \ + printf("skip: %s\n", (msg)); \ + return; \ + } while (0) + +#define DATA_LINES 3 + +static const char *data_ascii[] = { + "this represents an ascii sequence of lines to test the\n", + "fgetln() family of functions\n", + "last line without an ending newline", +}; +static const wchar_t *data_wide[] = { + L"this represénts an utf-8 seqüence of lînes to test the\n", + L"«fgetln()» family of functions § but with an extremely long " + "line to test that the reallocation logic works fine, and that " + "the strings end up being equal…\n", + L"last line ☭ without an ‽ ending newline ♥", +}; + +#define FILE_COUNT 32 + +#define LINE_COUNT 2 +#define LINE_LEN 2 + +struct file { + FILE *fp; + const void **lines; + + const void *got_buf; + int got_len; +}; + +static FILE * +pipe_feed(const char *fmt, const void **buf, int buf_nmemb) +{ + FILE *fp; + int rc; + int pipefd[2]; + pid_t pid; + + rc = pipe(pipefd); + assert(rc >= 0); + + pid = fork(); + assert(pid >= 0); + + if (pid == 0) { + int line; + + /* Child writes data to pipe. */ + rc = close(pipefd[0]); + assert(rc >= 0); + + fp = fdopen(pipefd[1], "w"); + assert(fp); + + for (line = 0; line < buf_nmemb; line++) { + rc = fprintf(fp, fmt, buf[line]); + assert(rc >= 0); + } + + rc = fclose(fp); + assert(rc >= 0); + + _exit(0); + } else { + /* Parent gets a FILE and reads from it. */ + rc = close(pipefd[1]); + assert(rc >= 0); + + fp = fdopen(pipefd[0], "r"); + assert(fp); + + return fp; + } +} + +static void +pipe_close(FILE *fp) +{ + fclose(fp); + wait(NULL); +} + +static void +test_fgetln_single(void) +{ + FILE *fp; + size_t len; + int i; + + fp = pipe_feed("%s", (const void **)data_ascii, DATA_LINES); + for (i = 0; i < DATA_LINES; i++) { + char *str = fgetln(fp, &len); + + assert(str); + assert(memcmp(str, data_ascii[i], len) == 0); + } + assert(fgetln(fp, &len) == NULL); + pipe_close(fp); +} + +static void +test_fgetln_multi(void) +{ + struct file files[FILE_COUNT]; + int i, l; + + for (i = 0; i < FILE_COUNT; i++) { + char *str; + + str = strdup("A\n"); + str[0] += i; + + files[i].lines = malloc(sizeof(char *) * LINE_COUNT); + files[i].lines[0] = str; + files[i].lines[1] = str; + files[i].fp = pipe_feed("%s", files[i].lines, LINE_COUNT); + } + + for (l = 0; l < LINE_COUNT; l++) { + for (i = 0; i < FILE_COUNT; i++) { + size_t len; + char *str; + + str = fgetln(files[i].fp, &len); + + assert(str); + assert(len == LINE_LEN); + + files[i].got_len = len; + files[i].got_buf = str; + } + + for (i = 0; i < FILE_COUNT; i++) { + assert(memcmp(files[i].lines[l], files[i].got_buf, + files[i].got_len) == 0); + } + } + + for (i = 0; i < LINE_COUNT; i++) + pipe_close(files[i].fp); +} + +static void +test_fgetwln_single(void) +{ + FILE *fp; + size_t len; + int i; + + fp = pipe_feed("%ls", (const void **)data_wide, DATA_LINES); + for (i = 0; i < DATA_LINES; i++) { + wchar_t *wstr; + + wstr = fgetwln(fp, &len); + assert(wstr); + + assert(wmemcmp(data_wide[i], wstr, len) == 0); + } + assert(fgetwln(fp, &len) == NULL); + pipe_close(fp); +} + +static void +test_fgetwln_multi(void) +{ + struct file files[FILE_COUNT]; + int i, l; + + for (i = 0; i < FILE_COUNT; i++) { + wchar_t *wstr; + + wstr = wcsdup(L"A\n"); + wstr[0] += i; + + files[i].lines = malloc(sizeof(char *) * LINE_COUNT); + files[i].lines[0] = wstr; + files[i].lines[1] = wstr; + files[i].fp = pipe_feed("%ls", files[i].lines, LINE_COUNT); + } + + for (l = 0; l < LINE_COUNT; l++) { + for (i = 0; i < FILE_COUNT; i++) { + size_t len; + wchar_t *wstr; + + wstr = fgetwln(files[i].fp, &len); + + assert(wstr); + assert(len == LINE_LEN); + + files[i].got_len = len; + files[i].got_buf = wstr; + } + + for (i = 0; i < FILE_COUNT; i++) { + assert(wmemcmp(files[i].lines[l], files[i].got_buf, + files[i].got_len) == 0); + } + } + + for (i = 0; i < LINE_COUNT; i++) + pipe_close(files[i].fp); +} + +static void +test_fgetwln(void) +{ + if (setlocale(LC_ALL, "C.UTF-8") == NULL && + setlocale(LC_ALL, "en_US.UTF-8") == NULL) + skip("no default UTF-8 locale found"); + + test_fgetwln_single(); + test_fgetwln_multi(); +} + +int +main(int argc, char **argv) +{ + test_fgetln_single(); + test_fgetln_multi(); + test_fgetwln(); + + return 0; +} |