skel-test.c

来自「linux subdivision ying gai ke yi le ba」· C语言 代码 · 共 929 行 · 第 1/2 页

C
929
字号
/* skel-test.c --- tests for the skeleton functions
 *
 * ====================================================================
 * Copyright (c) 2000-2004 CollabNet.  All rights reserved.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution.  The terms
 * are also available at http://subversion.tigris.org/license-1.html.
 * If newer versions of this license are posted there, you may use a
 * newer version instead, at your option.
 *
 * This software consists of voluntary contributions made by many
 * individuals.  For exact contribution history, see the revision
 * history and logs, available at http://subversion.tigris.org/.
 * ====================================================================
 */

#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>

#include <apr.h>

#include "svn_pools.h"
#include "svn_string.h"
#include "svn_test.h"
#include "../../libsvn_fs_base/fs.h"
#include "../../libsvn_fs_base/util/skel.h"


/* Some utility functions.  */


/* A quick way to create error messages.  */
static svn_error_t *
fail (apr_pool_t *pool, const char *fmt, ...)
{
  va_list ap;
  char *msg;

  va_start (ap, fmt);
  msg = apr_pvsprintf (pool, fmt, ap);
  va_end (ap);

  return svn_error_create (SVN_ERR_TEST_FAILED, 0, msg);
}


/* Free everything from pool, and return an empty Subversion string.  */
static svn_stringbuf_t *
get_empty_string (apr_pool_t *pool)
{
  svn_pool_clear (pool);

  return svn_stringbuf_ncreate (0, 0, pool);
}

/* Parse a skeleton from a Subversion string.  */
static skel_t *
parse_str (svn_stringbuf_t *str, apr_pool_t *pool)
{
  return svn_fs_base__parse_skel (str->data, str->len, pool);
}


/* Parse a skeleton from a C string.  */
static skel_t *
parse_cstr (char *str, apr_pool_t *pool)
{
  return svn_fs_base__parse_skel (str, strlen (str), pool);
}


enum char_type {
  type_nothing = 0,
  type_space = 1,
  type_digit = 2,
  type_paren = 3,
  type_name = 4
};

static int skel_char_map_initialized;
static enum char_type skel_char_map[256];

static void
init_char_types (void)
{
  int i;
  const char *c;

  if (skel_char_map_initialized)
    return;

  for (i = 0; i < 256; i++)
    skel_char_map[i] = type_nothing;

  for (i = '0'; i <= '9'; i++)
    skel_char_map[i] = type_digit;

  for (c = "\t\n\f\r "; *c; c++)
    skel_char_map[(unsigned char) *c] = type_space;

  for (c = "()[]"; *c; c++)
    skel_char_map[(unsigned char) *c] = type_paren;

  for (i = 'A'; i <= 'Z'; i++)
    skel_char_map[i] = type_name;
  for (i = 'a'; i <= 'z'; i++)
    skel_char_map[i] = type_name;
  
  skel_char_map_initialized = 1;
}

/* Return true iff BYTE is a whitespace byte.  */
static int
skel_is_space (char byte)
{
  init_char_types ();

  return skel_char_map[(unsigned char) byte] == type_space;
}

#if 0
/* Return true iff BYTE is a digit byte.  */
static int
skel_is_digit (char byte)
{
  init_char_types ();

  return skel_char_map[(unsigned char) byte] == type_digit;
}
#endif

/* Return true iff BYTE is a paren byte.  */
static int
skel_is_paren (char byte)
{
  init_char_types ();

  return skel_char_map[(unsigned char) byte] == type_paren;
}

/* Return true iff BYTE is a name byte.  */
static int
skel_is_name (char byte)
{
  init_char_types ();

  return skel_char_map[(unsigned char) byte] == type_name;
}


/* Check that SKEL is an atom, and its contents match LEN bytes of
   DATA. */
static int
check_atom (skel_t *skel, const char *data, apr_size_t len)
{
  return (skel
          && skel->is_atom
          && skel->len == len
          && ! memcmp (skel->data, data, len));
}


/* Functions that generate/check interesting implicit-length atoms.  */


/* Append to STR an implicit-length atom consisting of the byte BYTE,
   terminated by the character TERM.  BYTE must be a name byte,
   and TERM must be a valid skel separator, or NULL.  */
static void
put_implicit_length_byte (svn_stringbuf_t *str, char byte, char term)
{
  if (! skel_is_name (byte))
    abort ();
  if (term != '\0'
      && ! skel_is_space (term)
      && ! skel_is_paren (term))
    abort ();
  svn_stringbuf_appendbytes (str, &byte, 1);
  if (term != '\0')
    svn_stringbuf_appendbytes (str, &term, 1);
}


/* Return true iff SKEL is the parsed form of the atom produced by
   calling put_implicit_length with BYTE.  */
static int
check_implicit_length_byte (skel_t *skel, char byte)
{
  if (! skel_is_name (byte))
    abort ();

  return check_atom (skel, &byte, 1);
}


/* Subroutine for the *_implicit_length_all_chars functions.  */
static char *
gen_implicit_length_all_chars (apr_size_t *len_p)
{
  apr_size_t pos;
  int i;
  static char name[256];

  /* Gotta start with a valid name character.  */
  pos = 0;
  name[pos++] = 'x';
  for (i = 0; i < 256; i++)
    if (! skel_is_space ( (apr_byte_t)i)
        && ! skel_is_paren ( (apr_byte_t)i))
      name[pos++] = i;

  *len_p = pos;
  return name;
}


/* Append to STR an implicit-length atom containing every character
   that's legal in such atoms, terminated by the valid atom terminator
   TERM.  */
static void
put_implicit_length_all_chars (svn_stringbuf_t *str, char term)
{
  apr_size_t len;
  char *name = gen_implicit_length_all_chars (&len);

  if (term != '\0'
      && ! skel_is_space (term)
      && ! skel_is_paren (term))
    abort ();

  svn_stringbuf_appendbytes (str, name, len);
  if (term != '\0')
    svn_stringbuf_appendbytes (str, &term, 1);
}


/* Return true iff SKEL is the parsed form of the atom produced by
   calling put_implicit_length_all_chars.  */
static int
check_implicit_length_all_chars (skel_t *skel)
{
  apr_size_t len;
  char *name = gen_implicit_length_all_chars (&len);

  return check_atom (skel, name, len);
}



/* Test parsing of implicit-length atoms.  */

static svn_error_t *
parse_implicit_length (const char **msg, 
                       svn_boolean_t msg_only,
                       apr_pool_t *pool)
{
  svn_stringbuf_t *str = get_empty_string (pool);
  skel_t *skel;

  *msg = "parse implicit-length atoms";

  if (msg_only)
    return SVN_NO_ERROR;

  /* Try all valid single-byte atoms.  */
  {
    const char *c;
    int i;

    for (c = "\t\n\f\r ()[]"; *c; c++)
      for (i = 0; i < 256; i++)
        if (skel_is_name((apr_byte_t)i))
          {
            svn_stringbuf_setempty (str);
            put_implicit_length_byte (str, (apr_byte_t)i, *c);
            skel = parse_str (str, pool);
            if (! check_implicit_length_byte (skel,  (apr_byte_t)i))
              return fail (pool, "single-byte implicit-length skel 0x%02x"
                           " with terminator 0x%02x",
                           i, c);
          }
  }

  /* Try an atom that contains every character that's legal in an
     implicit-length atom.  */
  svn_stringbuf_setempty (str);
  put_implicit_length_all_chars (str, '\0');
  skel = parse_str (str, pool);
  if (! check_implicit_length_all_chars (skel))
    return fail (pool, "implicit-length skel containing all legal chars");

  return SVN_NO_ERROR;
}


/* Functions that generate/check interesting explicit-length atoms.  */


/* Append to STR the representation of the atom containing the LEN
   bytes at DATA, in explicit-length form, using SEP as the separator
   between the length and the data.  */
static void
put_explicit_length (svn_stringbuf_t *str, const char *data, apr_size_t len, 
                     char sep)
{
  char *buf = malloc (len + 100);
  apr_size_t length_len;

  if (! skel_is_space (sep))
    abort ();

  /* Generate the length and separator character.  */
  sprintf (buf, "%"APR_SIZE_T_FMT"%c", len, sep);
  length_len = strlen(buf);
  
  /* Copy in the real data (which may contain nulls).  */
  memcpy (buf + length_len, data, len);

  svn_stringbuf_appendbytes (str, buf, length_len + len);
  free (buf);
}


/* Return true iff SKEL is the parsed form of an atom generated by
   put_explicit_length.  */
static int
check_explicit_length (skel_t *skel, const char *data, apr_size_t len)
{
  return check_atom (skel, data, len);
}


/* Test parsing of explicit-length atoms.  */

static svn_error_t *
try_explicit_length (const char *data, apr_size_t len, apr_size_t check_len,
                     apr_pool_t *pool)
{
  int i;
  svn_stringbuf_t *str = get_empty_string (pool);
  skel_t *skel;

  /* Try it with every possible separator character.  */
  for (i = 0; i < 256; i++)
    if (skel_is_space ( (apr_byte_t)i))
      {
        svn_stringbuf_setempty (str);
        put_explicit_length (str, data, len,  (apr_byte_t)i);
        skel = parse_str (str, pool);
        if (! check_explicit_length (skel, data, check_len))
          return fail (pool, "failed to reparse explicit-length atom"); 
      }

  return SVN_NO_ERROR;
}


static svn_error_t *
parse_explicit_length (const char **msg, 
                       svn_boolean_t msg_only,
                       apr_pool_t *pool)
{
  *msg = "parse explicit-length atoms";

  if (msg_only)
    return SVN_NO_ERROR;

  /* Try to parse the empty atom.  */
  SVN_ERR (try_explicit_length ("", 0, 0, pool));

  /* Try to parse every one-character atom.  */
  {
    int i;

    for (i = 0; i < 256; i++)
      {
        char buf[1];

        buf[0] = i;
        SVN_ERR (try_explicit_length (buf, 1, 1, pool));
      }
  }

  /* Try to parse an atom containing every character.  */
  {
    int i;
    char data[256];

    for (i = 0; i < 256; i++)
      data[i] = i;

    SVN_ERR (try_explicit_length (data, 256, 256, pool));
  }

  return SVN_NO_ERROR;
}



/* Test parsing of invalid atoms. */

static struct invalid_atoms
{
  int type;
  apr_size_t len;
  const char *data;
} invalid_atoms[] = { { 1,  1, "(" },
                      { 1,  1, ")" },
                      { 1,  1, "[" },
                      { 1,  1, "]" },
                      { 1,  1, " " },
                      { 1, 13, "Hello, World!" },
                      { 1,  8, "1mplicit" },

                      { 2,  2, "1" },
                      { 2,  1, "12" },

                      { 7,  0, NULL } };

static svn_error_t *
parse_invalid_atoms (const char **msg, 
                     svn_boolean_t msg_only,
                     apr_pool_t *pool)
{
  struct invalid_atoms *ia = invalid_atoms;

  *msg = "parse invalid atoms";

  if (msg_only)
    return SVN_NO_ERROR;

  while (ia->type != 7)
    {
      if (ia->type == 1)
        {
          skel_t *skel = parse_cstr ((char *) ia->data, pool);
          if (check_atom (skel, ia->data, ia->len))
            return fail (pool, 
                         "failed to detect parsing error in '%s'", ia->data);
        }
      else
        {
          svn_error_t *err = try_explicit_length (ia->data, ia->len,
                                                  strlen (ia->data), pool);
          if (err == SVN_NO_ERROR)
            return fail (pool, "got wrong length in explicit-length atom");
          svn_error_clear (err);
        }

      ia++;
    }

  return SVN_NO_ERROR;
}



/* Functions that generate/check interesting lists.  */

/* Append the start of a list to STR, using LEN bytes of the
   whitespace character SPACE.  */
static void

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?