1 /* test/hfile.c -- Test cases for low-level input/output streams.
2
3 Copyright (C) 2013-2014, 2016 Genome Research Ltd.
4
5 Author: John Marshall <jm18@sanger.ac.uk>
6
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
13
14 The above copyright notice and this permission notice shall be included in
15 all copies or substantial portions of the Software.
16
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 DEALINGS IN THE SOFTWARE. */
24
25 #include <config.h>
26
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <errno.h>
31
32 #include <sys/stat.h>
33
34 #include "htslib/hfile.h"
35 #include "htslib/hts_defs.h"
36
fail(const char * format,...)37 void HTS_NORETURN fail(const char *format, ...)
38 {
39 int err = errno;
40 va_list args;
41 va_start(args, format);
42 vfprintf(stderr, format, args);
43 va_end(args);
44 if (err != 0) fprintf(stderr, ": %s", strerror(err));
45 fprintf(stderr, "\n");
46 exit(EXIT_FAILURE);
47 }
48
check_offset(hFILE * f,off_t off,const char * message)49 void check_offset(hFILE *f, off_t off, const char *message)
50 {
51 off_t ret = htell(f);
52 if (ret < 0) fail("htell(%s)", message);
53 if (ret == off) return;
54
55 fprintf(stderr, "%s offset incorrect: expected %ld but got %ld\n",
56 message, (long)off, (long)ret);
57 exit(EXIT_FAILURE);
58 }
59
slurp(const char * filename)60 char *slurp(const char *filename)
61 {
62 char *text;
63 struct stat sbuf;
64 size_t filesize;
65 FILE *f = fopen(filename, "rb");
66 if (f == NULL) fail("fopen(\"%s\", \"rb\")", filename);
67 if (fstat(fileno(f), &sbuf) != 0) fail("fstat(\"%s\")", filename);
68 filesize = sbuf.st_size;
69
70 text = (char *) malloc(filesize + 1);
71 if (text == NULL) fail("malloc(text)");
72
73 if (fread(text, 1, filesize, f) != filesize) fail("fread");
74 fclose(f);
75
76 text[filesize] = '\0';
77 return text;
78 }
79
80 hFILE *fin = NULL;
81 hFILE *fout = NULL;
82
reopen(const char * infname,const char * outfname)83 void reopen(const char *infname, const char *outfname)
84 {
85 if (fin) { if (hclose(fin) != 0) fail("hclose(input)"); }
86 if (fout) { if (hclose(fout) != 0) fail("hclose(output)"); }
87
88 fin = hopen(infname, "r");
89 if (fin == NULL) fail("hopen(\"%s\")", infname);
90
91 fout = hopen(outfname, "w");
92 if (fout == NULL) fail("hopen(\"%s\")", outfname);
93 }
94
main(void)95 int main(void)
96 {
97 static const int size[] = { 1, 13, 403, 999, 30000 };
98
99 char buffer[40000];
100 char *original;
101 int c, i;
102 ssize_t n;
103 off_t off;
104
105 reopen("vcf.c", "test/hfile1.tmp");
106 while ((c = hgetc(fin)) != EOF) {
107 if (hputc(c, fout) == EOF) fail("hputc");
108 }
109 if (herrno(fin)) { errno = herrno(fin); fail("hgetc"); }
110
111 reopen("test/hfile1.tmp", "test/hfile2.tmp");
112 if (hpeek(fin, buffer, 50) < 0) fail("hpeek");
113 while ((n = hread(fin, buffer, 17)) > 0) {
114 if (hwrite(fout, buffer, n) != n) fail("hwrite");
115 }
116 if (n < 0) fail("hread");
117
118 reopen("test/hfile2.tmp", "test/hfile3.tmp");
119 while ((n = hread(fin, buffer, sizeof buffer)) > 0) {
120 if (hwrite(fout, buffer, n) != n) fail("hwrite");
121 if (hpeek(fin, buffer, 700) < 0) fail("hpeek");
122 }
123 if (n < 0) fail("hread");
124
125 reopen("test/hfile3.tmp", "test/hfile4.tmp");
126 i = 0;
127 off = 0;
128 while ((n = hread(fin, buffer, size[i++ % 5])) > 0) {
129 off += n;
130 buffer[n] = '\0';
131 check_offset(fin, off, "pre-peek");
132 if (hputs(buffer, fout) == EOF) fail("hputs");
133 if ((n = hpeek(fin, buffer, size[(i+3) % 5])) < 0) fail("hpeek");
134 check_offset(fin, off, "post-peek");
135 }
136 if (n < 0) fail("hread");
137
138 reopen("test/hfile4.tmp", "test/hfile5.tmp");
139 while (hgets(buffer, 80, fin) != NULL) {
140 size_t l = strlen(buffer);
141 if (l > 79) fail("hgets read %zu bytes, should be < 80", l);
142 if (hwrite(fout, buffer, l) != l) fail("hwrite");
143 }
144 if (herrno(fin)) fail("hgets");
145
146 reopen("test/hfile5.tmp", "test/hfile6.tmp");
147 n = hread(fin, buffer, 200);
148 if (n < 0) fail("hread");
149 else if (n != 200) fail("hread only got %d", (int)n);
150 if (hwrite(fout, buffer, 1000) != 1000) fail("hwrite");
151 check_offset(fin, 200, "input/first200");
152 check_offset(fout, 1000, "output/first200");
153
154 if (hseek(fin, 800, SEEK_CUR) < 0) fail("hseek/cur");
155 check_offset(fin, 1000, "input/seek");
156 for (off = 1000; (n = hread(fin, buffer, sizeof buffer)) > 0; off += n)
157 if (hwrite(fout, buffer, n) != n) fail("hwrite");
158 if (n < 0) fail("hread");
159 check_offset(fin, off, "input/eof");
160 check_offset(fout, off, "output/eof");
161
162 if (hseek(fin, 200, SEEK_SET) < 0) fail("hseek/set");
163 if (hseek(fout, 200, SEEK_SET) < 0) fail("hseek(output)");
164 check_offset(fin, 200, "input/backto200");
165 check_offset(fout, 200, "output/backto200");
166 n = hread(fin, buffer, 800);
167 if (n < 0) fail("hread");
168 else if (n != 800) fail("hread only got %d", (int)n);
169 if (hwrite(fout, buffer, 800) != 800) fail("hwrite");
170 check_offset(fin, 1000, "input/wrote800");
171 check_offset(fout, 1000, "output/wrote800");
172
173 if (hflush(fout) == EOF) fail("hflush");
174
175 original = slurp("vcf.c");
176 for (i = 1; i <= 6; i++) {
177 char *text;
178 sprintf(buffer, "test/hfile%d.tmp", i);
179 text = slurp(buffer);
180 if (strcmp(original, text) != 0) {
181 fprintf(stderr, "%s differs from vcf.c\n", buffer);
182 return EXIT_FAILURE;
183 }
184 free(text);
185 }
186 free(original);
187
188 if (hclose(fin) != 0) fail("hclose(input)");
189 if (hclose(fout) != 0) fail("hclose(output)");
190
191 fout = hopen("test/hfile_chars.tmp", "w");
192 if (fout == NULL) fail("hopen(\"test/hfile_chars.tmp\")");
193 for (i = 0; i < 256; i++)
194 if (hputc(i, fout) != i) fail("chars: hputc (%d)", i);
195 if (hclose(fout) != 0) fail("hclose(test/hfile_chars.tmp)");
196
197 fin = hopen("test/hfile_chars.tmp", "r");
198 if (fin == NULL) fail("hopen(\"test/hfile_chars.tmp\") for reading");
199 for (i = 0; i < 256; i++)
200 if ((c = hgetc(fin)) != i)
201 fail("chars: hgetc (%d = 0x%x) returned %d = 0x%x", i, i, c, c);
202 if ((c = hgetc(fin)) != EOF) fail("chars: hgetc (EOF) returned %d", c);
203 if (hclose(fin) != 0) fail("hclose(test/hfile_chars.tmp) for reading");
204
205 fin = hopen("preload:test/hfile_chars.tmp", "r");
206 if (fin == NULL) fail("preloading \"test/hfile_chars.tmp\" for reading");
207 for (i = 0; i < 256; i++)
208 if ((c = hgetc(fin)) != i)
209 fail("preloading chars: hgetc (%d = 0x%x) returned %d = 0x%x", i, i, c, c);
210 if ((c = hgetc(fin)) != EOF) fail("preloading chars: hgetc (EOF) returned %d", c);
211 if (hclose(fin) != 0) fail("preloading hclose(test/hfile_chars.tmp) for reading");
212
213 char* test_string = strdup("Test string");
214 fin = hopen("mem:", "r:", test_string, 12);
215 if (fin == NULL) fail("hopen(\"mem:\", \"r:\", ...)");
216 if (hread(fin, buffer, 12) != 12)
217 fail("hopen('mem:', 'r') failed read");
218 if(strcmp(buffer, test_string) != 0)
219 fail("hopen('mem:', 'r') missread '%s' != '%s'", buffer, test_string);
220 char* internal_buf;
221 size_t interval_buf_len;
222 if((internal_buf = hfile_mem_get_buffer(fin, &interval_buf_len)) == NULL){
223 fail("hopen('mem:', 'r') failed to get internal buffer");
224 }
225 if (hclose(fin) != 0) fail("hclose mem for reading");
226
227 test_string = strdup("Test string");
228 fin = hopen("mem:", "wr:", test_string, 12);
229 if (fin == NULL) fail("hopen(\"mem:\", \"w:\", ...)");
230 if (hseek(fin, -1, SEEK_END) < 0)
231 fail("hopen('mem:', 'wr') failed seek");
232 if (hwrite(fin, " extra", 7) != 7)
233 fail("hopen('mem:', 'wr') failed write");
234 if (hseek(fin, 0, SEEK_SET) < 0)
235 fail("hopen('mem:', 'wr') failed seek");
236 if (hread(fin, buffer, 18) != 18)
237 fail("hopen('mem:', 'wr') failed read");
238 if (strcmp(buffer, "Test string extra") != 0)
239 fail("hopen('mem:', 'wr') misswrote '%s' != '%s'", buffer, "Test string extra");
240 if((internal_buf = hfile_mem_steal_buffer(fin, &interval_buf_len)) == NULL){
241 fail("hopen('mem:', 'wr') failed to get internal buffer");
242 }
243 free(internal_buf);
244 if (hclose(fin) != 0) fail("hclose mem for writing");
245
246 fin = hopen("data:,hello, world!%0A", "r");
247 if (fin == NULL) fail("hopen(\"data:...\")");
248 n = hread(fin, buffer, 300);
249 if (n < 0) fail("hread");
250 buffer[n] = '\0';
251 if (strcmp(buffer, "hello, world!\x0A") != 0) fail("hread result");
252 if (hclose(fin) != 0) fail("hclose(\"data:...\")");
253
254 fin = hopen("test/xx#blank.sam", "r");
255 if (fin == NULL) fail("hopen(\"test/xx#blank.sam\") for reading");
256 if (hread(fin, buffer, 100) != 0) fail("test/xx#blank.sam is non-empty");
257 if (hclose(fin) != 0) fail("hclose(\"test/xx#blank.sam\") for reading");
258
259 fin = hopen("data:,", "r");
260 if (fin == NULL) fail("hopen(\"data:\") for reading");
261 if (hread(fin, buffer, 100) != 0) fail("empty data: URL is non-empty");
262 if (hclose(fin) != 0) fail("hclose(\"data:\") for reading");
263
264 fin = hopen("data:;base64,"
265 // Wikipedia's example quote from Thomas Hobbes' Leviathan
266 "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz"
267 "IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg"
268 "dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu"
269 "dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo"
270 "ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=", "r");
271 if (fin == NULL) fail("hopen(\"data:;base64,...\")");
272 n = hread(fin, buffer, 300);
273 if (n < 0) fail("hread for base64");
274 buffer[n] = '\0';
275 if (strcmp(buffer, "Man is distinguished, not only by his reason, but by "
276 "this singular passion from other animals, which is a lust of the mind, that "
277 "by a perseverance of delight in the continued and indefatigable generation "
278 "of knowledge, exceeds the short vehemence of any carnal pleasure.") != 0)
279 fail("hread result for base64");
280 if (hclose(fin) != 0) fail("hclose(\"data:;base64,...\")");
281
282 return EXIT_SUCCESS;
283 }
284