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