contrib: make check-code.py check code fragments embedded in test scripts
authorFUJIWARA Katsunori <foozy@lares.dti.ne.jp>
Fri, 01 Mar 2019 02:53:09 +0900
changeset 41826 867883d454ea
parent 41825 6d6bd9039ecd
child 41827 faa04f45b5fe
contrib: make check-code.py check code fragments embedded in test scripts
contrib/check-code.py
tests/test-contrib-check-code.t
--- a/contrib/check-code.py	Fri Mar 01 02:53:09 2019 +0900
+++ b/contrib/check-code.py	Fri Mar 01 02:53:09 2019 +0900
@@ -40,6 +40,8 @@
 except ImportError:
     re2 = None
 
+import testparseutil
+
 def compilere(pat, multiline=False):
     if multiline:
         pat = '(?m)' + pat
@@ -402,6 +404,15 @@
   ] + commonpypats[1]
 ]
 
+# patterns to check *.py for embedded ones in test script
+embeddedpypats = [
+  [
+  ] + commonpypats[0],
+  # warnings
+  [
+  ] + commonpypats[1]
+]
+
 # common filters to convert *.py
 commonpyfilters = [
     (r"""(?msx)(?P<comment>\#.*?$)|
@@ -426,6 +437,10 @@
     [],
 ]
 
+# filters to convert *.py for embedded ones in test script
+embeddedpyfilters = [
+] + commonpyfilters
+
 # extension non-filter patterns
 pyextnfpats = [
     [(r'^"""\n?[A-Z]', "don't capitalize docstring title")],
@@ -560,6 +575,15 @@
      allfilesfilters, allfilespats),
 ]
 
+# (desc,
+#  func to pick up embedded code fragments,
+#  list of patterns to convert target files
+#  list of patterns to detect errors/warnings)
+embeddedchecks = [
+    ('embedded python',
+     testparseutil.pyembedded, embeddedpyfilters, embeddedpypats)
+]
+
 def _preparepats():
     def preparefailandwarn(failandwarn):
         for pats in failandwarn:
@@ -580,7 +604,7 @@
         for i, flt in enumerate(filters):
             filters[i] = re.compile(flt[0]), flt[1]
 
-    for cs in (checks,):
+    for cs in (checks, embeddedchecks):
         for c in cs:
             failandwarn = c[-1]
             preparefailandwarn(failandwarn)
@@ -674,6 +698,30 @@
         if fc:
             result = False
 
+    if f.endswith('.t') and "no-" "check-code" not in pre:
+        if debug:
+            print("Checking embedded code in %s" % (f))
+
+        prelines = pre.splitlines()
+        embeddederros = []
+        for name, embedded, filters, pats in embeddedchecks:
+            # "reset curmax at each repetition" treats maxerr as "max
+            # nubmer of errors in an actual file per entry of
+            # (embedded)checks"
+            curmaxerr = maxerr
+
+            for found in embedded(f, prelines, embeddederros):
+                filename, starts, ends, code = found
+                fc = _checkfiledata(name, f, code, filters, pats, context,
+                                    logfunc, curmaxerr, warnings, blame, debug,
+                                    lineno, offset=starts - 1)
+                if fc:
+                    result = False
+                    if curmaxerr:
+                        if fc >= curmaxerr:
+                            break
+                        curmaxerr -= fc
+
     return result
 
 def _checkfiledata(name, f, filedata, filters, pats, context,
--- a/tests/test-contrib-check-code.t	Fri Mar 01 02:53:09 2019 +0900
+++ b/tests/test-contrib-check-code.t	Fri Mar 01 02:53:09 2019 +0900
@@ -379,3 +379,51 @@
    > class empty(object):
    omit superfluous pass
   [1]
+
+Check code fragments embedded in test script
+
+  $ cat > embedded-code.t <<NO_CHECK_EOF
+  > code fragment in doctest style
+  >   >>> x = (1,2)
+  >   ... 
+  >   ... x = (1,2)
+  > 
+  > code fragment in heredoc style
+  >   $ python <<EOF
+  >   > x = (1,2)
+  >   > EOF
+  > 
+  > code fragment in file heredoc style
+  >   $ python > file.py <<EOF
+  >   > x = (1,2)
+  >   > EOF
+  > NO_CHECK_EOF
+  $ "$check_code" embedded-code.t
+  embedded-code.t:2:
+   > x = (1,2)
+   missing whitespace after ,
+  embedded-code.t:4:
+   > x = (1,2)
+   missing whitespace after ,
+  embedded-code.t:8:
+   > x = (1,2)
+   missing whitespace after ,
+  embedded-code.t:13:
+   > x = (1,2)
+   missing whitespace after ,
+  [1]
+
+"max warnings per file" is shared by all embedded code fragments
+
+  $ "$check_code" --per-file=3 embedded-code.t
+  embedded-code.t:2:
+   > x = (1,2)
+   missing whitespace after ,
+  embedded-code.t:4:
+   > x = (1,2)
+   missing whitespace after ,
+  embedded-code.t:8:
+   > x = (1,2)
+   missing whitespace after ,
+   (too many errors, giving up)
+  [1]