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