~svn/ubuntu/oneiric/subversion/ppa

« back to all changes in this revision

Viewing changes to subversion/tests/libsvn_fs_base/skel-test.c

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-12-05 01:26:14 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20051205012614-qom4xfypgtsqc2xq
Tags: 1.2.3dfsg1-3ubuntu1
Merge with the final Debian release of 1.2.3dfsg1-3, bringing in
fixes to the clean target, better documentation of the libdb4.3
upgrade and build fixes to work with swig1.3_1.3.27.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* skel-test.c --- tests for the skeleton functions
 
2
 *
 
3
 * ====================================================================
 
4
 * Copyright (c) 2000-2004 CollabNet.  All rights reserved.
 
5
 *
 
6
 * This software is licensed as described in the file COPYING, which
 
7
 * you should have received as part of this distribution.  The terms
 
8
 * are also available at http://subversion.tigris.org/license-1.html.
 
9
 * If newer versions of this license are posted there, you may use a
 
10
 * newer version instead, at your option.
 
11
 *
 
12
 * This software consists of voluntary contributions made by many
 
13
 * individuals.  For exact contribution history, see the revision
 
14
 * history and logs, available at http://subversion.tigris.org/.
 
15
 * ====================================================================
 
16
 */
 
17
 
 
18
#include <stdlib.h>
 
19
#include <stdarg.h>
 
20
#include <string.h>
 
21
#include <stdio.h>
 
22
 
 
23
#include <apr.h>
 
24
 
 
25
#include "svn_pools.h"
 
26
#include "svn_string.h"
 
27
#include "svn_test.h"
 
28
#include "../../libsvn_fs_base/fs.h"
 
29
#include "../../libsvn_fs_base/util/skel.h"
 
30
 
 
31
 
 
32
/* Some utility functions.  */
 
33
 
 
34
 
 
35
/* A quick way to create error messages.  */
 
36
static svn_error_t *
 
37
fail (apr_pool_t *pool, const char *fmt, ...)
 
38
{
 
39
  va_list ap;
 
40
  char *msg;
 
41
 
 
42
  va_start (ap, fmt);
 
43
  msg = apr_pvsprintf (pool, fmt, ap);
 
44
  va_end (ap);
 
45
 
 
46
  return svn_error_create (SVN_ERR_TEST_FAILED, 0, msg);
 
47
}
 
48
 
 
49
 
 
50
/* Free everything from pool, and return an empty Subversion string.  */
 
51
static svn_stringbuf_t *
 
52
get_empty_string (apr_pool_t *pool)
 
53
{
 
54
  svn_pool_clear (pool);
 
55
 
 
56
  return svn_stringbuf_ncreate (0, 0, pool);
 
57
}
 
58
 
 
59
/* Parse a skeleton from a Subversion string.  */
 
60
static skel_t *
 
61
parse_str (svn_stringbuf_t *str, apr_pool_t *pool)
 
62
{
 
63
  return svn_fs_base__parse_skel (str->data, str->len, pool);
 
64
}
 
65
 
 
66
 
 
67
/* Parse a skeleton from a C string.  */
 
68
static skel_t *
 
69
parse_cstr (const char *str, apr_pool_t *pool)
 
70
{
 
71
  return svn_fs_base__parse_skel (str, strlen (str), pool);
 
72
}
 
73
 
 
74
 
 
75
enum char_type {
 
76
  type_nothing = 0,
 
77
  type_space = 1,
 
78
  type_digit = 2,
 
79
  type_paren = 3,
 
80
  type_name = 4
 
81
};
 
82
 
 
83
static int skel_char_map_initialized;
 
84
static enum char_type skel_char_map[256];
 
85
 
 
86
static void
 
87
init_char_types (void)
 
88
{
 
89
  int i;
 
90
  const char *c;
 
91
 
 
92
  if (skel_char_map_initialized)
 
93
    return;
 
94
 
 
95
  for (i = 0; i < 256; i++)
 
96
    skel_char_map[i] = type_nothing;
 
97
 
 
98
  for (i = '0'; i <= '9'; i++)
 
99
    skel_char_map[i] = type_digit;
 
100
 
 
101
  for (c = "\t\n\f\r "; *c; c++)
 
102
    skel_char_map[(unsigned char) *c] = type_space;
 
103
 
 
104
  for (c = "()[]"; *c; c++)
 
105
    skel_char_map[(unsigned char) *c] = type_paren;
 
106
 
 
107
  for (i = 'A'; i <= 'Z'; i++)
 
108
    skel_char_map[i] = type_name;
 
109
  for (i = 'a'; i <= 'z'; i++)
 
110
    skel_char_map[i] = type_name;
 
111
  
 
112
  skel_char_map_initialized = 1;
 
113
}
 
114
 
 
115
/* Return true iff BYTE is a whitespace byte.  */
 
116
static int
 
117
skel_is_space (char byte)
 
118
{
 
119
  init_char_types ();
 
120
 
 
121
  return skel_char_map[(unsigned char) byte] == type_space;
 
122
}
 
123
 
 
124
#if 0
 
125
/* Return true iff BYTE is a digit byte.  */
 
126
static int
 
127
skel_is_digit (char byte)
 
128
{
 
129
  init_char_types ();
 
130
 
 
131
  return skel_char_map[(unsigned char) byte] == type_digit;
 
132
}
 
133
#endif
 
134
 
 
135
/* Return true iff BYTE is a paren byte.  */
 
136
static int
 
137
skel_is_paren (char byte)
 
138
{
 
139
  init_char_types ();
 
140
 
 
141
  return skel_char_map[(unsigned char) byte] == type_paren;
 
142
}
 
143
 
 
144
/* Return true iff BYTE is a name byte.  */
 
145
static int
 
146
skel_is_name (char byte)
 
147
{
 
148
  init_char_types ();
 
149
 
 
150
  return skel_char_map[(unsigned char) byte] == type_name;
 
151
}
 
152
 
 
153
 
 
154
/* Check that SKEL is an atom, and its contents match LEN bytes of
 
155
   DATA. */
 
156
static int
 
157
check_atom (skel_t *skel, const char *data, apr_size_t len)
 
158
{
 
159
  return (skel
 
160
          && skel->is_atom
 
161
          && skel->len == len
 
162
          && ! memcmp (skel->data, data, len));
 
163
}
 
164
 
 
165
 
 
166
/* Functions that generate/check interesting implicit-length atoms.  */
 
167
 
 
168
 
 
169
/* Append to STR an implicit-length atom consisting of the byte BYTE,
 
170
   terminated by the character TERM.  BYTE must be a name byte,
 
171
   and TERM must be a valid skel separator, or NULL.  */
 
172
static void
 
173
put_implicit_length_byte (svn_stringbuf_t *str, char byte, char term)
 
174
{
 
175
  if (! skel_is_name (byte))
 
176
    abort ();
 
177
  if (term != '\0'
 
178
      && ! skel_is_space (term)
 
179
      && ! skel_is_paren (term))
 
180
    abort ();
 
181
  svn_stringbuf_appendbytes (str, &byte, 1);
 
182
  if (term != '\0')
 
183
    svn_stringbuf_appendbytes (str, &term, 1);
 
184
}
 
185
 
 
186
 
 
187
/* Return true iff SKEL is the parsed form of the atom produced by
 
188
   calling put_implicit_length with BYTE.  */
 
189
static int
 
190
check_implicit_length_byte (skel_t *skel, char byte)
 
191
{
 
192
  if (! skel_is_name (byte))
 
193
    abort ();
 
194
 
 
195
  return check_atom (skel, &byte, 1);
 
196
}
 
197
 
 
198
 
 
199
/* Subroutine for the *_implicit_length_all_chars functions.  */
 
200
static char *
 
201
gen_implicit_length_all_chars (apr_size_t *len_p)
 
202
{
 
203
  apr_size_t pos;
 
204
  int i;
 
205
  static char name[256];
 
206
 
 
207
  /* Gotta start with a valid name character.  */
 
208
  pos = 0;
 
209
  name[pos++] = 'x';
 
210
  for (i = 0; i < 256; i++)
 
211
    if (! skel_is_space ( (apr_byte_t)i)
 
212
        && ! skel_is_paren ( (apr_byte_t)i))
 
213
      name[pos++] = i;
 
214
 
 
215
  *len_p = pos;
 
216
  return name;
 
217
}
 
218
 
 
219
 
 
220
/* Append to STR an implicit-length atom containing every character
 
221
   that's legal in such atoms, terminated by the valid atom terminator
 
222
   TERM.  */
 
223
static void
 
224
put_implicit_length_all_chars (svn_stringbuf_t *str, char term)
 
225
{
 
226
  apr_size_t len;
 
227
  char *name = gen_implicit_length_all_chars (&len);
 
228
 
 
229
  if (term != '\0'
 
230
      && ! skel_is_space (term)
 
231
      && ! skel_is_paren (term))
 
232
    abort ();
 
233
 
 
234
  svn_stringbuf_appendbytes (str, name, len);
 
235
  if (term != '\0')
 
236
    svn_stringbuf_appendbytes (str, &term, 1);
 
237
}
 
238
 
 
239
 
 
240
/* Return true iff SKEL is the parsed form of the atom produced by
 
241
   calling put_implicit_length_all_chars.  */
 
242
static int
 
243
check_implicit_length_all_chars (skel_t *skel)
 
244
{
 
245
  apr_size_t len;
 
246
  char *name = gen_implicit_length_all_chars (&len);
 
247
 
 
248
  return check_atom (skel, name, len);
 
249
}
 
250
 
 
251
 
 
252
 
 
253
/* Test parsing of implicit-length atoms.  */
 
254
 
 
255
static svn_error_t *
 
256
parse_implicit_length (const char **msg, 
 
257
                       svn_boolean_t msg_only,
 
258
                       svn_test_opts_t *opts,
 
259
                       apr_pool_t *pool)
 
260
{
 
261
  svn_stringbuf_t *str = get_empty_string (pool);
 
262
  skel_t *skel;
 
263
 
 
264
  *msg = "parse implicit-length atoms";
 
265
 
 
266
  if (msg_only)
 
267
    return SVN_NO_ERROR;
 
268
 
 
269
  /* Try all valid single-byte atoms.  */
 
270
  {
 
271
    const char *c;
 
272
    int i;
 
273
 
 
274
    for (c = "\t\n\f\r ()[]"; *c; c++)
 
275
      for (i = 0; i < 256; i++)
 
276
        if (skel_is_name((apr_byte_t)i))
 
277
          {
 
278
            svn_stringbuf_setempty (str);
 
279
            put_implicit_length_byte (str, (apr_byte_t)i, *c);
 
280
            skel = parse_str (str, pool);
 
281
            if (! check_implicit_length_byte (skel,  (apr_byte_t)i))
 
282
              return fail (pool, "single-byte implicit-length skel 0x%02x"
 
283
                           " with terminator 0x%02x",
 
284
                           i, c);
 
285
          }
 
286
  }
 
287
 
 
288
  /* Try an atom that contains every character that's legal in an
 
289
     implicit-length atom.  */
 
290
  svn_stringbuf_setempty (str);
 
291
  put_implicit_length_all_chars (str, '\0');
 
292
  skel = parse_str (str, pool);
 
293
  if (! check_implicit_length_all_chars (skel))
 
294
    return fail (pool, "implicit-length skel containing all legal chars");
 
295
 
 
296
  return SVN_NO_ERROR;
 
297
}
 
298
 
 
299
 
 
300
/* Functions that generate/check interesting explicit-length atoms.  */
 
301
 
 
302
 
 
303
/* Append to STR the representation of the atom containing the LEN
 
304
   bytes at DATA, in explicit-length form, using SEP as the separator
 
305
   between the length and the data.  */
 
306
static void
 
307
put_explicit_length (svn_stringbuf_t *str, const char *data, apr_size_t len, 
 
308
                     char sep)
 
309
{
 
310
  char *buf = malloc (len + 100);
 
311
  apr_size_t length_len;
 
312
 
 
313
  if (! skel_is_space (sep))
 
314
    abort ();
 
315
 
 
316
  /* Generate the length and separator character.  */
 
317
  sprintf (buf, "%"APR_SIZE_T_FMT"%c", len, sep);
 
318
  length_len = strlen(buf);
 
319
  
 
320
  /* Copy in the real data (which may contain nulls).  */
 
321
  memcpy (buf + length_len, data, len);
 
322
 
 
323
  svn_stringbuf_appendbytes (str, buf, length_len + len);
 
324
  free (buf);
 
325
}
 
326
 
 
327
 
 
328
/* Return true iff SKEL is the parsed form of an atom generated by
 
329
   put_explicit_length.  */
 
330
static int
 
331
check_explicit_length (skel_t *skel, const char *data, apr_size_t len)
 
332
{
 
333
  return check_atom (skel, data, len);
 
334
}
 
335
 
 
336
 
 
337
/* Test parsing of explicit-length atoms.  */
 
338
 
 
339
static svn_error_t *
 
340
try_explicit_length (const char *data, apr_size_t len, apr_size_t check_len,
 
341
                     apr_pool_t *pool)
 
342
{
 
343
  int i;
 
344
  svn_stringbuf_t *str = get_empty_string (pool);
 
345
  skel_t *skel;
 
346
 
 
347
  /* Try it with every possible separator character.  */
 
348
  for (i = 0; i < 256; i++)
 
349
    if (skel_is_space ( (apr_byte_t)i))
 
350
      {
 
351
        svn_stringbuf_setempty (str);
 
352
        put_explicit_length (str, data, len,  (apr_byte_t)i);
 
353
        skel = parse_str (str, pool);
 
354
        if (! check_explicit_length (skel, data, check_len))
 
355
          return fail (pool, "failed to reparse explicit-length atom"); 
 
356
      }
 
357
 
 
358
  return SVN_NO_ERROR;
 
359
}
 
360
 
 
361
 
 
362
static svn_error_t *
 
363
parse_explicit_length (const char **msg, 
 
364
                       svn_boolean_t msg_only,
 
365
                       svn_test_opts_t *opts,
 
366
                       apr_pool_t *pool)
 
367
{
 
368
  *msg = "parse explicit-length atoms";
 
369
 
 
370
  if (msg_only)
 
371
    return SVN_NO_ERROR;
 
372
 
 
373
  /* Try to parse the empty atom.  */
 
374
  SVN_ERR (try_explicit_length ("", 0, 0, pool));
 
375
 
 
376
  /* Try to parse every one-character atom.  */
 
377
  {
 
378
    int i;
 
379
 
 
380
    for (i = 0; i < 256; i++)
 
381
      {
 
382
        char buf[1];
 
383
 
 
384
        buf[0] = i;
 
385
        SVN_ERR (try_explicit_length (buf, 1, 1, pool));
 
386
      }
 
387
  }
 
388
 
 
389
  /* Try to parse an atom containing every character.  */
 
390
  {
 
391
    int i;
 
392
    char data[256];
 
393
 
 
394
    for (i = 0; i < 256; i++)
 
395
      data[i] = i;
 
396
 
 
397
    SVN_ERR (try_explicit_length (data, 256, 256, pool));
 
398
  }
 
399
 
 
400
  return SVN_NO_ERROR;
 
401
}
 
402
 
 
403
 
 
404
 
 
405
/* Test parsing of invalid atoms. */
 
406
 
 
407
static struct invalid_atoms
 
408
{
 
409
  int type;
 
410
  apr_size_t len;
 
411
  const char *data;
 
412
} invalid_atoms[] = { { 1,  1, "(" },
 
413
                      { 1,  1, ")" },
 
414
                      { 1,  1, "[" },
 
415
                      { 1,  1, "]" },
 
416
                      { 1,  1, " " },
 
417
                      { 1, 13, "Hello, World!" },
 
418
                      { 1,  8, "1mplicit" },
 
419
 
 
420
                      { 2,  2, "1" },
 
421
                      { 2,  1, "12" },
 
422
 
 
423
                      { 7,  0, NULL } };
 
424
 
 
425
static svn_error_t *
 
426
parse_invalid_atoms (const char **msg, 
 
427
                     svn_boolean_t msg_only,
 
428
                     svn_test_opts_t *opts,
 
429
                     apr_pool_t *pool)
 
430
{
 
431
  struct invalid_atoms *ia = invalid_atoms;
 
432
 
 
433
  *msg = "parse invalid atoms";
 
434
 
 
435
  if (msg_only)
 
436
    return SVN_NO_ERROR;
 
437
 
 
438
  while (ia->type != 7)
 
439
    {
 
440
      if (ia->type == 1)
 
441
        {
 
442
          skel_t *skel = parse_cstr (ia->data, pool);
 
443
          if (check_atom (skel, ia->data, ia->len))
 
444
            return fail (pool, 
 
445
                         "failed to detect parsing error in '%s'", ia->data);
 
446
        }
 
447
      else
 
448
        {
 
449
          svn_error_t *err = try_explicit_length (ia->data, ia->len,
 
450
                                                  strlen (ia->data), pool);
 
451
          if (err == SVN_NO_ERROR)
 
452
            return fail (pool, "got wrong length in explicit-length atom");
 
453
          svn_error_clear (err);
 
454
        }
 
455
 
 
456
      ia++;
 
457
    }
 
458
 
 
459
  return SVN_NO_ERROR;
 
460
}
 
461
 
 
462
 
 
463
 
 
464
/* Functions that generate/check interesting lists.  */
 
465
 
 
466
/* Append the start of a list to STR, using LEN bytes of the
 
467
   whitespace character SPACE.  */
 
468
static void
 
469
put_list_start (svn_stringbuf_t *str, char space, int len)
 
470
{
 
471
  int i;
 
472
 
 
473
  if (len > 0 && ! skel_is_space (space))
 
474
    abort ();
 
475
 
 
476
  svn_stringbuf_appendcstr (str, "(");
 
477
  for (i = 0; i < len; i++)
 
478
    svn_stringbuf_appendbytes (str, &space, 1);
 
479
}
 
480
 
 
481
 
 
482
/* Append the end of a list to STR, using LEN bytes of the
 
483
   whitespace character SPACE.  */
 
484
static void
 
485
put_list_end (svn_stringbuf_t *str, char space, int len)
 
486
{
 
487
  int i;
 
488
 
 
489
  if (len > 0 && ! skel_is_space (space))
 
490
    abort ();
 
491
 
 
492
  for (i = 0; i < len; i++)
 
493
    svn_stringbuf_appendbytes (str, &space, 1);
 
494
  svn_stringbuf_appendcstr (str, ")");
 
495
}
 
496
 
 
497
 
 
498
/* Return true iff SKEL is a list of length DESIRED_LEN.  */
 
499
static int
 
500
check_list (skel_t *skel, int desired_len)
 
501
{
 
502
  int len;
 
503
  skel_t *child;
 
504
 
 
505
  if (! (skel
 
506
         && ! skel->is_atom))
 
507
    return 0;
 
508
 
 
509
  len = 0;
 
510
  for (child = skel->children; child; child = child->next)
 
511
    len++;
 
512
 
 
513
  return len == desired_len;
 
514
}
 
515
 
 
516
 
 
517
 
 
518
/* Parse lists.  */
 
519
 
 
520
static svn_error_t *
 
521
parse_list (const char **msg, 
 
522
            svn_boolean_t msg_only,
 
523
            svn_test_opts_t *opts,
 
524
            apr_pool_t *pool)
 
525
{
 
526
  *msg = "parse lists";
 
527
 
 
528
  if (msg_only)
 
529
    return SVN_NO_ERROR;
 
530
 
 
531
  {
 
532
    /* Try lists of varying length.  */
 
533
    int list_len;
 
534
 
 
535
    for (list_len = 0;
 
536
         list_len < 30;
 
537
         list_len < 4 ? list_len++ : (list_len *= 3))
 
538
      {
 
539
        /* Try lists with different separators.  */
 
540
        int sep;
 
541
 
 
542
        for (sep = 0; sep < 256; sep++)
 
543
          if (skel_is_space ( (apr_byte_t)sep))
 
544
            {
 
545
              /* Try lists with different numbers of separator
 
546
                 characters between the elements.  */
 
547
              int sep_count;
 
548
 
 
549
              for (sep_count = 0;
 
550
                   sep_count < 30;
 
551
                   sep_count < 4 ? sep_count++ : (sep_count *= 3))
 
552
                {
 
553
                  /* Try various single-byte implicit-length atoms
 
554
                     for elements.  */
 
555
                  int atom_byte;
 
556
 
 
557
                  for (atom_byte = 0; atom_byte < 256; atom_byte++)
 
558
                    if (skel_is_name ( (apr_byte_t)atom_byte))
 
559
                      {
 
560
                        int i;
 
561
                        svn_stringbuf_t *str = get_empty_string (pool);
 
562
                        skel_t *skel;
 
563
                        skel_t *child;
 
564
 
 
565
                        put_list_start (str,  (apr_byte_t)sep, sep_count);
 
566
                        for (i = 0; i < list_len; i++)
 
567
                          put_implicit_length_byte (str,
 
568
                                                    (apr_byte_t)atom_byte,
 
569
                                                    (apr_byte_t)sep);
 
570
                        put_list_end (str,  (apr_byte_t)sep, sep_count);
 
571
 
 
572
                        skel = parse_str (str, pool);
 
573
                        if (! check_list (skel, list_len))
 
574
                          return fail (pool, "couldn't parse list");
 
575
                        for (child = skel->children;
 
576
                             child;
 
577
                             child = child->next)
 
578
                          if (! check_implicit_length_byte 
 
579
                                 (child, (apr_byte_t)atom_byte))
 
580
                            return fail (pool, 
 
581
                                         "list was reparsed incorrectly");
 
582
                      }
 
583
 
 
584
                  /* Try the atom containing every character that's
 
585
                     legal in an implicit-length atom as the element.  */
 
586
                  {
 
587
                    int i;
 
588
                    svn_stringbuf_t *str = get_empty_string (pool);
 
589
                    skel_t *skel;
 
590
                    skel_t *child;
 
591
 
 
592
                    put_list_start (str,  (apr_byte_t)sep, sep_count);
 
593
                    for (i = 0; i < list_len; i++)
 
594
                      put_implicit_length_all_chars (str,  (apr_byte_t)sep);
 
595
                    put_list_end (str,  (apr_byte_t)sep, sep_count);
 
596
 
 
597
                    skel = parse_str (str, pool);
 
598
                    if (! check_list (skel, list_len))
 
599
                      return fail (pool, "couldn't parse list");
 
600
                    for (child = skel->children;
 
601
                         child;
 
602
                         child = child->next)
 
603
                      if (! check_implicit_length_all_chars (child))
 
604
                        return fail (pool, "couldn't parse list");
 
605
                  }
 
606
 
 
607
                  /* Try using every one-byte explicit-length atom as
 
608
                     an element.  */
 
609
                  for (atom_byte = 0; atom_byte < 256; atom_byte++)
 
610
                    {
 
611
                      int i;
 
612
                      svn_stringbuf_t *str = get_empty_string (pool);
 
613
                      skel_t *skel;
 
614
                      skel_t *child;
 
615
                      char buf[1];
 
616
 
 
617
                      buf[0] = atom_byte;
 
618
 
 
619
                      put_list_start (str,  (apr_byte_t)sep, sep_count);
 
620
                      for (i = 0; i < list_len; i++)
 
621
                        put_explicit_length (str, buf, 1,  (apr_byte_t)sep);
 
622
                      put_list_end (str,  (apr_byte_t)sep, sep_count);
 
623
 
 
624
                      skel = parse_str (str, pool);
 
625
                      if (! check_list (skel, list_len))
 
626
                        return fail (pool, "couldn't parse list");
 
627
                      for (child = skel->children;
 
628
                           child;
 
629
                           child = child->next)
 
630
                        if (! check_explicit_length (child, buf, 1))
 
631
                          return fail (pool, "list was reparsed incorrectly");
 
632
                    }
 
633
 
 
634
                  /* Try using an atom containing every character as
 
635
                     an element.  */
 
636
                  {
 
637
                    int i;
 
638
                    svn_stringbuf_t *str = get_empty_string (pool);
 
639
                    skel_t *skel;
 
640
                    skel_t *child;
 
641
                    char data[256];
 
642
 
 
643
                    for (i = 0; i < 256; i++)
 
644
                      data[i] = i;
 
645
 
 
646
                    put_list_start (str,  (apr_byte_t)sep, sep_count);
 
647
                    for (i = 0; i < list_len; i++)
 
648
                      put_explicit_length (str, data, 256,  (apr_byte_t)sep);
 
649
                    put_list_end (str,  (apr_byte_t)sep, sep_count);
 
650
 
 
651
                    skel = parse_str (str, pool);
 
652
                    if (! check_list (skel, list_len))
 
653
                      return fail (pool, "couldn't parse list");
 
654
                    for (child = skel->children;
 
655
                         child;
 
656
                         child = child->next)
 
657
                      if (! check_explicit_length (child, data, 256))
 
658
                        return fail (pool, "list was re-parsed incorrectly");
 
659
                  }
 
660
                }
 
661
            }
 
662
      }
 
663
  }
 
664
 
 
665
  /* Try to parse some invalid lists.  */
 
666
  {
 
667
    int sep;
 
668
 
 
669
    /* Try different separators.  */ 
 
670
    for (sep = 0; sep < 256; sep++)
 
671
      if (skel_is_space ( (apr_byte_t)sep))
 
672
        {
 
673
          /* Try lists with different numbers of separator
 
674
             characters between the elements.  */
 
675
          int sep_count;
 
676
 
 
677
          for (sep_count = 0;
 
678
               sep_count < 100;
 
679
               sep_count < 10 ? sep_count++ : (sep_count *= 3))
 
680
            {
 
681
              svn_stringbuf_t *str;
 
682
 
 
683
              /* A list with only a separator.  */
 
684
              str = get_empty_string (pool);
 
685
              put_list_start (str,  (apr_byte_t)sep, sep_count);
 
686
              if (parse_str (str, pool))
 
687
                return fail (pool, "failed to detect syntax error");
 
688
 
 
689
              /* A list with only a terminator.  */
 
690
              str = get_empty_string (pool);
 
691
              put_list_end (str,  (apr_byte_t)sep, sep_count);
 
692
              if (parse_str (str, pool))
 
693
                return fail (pool, "failed to detect syntax error");
 
694
 
 
695
              /* A list containing an invalid element.  */
 
696
              str = get_empty_string (pool);
 
697
              put_list_start (str,  (apr_byte_t)sep, sep_count);
 
698
              svn_stringbuf_appendcstr (str, "100 ");
 
699
              put_list_end (str,  (apr_byte_t)sep, sep_count);
 
700
              if (parse_str (str, pool))
 
701
                return fail (pool, "failed to detect invalid element");
 
702
            }
 
703
        }
 
704
  }
 
705
 
 
706
  return SVN_NO_ERROR;
 
707
}
 
708
 
 
709
 
 
710
 
 
711
/* Building interesting skels.  */
 
712
 
 
713
/* Build an atom skel containing the LEN bytes at DATA.  */
 
714
static skel_t *
 
715
build_atom (apr_size_t len, char *data, apr_pool_t *pool)
 
716
{
 
717
  char *copy = apr_palloc (pool, len);
 
718
  skel_t *skel = apr_palloc (pool, sizeof (*skel));
 
719
 
 
720
  memcpy (copy, data, len);
 
721
  skel->is_atom = 1;
 
722
  skel->len = len;
 
723
  skel->data = copy;
 
724
 
 
725
  return skel;
 
726
}
 
727
 
 
728
/* Build an empty list skel.  */
 
729
static skel_t *
 
730
empty (apr_pool_t *pool)
 
731
{
 
732
  skel_t *skel = apr_palloc (pool, sizeof (*skel));
 
733
 
 
734
  skel->is_atom = 0;
 
735
  skel->children = 0;
 
736
 
 
737
  return skel;
 
738
}
 
739
 
 
740
/* Stick ELEMENT at the beginning of the list skeleton LIST.  */
 
741
static void
 
742
add (skel_t *element, skel_t *list)
 
743
{
 
744
  element->next = list->children;
 
745
  list->children = element;
 
746
}
 
747
 
 
748
 
 
749
/* Return true if the contents of skel A are identical to those of
 
750
   skel B.  */
 
751
static int
 
752
skel_equal (skel_t *a, skel_t *b)
 
753
{
 
754
  if (a->is_atom != b->is_atom)
 
755
    return 0;
 
756
 
 
757
  if (a->is_atom)
 
758
    return (a->len == b->len
 
759
            && ! memcmp (a->data, b->data, a->len));
 
760
  else
 
761
    {
 
762
      skel_t *a_child, *b_child;
 
763
 
 
764
      for (a_child = a->children, b_child = b->children;
 
765
           a_child && b_child;
 
766
           a_child = a_child->next, b_child = b_child->next)
 
767
        if (! skel_equal (a_child, b_child))
 
768
          return 0;
 
769
 
 
770
      if (a_child || b_child)
 
771
        return 0;
 
772
    }
 
773
 
 
774
  return 1;
 
775
}
 
776
 
 
777
 
 
778
/* Unparsing implicit-length atoms.  */
 
779
 
 
780
static svn_error_t *
 
781
unparse_implicit_length (const char **msg, 
 
782
                         svn_boolean_t msg_only,
 
783
                         svn_test_opts_t *opts,
 
784
                         apr_pool_t *pool)
 
785
{
 
786
  *msg = "unparse implicit-length atoms";
 
787
 
 
788
  if (msg_only)
 
789
    return SVN_NO_ERROR;
 
790
 
 
791
  /* Unparse and check every single-byte implicit-length atom.  */
 
792
  {
 
793
    int byte;
 
794
 
 
795
    for (byte = 0; byte < 256; byte++)
 
796
      if (skel_is_name ( (apr_byte_t)byte))
 
797
        {
 
798
          svn_stringbuf_t *str = get_empty_string (pool);
 
799
          char buf =  (char)byte;
 
800
          skel_t *skel = build_atom (1, &buf, pool);
 
801
 
 
802
          str = svn_fs_base__unparse_skel (skel, pool);
 
803
 
 
804
          if (! (str
 
805
                 && str->len == 1
 
806
                 && str->data[0] == (char)byte))
 
807
            return fail (pool, "incorrectly unparsed single-byte "
 
808
                         "implicit-length atom");
 
809
        }
 
810
  }
 
811
 
 
812
  return SVN_NO_ERROR;
 
813
}
 
814
 
 
815
 
 
816
 
 
817
/* Unparse some lists.  */
 
818
 
 
819
static svn_error_t *
 
820
unparse_list (const char **msg, 
 
821
              svn_boolean_t msg_only,
 
822
              svn_test_opts_t *opts,
 
823
              apr_pool_t *pool)
 
824
{
 
825
  *msg = "unparse lists";
 
826
 
 
827
  if (msg_only)
 
828
    return SVN_NO_ERROR;
 
829
 
 
830
  /* Make a list of all the single-byte implicit-length atoms.  */
 
831
  {
 
832
    svn_stringbuf_t *str = get_empty_string (pool);
 
833
    int byte;
 
834
    skel_t *list = empty (pool);
 
835
    skel_t *reparsed, *elt;
 
836
 
 
837
    for (byte = 0; byte < 256; byte++)
 
838
      if (skel_is_name ( (apr_byte_t)byte))
 
839
        {
 
840
          char buf = byte;
 
841
          add (build_atom (1, &buf, pool), list);
 
842
        }
 
843
 
 
844
    /* Unparse that, parse it again, and see if we got the same thing
 
845
       back.  */
 
846
    str = svn_fs_base__unparse_skel (list, pool);
 
847
    reparsed = svn_fs_base__parse_skel (str->data, str->len, pool);
 
848
 
 
849
    if (! reparsed || reparsed->is_atom)
 
850
      return fail (pool, "result is syntactically misformed, or not a list");
 
851
 
 
852
    if (! skel_equal (list, reparsed))
 
853
      return fail (pool, "unparsing and parsing didn't preserve contents");
 
854
 
 
855
    elt = reparsed->children;
 
856
    for (byte = 255; byte >= 0; byte--)
 
857
      if (skel_is_name ( (apr_byte_t)byte))
 
858
        {
 
859
          if (! (elt
 
860
                 && elt->is_atom
 
861
                 && elt->len == 1
 
862
                 && elt->data[0] == byte))
 
863
            return fail (pool, "bad element");
 
864
 
 
865
          /* Verify that each element's data falls within the string.  */
 
866
          if (elt->data < str->data
 
867
              || elt->data + elt->len > str->data + str->len)
 
868
            return fail (pool, "bad element");
 
869
 
 
870
          elt = elt->next;
 
871
        }
 
872
 
 
873
    /* We should have reached the end of the list at this point.  */
 
874
    if (elt)
 
875
      return fail (pool, "list too long");
 
876
  }
 
877
 
 
878
  /* Make a list of lists.  */
 
879
  {
 
880
    svn_stringbuf_t *str = get_empty_string (pool);
 
881
    skel_t *top = empty (pool);
 
882
    skel_t *reparsed;
 
883
    int i;
 
884
 
 
885
    for (i = 0; i < 10; i++)
 
886
      {
 
887
        skel_t *middle = empty (pool);
 
888
        int j;
 
889
 
 
890
        for (j = 0; j < 10; j++)
 
891
          {
 
892
            char buf[10];
 
893
            apr_size_t k;
 
894
            int val;
 
895
 
 
896
            /* Make some interesting atom, containing lots of binary
 
897
               characters.  */
 
898
            val = i * 10 + j;
 
899
            for (k = 0; k < sizeof (buf); k++)
 
900
              {
 
901
                buf[k] = val;
 
902
                val += j;
 
903
              }
 
904
 
 
905
            add (build_atom (sizeof (buf), buf, pool), middle);
 
906
          }
 
907
 
 
908
        add (middle, top);
 
909
      }
 
910
 
 
911
    str = svn_fs_base__unparse_skel (top, pool);
 
912
    reparsed = svn_fs_base__parse_skel (str->data, str->len, pool);
 
913
 
 
914
    if (! skel_equal (top, reparsed))
 
915
      return fail (pool, "failed to reparse list of lists");
 
916
  }
 
917
 
 
918
  return SVN_NO_ERROR;
 
919
}
 
920
 
 
921
 
 
922
/* The test table.  */
 
923
 
 
924
struct svn_test_descriptor_t test_funcs[] =
 
925
  {
 
926
    SVN_TEST_NULL,
 
927
    SVN_TEST_PASS (parse_implicit_length),
 
928
    SVN_TEST_PASS (parse_explicit_length),
 
929
    SVN_TEST_PASS (parse_invalid_atoms),
 
930
    SVN_TEST_PASS (parse_list),
 
931
    SVN_TEST_PASS (unparse_implicit_length),
 
932
    SVN_TEST_PASS (unparse_list),
 
933
    SVN_TEST_NULL
 
934
  };