Commit 7196b4dc authored by Guillem Jover's avatar Guillem Jover

test: Add new fgetln() and fgetwln() unit test

parent a97ce513
endian
fgetln
headers
overlay
......@@ -11,6 +11,9 @@ check_PROGRAMS = \
headers \
overlay \
endian \
fgetln \
$(nil)
fgetln_LDFLAGS = $(top_builddir)/src/libbsd.la
TESTS = $(check_PROGRAMS)
/*
* 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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment