Merge pull request #4 from caitp/anbafy-it

Incorporate changes from test262/41edfcebce1a85096
diff --git a/src/parseTestRecord.py b/src/parseTestRecord.py
index 22d5664..6982540 100644
--- a/src/parseTestRecord.py
+++ b/src/parseTestRecord.py
@@ -6,79 +6,41 @@
 # TODO: resolve differences with common.py and unify into one file.
 
 
-import logging
-import optparse
+from __future__ import print_function
+
 import os
-from os import path
-import platform
 import re
-import subprocess
-import sys
-import tempfile
-import time
 import imp
 
 from _monkeyYaml import load as yamlLoad
 
-headerPatternStr = r"(?:(?:\s*\/\/.*)?\s*\n)*"
-captureCommentPatternStr = r"\/\*\*?((?:\s|\S)*?)\*\/\s*\n"
-anyPatternStr = r"(?:\s|\S)*"
+#def onerror(message):
+#    print(message)
 
-headerPattern = re.compile("^" + headerPatternStr)
+# Matches trailing whitespace and any following blank lines.
+_BLANK_LINES = r"([ \t]*[\r\n]{1,2})*"
 
-# Should match anything
-testRecordPattern = re.compile(r"^(" + headerPatternStr +
-                               r")(?:" + captureCommentPatternStr +
-                               r")?(" + anyPatternStr +
-                               r")$")
+# Matches the YAML frontmatter block.
+_YAML_PATTERN = re.compile(r"/\*---(.*)---\*/" + _BLANK_LINES, re.DOTALL)
 
-stars = re.compile(r"\s*\n\s*\*\s?")
-atattrs = re.compile(r"\s*\n\s*\*\s*@")
+# Matches all known variants for the license block.
+_LICENSE_PATTERN = re.compile(
+   r'// Copyright( \(C\))? (\w+) .+\. {1,2}All rights reserved\.[\r\n]{1,2}' +
+   r'(' +
+       r'// This code is governed by the( BSD)? license found in the LICENSE file\.' +
+       r'|' +
+       r'// See LICENSE for details\.' +
+       r'|' +
+       r'// Use of this source code is governed by a BSD-style license that can be[\r\n]{1,2}' +
+       r'// found in the LICENSE file\.' +
+       r'|' +
+       r'// See LICENSE or https://github\.com/tc39/test262/blob/master/LICENSE' +
+   r')[\r\n]{1,2}' + _BLANK_LINES, re.IGNORECASE)
 
-yamlPattern = re.compile(r"---((?:\s|\S)*)---")
-newlinePattern = re.compile(r"\n")
-
-def stripStars(text):
-    return stars.sub('\n', text).strip()
-
-def stripHeader(src):
-    header = headerPattern.match(src).group(0)
-    return src[len(header):]
-
-def matchParts(src, name):
-    match = testRecordPattern.match(src)
-    if match == None:
-        raise Exception('unrecognized: ' + name)
-    return match
-
-def hasYAML(text):
-    match = yamlPattern.match(text)
-    if match == None:
-        return False
-    return True
-
-def oldAttrParser(testRecord, body, name):
-    propTexts = atattrs.split(body)
-    testRecord['commentary'] = stripStars(propTexts[0])
-    del propTexts[0]
-    for propText in propTexts:
-        propMatch = re.match(r"^\w+", propText)
-        if propMatch == None:
-            raise Exception('Malformed "@" attribute: ' + name)
-        propName = propMatch.group(0)
-        propVal = stripStars(propText[len(propName):])
-
-        if propName in testRecord:
-            raise Exception('duplicate: ' + propName)
-        testRecord[propName] = propVal;
-
-def yamlAttrParser(testRecord, attrs, name):
-    match = yamlPattern.match(attrs)
-    body = match.group(1)
-    parsed = yamlLoad(body)
-
-    if (parsed is None):
-        print "Failed to parse yaml in name %s"%(name)
+def yamlAttrParser(testRecord, attrs, name, onerror = print):
+    parsed = yamlLoad(attrs)
+    if parsed is None:
+        onerror("Failed to parse yaml in name %s" % name)
         return
 
     for key in parsed:
@@ -91,17 +53,60 @@
         for flag in testRecord['flags']:
             testRecord[flag] = ""
 
-def parseTestRecord(src, name):
-    testRecord = {}
-    match = matchParts(src, name)
-    testRecord['header'] = match.group(1).strip()
-    testRecord['test'] = match.group(3) # do not trim
+def findLicense(src):
+    match = _LICENSE_PATTERN.search(src)
+    if not match:
+        return None
 
-    attrs = match.group(2)
+    return match.group(0)
+
+def findAttrs(src):
+    match = _YAML_PATTERN.search(src)
+    if not match:
+        return (None, None)
+
+    return (match.group(0), match.group(1).strip())
+
+def parseTestRecord(src, name, onerror = print):
+    # Find the license block.
+    header = findLicense(src)
+
+    # Find the YAML frontmatter.
+    (frontmatter, attrs) = findAttrs(src)
+
+    # YAML frontmatter is required for all tests.
+    if frontmatter is None:
+        onerror("Missing frontmatter: %s" % name)
+
+    # The license shuold be placed before the frontmatter and there shouldn't be
+    # any extra content between the license and the frontmatter.
+    if header is not None and frontmatter is not None:
+        headerIdx = src.index(header)
+        frontmatterIdx = src.index(frontmatter)
+        if headerIdx > frontmatterIdx:
+            onerror("Unexpected license after frontmatter: %s" % name)
+
+        # Search for any extra test content, but ignore whitespace only or comment lines.
+        extra = src[headerIdx + len(header) : frontmatterIdx]
+        if extra and any(line.strip() and not line.lstrip().startswith("//") for line in extra.split("\n")):
+            onerror("Unexpected test content between license and frontmatter: %s" % name)
+
+    # Remove the license and YAML parts from the actual test content.
+    test = src
+    if frontmatter is not None:
+        test = test.replace(frontmatter, '')
+    if header is not None:
+        test = test.replace(header, '')
+
+    testRecord = {}
+    testRecord['header'] = header.strip() if header else ''
+    testRecord['test'] = test
+
     if attrs:
-        if hasYAML(attrs):
-            yamlAttrParser(testRecord, attrs, name)
-        else:
-            oldAttrParser(testRecord, attrs, name)
+        yamlAttrParser(testRecord, attrs, name, onerror)
+
+    # Report if the license block is missing in non-generated tests.
+    if header is None and "generated" not in testRecord and "hashbang" not in name:
+        onerror("No license found in: %s" % name)
 
     return testRecord