]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Add program to generate ipptool test files from the IANA XML registry.
authormike <mike@7a7537e8-13f0-0310-91df-b6672ffda945>
Wed, 21 Sep 2011 00:23:08 +0000 (00:23 +0000)
committermike <mike@7a7537e8-13f0-0310-91df-b6672ffda945>
Wed, 21 Sep 2011 00:23:08 +0000 (00:23 +0000)
git-svn-id: svn+ssh://src.apple.com/svn/cups/cups.org/trunk@10007 7a7537e8-13f0-0310-91df-b6672ffda945

test/Dependencies
test/Makefile
test/xmltotest.c [new file with mode: 0644]

index 32891447ef8e69813a38b27ad2e29ef057831161..63cc5bd70361721678d090acf725dd9ed04556f0 100644 (file)
@@ -18,3 +18,5 @@ ipptool.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h
 ipptool.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h
 ipptool.o: ../cups/transcode.h ../cups/thread-private.h
 ipptool.o: ../cups/file-private.h ../cups/cups-private.h
+xmltotest.o: ../cups/cups.h ../cups/file.h ../cups/versioning.h ../cups/ipp.h
+xmltotest.o: ../cups/http.h ../cups/array.h ../cups/language.h
index d9e6f57fa6943f063223c02d5174ea3e7bc10cd6..58e670ef5e4f6c66d4cb5bd5956de4b2cc90c610 100644 (file)
@@ -44,7 +44,8 @@ TESTFILES     =       \
                        testfile.txt
 OBJS           =       \
                        ippserver.o \
-                       ipptool.o
+                       ipptool.o \
+                       xmltotest.o
 TARGETS                =       \
                        ippserver \
                        ipptool \
@@ -180,6 +181,17 @@ ipptool-static:    ipptool.o ../cups/$(LIBCUPSSTATIC)
                $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
 
 
+#
+# xmltotest
+#
+
+xmltotest: xmltotest.o ../cups/$(LIBUPSSTATIC)
+       echo Linking $@...
+       $(CC) $(LDFLAGS) -o $@ xmltotest.o  ../cups/$(LIBCUPSSTATIC) \
+               $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) \
+               -lmxml
+
+
 #
 # Dependencies...
 #
diff --git a/test/xmltotest.c b/test/xmltotest.c
new file mode 100644 (file)
index 0000000..14ecf57
--- /dev/null
@@ -0,0 +1,518 @@
+/*
+ * "$Id$"
+ *
+ *   IANA XML registration to test file generator for CUPS.
+ *
+ *   Copyright 2011 by Apple Inc.
+ *
+ *   These coded instructions, statements, and computer programs are the
+ *   property of Apple Inc. and are protected by Federal copyright
+ *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+ *   which should have been included with this file.  If this file is
+ *   file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ *   This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Usage:
+ *
+ *   ./xmltotest [--ref standard] {--job|--printer} [XML file/URL] >file.test
+ *
+ *   If not specified, loads the XML registrations from:
+ *
+ *     http://www.iana.org/assignments/ipp-registrations/ipp-registrations.xml
+ *
+ *   "Standard" is of the form "rfcNNNN" or "pwgNNNN.N".
+ *
+ * Contents:
+ *
+ *   main()        - Process command-line arguments.
+ *   compare_reg()  - Compare two registrations.
+ *   load_xml()     - Load the XML registration file or URL.
+ *   match_xref()   - Compare the xref against the named standard.
+ *   new_reg()     - Create a new registration record.
+ *   usage()       - Show usage message.
+ *   write_expect() - Write an EXPECT test for an attribute.
+ */
+
+#include <mxml.h>
+#include <cups/cups.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+
+/*
+ * Local types...
+ */
+
+typedef struct _cups_reg_s             /**** Registration data ****/
+{
+  char *name,                          /* Attribute name */
+       *member,                        /* Member attribute name */
+       *sub_member,                    /* Sub-member attribute name */
+       *syntax;                        /* Attribute syntax */
+} _cups_reg_t;
+
+
+/*
+ * Local functions...
+ */
+
+static int             compare_reg(_cups_reg_t *a, _cups_reg_t *b);
+static mxml_node_t     *load_xml(const char *reg_file);
+static int             match_xref(mxml_node_t *xref, const char *standard);
+static _cups_reg_t     *new_reg(mxml_node_t *name, mxml_node_t *member,
+                                mxml_node_t *sub_member, mxml_node_t *syntax);
+static int             usage(void);
+static void            write_expect(_cups_reg_t *reg, ipp_tag_t group);
+
+
+/*
+ * 'main()' - Process command-line arguments.
+ */
+
+int
+main(int  argc,                                /* I - Number of command-line args */
+     char *argv[])                     /* I - Command-line arguments */
+{
+  int          i;                      /* Looping var */
+  const char   *reg_file = NULL,       /* Registration file/URL to use */
+               *reg_standard = NULL;   /* Which standard to extract */
+  mxml_node_t  *reg_xml,               /* Registration XML data */
+               *reg_2,                 /* ipp-registrations-2 */
+               *reg_record,            /* <record> */
+               *reg_collection,        /* <collection> */
+               *reg_name,              /* <name> */
+               *reg_member,            /* <member_attribute> */
+               *reg_sub_member,        /* <sub-member_attribute> */
+               *reg_syntax,            /* <syntax> */
+               *reg_xref;              /* <xref> */
+  cups_array_t *attrs;                 /* Attribute registrations */
+  _cups_reg_t  *current;               /* Current attribute registration */
+  ipp_tag_t    group = IPP_TAG_ZERO,   /* Which attributes to test */
+               reg_group;              /* Group for registration */
+
+
+ /*
+  * Parse command-line...
+  */
+
+  for (i = 1; i < argc; i ++)
+  {
+    if (!strcmp(argv[i], "--job") && group == IPP_TAG_ZERO)
+      group = IPP_TAG_JOB;
+    else if (!strcmp(argv[i], "--ref"))
+    {
+      i ++;
+      if (i >= argc)
+        return (usage());
+
+      reg_standard = argv[i];
+    }
+    else if (!strcmp(argv[i], "--printer") && group == IPP_TAG_ZERO)
+      group = IPP_TAG_PRINTER;
+    else if (argv[i][0] == '-' || reg_file)
+      return (usage());
+    else
+      reg_file = argv[i];
+  }
+
+  if (group == IPP_TAG_ZERO)
+    return (usage());
+
+ /*
+  * Read registrations...
+  */
+
+  if (!reg_file)
+    reg_file = "http://www.iana.org/assignments/ipp-registrations/"
+              "ipp-registrations.xml";
+
+  if ((reg_xml = load_xml(reg_file)) == NULL)
+    return (1);
+
+ /*
+  * Scan registrations for attributes...
+  */
+
+  if ((reg_2 = mxmlFindElement(reg_xml, reg_xml, "registry", "id",
+                               "ipp-registrations-2",
+                               MXML_DESCEND)) == NULL)
+  {
+    fprintf(stderr, "xmltotest: No IPP attribute registrations in \"%s\".\n",
+            reg_file);
+    return (1);
+  }
+
+  attrs = cupsArrayNew((cups_array_func_t)compare_reg, NULL);
+
+  for (reg_record = mxmlFindElement(reg_2, reg_2, "record", NULL, NULL,
+                                   MXML_DESCEND);
+       reg_record;
+       reg_record = mxmlFindElement(reg_record, reg_2, "record", NULL, NULL,
+                                    MXML_NO_DESCEND))
+  {
+   /*
+    * Get the values from the current record...
+    */
+
+    reg_collection = mxmlFindElement(reg_record, reg_record, "collection",
+                                     NULL, NULL, MXML_DESCEND);
+    reg_name       = mxmlFindElement(reg_record, reg_record, "name", NULL, NULL,
+                                     MXML_DESCEND);
+    reg_member     = mxmlFindElement(reg_record, reg_record, "member_attribute",
+                                     NULL, NULL, MXML_DESCEND);
+    reg_sub_member = mxmlFindElement(reg_record, reg_record,
+                                     "sub-member_attribute", NULL, NULL,
+                                     MXML_DESCEND);
+    reg_syntax     = mxmlFindElement(reg_record, reg_record, "syntax", NULL,
+                                     NULL, MXML_DESCEND);
+    reg_xref       = mxmlFindElement(reg_record, reg_record, "xref", NULL, NULL,
+                                     MXML_DESCEND);
+
+    if (!reg_collection || !reg_name || !reg_syntax || !reg_xref)
+      continue;
+
+   /*
+    * Filter based on group and standard...
+    */
+
+    if (!strcmp(reg_collection->child->value.opaque, "Printer Description"))
+      reg_group = IPP_TAG_PRINTER;
+    else if (!strcmp(reg_collection->child->value.opaque, "Job Description"))
+      reg_group = IPP_TAG_JOB;
+    else if (!strcmp(reg_collection->child->value.opaque, "Job Template"))
+    {
+      if (strstr(reg_name->child->value.opaque, "-default") ||
+          strstr(reg_name->child->value.opaque, "-supported"))
+       reg_group = IPP_TAG_PRINTER;
+      else
+       reg_group = IPP_TAG_JOB;
+    }
+    else
+      reg_group = IPP_TAG_ZERO;
+
+    if (reg_group != group)
+      continue;
+
+    if (reg_standard && !match_xref(reg_xref, reg_standard))
+      continue;
+
+   /*
+    * Add the record to the array...
+    */
+
+    if ((current = new_reg(reg_name, reg_member, reg_sub_member,
+                           reg_syntax)) != NULL)
+      cupsArrayAdd(attrs, current);
+  }
+
+ /*
+  * Write out a test for all of the selected attributes...
+  */
+
+  puts("{");
+
+  if (group == IPP_TAG_PRINTER)
+  {
+    puts("\tOPERATION Get-Printer-Attributes");
+    puts("\tGROUP operation-attributes-tag");
+    puts("\tATTR charset attributes-charset utf-8");
+    puts("\tATTR naturalLanguage attributes-natural-language en");
+    puts("\tATTR uri printer-uri $uri");
+    puts("\tATTR name requesting-user-name $user");
+    puts("\tATTR keyword requested-attributes all,media-col-database");
+    puts("");
+    puts("\tSTATUS successful-ok");
+    puts("\tSTATUS successful-ok-ignored-or-substituted-attributes");
+    puts("");
+  }
+  else
+  {
+    puts("\tOPERATION Get-Job-Attributes");
+    puts("\tGROUP operation-attributes-tag");
+    puts("\tATTR charset attributes-charset utf-8");
+    puts("\tATTR naturalLanguage attributes-natural-language en");
+    puts("\tATTR uri printer-uri $uri");
+    puts("\tATTR integer job-id $job-id");
+    puts("\tATTR name requesting-user-name $user");
+    puts("");
+    puts("\tSTATUS successful-ok");
+    puts("");
+  }
+
+  for (current = cupsArrayFirst(attrs);
+       current;
+       current = cupsArrayNext(attrs))
+    write_expect(current, group);
+
+  puts("}");
+
+  return (0);
+}
+
+
+/*
+ * 'compare_reg()' - Compare two registrations.
+ */
+
+static int                             /* O - Result of comparison */
+compare_reg(_cups_reg_t *a,            /* I - First registration */
+            _cups_reg_t *b)            /* I - Second registration */
+{
+  int  retval;                         /* Return value */
+
+
+  if ((retval = strcmp(a->name, b->name)) != 0)
+    return (retval);
+
+  if (a->member && b->member)
+    retval = strcmp(a->member, b->member);
+  else if (a->member)
+    retval = 1;
+  else if (b->member)
+    retval = -1;
+
+  if (retval)
+    return (retval);
+
+  if (a->sub_member && b->sub_member)
+    retval = strcmp(a->sub_member, b->sub_member);
+  else if (a->sub_member)
+    retval = 1;
+  else if (b->sub_member)
+    retval = -1;
+
+  return (retval);
+}
+
+
+/*
+ * 'load_xml()' - Load the XML registration file or URL.
+ */
+
+static mxml_node_t *                   /* O - XML file or NULL */
+load_xml(const char *reg_file)         /* I - Filename or URL */
+{
+  mxml_node_t          *xml;           /* XML file */
+  char                 scheme[256],    /* Scheme */
+                       userpass[256],  /* Username and password */
+                       hostname[256],  /* Hostname */
+                       resource[1024], /* Resource path */
+                       filename[1024]; /* Temporary file */
+  int                  port,           /* Port number */
+                       fd;             /* File descriptor */
+
+
+  if (httpSeparateURI(HTTP_URI_CODING_ALL, reg_file, scheme, sizeof(scheme),
+                      userpass, sizeof(userpass), hostname, sizeof(hostname),
+                      &port, resource, sizeof(resource)) < HTTP_URI_OK)
+  {
+    fprintf(stderr, "xmltotest: Bad URI or filename \"%s\".\n", reg_file);
+    return (NULL);
+  }
+
+  if (!strcmp(scheme, "file"))
+  {
+   /*
+    * Local file...
+    */
+
+    if ((fd = open(resource, O_RDONLY)) < 0)
+    {
+      fprintf(stderr, "xmltotest: Unable to open \"%s\": %s\n", resource,
+              strerror(errno));
+      return (NULL);
+    }
+
+    filename[0] = '\0';
+  }
+  else if (strcmp(scheme, "http") && strcmp(scheme, "https"))
+  {
+    fprintf(stderr, "xmltotest: Unsupported URI scheme \"%s\".\n", scheme);
+    return (NULL);
+  }
+  else
+  {
+    http_t             *http;          /* HTTP connection */
+    http_encryption_t  encryption;     /* Encryption to use */
+    http_status_t      status;         /* Status of HTTP GET */
+
+    if (!strcmp(scheme, "https") || port == 443)
+      encryption = HTTP_ENCRYPT_ALWAYS;
+    else
+      encryption = HTTP_ENCRYPT_IF_REQUESTED;
+
+    if ((http = httpConnectEncrypt(hostname, port, encryption)) == NULL)
+    {
+      fprintf(stderr, "xmltotest: Unable to connect to \"%s\": %s\n", hostname,
+              cupsLastErrorString());
+      return (NULL);
+    }
+
+    if ((fd = cupsTempFd(filename, sizeof(filename))) < 0)
+    {
+      fprintf(stderr, "xmltotest: Unable to create temporary file: %s\n",
+              strerror(errno));
+      httpClose(http);
+      return (NULL);
+    }
+
+    status = cupsGetFd(http, resource, fd);
+    httpClose(http);
+
+    if (status != HTTP_OK)
+    {
+      fprintf(stderr, "mxmltotest: Unable to get \"%s\": %d\n", reg_file,
+              status);
+      close(fd);
+      unlink(filename);
+      return (NULL);
+    }
+
+    lseek(fd, 0, SEEK_SET);
+  }
+
+ /*
+  * Load the XML file...
+  */
+
+  xml = mxmlLoadFd(NULL, fd, MXML_OPAQUE_CALLBACK);
+
+  close(fd);
+
+  if (filename[0])
+    unlink(filename);
+
+  return (xml);
+}
+
+
+/*
+ * 'match_xref()' - Compare the xref against the named standard.
+ */
+
+static int                             /* O - 1 if match, 0 if not */
+match_xref(mxml_node_t *xref,          /* I - <xref> node */
+           const char  *standard)      /* I - Name of standard */
+{
+  const char   *data;                  /* "data" attribute */
+  char         s[256];                 /* String to look for */
+
+
+  if ((data = mxmlElementGetAttr(xref, "data")) == NULL)
+    return (1);
+
+  if (!strcmp(data, standard))
+    return (1);
+
+  if (!strncmp(standard, "pwg", 3))
+  {
+    snprintf(s, sizeof(s), "-%s.pdf", standard + 3);
+    return (strstr(data, s) != NULL);
+  }
+  else
+    return (0);
+}
+
+
+/*
+ * 'new_reg()' - Create a new registration record.
+ */
+
+static _cups_reg_t *                   /* O - New record */
+new_reg(mxml_node_t *name,             /* I - Attribute name */
+        mxml_node_t *member,           /* I - Member attribute, if any */
+        mxml_node_t *sub_member,       /* I - Sub-member attribute, if any */
+        mxml_node_t *syntax)           /* I - Syntax */
+{
+  _cups_reg_t  *reg;                   /* New record */
+
+
+  if ((reg = calloc(1, sizeof(_cups_reg_t))) != NULL)
+  {
+    reg->name   = name->child->value.opaque;
+    reg->syntax = syntax->child->value.opaque;
+
+    if (member)
+      reg->member = member->child->value.opaque;
+
+    if (sub_member)
+      reg->sub_member = sub_member->child->value.opaque;
+  }
+
+  return (reg);
+}
+
+
+/*
+ * 'usage()' - Show usage message.
+ */
+
+static int                             /* O - Exit status */
+usage(void)
+{
+  puts("Usage ./xmltotest [--ref standard] {--job|--printer} [XML file/URL] "
+       ">file.test");
+  return (1);
+}
+
+
+/*
+ * 'write_expect()' - Write an EXPECT test for an attribute.
+ */
+
+static void
+write_expect(_cups_reg_t *reg,         /* I - Registration information */
+             ipp_tag_t   group)                /* I - Attribute group tag */
+{
+  const char   *syntax;                /* Pointer into syntax string */
+  int          single = 1,             /* Single valued? */
+               skip = 0;               /* Skip characters? */
+
+
+  printf("\tEXPECT ?%s OF-TYPE ", reg->name);
+
+  syntax = reg->syntax;
+
+  while (*syntax)
+  {
+    if (!strncmp(syntax, "1setOf", 6))
+    {
+      single = 0;
+      syntax += 6;
+
+      while (isspace(*syntax & 255))
+        syntax ++;
+
+      if (*syntax == '(')
+        syntax ++;
+    }
+    else if (!strncmp(syntax, "type1", 5) || !strncmp(syntax, "type2", 5) ||
+             !strncmp(syntax, "type3", 5))
+      syntax += 5;
+    else if (*syntax == '(')
+    {
+      skip = 1;
+      syntax ++;
+    }
+    else if (*syntax == ')')
+    {
+      skip = 0;
+      syntax ++;
+    }
+    else if (!skip && (*syntax == '|' || isalpha(*syntax & 255)))
+      putchar(*syntax++);
+    else
+      syntax ++;
+  }
+
+  if (single)
+    printf(" IN-GROUP %s COUNT 1\n", ippTagString(group));
+  else
+    printf(" IN-GROUP %s\n", ippTagString(group));
+}
+
+
+/*
+ * End of "$Id$".
+ */