]>
Commit | Line | Data |
---|---|---|
e8aa0cd3 | 1 | #include "reverse_lib.h" |
bdb40a5a | 2 | #include "temp_file.h" |
e8aa0cd3 SW |
3 | |
4 | #include <err.h> | |
5 | #include <stdio.h> | |
6 | #include <stdlib.h> | |
7 | #include <string.h> | |
8 | #include <sysexits.h> | |
9 | #include <unistd.h> | |
10 | ||
a3915755 SW |
11 | /* Reverse input_file. Dump the result in a temporary file. Return the temp |
12 | * file's name. The caller must free the filename. */ | |
e8aa0cd3 | 13 | char* reverse_to_temp_file(const char* input_file) { |
bdb40a5a SW |
14 | char* temp_filename; |
15 | FILE* f; | |
16 | make_temporary_file(&temp_filename, &f); | |
a99e77b4 SW |
17 | reverse_file(input_file, f); |
18 | if (fclose(f) == EOF) err(EX_IOERR, "Couldn't close temporary file"); | |
e8aa0cd3 SW |
19 | return temp_filename; |
20 | } | |
21 | ||
a3915755 SW |
22 | /* Compare the contents of two files. Terminate with a diagnostic if they |
23 | * differ. */ | |
24 | void compare(const char* filename1, const char* filename2) { | |
25 | FILE* f1 = fopen(filename1, "r"); | |
26 | if (f1 == NULL) err(EX_IOERR, "Couldn't open file %s", filename1); | |
27 | FILE* f2 = fopen(filename2, "r"); | |
28 | if (f2 == NULL) err(EX_IOERR, "Couldn't open file %s", filename2); | |
e8aa0cd3 SW |
29 | |
30 | for (int pos = 0; ; pos++) { | |
31 | int c1 = fgetc(f1); | |
32 | int c2 = fgetc(f2); | |
a3915755 SW |
33 | if (c1 == EOF && ferror(f1)) err(EX_IOERR, "Error reading file %s", filename1); |
34 | if (c2 == EOF && ferror(f2)) err(EX_IOERR, "Error reading file %s", filename2); | |
e8aa0cd3 SW |
35 | if (c1 != c2) { |
36 | errx(EX_SOFTWARE, "Unexpected difference found at offset %d after reversing twice. " | |
37 | "Expected %d but found %d", pos, c1, c2); | |
38 | } | |
39 | if (c1 == EOF) break; | |
40 | } | |
41 | ||
a3915755 SW |
42 | if (fclose(f1) != 0) err(EX_IOERR, "Couldn't close file %s", filename1); |
43 | if (fclose(f2) != 0) err(EX_IOERR, "Couldn't close file %s", filename2); | |
44 | } | |
45 | ||
622af8d7 SW |
46 | void test_reverse_twice_from_files_is_the_same(const char* test_filename) { |
47 | char* intermediate = reverse_to_temp_file(test_filename); | |
a3915755 SW |
48 | char* back_to_normal = reverse_to_temp_file(intermediate); |
49 | ||
622af8d7 | 50 | compare(test_filename, back_to_normal); |
a3915755 | 51 | |
e8aa0cd3 SW |
52 | if (unlink(intermediate) == -1) err(EX_IOERR, "Couldn't remove intermediate temp file"); |
53 | if (unlink(back_to_normal) == -1) err(EX_IOERR, "Couldn't remove twice-reversed temp file"); | |
54 | free(intermediate); | |
55 | free(back_to_normal); | |
56 | } | |
57 | ||
622af8d7 | 58 | void test_reverse_from_file_then_from_stream_is_the_same(const char* test_filename) { |
a3915755 SW |
59 | int pipefd[2]; |
60 | if (pipe(pipefd) == -1) err(EX_OSERR, "Couldn't create pipe"); | |
61 | ||
62 | pid_t pid = fork(); | |
63 | if (pid == -1) err(EX_OSERR, "Couldn't fork"); | |
64 | if (pid == 0) { | |
65 | if (close(pipefd[0]) == -1) err(EX_OSERR, "Couldn't close unneeded pipe descriptor"); | |
66 | FILE* to_second = fdopen(pipefd[1], "w"); | |
67 | if (to_second == NULL) err(EX_IOERR, "Couldn't open pipe for writing"); | |
622af8d7 | 68 | reverse_file(test_filename, to_second); |
a3915755 SW |
69 | exit(0); |
70 | } | |
71 | if (close(pipefd[1]) == -1) err(EX_OSERR, "Couldn't close unneeded pipe descriptor"); | |
72 | FILE* from_first = fdopen(pipefd[0], "r"); | |
73 | if (from_first == NULL) err(EX_IOERR, "Couldn't open pipe for reading"); | |
bdb40a5a SW |
74 | char* out_temp_filename; |
75 | FILE* out_file; | |
76 | make_temporary_file(&out_temp_filename, &out_file); | |
a3915755 SW |
77 | reverse_stream(from_first, out_file); |
78 | if (fclose(out_file) == EOF) err(EX_IOERR, "Couldn't close temporary file"); | |
79 | ||
622af8d7 | 80 | compare(test_filename, out_temp_filename); |
a3915755 SW |
81 | |
82 | if (unlink(out_temp_filename) == -1) err(EX_IOERR, "Couldn't remove temp output file"); | |
83 | free(out_temp_filename); | |
84 | } | |
85 | ||
622af8d7 SW |
86 | int main(int argc, char** argv) { |
87 | char* test_filename = "reverse.c"; | |
88 | if (argc > 2) { | |
89 | errx(EX_USAGE, "usage: reverse_test [datafile]"); | |
90 | } else if (argc == 2) { | |
91 | test_filename = argv[1]; | |
92 | } | |
93 | ||
94 | test_reverse_twice_from_files_is_the_same(test_filename); | |
95 | test_reverse_from_file_then_from_stream_is_the_same(test_filename); | |
96 | ||
e8aa0cd3 SW |
97 | puts("PASS"); |
98 | return 0; | |
99 | } |