Bug 1402151, part 9 - Implement gtest for FTP directory listing parsing. r=michal draft
authorAndrew McCreight <continuation@gmail.com>
Mon, 25 Sep 2017 11:19:33 -0700
changeset 680199 71af3ee22aecc57de640a54f5b7c269a23f14883
parent 680198 6a39a32f1cc64b10466a12044d97680ec07ecabb
child 735782 278163f7ddec091809eba6018eef85df06f5b1cc
push id84417
push userbmo:continuation@gmail.com
push dateFri, 13 Oct 2017 16:41:48 +0000
reviewersmichal
bugs1402151
milestone58.0a1
Bug 1402151, part 9 - Implement gtest for FTP directory listing parsing. r=michal This test turns the existing stand alone test for the FTP directory listing parser into a gtest. MozReview-Commit-ID: 7n60TfcTXTJ
netwerk/streamconv/converters/ParseFTPList.cpp
netwerk/test/gtest/moz.build
netwerk/test/gtest/parse-ftp/TestParseFTPList.cpp
netwerk/test/gtest/parse-ftp/moz.build
testing/cppunittest.ini
--- a/netwerk/streamconv/converters/ParseFTPList.cpp
+++ b/netwerk/streamconv/converters/ParseFTPList.cpp
@@ -1660,212 +1660,8 @@ int ParseFTPList(const char *line, struc
 
     /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
 
   } /* if (linelen > 0) */
 
   return ParsingFailed(state);
 }
 
-/* ==================================================================== */
-/* standalone testing                                                   */
-/* ==================================================================== */
-#if 0
-
-#include <stdio.h>
-
-static int do_it(FILE *outfile,
-                 char *line, size_t linelen, struct list_state *state,
-                 char **cmnt_buf, unsigned int *cmnt_buf_sz,
-                 char **list_buf, unsigned int *list_buf_sz )
-{
-  struct list_result result;
-  char *p;
-  int rc;
-
-  rc = ParseFTPList( line, state, &result );
-
-  if (!outfile)
-  {
-    outfile = stdout;
-    if (rc == '?')
-      fprintf(outfile, "junk: %.*s\n", (int)linelen, line );
-    else if (rc == '"')
-      fprintf(outfile, "cmnt: %.*s\n", (int)linelen, line );
-    else
-      fprintf(outfile,
-              "list: %02u-%02u-%02u  %02u:%02u%cM %20s %.*s%s%.*s\n",
-              (result.fe_time.tm_mday ? (result.fe_time.tm_month + 1) : 0),
-              result.fe_time.tm_mday,
-              (result.fe_time.tm_mday ? (result.fe_time.tm_year % 100) : 0),
-              result.fe_time.tm_hour -
-                ((result.fe_time.tm_hour > 12)?(12):(0)),
-              result.fe_time.tm_min,
-              ((result.fe_time.tm_hour >= 12) ? 'P' : 'A'),
-              (rc == 'd' ? "<DIR>         " :
-              (rc == 'l' ? "<JUNCTION>    " : result.fe_size)),
-              (int)result.fe_fnlen, result.fe_fname,
-              ((rc == 'l' && result.fe_lnlen) ? " -> " : ""),
-              (int)((rc == 'l' && result.fe_lnlen) ? result.fe_lnlen : 0),
-              ((rc == 'l' && result.fe_lnlen) ? result.fe_lname : "") );
-  }
-  else if (rc != '?') /* NOT junk */
-  {
-    char **bufp = list_buf;
-    unsigned int *bufz = list_buf_sz;
-
-    if (rc == '"') /* comment - make it a 'result' */
-    {
-      memset( &result, 0, sizeof(result));
-      result.fe_fname = line;
-      result.fe_fnlen = linelen;
-      result.fe_type = 'f';
-      if (line[linelen-1] == '/')
-      {
-        result.fe_type = 'd';
-        result.fe_fnlen--;
-      }
-      bufp = cmnt_buf;
-      bufz = cmnt_buf_sz;
-      rc = result.fe_type;
-    }
-
-    linelen = 80 + result.fe_fnlen + result.fe_lnlen;
-    p = (char *)realloc( *bufp, *bufz + linelen );
-    if (!p)
-      return -1;
-    sprintf( &p[*bufz],
-             "%02u-%02u-%04u  %02u:%02u:%02u %20s %.*s%s%.*s\n",
-              (result.fe_time.tm_mday ? (result.fe_time.tm_month + 1) : 0),
-              result.fe_time.tm_mday,
-              (result.fe_time.tm_mday ? (result.fe_time.tm_year + 1900) : 0),
-              result.fe_time.tm_hour,
-              result.fe_time.tm_min,
-              result.fe_time.tm_sec,
-              (rc == 'd' ? "<DIR>         " :
-              (rc == 'l' ? "<JUNCTION>    " : result.fe_size)),
-              (int)result.fe_fnlen, result.fe_fname,
-              ((rc == 'l' && result.fe_lnlen) ? " -> " : ""),
-              (int)((rc == 'l' && result.fe_lnlen) ? result.fe_lnlen : 0),
-              ((rc == 'l' && result.fe_lnlen) ? result.fe_lname : "") );
-    linelen = strlen(&p[*bufz]);
-    *bufp = p;
-    *bufz = *bufz + linelen;
-  }
-  return 0;
-}
-
-int main(int argc, char *argv[])
-{
-  FILE *infile = (FILE *)0;
-  FILE *outfile = (FILE *)0;
-  int need_close_in = 0;
-  int need_close_out = 0;
-
-  if (argc > 1)
-  {
-    infile = stdin;
-    if (strcmp(argv[1], "-") == 0)
-      need_close_in = 0;
-    else if ((infile = fopen(argv[1], "r")) != ((FILE *)0))
-      need_close_in = 1;
-    else
-      fprintf(stderr, "Unable to open input file '%s'\n", argv[1]);
-  }
-  if (infile && argc > 2)
-  {
-    outfile = stdout;
-    if (strcmp(argv[2], "-") == 0)
-      need_close_out = 0;
-    else if ((outfile = fopen(argv[2], "w")) != ((FILE *)0))
-      need_close_out = 1;
-    else
-    {
-      fprintf(stderr, "Unable to open output file '%s'\n", argv[2]);
-      fclose(infile);
-      infile = (FILE *)0;
-    }
-  }
-
-  if (!infile)
-  {
-    char *appname = &(argv[0][strlen(argv[0])]);
-    while (appname > argv[0])
-    {
-      appname--;
-      if (*appname == '/' || *appname == '\\' || *appname == ':')
-      {
-        appname++;
-        break;
-      }
-    }
-    fprintf(stderr,
-        "Usage: %s <inputfilename> [<outputfilename>]\n"
-        "\nIf an outout file is specified the results will be"
-        "\nbe post-processed, and only the file entries will appear"
-        "\n(or all comments if there are no file entries)."
-        "\nNot specifying an output file causes %s to run in \"debug\""
-        "\nmode, ie results are printed as lines are parsed."
-        "\nIf a filename is a single dash ('-'), stdin/stdout is used."
-        "\n", appname, appname );
-  }
-  else
-  {
-    char *cmnt_buf = (char *)0;
-    unsigned int cmnt_buf_sz = 0;
-    char *list_buf = (char *)0;
-    unsigned int list_buf_sz = 0;
-
-    struct list_state state;
-    char line[512];
-
-    memset( &state, 0, sizeof(state) );
-    while (fgets(line, sizeof(line), infile))
-    {
-      size_t linelen = strlen(line);
-      if (linelen < (sizeof(line)-1))
-      {
-        if (linelen > 0 && line[linelen-1] == '\n')
-          linelen--;
-        if (do_it( outfile, line, linelen, &state,
-                   &cmnt_buf, &cmnt_buf_sz, &list_buf, &list_buf_sz) != 0)
-        {
-          fprintf(stderr, "Insufficient memory. Listing may be incomplete.\n");
-          break;
-        }
-      }
-      else
-      {
-        /* no '\n' found. drop this and everything up to the next '\n' */
-        fprintf(stderr, "drop: %.*s", (int)linelen, line );
-        while (linelen == sizeof(line))
-        {
-          if (!fgets(line, sizeof(line), infile))
-            break;
-          linelen = 0;
-          while (linelen < sizeof(line) && line[linelen] != '\n')
-            linelen++;
-          fprintf(stderr, "%.*s", (int)linelen, line );
-        }
-        fprintf(stderr, "\n");
-      }
-    }
-    if (outfile)
-    {
-      if (list_buf)
-        fwrite( list_buf, 1, list_buf_sz, outfile );
-      else if (cmnt_buf)
-        fwrite( cmnt_buf, 1, cmnt_buf_sz, outfile );
-    }
-    if (list_buf)
-      free(list_buf);
-    if (cmnt_buf)
-      free(cmnt_buf);
-
-    if (need_close_in)
-      fclose(infile);
-    if (outfile && need_close_out)
-      fclose(outfile);
-  }
-
-  return 0;
-}
-#endif
--- a/netwerk/test/gtest/moz.build
+++ b/netwerk/test/gtest/moz.build
@@ -8,11 +8,15 @@ UNIFIED_SOURCES += [
     'TestHeaders.cpp',
     'TestHttpAuthUtils.cpp',
     'TestMozURL.cpp',
     'TestPartiallySeekableInputStream.cpp',
     'TestProtocolProxyService.cpp',
     'TestStandardURL.cpp',
 ]
 
+TEST_DIRS += [
+    'parse-ftp',
+]
+
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul-gtest'
new file mode 100644
--- /dev/null
+++ b/netwerk/test/gtest/parse-ftp/TestParseFTPList.cpp
@@ -0,0 +1,169 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+#include "mozilla/ArrayUtils.h"
+#include "nsPrintfCString.h"
+#include <stdio.h>
+
+#include "ParseFTPList.h"
+
+
+PRTime gTestTime = 0;
+
+// Pretend this is the current time for the purpose of running the
+// test. The day and year matter because they are used to figure out a
+// default value when no year is specified. Tests will fail if this is
+// changed too much.
+const char* kDefaultTestTime = "01-Aug-2002 00:00:00 GMT";
+
+static PRTime
+TestTime()
+{
+  return gTestTime;
+}
+
+static void
+ParseFTPLine(char* inputLine,
+             FILE* resultFile,
+             list_state* state)
+{
+  struct list_result result;
+  int rc = ParseFTPList(inputLine, state, &result, PR_GMTParameters, TestTime);
+
+  if (rc == '?' || rc == '"') {
+    // Ignore junk and comments.
+    return;
+  }
+
+  if (!resultFile) {
+    // No result file was passed in, so there's nothing to check.
+    return;
+  }
+
+  char resultLine[512];
+  ASSERT_NE(fgets(resultLine, sizeof(resultLine), resultFile), nullptr);
+
+  nsPrintfCString parsed("%02u-%02u-%04u  %02u:%02u:%02u %20s %.*s%s%.*s\n",
+                         (result.fe_time.tm_mday ? (result.fe_time.tm_month + 1) : 0),
+                         result.fe_time.tm_mday,
+                         (result.fe_time.tm_mday ? result.fe_time.tm_year : 0),
+                         result.fe_time.tm_hour,
+                         result.fe_time.tm_min,
+                         result.fe_time.tm_sec,
+                         (rc == 'd' ? "<DIR>         " :
+                          (rc == 'l' ? "<JUNCTION>    " : result.fe_size)),
+                         (int)result.fe_fnlen, result.fe_fname,
+                         ((rc == 'l' && result.fe_lnlen) ? " -> " : ""),
+                         (int)((rc == 'l' && result.fe_lnlen) ? result.fe_lnlen : 0),
+                         ((rc == 'l' && result.fe_lnlen) ? result.fe_lname : ""));
+
+  ASSERT_STREQ(parsed.get(), resultLine);
+}
+
+FILE*
+OpenResultFile(const char* resultFileName)
+{
+  if (!resultFileName) {
+    return nullptr;
+  }
+
+  FILE* resultFile = fopen(resultFileName, "r");
+  EXPECT_NE(resultFile, nullptr);
+
+  // Ignore anything in the expected result file before and including the first blank line.
+  char resultLine[512];
+  while (fgets(resultLine, sizeof(resultLine), resultFile)) {
+    size_t lineLen = strlen(resultLine);
+    EXPECT_LT(lineLen, sizeof(resultLine) - 1);
+    if (lineLen > 0 && resultLine[lineLen - 1] == '\n') {
+      lineLen--;
+    }
+    if (lineLen == 0) {
+      break;
+    }
+  }
+
+  // There must be a blank line somewhere in the result file.
+  EXPECT_EQ(strcmp(resultLine, "\n"), 0);
+
+  return resultFile;
+}
+
+void
+ParseFTPFile(const char* inputFileName,
+             const char* resultFileName)
+{
+  printf("Checking %s\n", inputFileName);
+  FILE* inFile = fopen(inputFileName, "r");
+  ASSERT_NE(inFile, nullptr);
+
+  FILE* resultFile = OpenResultFile(resultFileName);
+
+  char inputLine[512];
+  struct list_state state;
+  memset(&state, 0, sizeof(state));
+  while (fgets(inputLine, sizeof(inputLine), inFile)) {
+    size_t lineLen = strlen(inputLine);
+    EXPECT_LT(lineLen, sizeof(inputLine) - 1);
+    if (lineLen > 0 && inputLine[lineLen - 1] == '\n') {
+      lineLen--;
+    }
+
+    ParseFTPLine(inputLine, resultFile, &state);
+  }
+
+  // Make sure there are no extra lines in the result file.
+  if (resultFile) {
+    char resultLine[512];
+    EXPECT_EQ(fgets(resultLine, sizeof(resultLine), resultFile), nullptr) <<
+      "There should not be more lines in the expected results file than in the parser output.";
+    fclose(resultFile);
+  }
+
+  fclose(inFile);
+}
+
+static const char* testFiles[] = {
+  "3-guess",
+  "C-VMold",
+  "C-zVM",
+  "D-WinNT",
+  "E-EPLF",
+  "O-guess",
+  "R-dls",
+  "U-HellSoft",
+  "U-hethmon",
+  "U-murksw",
+  "U-ncFTPd",
+  "U-NetPresenz",
+  "U-NetWare",
+  "U-nogid",
+  "U-no_ug",
+  "U-Novonyx",
+  "U-proftpd",
+  "U-Surge",
+  "U-WarFTPd",
+  "U-WebStar",
+  "U-WinNT",
+  "U-wu",
+  "V-MultiNet",
+  "V-VMS-mix",
+};
+
+TEST(ParseFTPTest, Check)
+{
+  PRStatus result = PR_ParseTimeString(kDefaultTestTime, true, &gTestTime);
+  ASSERT_EQ(PR_SUCCESS, result);
+
+  char inputFileName[200];
+  char resultFileName[200];
+  for (size_t test = 0; test < mozilla::ArrayLength(testFiles); ++test) {
+    snprintf(inputFileName, mozilla::ArrayLength(inputFileName), "%s.in", testFiles[test]);
+    snprintf(resultFileName, mozilla::ArrayLength(inputFileName), "%s.out", testFiles[test]);
+    ParseFTPFile(inputFileName, resultFileName);
+  }
+}
+
new file mode 100644
--- /dev/null
+++ b/netwerk/test/gtest/parse-ftp/moz.build
@@ -0,0 +1,68 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+UNIFIED_SOURCES += [
+    'TestParseFTPList.cpp',
+]
+
+TEST_HARNESS_FILES.gtest += [
+    '3-guess.in',
+    '3-guess.out',
+    'C-VMold.in',
+    'C-VMold.out',
+    'C-zVM.in',
+    'C-zVM.out',
+    'D-WinNT.in',
+    'D-WinNT.out',
+    'E-EPLF.in',
+    'E-EPLF.out',
+    'O-guess.in',
+    'O-guess.out',
+    'R-dls.in',
+    'R-dls.out',
+    'U-HellSoft.in',
+    'U-HellSoft.out',
+    'U-hethmon.in',
+    'U-hethmon.out',
+    'U-murksw.in',
+    'U-murksw.out',
+    'U-ncFTPd.in',
+    'U-ncFTPd.out',
+    'U-NetPresenz.in',
+    'U-NetPresenz.out',
+    'U-NetWare.in',
+    'U-NetWare.out',
+    'U-no_ug.in',
+    'U-no_ug.out',
+    'U-nogid.in',
+    'U-nogid.out',
+    'U-Novonyx.in',
+    'U-Novonyx.out',
+    'U-proftpd.in',
+    'U-proftpd.out',
+    'U-Surge.in',
+    'U-Surge.out',
+    'U-WarFTPd.in',
+    'U-WarFTPd.out',
+    'U-WebStar.in',
+    'U-WebStar.out',
+    'U-WinNT.in',
+    'U-WinNT.out',
+    'U-wu.in',
+    'U-wu.out',
+    'V-MultiNet.in',
+    'V-MultiNet.out',
+    'V-VMS-mix.in',
+    'V-VMS-mix.out',
+]
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+LOCAL_INCLUDES += [
+    '/netwerk/streamconv/converters',
+]
+
+FINAL_LIBRARY = 'xul-gtest'
--- a/testing/cppunittest.ini
+++ b/testing/cppunittest.ini
@@ -23,16 +23,17 @@ skip-if = os != 'win'
 [TestIntegerPrintfMacros]
 [TestIntegerRange]
 [TestJSONWriter]
 [TestLinkedList]
 [TestMacroArgs]
 [TestMacroForEach]
 [TestMathAlgorithms]
 [TestMaybe]
+[TestParseFTPList]
 [TestPLDHash]
 skip-if = os == 'b2g'  #Bug 1038197
 [TestPair]
 [TestPoisonArea]
 skip-if = os == 'android' # Bug 1147630
 [TestRefPtr]
 [TestRollingMean]
 [TestScopeExit]