1 /*
2 * File test program for CUPS.
3 *
4 * Copyright © 2007-2018 by Apple Inc.
5 * Copyright © 1997-2007 by Easy Software Products.
6 *
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more
8 * information.
9 */
10
11 /*
12 * Include necessary headers...
13 */
14
15 #include "string-private.h"
16 #include "debug-private.h"
17 #include "file.h"
18 #include <stdlib.h>
19 #include <time.h>
20 #ifdef _WIN32
21 # include <io.h>
22 #else
23 # include <unistd.h>
24 #endif /* _WIN32 */
25 #include <fcntl.h>
26
27
28 /*
29 * Local functions...
30 */
31
32 static int count_lines(cups_file_t *fp);
33 static int random_tests(void);
34 static int read_write_tests(int compression);
35
36
37 /*
38 * 'main()' - Main entry.
39 */
40
41 int /* O - Exit status */
main(int argc,char * argv[])42 main(int argc, /* I - Number of command-line arguments */
43 char *argv[]) /* I - Command-line arguments */
44 {
45 int status; /* Exit status */
46 char filename[1024]; /* Filename buffer */
47 cups_file_t *fp; /* File pointer */
48 #ifndef _WIN32
49 int fds[2]; /* Open file descriptors */
50 cups_file_t *fdfile; /* File opened with cupsFileOpenFd() */
51 #endif /* !_WIN32 */
52 int count; /* Number of lines in file */
53
54
55 if (argc == 1)
56 {
57 /*
58 * Do uncompressed file tests...
59 */
60
61 status = read_write_tests(0);
62
63 #ifdef HAVE_LIBZ
64 /*
65 * Do compressed file tests...
66 */
67
68 putchar('\n');
69
70 status += read_write_tests(1);
71 #endif /* HAVE_LIBZ */
72
73 /*
74 * Do uncompressed random I/O tests...
75 */
76
77 status += random_tests();
78
79 #ifndef _WIN32
80 /*
81 * Test fdopen and close without reading...
82 */
83
84 pipe(fds);
85 close(fds[1]);
86
87 fputs("\ncupsFileOpenFd(fd, \"r\"): ", stdout);
88 fflush(stdout);
89
90 if ((fdfile = cupsFileOpenFd(fds[0], "r")) == NULL)
91 {
92 puts("FAIL");
93 status ++;
94 }
95 else
96 {
97 /*
98 * Able to open file, now close without reading. If we don't return
99 * before the alarm fires, that is a failure and we will crash on the
100 * alarm signal...
101 */
102
103 puts("PASS");
104 fputs("cupsFileClose(no read): ", stdout);
105 fflush(stdout);
106
107 alarm(5);
108 cupsFileClose(fdfile);
109 alarm(0);
110
111 puts("PASS");
112 }
113 #endif /* !_WIN32 */
114
115 /*
116 * Count lines in test file, rewind, then count again.
117 */
118
119 fputs("\ncupsFileOpen(\"testfile.txt\", \"r\"): ", stdout);
120
121 if ((fp = cupsFileOpen("testfile.txt", "r")) == NULL)
122 {
123 puts("FAIL");
124 status ++;
125 }
126 else
127 {
128 puts("PASS");
129 fputs("cupsFileGets: ", stdout);
130
131 if ((count = count_lines(fp)) != 477)
132 {
133 printf("FAIL (got %d lines, expected 477)\n", count);
134 status ++;
135 }
136 else
137 {
138 puts("PASS");
139 fputs("cupsFileRewind: ", stdout);
140
141 if (cupsFileRewind(fp) != 0)
142 {
143 puts("FAIL");
144 status ++;
145 }
146 else
147 {
148 puts("PASS");
149 fputs("cupsFileGets: ", stdout);
150
151 if ((count = count_lines(fp)) != 477)
152 {
153 printf("FAIL (got %d lines, expected 477)\n", count);
154 status ++;
155 }
156 else
157 puts("PASS");
158 }
159 }
160
161 cupsFileClose(fp);
162 }
163
164 /*
165 * Test path functions...
166 */
167
168 fputs("\ncupsFileFind: ", stdout);
169 #ifdef _WIN32
170 if (cupsFileFind("notepad.exe", "C:/WINDOWS", 1, filename, sizeof(filename)) &&
171 cupsFileFind("notepad.exe", "C:/WINDOWS;C:/WINDOWS/SYSTEM32", 1, filename, sizeof(filename)))
172 #else
173 if (cupsFileFind("cat", "/bin", 1, filename, sizeof(filename)) &&
174 cupsFileFind("cat", "/bin:/usr/bin", 1, filename, sizeof(filename)))
175 #endif /* _WIN32 */
176 printf("PASS (%s)\n", filename);
177 else
178 {
179 puts("FAIL");
180 status ++;
181 }
182
183 /*
184 * Summarize the results and return...
185 */
186
187 if (!status)
188 puts("\nALL TESTS PASSED!");
189 else
190 printf("\n%d TEST(S) FAILED!\n", status);
191 }
192 else
193 {
194 /*
195 * Cat the filename on the command-line...
196 */
197
198 char line[8192]; /* Line from file */
199
200 if ((fp = cupsFileOpen(argv[1], "r")) == NULL)
201 {
202 perror(argv[1]);
203 status = 1;
204 }
205 else if (argc == 2)
206 {
207 status = 0;
208
209 while (cupsFileGets(fp, line, sizeof(line)))
210 puts(line);
211
212 if (!cupsFileEOF(fp))
213 perror(argv[1]);
214
215 cupsFileClose(fp);
216 }
217 else
218 {
219 status = 0;
220 ssize_t bytes;
221
222 while ((bytes = cupsFileRead(fp, line, sizeof(line))) > 0)
223 printf("%s: %d bytes\n", argv[1], (int)bytes);
224
225 if (cupsFileEOF(fp))
226 printf("%s: EOF\n", argv[1]);
227 else
228 perror(argv[1]);
229
230 cupsFileClose(fp);
231 }
232 }
233
234 return (status);
235 }
236
237
238 /*
239 * 'count_lines()' - Count the number of lines in a file.
240 */
241
242 static int /* O - Number of lines */
count_lines(cups_file_t * fp)243 count_lines(cups_file_t *fp) /* I - File to read from */
244 {
245 int count; /* Number of lines */
246 char line[1024]; /* Line buffer */
247
248
249 for (count = 0; cupsFileGets(fp, line, sizeof(line)); count ++);
250
251 return (count);
252 }
253
254
255 /*
256 * 'random_tests()' - Do random access tests.
257 */
258
259 static int /* O - Status */
random_tests(void)260 random_tests(void)
261 {
262 int status, /* Status of tests */
263 pass, /* Current pass */
264 count, /* Number of records read */
265 record, /* Current record */
266 num_records; /* Number of records */
267 off_t pos; /* Position in file */
268 ssize_t expected; /* Expected position in file */
269 cups_file_t *fp; /* File */
270 char buffer[512]; /* Data buffer */
271
272
273 /*
274 * Run 4 passes, each time appending to a data file and then reopening the
275 * file for reading to validate random records in the file.
276 */
277
278 for (status = 0, pass = 0; pass < 4; pass ++)
279 {
280 /*
281 * cupsFileOpen(append)
282 */
283
284 printf("\ncupsFileOpen(append %d): ", pass);
285
286 if ((fp = cupsFileOpen("testfile.dat", "a")) == NULL)
287 {
288 printf("FAIL (%s)\n", strerror(errno));
289 status ++;
290 break;
291 }
292 else
293 puts("PASS");
294
295 /*
296 * cupsFileTell()
297 */
298
299 expected = 256 * (ssize_t)sizeof(buffer) * pass;
300
301 fputs("cupsFileTell(): ", stdout);
302 if ((pos = cupsFileTell(fp)) != (off_t)expected)
303 {
304 printf("FAIL (" CUPS_LLFMT " instead of " CUPS_LLFMT ")\n",
305 CUPS_LLCAST pos, CUPS_LLCAST expected);
306 status ++;
307 break;
308 }
309 else
310 puts("PASS");
311
312 /*
313 * cupsFileWrite()
314 */
315
316 fputs("cupsFileWrite(256 512-byte records): ", stdout);
317 for (record = 0; record < 256; record ++)
318 {
319 memset(buffer, record, sizeof(buffer));
320 if (cupsFileWrite(fp, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer))
321 break;
322 }
323
324 if (record < 256)
325 {
326 printf("FAIL (%d: %s)\n", record, strerror(errno));
327 status ++;
328 break;
329 }
330 else
331 puts("PASS");
332
333 /*
334 * cupsFileTell()
335 */
336
337 expected += 256 * (ssize_t)sizeof(buffer);
338
339 fputs("cupsFileTell(): ", stdout);
340 if ((pos = cupsFileTell(fp)) != (off_t)expected)
341 {
342 printf("FAIL (" CUPS_LLFMT " instead of " CUPS_LLFMT ")\n",
343 CUPS_LLCAST pos, CUPS_LLCAST expected);
344 status ++;
345 break;
346 }
347 else
348 puts("PASS");
349
350 cupsFileClose(fp);
351
352 /*
353 * cupsFileOpen(read)
354 */
355
356 printf("\ncupsFileOpen(read %d): ", pass);
357
358 if ((fp = cupsFileOpen("testfile.dat", "r")) == NULL)
359 {
360 printf("FAIL (%s)\n", strerror(errno));
361 status ++;
362 break;
363 }
364 else
365 puts("PASS");
366
367 /*
368 * cupsFileSeek, cupsFileRead
369 */
370
371 fputs("cupsFileSeek(), cupsFileRead(): ", stdout);
372
373 for (num_records = (pass + 1) * 256, count = (pass + 1) * 256, record = ((int)CUPS_RAND() & 65535) % num_records;
374 count > 0;
375 count --, record = (record + ((int)CUPS_RAND() & 31) - 16 + num_records) % num_records)
376 {
377 /*
378 * The last record is always the first...
379 */
380
381 if (count == 1)
382 record = 0;
383
384 /*
385 * Try reading the data for the specified record, and validate the
386 * contents...
387 */
388
389 expected = (ssize_t)sizeof(buffer) * record;
390
391 if ((pos = cupsFileSeek(fp, expected)) != expected)
392 {
393 printf("FAIL (" CUPS_LLFMT " instead of " CUPS_LLFMT ")\n",
394 CUPS_LLCAST pos, CUPS_LLCAST expected);
395 status ++;
396 break;
397 }
398 else
399 {
400 if (cupsFileRead(fp, buffer, sizeof(buffer)) != sizeof(buffer))
401 {
402 printf("FAIL (%s)\n", strerror(errno));
403 status ++;
404 break;
405 }
406 else if ((buffer[0] & 255) != (record & 255) ||
407 memcmp(buffer, buffer + 1, sizeof(buffer) - 1))
408 {
409 printf("FAIL (Bad Data - %d instead of %d)\n", buffer[0] & 255,
410 record & 255);
411 status ++;
412 break;
413 }
414 }
415 }
416
417 if (count == 0)
418 puts("PASS");
419
420 cupsFileClose(fp);
421 }
422
423 /*
424 * Remove the test file...
425 */
426
427 unlink("testfile.dat");
428
429 /*
430 * Return the test status...
431 */
432
433 return (status);
434 }
435
436
437 /*
438 * 'read_write_tests()' - Perform read/write tests.
439 */
440
441 static int /* O - Status */
read_write_tests(int compression)442 read_write_tests(int compression) /* I - Use compression? */
443 {
444 int i; /* Looping var */
445 cups_file_t *fp; /* File */
446 int status; /* Exit status */
447 char line[1024], /* Line from file */
448 *value; /* Directive value from line */
449 int linenum; /* Line number */
450 unsigned char readbuf[8192], /* Read buffer */
451 writebuf[8192]; /* Write buffer */
452 int byte; /* Byte from file */
453 ssize_t bytes; /* Number of bytes read/written */
454 off_t length; /* Length of file */
455 static const char *partial_line = "partial line";
456 /* Partial line */
457
458
459 /*
460 * No errors so far...
461 */
462
463 status = 0;
464
465 /*
466 * Initialize the write buffer with random data...
467 */
468
469 CUPS_SRAND((unsigned)time(NULL));
470
471 for (i = 0; i < (int)sizeof(writebuf); i ++)
472 writebuf[i] = (unsigned char)CUPS_RAND();
473
474 /*
475 * cupsFileOpen(write)
476 */
477
478 printf("cupsFileOpen(write%s): ", compression ? " compressed" : "");
479
480 fp = cupsFileOpen(compression ? "testfile.dat.gz" : "testfile.dat",
481 compression ? "w9" : "w");
482 if (fp)
483 {
484 puts("PASS");
485
486 /*
487 * cupsFileCompression()
488 */
489
490 fputs("cupsFileCompression(): ", stdout);
491
492 if (cupsFileCompression(fp) == compression)
493 puts("PASS");
494 else
495 {
496 printf("FAIL (Got %d, expected %d)\n", cupsFileCompression(fp),
497 compression);
498 status ++;
499 }
500
501 /*
502 * cupsFilePuts()
503 */
504
505 fputs("cupsFilePuts(): ", stdout);
506
507 if (cupsFilePuts(fp, "# Hello, World\n") > 0)
508 puts("PASS");
509 else
510 {
511 printf("FAIL (%s)\n", strerror(errno));
512 status ++;
513 }
514
515 /*
516 * cupsFilePrintf()
517 */
518
519 fputs("cupsFilePrintf(): ", stdout);
520
521 for (i = 0; i < 1000; i ++)
522 if (cupsFilePrintf(fp, "TestLine %03d\n", i) < 0)
523 break;
524
525 if (i >= 1000)
526 puts("PASS");
527 else
528 {
529 printf("FAIL (%s)\n", strerror(errno));
530 status ++;
531 }
532
533 /*
534 * cupsFilePutChar()
535 */
536
537 fputs("cupsFilePutChar(): ", stdout);
538
539 for (i = 0; i < 256; i ++)
540 if (cupsFilePutChar(fp, i) < 0)
541 break;
542
543 if (i >= 256)
544 puts("PASS");
545 else
546 {
547 printf("FAIL (%s)\n", strerror(errno));
548 status ++;
549 }
550
551 /*
552 * cupsFileWrite()
553 */
554
555 fputs("cupsFileWrite(): ", stdout);
556
557 for (i = 0; i < 10000; i ++)
558 if (cupsFileWrite(fp, (char *)writebuf, sizeof(writebuf)) < 0)
559 break;
560
561 if (i >= 10000)
562 puts("PASS");
563 else
564 {
565 printf("FAIL (%s)\n", strerror(errno));
566 status ++;
567 }
568
569 /*
570 * cupsFilePuts() with partial line...
571 */
572
573 fputs("cupsFilePuts(\"partial line\"): ", stdout);
574
575 if (cupsFilePuts(fp, partial_line) > 0)
576 puts("PASS");
577 else
578 {
579 printf("FAIL (%s)\n", strerror(errno));
580 status ++;
581 }
582
583 /*
584 * cupsFileTell()
585 */
586
587 fputs("cupsFileTell(): ", stdout);
588
589 if ((length = cupsFileTell(fp)) == 81933283)
590 puts("PASS");
591 else
592 {
593 printf("FAIL (" CUPS_LLFMT " instead of 81933283)\n", CUPS_LLCAST length);
594 status ++;
595 }
596
597 /*
598 * cupsFileClose()
599 */
600
601 fputs("cupsFileClose(): ", stdout);
602
603 if (!cupsFileClose(fp))
604 puts("PASS");
605 else
606 {
607 printf("FAIL (%s)\n", strerror(errno));
608 status ++;
609 }
610 }
611 else
612 {
613 printf("FAIL (%s)\n", strerror(errno));
614 status ++;
615 }
616
617 /*
618 * cupsFileOpen(read)
619 */
620
621 fputs("\ncupsFileOpen(read): ", stdout);
622
623 fp = cupsFileOpen(compression ? "testfile.dat.gz" : "testfile.dat", "r");
624 if (fp)
625 {
626 puts("PASS");
627
628 /*
629 * cupsFileGets()
630 */
631
632 fputs("cupsFileGets(): ", stdout);
633
634 if (cupsFileGets(fp, line, sizeof(line)))
635 {
636 if (line[0] == '#')
637 puts("PASS");
638 else
639 {
640 printf("FAIL (Got line \"%s\", expected comment line)\n", line);
641 status ++;
642 }
643 }
644 else
645 {
646 printf("FAIL (%s)\n", strerror(errno));
647 status ++;
648 }
649
650 /*
651 * cupsFileCompression()
652 */
653
654 fputs("cupsFileCompression(): ", stdout);
655
656 if (cupsFileCompression(fp) == compression)
657 puts("PASS");
658 else
659 {
660 printf("FAIL (Got %d, expected %d)\n", cupsFileCompression(fp),
661 compression);
662 status ++;
663 }
664
665 /*
666 * cupsFileGetConf()
667 */
668
669 linenum = 1;
670
671 fputs("cupsFileGetConf(): ", stdout);
672
673 for (i = 0, value = NULL; i < 1000; i ++)
674 if (!cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
675 break;
676 else if (_cups_strcasecmp(line, "TestLine") || !value || atoi(value) != i ||
677 linenum != (i + 2))
678 break;
679
680 if (i >= 1000)
681 puts("PASS");
682 else if (line[0])
683 {
684 printf("FAIL (Line %d, directive \"%s\", value \"%s\")\n", linenum,
685 line, value ? value : "(null)");
686 status ++;
687 }
688 else
689 {
690 printf("FAIL (%s)\n", strerror(errno));
691 status ++;
692 }
693
694 /*
695 * cupsFileGetChar()
696 */
697
698 fputs("cupsFileGetChar(): ", stdout);
699
700 for (i = 0, byte = 0; i < 256; i ++)
701 if ((byte = cupsFileGetChar(fp)) != i)
702 break;
703
704 if (i >= 256)
705 puts("PASS");
706 else if (byte >= 0)
707 {
708 printf("FAIL (Got %d, expected %d)\n", byte, i);
709 status ++;
710 }
711 else
712 {
713 printf("FAIL (%s)\n", strerror(errno));
714 status ++;
715 }
716
717 /*
718 * cupsFileRead()
719 */
720
721 fputs("cupsFileRead(): ", stdout);
722
723 for (i = 0, bytes = 0; i < 10000; i ++)
724 if ((bytes = cupsFileRead(fp, (char *)readbuf, sizeof(readbuf))) < 0)
725 break;
726 else if (memcmp(readbuf, writebuf, sizeof(readbuf)))
727 break;
728
729 if (i >= 10000)
730 puts("PASS");
731 else if (bytes > 0)
732 {
733 printf("FAIL (Pass %d, ", i);
734
735 for (i = 0; i < (int)sizeof(readbuf); i ++)
736 if (readbuf[i] != writebuf[i])
737 break;
738
739 printf("match failed at offset %d - got %02X, expected %02X)\n",
740 i, readbuf[i], writebuf[i]);
741 }
742 else
743 {
744 printf("FAIL (%s)\n", strerror(errno));
745 status ++;
746 }
747
748 /*
749 * cupsFileGetChar() with partial line...
750 */
751
752 fputs("cupsFileGetChar(partial line): ", stdout);
753
754 for (i = 0; i < (int)strlen(partial_line); i ++)
755 if ((byte = cupsFileGetChar(fp)) < 0)
756 break;
757 else if (byte != partial_line[i])
758 break;
759
760 if (!partial_line[i])
761 puts("PASS");
762 else
763 {
764 printf("FAIL (got '%c', expected '%c')\n", byte, partial_line[i]);
765 status ++;
766 }
767
768 /*
769 * cupsFileTell()
770 */
771
772 fputs("cupsFileTell(): ", stdout);
773
774 if ((length = cupsFileTell(fp)) == 81933283)
775 puts("PASS");
776 else
777 {
778 printf("FAIL (" CUPS_LLFMT " instead of 81933283)\n", CUPS_LLCAST length);
779 status ++;
780 }
781
782 /*
783 * cupsFileClose()
784 */
785
786 fputs("cupsFileClose(): ", stdout);
787
788 if (!cupsFileClose(fp))
789 puts("PASS");
790 else
791 {
792 printf("FAIL (%s)\n", strerror(errno));
793 status ++;
794 }
795 }
796 else
797 {
798 printf("FAIL (%s)\n", strerror(errno));
799 status ++;
800 }
801
802 /*
803 * Remove the test file...
804 */
805
806 if (!status)
807 unlink(compression ? "testfile.dat.gz" : "testfile.dat");
808
809 /*
810 * Return the test status...
811 */
812
813 return (status);
814 }
815