blob: c9bcea80e1dfaf354911492466aa69b8a7530af7 [file] [log] [blame]
/* libnih
*
* Copyright © 2009 Scott James Remnant <scott@netsplit.com>.
* Copyright © 2009 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef NIH_TEST_FILES_H
#define NIH_TEST_FILES_H
#ifndef NIH_IN_TEST_H
# error "This header may only be included by <nih/test.h>"
#endif /* NIH_IN_TEST_H */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fnmatch.h>
/**
* TEST_FILENAME:
* @_var: variable to store filename in.
*
* Generate a filename that may be used for testing, it's unlinked it if
* exists and it's up to you to unlink it when done. @_var should be at
* least PATH_MAX long.
**/
#define TEST_FILENAME(_var) \
do { \
snprintf ((_var), sizeof (_var), "/tmp/%s-%s-%d-%d", \
strrchr (__FILE__, '/') ? strrchr (__FILE__, '/') + 1 : __FILE__, \
__FUNCTION__, __LINE__, getpid ()); \
unlink (_var); \
} while (0)
/**
* TEST_FILE_EQ:
* @_file: FILE to read from,
* @_line: line to expect.
*
* Check that the next line in the file @_file is @_line, which should
* include the terminating newline if one is expected.
**/
#define TEST_FILE_EQ(_file, _line) \
do { \
char _test_file[512]; \
if (! fgets (_test_file, sizeof (_test_file), (_file))) \
TEST_FAILED ("eof on file %p (%s), expected '%s'", \
(_file), #_file, (_line)); \
if (strcmp (_test_file, (_line))) \
TEST_FAILED ("wrong content in file %p (%s), expected '%s' got '%s'", \
(_file), #_file, (_line), _test_file); \
} while (0)
/**
* TEST_FILE_MATCH:
* @_file: FILE to read from,
* @_pattern: pattern to expect.
*
* Check that the next line in the file @_file matches the glob pattern
* @_pattern, which should include the terminating newline if one is expected.
**/
#define TEST_FILE_MATCH(_file, _pattern) \
do { \
char _test_file[512]; \
if (! fgets (_test_file, sizeof (_test_file), (_file))) \
TEST_FAILED ("eof on file %p (%s), expected '%s'", \
(_file), #_file, (_pattern)); \
if (fnmatch ((_pattern), _test_file, 0)) \
TEST_FAILED ("wrong content in file %p (%s), expected '%s' got '%s'", \
(_file), #_file, (_pattern), _test_file); \
} while (0)
/**
* TEST_FILE_EQ_N:
* @_file: FILE to read from,
* @_line: line to expect.
*
* Check that the start of the next line in the file @_file is @_line, up to
* the length of that argument.
**/
#define TEST_FILE_EQ_N(_file, _line) \
do { \
char _test_file[512]; \
if (! fgets (_test_file, sizeof (_test_file), (_file))) \
TEST_FAILED ("eof on file %p (%s), expected '%s'", \
(_file), #_file, (_line)); \
if (strncmp (_test_file, (_line), strlen (_line))) \
TEST_FAILED ("wrong content in file %p (%s), expected '%.*s' got '%.*s'", \
(_file), #_file, (int)strlen (_line), (_line), \
(int)strlen (_line), _test_file); \
} while (0)
/**
* TEST_FILE_NE:
* @_file: FILE to read from,
* @_line: line to expect.
*
* Check that the next line in the file @_file is not @_line, but also not
* end of file.
**/
#define TEST_FILE_NE(_file, _line) \
do { \
char _test_file[512]; \
if (! fgets (_test_file, sizeof (_test_file), (_file))) \
TEST_FAILED ("eof on file %p (%s), expected line other than '%s'", \
(_file), #_file, (_line)); \
if (! strcmp (_test_file, (_line))) \
TEST_FAILED ("wrong content in file %p (%s), got unexpected '%s'", \
(_file), #_file, (_line)); \
} while (0)
/**
* TEST_FILE_NE_N:
* @_file: FILE to read from,
* @_line: line to expect.
*
* Check that the next line in the file @_file does not start with @_line,
* up to the length of that argument; but also not end of file.
**/
#define TEST_FILE_NE_N(_file, _line) \
do { \
char _test_file[512]; \
if (! fgets (_test_file, sizeof (_test_file), (_file))) \
TEST_FAILED ("eof on file %p (%s), expected line other than '%s'", \
(_file), #_file, (_line)); \
if (! strncmp (_test_file, (_line), strlen (_line))) \
TEST_FAILED ("wrong content in file %p (%s), got unexpected '%.*s'", \
(_file), #_file, (int)strlen (_line), (_line)); \
} while (0)
/**
* TEST_FILE_END:
* @_file: FILE to check.
*
* Check that the end of the file @_file has been reached, and that there
* are no more lines to read.
**/
#define TEST_FILE_END(_file) \
do { \
char _test_file[512];\
if (fgets (_test_file, sizeof (_test_file), (_file))) \
TEST_FAILED ("wrong content in file %p (%s), expected eof got '%s'", \
(_file), #_file, _test_file); \
} while (0)
/**
* TEST_FILE_RESET:
* @_file: FILE to reset.
*
* This macro may be used to reset a temporary file such that it can be
* treated as a new one.
**/
#define TEST_FILE_RESET(_file) \
do { \
fflush (_file); \
rewind (_file); \
assert0 (ftruncate (fileno (_file), 0)); \
} while (0)
/**
* TEST_EXPECTED_STR:
* @_str: string to check,
* @_filename: filename to compare against.
*
* Check that the string @_str exactly matches the contents of the
* file @_filename, which is local to the expected directory.
**/
#define TEST_EXPECTED_STR(_str, _filename) \
do { \
char _test_file[512]; \
char * _test_basename; \
int _test_fd; \
struct stat _test_stat; \
char * _test_buf; \
\
strcpy (_test_file, __FILE__); \
_test_basename = strrchr (_test_file, '/'); \
strcpy (_test_basename ? _test_basename + 1 : _test_file, "expected/"); \
strcat (_test_file, (_filename)); \
\
_test_fd = open (_test_file, O_RDONLY); \
assert (_test_fd >= 0); \
\
assert (fstat (_test_fd, &_test_stat) == 0); \
\
_test_buf = mmap (NULL, _test_stat.st_size, PROT_READ, \
MAP_SHARED, _test_fd, 0); \
assert (_test_buf != MAP_FAILED); \
\
if ((_str) == NULL) { \
TEST_FAILED ("wrong value for %s, expected '%.*s' got NULL", \
#_str, (int)_test_stat.st_size, _test_buf); \
} else if ((strlen (_str) != (size_t)_test_stat.st_size) \
|| strncmp ((_str), _test_buf, _test_stat.st_size)) \
TEST_FAILED ("wrong value for %s, expected '%.*s' got '%s'", \
#_str, (int)_test_stat.st_size, _test_buf, \
(_str)); \
\
assert (munmap (_test_buf, _test_stat.st_size) == 0); \
assert (close (_test_fd) == 0); \
} while (0)
/**
* TEST_EXPECTED_FILE:
* @_file: open file to check,
* @_filename: filename to compare against.
*
* Check that the contents of file @_file exactly matches the contents of
* the file @_filename, which is local to the expected directory.
**/
#define TEST_EXPECTED_FILE(_file, _filename) \
do { \
char _test_file[512]; \
char * _test_basename; \
int _test_fd; \
struct stat _test_stat_a; \
struct stat _test_stat_b; \
char * _test_buf_a; \
char * _test_buf_b; \
\
strcpy (_test_file, __FILE__); \
_test_basename = strrchr (_test_file, '/'); \
strcpy (_test_basename ? _test_basename + 1 : _test_file, "expected/"); \
strcat (_test_file, (_filename)); \
\
_test_fd = open (_test_file, O_RDONLY); \
assert (_test_fd >= 0); \
\
assert (fstat (_test_fd, &_test_stat_a) == 0); \
assert (fstat (fileno (_file), &_test_stat_b) == 0); \
\
_test_buf_a = mmap (NULL, _test_stat_a.st_size, PROT_READ, \
MAP_SHARED, _test_fd, 0); \
assert (_test_buf_a != MAP_FAILED); \
\
_test_buf_b = mmap (NULL, _test_stat_b.st_size, PROT_READ, \
MAP_SHARED, fileno (_file), 0); \
assert (_test_buf_b != MAP_FAILED); \
\
if ((_test_stat_a.st_size != _test_stat_b.st_size) \
|| strncmp (_test_buf_a, _test_buf_b, \
_test_stat_a.st_size)) \
TEST_FAILED ("wrong value for %s, expected '%.*s' got '%.*s'", \
#_file, (int)_test_stat_a.st_size, _test_buf_a, \
(int)_test_stat_b.st_size, _test_buf_b); \
\
assert (munmap (_test_buf_a, _test_stat_a.st_size) == 0); \
assert (munmap (_test_buf_b, _test_stat_b.st_size) == 0); \
assert (close (_test_fd) == 0); \
} while (0)
#endif /* NIH_TEST_FILES_H */