| /* 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 */ |