Bug 1437004 - BinAST test harness improvements;r?arai,jorendorff draft
authorDavid Teller <dteller@mozilla.com>
Thu, 15 Feb 2018 11:55:07 +0100
changeset 755407 36e298da7129f887a39678c7b0edd45dc9307170
parent 755406 d78cf5a78084ab4a84813183e1371f868ad164a1
child 755408 887868b8dbc56969b516025ba1d7eb38b240b678
push id99175
push userbmo:dteller@mozilla.com
push dateThu, 15 Feb 2018 11:14:51 +0000
reviewersarai, jorendorff
bugs1437004
milestone59.0a1
Bug 1437004 - BinAST test harness improvements;r?arai,jorendorff - the test harness now walks subdirectories. - the test harness now performs garbage-collection before each test. MozReview-Commit-ID: Hgu6wCMmFK7
js/src/jsapi-tests/testBinASTReader.cpp
--- a/js/src/jsapi-tests/testBinASTReader.cpp
+++ b/js/src/jsapi-tests/testBinASTReader.cpp
@@ -5,16 +5,18 @@
  * 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/. */
 
 
 #if defined(XP_UNIX)
 
 #include <dirent.h>
 #include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
 
 #elif defined(XP_WIN)
 
 #include <windows.h>
 
 #endif
 
 #include "jsapi.h"
@@ -46,111 +48,142 @@ readFull(JSContext* cx, const char* path
 
     js::Vector<uint8_t> intermediate(cx);
     readFull(path, intermediate);
 
     if (!buf.appendAll(intermediate))
         MOZ_CRASH("Couldn't read data");
 }
 
-BEGIN_TEST(testBinASTReaderECMAScript2)
+// Invariant: `path` must end with directory separator.
+void
+runTestFromPath(JSContext* cx, const char* path)
 {
     const char BIN_SUFFIX[] = ".binjs";
     const char TXT_SUFFIX[] = ".js";
-
-    CompileOptions options(cx);
-    options.setIntroductionType("unit test parse")
-           .setFileAndLine("<string>", 1);
+    fprintf(stderr, "runTestFromPath: entering directory '%s'\n", path);
+    const size_t pathlen = strlen(path);
 
 #if defined(XP_UNIX)
 
-    const char PATH[] = "jsapi-tests/binast/parser/tester/";
-
     // Read the list of files in the directory.
     enterJsDirectory();
-    DIR* dir = opendir(PATH);
+    DIR* dir = opendir(path);
     exitJsDirectory();
     if (!dir)
         MOZ_CRASH("Couldn't open directory");
 
 
     while (auto entry = readdir(dir)) {
-        // Find files whose name ends with ".binjs".
         const char* d_name = entry->d_name;
+        const bool isDirectory = entry->d_type == DT_DIR;
+
 
 #elif defined(XP_WIN)
 
-    const char PATTERN[] = "jsapi-tests\\binast\\parser\\tester\\*.binjs";
-    const char PATH[] = "jsapi-tests\\binast\\parser\\tester\\";
+    const char PATTERN[] = "*";
 
     WIN32_FIND_DATA FindFileData;
     enterJsDirectory();
     HANDLE hFind = FindFirstFile(PATTERN, &FindFileData);
     exitJsDirectory();
     for (bool found = (hFind != INVALID_HANDLE_VALUE);
             found;
             found = FindNextFile(hFind, &FindFileData))
     {
         const char* d_name = FindFileData.cFileName;
+        const bool isDirectory = FindFileData.dwFileAttributes | FILE_ATTRIBUTE_DIRECTORY);
 
 #endif // defined(XP_UNIX) || defined(XP_WIN)
 
         const size_t namlen = strlen(d_name);
+
+        // Recurse through subdirectories.
+        if (isDirectory) {
+            if (strcmp(d_name, ".") == 0) {
+                continue;
+            }
+            if (strcmp(d_name, "..") == 0) {
+                continue;
+            }
+            UniqueChars subPath(static_cast<char*>(js_malloc(pathlen + /* separator */ 1 + namlen + /* NUL */1)));
+            strncpy(subPath.get(), path, pathlen); // Assuming that `path` ends with a directory separator.
+            strncpy(subPath.get() + pathlen, d_name, namlen);
+            subPath.get()[pathlen + namlen] = path[pathlen - 1]; // Directory separator.
+            subPath.get()[pathlen + namlen + 1 ] = '\0';
+            runTestFromPath(cx, subPath.get());
+            continue;
+        }
+
+        {
+            JS::PrepareForFullGC(cx);
+            cx->runtime()->gc.gc(GC_NORMAL, JS::gcreason::NO_REASON);
+        }
+        LifoAllocScope allocScope(&cx->tempLifoAlloc());
+
+        // Find files whose name ends with ".binjs".
+        fprintf(stderr, "Considering %s\n", d_name);
         if (namlen < sizeof(BIN_SUFFIX))
             continue;
         if (strncmp(d_name + namlen - (sizeof(BIN_SUFFIX) - 1), BIN_SUFFIX, sizeof(BIN_SUFFIX)) != 0)
             continue;
 
         // Find text file.
-        UniqueChars txtPath(static_cast<char*>(js_malloc(namlen + sizeof(PATH) + 1)));
-        strncpy(txtPath.get(), PATH, sizeof(PATH));
-        strncpy(txtPath.get() + sizeof(PATH) - 1, d_name, namlen);
-        strncpy(txtPath.get() + sizeof(PATH) + namlen - sizeof(BIN_SUFFIX), TXT_SUFFIX, sizeof(TXT_SUFFIX));
-        txtPath[sizeof(PATH) + namlen - sizeof(BIN_SUFFIX) + sizeof(TXT_SUFFIX) - 1] = 0;
+        UniqueChars txtPath(static_cast<char*>(js_malloc(namlen + pathlen + 1)));
+        strncpy(txtPath.get(), path, pathlen);
+        strncpy(txtPath.get() + pathlen, d_name, namlen);
+        strncpy(txtPath.get() + pathlen + namlen + 1 - sizeof(BIN_SUFFIX), TXT_SUFFIX, sizeof(TXT_SUFFIX));
+        txtPath[pathlen + namlen - sizeof(BIN_SUFFIX) + sizeof(TXT_SUFFIX)] = 0;
         fprintf(stderr, "Testing %s\n", txtPath.get());
 
         // Read text file.
         js::Vector<char16_t> txtSource(cx);
         readFull(cx, txtPath.get(), txtSource);
 
         // Parse text file.
+        CompileOptions txtOptions(cx);
+        txtOptions.setIntroductionType(txtPath.get());
+
         UsedNameTracker txtUsedNames(cx);
         if (!txtUsedNames.init())
             MOZ_CRASH("Couldn't initialize used names");
-        js::frontend::Parser<js::frontend::FullParseHandler, char16_t> parser(cx, cx->tempLifoAlloc(), options, txtSource.begin(), txtSource.length(),
+        js::frontend::Parser<js::frontend::FullParseHandler, char16_t> txtParser(cx, allocScope.alloc(), txtOptions, txtSource.begin(), txtSource.length(),
                                                   /* foldConstants = */ false, txtUsedNames, nullptr,
                                                   nullptr);
-        if (!parser.checkOptions())
+        if (!txtParser.checkOptions())
             MOZ_CRASH("Bad options");
 
-        auto txtParsed = parser.parse(); // Will be deallocated once `parser` goes out of scope.
+        auto txtParsed = txtParser.parse(); // Will be deallocated once `parser` goes out of scope.
         RootedValue txtExn(cx);
         if (!txtParsed) {
             // Save exception for more detailed error message, if necessary.
             if (!js::GetAndClearException(cx, &txtExn))
                 MOZ_CRASH("Couldn't clear exception");
         }
 
         // Read binary file.
-        UniqueChars binPath(static_cast<char*>(js_malloc(namlen + sizeof(PATH) + 1)));
-        strncpy(binPath.get(), PATH, sizeof(PATH));
-        strncpy(binPath.get() + sizeof(PATH) - 1, d_name, namlen);
-        binPath[namlen + sizeof(PATH) - 1] = 0;
+        UniqueChars binPath(static_cast<char*>(js_malloc(namlen + pathlen + 1)));
+        strncpy(binPath.get(), path, pathlen);
+        strncpy(binPath.get() + pathlen, d_name, namlen);
+        binPath[namlen + pathlen] = 0;
 
         js::Vector<uint8_t> binSource(cx);
         readFull(binPath.get(), binSource);
 
         // Parse binary file.
+        CompileOptions binOptions(cx);
+        binOptions.setIntroductionType(txtPath.get());
+
         js::frontend::UsedNameTracker binUsedNames(cx);
         if (!binUsedNames.init())
             MOZ_CRASH("Couldn't initialized binUsedNames");
 
-        js::frontend::BinASTParser reader(cx, cx->tempLifoAlloc(), binUsedNames, options);
+        js::frontend::BinASTParser binParser(cx, allocScope.alloc(), binUsedNames, binOptions);
 
-        auto binParsed = reader.parse(binSource); // Will be deallocated once `reader` goes out of scope.
+        auto binParsed = binParser.parse(binSource); // Will be deallocated once `reader` goes out of scope.
         RootedValue binExn(cx);
         if (binParsed.isErr()) {
             // Save exception for more detailed error message, if necessary.
             if (!js::GetAndClearException(cx, &binExn))
                 MOZ_CRASH("Couldn't clear binExn");
         }
 
         // The binary parser should accept the file iff the text parser has.
@@ -189,28 +222,57 @@ BEGIN_TEST(testBinASTReaderECMAScript2)
         DumpParseTree(binParsed.unwrap(), binPrinter);
 
         Sprinter txtPrinter(cx);
         if (!txtPrinter.init())
             MOZ_CRASH("Couldn't display txtParsed");
         DumpParseTree(txtParsed, txtPrinter);
 
         if (strcmp(binPrinter.string(), txtPrinter.string()) != 0) {
-            fprintf(stderr, "Got distinct ASTs when parsing %s:\n\tBINARY\n%s\n\n\tTEXT\n%s\n", txtPath.get(), binPrinter.string(), txtPrinter.string());
+            fprintf(stderr, "Got distinct ASTs when parsing %s (%lu/%lu):\n\tBINARY\n%s\n\n\tTEXT\n%s\n",
+                txtPath.get(),
+                binPrinter.getOffset(), txtPrinter.getOffset(),
+                binPrinter.string(), txtPrinter.string());
+#if 0 // Not for release
+            auto fd = open("/tmp/bin.ast", O_CREAT | O_TRUNC | O_WRONLY, 0666);
+            if (!fd)
+                MOZ_CRASH("Could not open bin.ast");
+            auto result = write(fd, binPrinter.string(), binPrinter.stringEnd() - binPrinter.string());
+            if (result <= 0)
+                MOZ_CRASH("Could not write to bin.ast");
+            result = close(fd);
+            if (result != 0)
+                MOZ_CRASH("Could not close bin.ast");
+
+            fd = open("/tmp/txt.ast", O_CREAT | O_TRUNC | O_WRONLY, 0666);
+            if (!fd)
+                MOZ_CRASH("Could not open txt.ast");
+            result = write(fd, txtPrinter.string(), txtPrinter.stringEnd() - txtPrinter.string());
+            if (result <= 0)
+                MOZ_CRASH("Could not write to txt.ast");
+            result = close(fd);
+            if (result != 0)
+                MOZ_CRASH("Could not close txt.ast");
+#endif // 0
             MOZ_CRASH("Got distinct ASTs");
         }
-        fprintf(stderr, "Got the same AST when parsing %s\n", txtPath.get());
 
+        fprintf(stderr, "Got the same AST when parsing %s\n%s\n", txtPath.get(), binPrinter.string());
 #endif // defined(DEBUG)
     }
 
 #if defined(XP_WIN)
     if (!FindClose(hFind))
         MOZ_CRASH("Could not close Find");
 #elif defined(XP_UNIX)
     if (closedir(dir) != 0)
         MOZ_CRASH("Could not close dir");
 #endif // defined(XP_WIN)
+}
+
+BEGIN_TEST(testBinASTReaderECMAScript2)
+{
+    runTestFromPath(cx, "jsapi-tests/binast/parser/tester/");
 
     return true;
 }
 END_TEST(testBinASTReaderECMAScript2)