#include "reverse_lib.h" #include "temp_file.h" #include #include #include #include #include #include /* Reverse input_file. Dump the result in a temporary file. Return the temp * file's name. The caller must free the filename. */ char* reverse_to_temp_file(const char* input_file) { char* temp_filename; FILE* f; make_temporary_file(&temp_filename, &f); reverse_file(input_file, f); if (fclose(f) == EOF) err(EX_IOERR, "Couldn't close temporary file"); return temp_filename; } /* Compare the contents of two files. Terminate with a diagnostic if they * differ. */ void compare(const char* filename1, const char* filename2) { FILE* f1 = fopen(filename1, "r"); if (f1 == NULL) err(EX_IOERR, "Couldn't open file %s", filename1); FILE* f2 = fopen(filename2, "r"); if (f2 == NULL) err(EX_IOERR, "Couldn't open file %s", filename2); for (int pos = 0; ; pos++) { int c1 = fgetc(f1); int c2 = fgetc(f2); if (c1 == EOF && ferror(f1)) err(EX_IOERR, "Error reading file %s", filename1); if (c2 == EOF && ferror(f2)) err(EX_IOERR, "Error reading file %s", filename2); if (c1 != c2) { errx(EX_SOFTWARE, "Unexpected difference found at offset %d after reversing twice. " "Expected %d but found %d", pos, c1, c2); } if (c1 == EOF) break; } if (fclose(f1) != 0) err(EX_IOERR, "Couldn't close file %s", filename1); if (fclose(f2) != 0) err(EX_IOERR, "Couldn't close file %s", filename2); } void test_reverse_twice_from_files_is_the_same(const char* test_filename) { char* intermediate = reverse_to_temp_file(test_filename); char* back_to_normal = reverse_to_temp_file(intermediate); compare(test_filename, back_to_normal); if (unlink(intermediate) == -1) err(EX_IOERR, "Couldn't remove intermediate temp file"); if (unlink(back_to_normal) == -1) err(EX_IOERR, "Couldn't remove twice-reversed temp file"); free(intermediate); free(back_to_normal); } void test_reverse_from_file_then_from_stream_is_the_same(const char* test_filename) { int pipefd[2]; if (pipe(pipefd) == -1) err(EX_OSERR, "Couldn't create pipe"); pid_t pid = fork(); if (pid == -1) err(EX_OSERR, "Couldn't fork"); if (pid == 0) { if (close(pipefd[0]) == -1) err(EX_OSERR, "Couldn't close unneeded pipe descriptor"); FILE* to_second = fdopen(pipefd[1], "w"); if (to_second == NULL) err(EX_IOERR, "Couldn't open pipe for writing"); reverse_file(test_filename, to_second); exit(0); } if (close(pipefd[1]) == -1) err(EX_OSERR, "Couldn't close unneeded pipe descriptor"); FILE* from_first = fdopen(pipefd[0], "r"); if (from_first == NULL) err(EX_IOERR, "Couldn't open pipe for reading"); char* out_temp_filename; FILE* out_file; make_temporary_file(&out_temp_filename, &out_file); reverse_stream(from_first, out_file); if (fclose(out_file) == EOF) err(EX_IOERR, "Couldn't close temporary file"); compare(test_filename, out_temp_filename); if (unlink(out_temp_filename) == -1) err(EX_IOERR, "Couldn't remove temp output file"); free(out_temp_filename); } int main(int argc, char** argv) { char* test_filename = "reverse.c"; if (argc > 2) { errx(EX_USAGE, "usage: reverse_test [datafile]"); } else if (argc == 2) { test_filename = argv[1]; } test_reverse_twice_from_files_is_the_same(test_filename); test_reverse_from_file_then_from_stream_is_the_same(test_filename); puts("PASS"); return 0; }