[SCM] Samba Shared Repository - branch master updated

Andrew Bartlett abartlet at samba.org
Fri Jul 5 02:25:04 UTC 2019


The branch, master has been updated
       via  9d90ac352d4 util: Fix off-by-one error in message about overflow
       via  5f7d82a8899 util: Avoid localised underflow
       via  31345376406 s4/scripting/smbstatus: begone
       via  c6bb0497a02 s4/torture: remove autoidl
       via  3822a41f74c s4/scripting/autoidl: remove it
       via  9fc8e2a6d0c tests/usage: test for --help consistency
       via  272a6c3c305 tests/samba-tool: test --help consistency
       via  027d35bda1e python/tests: helper function for checking --help consistency
       via  089034628b9 tests/usage: generalise to cover non-python scripts
       via  854e554c990 tests/usage: python scripts --help should be helpful
       via  075bf608369 s4/scripting/samba_dnsupdate: print usage with no arguments
       via  c78eef6810a s4/scripting/demodirsync: print usage if no host named
       via  ffdb0ca8b09 s4/scripting/mymachinepw: print usage with bad arguments
       via  e5e4c113713 s4/scripting/get-descriptors: print usage with insufficient arguments
       via  96148436b7f script/compare_cc_results: print usage on too few args
       via  77d69ab8207 dns_hub: print usage with too few args
       via  538ffe1960a tests: ensure that most python scripts have usage text
      from  eb8f74f26d5 WHATSNEW: entries for gnutls and samba-tool

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 9d90ac352d409c6cda7598a4cfbb79c2b9f75754
Author: Martin Schwenke <martin at meltin.net>
Date:   Mon Jul 1 21:42:56 2019 +1000

    util: Fix off-by-one error in message about overflow
    
    len includes space for the NUL character, so the calculation needs to
    take the NUL character into account.
    
    While touching this, drop unnecessary casts by updating format string
    and update to modern debug macro.
    
    Signed-off-by: Martin Schwenke <martin at meltin.net>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    
    Autobuild-User(master): Andrew Bartlett <abartlet at samba.org>
    Autobuild-Date(master): Fri Jul  5 02:24:52 UTC 2019 on sn-devel-184

commit 5f7d82a88991d93d32f9cd1bbbfa3c3629e471c7
Author: Martin Schwenke <martin at meltin.net>
Date:   Mon Jul 1 21:28:43 2019 +1000

    util: Avoid localised underflow
    
    Avoid parenthesising an unsigned subtraction that can be negative and,
    therefore, underflow.  There is no need for the parentheses and
    removing them results in an expression that is evaluated left-to-right
    and can not underflow.
    
    It isn't clear that the underflow matters.  lp <= ls, so if (li - lp)
    underflows then ls + (li - lp) will always overflow.  This should
    produce the correct answer.  However, depending on this seems wrong.
    
    Signed-off-by: Martin Schwenke <martin at meltin.net>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 31345376406562e375516fdad5a1bcabf6b8dc27
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Tue Jul 2 12:30:26 2019 +1200

    s4/scripting/smbstatus: begone
    
    Untested and unused.
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit c6bb0497a0237bcc062b24abecc25c69fca6face
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Tue Jul 2 12:25:22 2019 +1200

    s4/torture: remove autoidl
    
    This has been turned off by default for 10 years
    (since 26e114b83ce1de7515bfbf365), and is only interesting for
    nostalgia purposes.
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 3822a41f74c037e79ca3ed308983c68960bc4ddd
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Tue Jul 2 11:55:46 2019 +1200

    s4/scripting/autoidl: remove it
    
    What does it even do? Possibly nothing, not least because nobody ever
    runs it.
    
    It was introduced as source4/scripting/bin/autoidl.py in
    a2446e5f8550582c0d4353bb85874dea17cf1d98 ("initial work for script
    that uses probing to figure out IDL"). Since then it has only had
    superficial patches, generally aimed at Python 3.
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 9fc8e2a6d0c037505edde1395c0f8651663e1acd
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Thu Jun 27 16:57:22 2019 +1200

    tests/usage: test for --help consistency
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 272a6c3c305a446ac5c40b5844d9169e15b85971
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Thu Jun 27 16:57:22 2019 +1200

    tests/samba-tool: test --help consistency
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 027d35bda1e77c89d3ea03a768ff4cf60717de90
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Thu Jun 27 16:57:22 2019 +1200

    python/tests: helper function for checking --help consistency
    
    Check that --help output doesn't contradict itself by assigning the same
    option string to different meanings (which *does* happen in the ldb tools).
    
    This will be used in the samba-tool help tests and the usage tests.
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 089034628b98554298af799722ecf1be09bfa427
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Thu Jun 27 16:57:22 2019 +1200

    tests/usage: generalise to cover non-python scripts
    
    It is not as simple as running everything executable, because for example
    .so library files are marked as executable.
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 854e554c99064b111bf60ce036c223a7394340e9
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Thu Jun 27 16:57:22 2019 +1200

    tests/usage: python scripts --help should be helpful
    
    We want to be sure it says *something* and returns success.
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 075bf608369896e1f1475a6ecb99118637c73698
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Thu Jun 27 16:57:21 2019 +1200

    s4/scripting/samba_dnsupdate: print usage with no arguments
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit c78eef6810ae5a7a48f126ec9ede2b76a77fdb0c
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Thu Jun 27 16:57:21 2019 +1200

    s4/scripting/demodirsync: print usage if no host named
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit ffdb0ca8b099ce638854dbb974093b2021f7ed50
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Thu Jun 27 16:57:21 2019 +1200

    s4/scripting/mymachinepw: print usage with bad arguments
    
    Also, use sys.exit() function, not exit(), because sys.exit() reliably
    exists.
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit e5e4c113713ffbc88836db6cea0245a32151748f
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Thu Jun 27 16:57:21 2019 +1200

    s4/scripting/get-descriptors: print usage with insufficient arguments
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 96148436b7f8633da920ef5b52d8ad3aa735a9cc
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Thu Jun 27 16:57:20 2019 +1200

    script/compare_cc_results: print usage on too few args
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 77d69ab8207aeab03c428e07a2d131ce01ddb31a
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Thu Jun 27 16:57:20 2019 +1200

    dns_hub: print usage with too few args
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 538ffe1960a8640875759ca194cc4cc9fae2c5bc
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Sun Mar 17 14:47:40 2019 +1300

    tests: ensure that most python scripts have usage text
    
    When a script is run with the wrong arguments, it should at least say
    something like this:
    
        Usage: samba-foo [OPTIONS]
    
    For many samba scripts, especially without a server environment, having
    no arguments is the wrong arguments.
    
    Here we look for every executable file with '#![...]python[3]' on the
    first line, and exclude certain files and directories that have excuses
    to fail the test. For example, many selftest scripts are stream-oriented
    and will hang forever waiting for stdin, which is not an error. Some
    test modules are designed so they can be optionally run from the command
    line, but this option is typically only used by the developer who is
    writing them.
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

-----------------------------------------------------------------------

Summary of changes:
 lib/util/substitute.c                  |  26 +--
 python/samba/tests/__init__.py         | 118 +++++++++++
 python/samba/tests/samba_tool/help.py  |   8 +
 python/samba/tests/usage.py            | 362 +++++++++++++++++++++++++++++++++
 script/compare_cc_results.py           |  12 +-
 selftest/knownfail.d/usage             |  42 ++++
 selftest/skip                          |   1 -
 selftest/target/dns_hub.py             |   4 +
 source4/scripting/bin/autoidl          | 164 ---------------
 source4/scripting/bin/get-descriptors  |   4 +
 source4/scripting/bin/mymachinepw      |   9 +-
 source4/scripting/bin/samba_dnsupdate  |  20 +-
 source4/scripting/bin/smbstatus        |  92 ---------
 source4/scripting/devel/demodirsync.py |   3 +
 source4/selftest/tests.py              |   2 +
 source4/torture/rpc/autoidl.c          | 312 ----------------------------
 source4/torture/rpc/rpc.c              |   1 -
 source4/torture/wscript_build          |   1 -
 18 files changed, 588 insertions(+), 593 deletions(-)
 create mode 100644 python/samba/tests/usage.py
 create mode 100644 selftest/knownfail.d/usage
 delete mode 100755 source4/scripting/bin/autoidl
 delete mode 100755 source4/scripting/bin/smbstatus
 delete mode 100644 source4/torture/rpc/autoidl.c


Changeset truncated at 500 lines:

diff --git a/lib/util/substitute.c b/lib/util/substitute.c
index 2249035f704..2d88e97fd19 100644
--- a/lib/util/substitute.c
+++ b/lib/util/substitute.c
@@ -65,11 +65,12 @@ static void string_sub2(char *s,const char *pattern, const char *insert, size_t
 		len = ls + 1; /* len is number of *bytes* */
 
 	while (lp <= ls && (p = strstr_m(s,pattern))) {
-		if (ls + (li-lp) >= len) {
-			DEBUG(0,("ERROR: string overflow by "
-				"%d in string_sub(%.50s, %d)\n",
-				 (int)(ls + (li-lp) - len),
-				 pattern, (int)len));
+		if (ls + li - lp >= len) {
+			DBG_ERR("ERROR: string overflow by "
+				"%zu in string_sub(%.50s, %zu)\n",
+				ls + li - lp + 1 - len,
+				pattern,
+				len);
 			break;
 		}
 		if (li != lp) {
@@ -105,7 +106,7 @@ static void string_sub2(char *s,const char *pattern, const char *insert, size_t
 			}
 		}
 		s = p + li;
-		ls += (li-lp);
+		ls = ls + li - lp;
 
 		if (replace_once)
 			break;
@@ -192,11 +193,12 @@ _PUBLIC_ void all_string_sub(char *s,const char *pattern,const char *insert, siz
 		len = ls + 1; /* len is number of *bytes* */
 
 	while (lp <= ls && (p = strstr_m(s,pattern))) {
-		if (ls + (li-lp) >= len) {
-			DEBUG(0,("ERROR: string overflow by "
-				"%d in all_string_sub(%.50s, %d)\n",
-				 (int)(ls + (li-lp) - len),
-				 pattern, (int)len));
+		if (ls + li - lp >= len) {
+			DBG_ERR("ERROR: string overflow by "
+				"%zu in all_string_sub(%.50s, %zu)\n",
+				ls + li - lp + 1 - len,
+				pattern,
+				len);
 			break;
 		}
 		if (li != lp) {
@@ -204,6 +206,6 @@ _PUBLIC_ void all_string_sub(char *s,const char *pattern,const char *insert, siz
 		}
 		memcpy(p, insert, li);
 		s = p + li;
-		ls += (li-lp);
+		ls = ls + li - lp;
 	}
 }
diff --git a/python/samba/tests/__init__.py b/python/samba/tests/__init__.py
index 674cdee1a3e..c5c212ef829 100644
--- a/python/samba/tests/__init__.py
+++ b/python/samba/tests/__init__.py
@@ -31,6 +31,7 @@ import subprocess
 import sys
 import unittest
 import re
+from enum import IntEnum, unique
 import samba.auth
 import samba.dcerpc.base
 from samba.compat import text_type
@@ -581,3 +582,120 @@ def create_test_ou(samdb, name):
     dn = ldb.Dn(samdb, "OU=%s%d,%s" % (name, rand, samdb.get_default_basedn()))
     samdb.add({"dn": dn, "objectclass": "organizationalUnit"})
     return dn
+
+
+ at unique
+class OptState(IntEnum):
+    NOOPT = 0
+    HYPHEN1 = 1
+    HYPHEN2 = 2
+    NAME = 3
+
+
+def parse_help_consistency(out,
+                           options_start=None,
+                           options_end=None,
+                           optmap=None,
+                           max_leading_spaces=10):
+    if options_start is None:
+        opt_lines = []
+    else:
+        opt_lines = None
+
+    for raw_line in out.split('\n'):
+        line = raw_line.lstrip()
+        if line == '':
+            continue
+        if opt_lines is None:
+            if line == options_start:
+                opt_lines = []
+            else:
+                continue
+        if len(line) < len(raw_line) - max_leading_spaces:
+            # for the case where we have:
+            #
+            #  --foo        frobnicate or barlify depending on
+            #               --bar option.
+            #
+            # where we want to ignore the --bar.
+            continue
+        if line[0] == '-':
+            opt_lines.append(line)
+        if line == options_end:
+            break
+
+    if opt_lines is None:
+        # No --help options is not an error in *this* test.
+        return
+
+    is_longname_char = re.compile(r'^[\w-]$').match
+    for line in opt_lines:
+        state = OptState.NOOPT
+        name = None
+        prev = ' '
+        for c in line:
+            if state == OptState.NOOPT:
+                if c == '-' and  prev.isspace():
+                    state = OptState.HYPHEN1
+                prev = c
+                continue
+            if state == OptState.HYPHEN1:
+                if c.isalnum():
+                    name = '-' + c
+                    state = OptState.NAME
+                elif c == '-':
+                    state = OptState.HYPHEN2
+                continue
+            if state == OptState.HYPHEN2:
+                if c.isalnum():
+                    name = '--' + c
+                    state = OptState.NAME
+                else: # WTF, perhaps '--' ending option list.
+                    state = OptState.NOOPT
+                    prev = c
+                continue
+            if state == OptState.NAME:
+                if is_longname_char(c):
+                    name += c
+                else:
+                    optmap.setdefault(name, []).append(line)
+                    state = OptState.NOOPT
+                    prev = c
+
+        if state == OptState.NAME:
+            optmap.setdefault(name, []).append(line)
+
+
+def check_help_consistency(out,
+                           options_start=None,
+                           options_end=None):
+    """Ensure that options are not repeated and redefined in --help
+    output.
+
+    Returns None if everything is OK, otherwise a string indicating
+    the problems.
+
+    If options_start and/or options_end are provided, only the bit in
+    the output between these two lines is considered. For example,
+    with samba-tool,
+
+    options_start='Options:', options_end='Available subcommands:'
+
+    will prevent the test looking at the preamble which may contain
+    examples using options.
+    """
+    # Silly test, you might think, but this happens
+    optmap = {}
+    parse_help_consistency(out,
+                           options_start,
+                           options_end,
+                           optmap)
+
+    errors = []
+    for k, values in sorted(optmap.items()):
+        if len(values) > 1:
+            for v in values:
+                errors.append("%s: %s" % (k, v))
+
+    if errors:
+        return "\n".join(errors)
diff --git a/python/samba/tests/samba_tool/help.py b/python/samba/tests/samba_tool/help.py
index db70f617355..669895041ea 100644
--- a/python/samba/tests/samba_tool/help.py
+++ b/python/samba/tests/samba_tool/help.py
@@ -20,8 +20,10 @@
 import re
 from samba.tests.samba_tool.base import SambaToolCmdTest
 from samba.tests import BlackboxProcessError
+from samba.tests import check_help_consistency
 from samba.compat import get_string
 
+
 class HelpTestCase(SambaToolCmdTest):
     """Tests for samba-tool help and --help
 
@@ -65,6 +67,12 @@ class HelpTestCase(SambaToolCmdTest):
                 output2 = get_string(output2)
                 self.assertEqual(output, output2)
 
+                err = check_help_consistency(output,
+                                             options_start='Options:',
+                                             options_end='Available subcommands:')
+                if err is not None:
+                    self.fail("consistency error with %s:\n%s" % (line, err))
+
             if not new_commands:
                 break
 
diff --git a/python/samba/tests/usage.py b/python/samba/tests/usage.py
new file mode 100644
index 00000000000..ba18a3e0729
--- /dev/null
+++ b/python/samba/tests/usage.py
@@ -0,0 +1,362 @@
+# Unix SMB/CIFS implementation.
+# Copyright © Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+import os
+import sys
+import subprocess
+from samba.tests import TestCase, check_help_consistency
+from unittest import TestSuite
+import re
+import stat
+
+if 'SRCDIR_ABS' in os.environ:
+    BASEDIR = os.environ['SRCDIR_ABS']
+else:
+    BASEDIR = os.path.abspath(os.path.join(os.path.dirname(__file__),
+                                           '../../..'))
+
+TEST_DIRS = [
+    "bootstrap",
+    "testdata",
+    "ctdb",
+    "dfs_server",
+    "pidl",
+    "auth",
+    "packaging",
+    "python",
+    "include",
+    "nsswitch",
+    "libcli",
+    "coverity",
+    "release-scripts",
+    "testprogs",
+    "bin",
+    "source3",
+    "docs-xml",
+    "buildtools",
+    "file_server",
+    "dynconfig",
+    "source4",
+    "tests",
+    "libds",
+    "selftest",
+    "lib",
+    "script",
+    "traffic",
+    "testsuite",
+    "libgpo",
+    "wintest",
+    "librpc",
+]
+
+
+EXCLUDE_USAGE = {
+    'script/autobuild.py',  # defaults to mount /memdisk/
+    'script/bisect-test.py',
+    'ctdb/utils/etcd/ctdb_etcd_lock',
+    'selftest/filter-subunit',
+    'selftest/format-subunit',
+    'bin/gen_output.py',  # too much output!
+    'source4/scripting/bin/gen_output.py',
+    'lib/ldb/tests/python/index.py',
+    'lib/ldb/tests/python/api.py',
+    'source4/selftest/tests.py',
+    'buildtools/bin/waf',
+    'selftest/tap2subunit',
+    'script/show_test_time',
+    'source4/scripting/bin/subunitrun',
+    'source3/selftest/tests.py',
+    'selftest/tests.py',
+    'python/samba/subunit/run.py',
+    'bin/python/samba/subunit/run.py',
+    'python/samba/tests/dcerpc/raw_protocol.py'
+}
+
+EXCLUDE_HELP = {
+    'selftest/tap2subunit',
+    'wintest/test-s3.py',
+    'wintest/test-s4-howto.py',
+}
+
+
+EXCLUDE_DIRS = {
+    'source3/script/tests',
+    'python/examples',
+    'source4/dsdb/tests/python',
+    'bin/ab',
+    'bin/python/samba/tests',
+    'bin/python/samba/tests/dcerpc',
+}
+
+
+def _init_git_file_finder():
+    """Generate a function that quickly answers the question:
+    'is this a git file?'
+    """
+    git_file_cache = set()
+    p = subprocess.run(['git',
+                        '-C', BASEDIR,
+                        'ls-files',
+                        '-z'],
+                       stdout=subprocess.PIPE)
+    if p.returncode == 0:
+        for fn in p.stdout.split(b'\0'):
+            git_file_cache.add(os.path.join(BASEDIR, fn.decode('utf-8')))
+    return git_file_cache.__contains__
+
+
+is_git_file = _init_git_file_finder()
+
+
+def script_iterator(d=BASEDIR, cache=None,
+                    shebang_filter=None,
+                    filename_filter=None,
+                    subdirs=TEST_DIRS):
+    if not cache:
+        safename = re.compile(r'\W+').sub
+        for subdir in subdirs:
+            sd = os.path.join(d, subdir)
+            for root, dirs, files in os.walk(sd, followlinks=False):
+                for fn in files:
+                    if fn.endswith('~'):
+                        continue
+                    if fn.endswith('.inst'):
+                        continue
+                    ffn = os.path.join(root, fn)
+                    try:
+                        s = os.stat(ffn)
+                    except FileNotFoundError:
+                        continue
+                    if not s.st_mode & stat.S_IXUSR:
+                        continue
+                    if not (subdir == 'bin' or is_git_file(ffn)):
+                        continue
+
+                    if filename_filter is not None:
+                        if not filename_filter(ffn):
+                            continue
+
+                    if shebang_filter is not None:
+                        try:
+                            f = open(ffn, 'rb')
+                        except OSError as e:
+                            print("could not open %s: %s" % (ffn, e))
+                            continue
+                        line = f.read(40)
+                        f.close()
+                        if not shebang_filter(line):
+                            continue
+
+                    name = safename('_', fn)
+                    while name in cache:
+                        name += '_'
+                    cache[name] = ffn
+
+    return cache.items()
+
+# For ELF we only look at /bin/* top level.
+def elf_file_name(fn):
+    fn = fn.partition('bin/')[2]
+    return fn and '/' not in fn and 'test' not in fn and 'ldb' in fn
+
+def elf_shebang(x):
+    return x[:4] == b'\x7fELF'
+
+elf_cache = {}
+def elf_iterator():
+    return script_iterator(BASEDIR, elf_cache,
+                           shebang_filter=elf_shebang,
+                           filename_filter=elf_file_name,
+                           subdirs=['bin'])
+
+
+perl_shebang = re.compile(br'#!.+perl').match
+
+perl_script_cache = {}
+def perl_script_iterator():
+    return script_iterator(BASEDIR, perl_script_cache, perl_shebang)
+
+
+python_shebang = re.compile(br'#!.+python').match
+
+python_script_cache = {}
+def python_script_iterator():
+    return script_iterator(BASEDIR, python_script_cache, python_shebang)
+
+
+class PerlScriptUsageTests(TestCase):
+    """Perl scripts run without arguments should print a usage string,
+        not fail with a traceback.
+    """
+
+    @classmethod
+    def initialise(cls):
+        for name, filename in perl_script_iterator():
+            print(name, filename)
+
+
+class PythonScriptUsageTests(TestCase):
+    """Python scripts run without arguments should print a usage string,
+        not fail with a traceback.
+    """
+
+    @classmethod
+    def initialise(cls):
+        for name, filename in python_script_iterator():
+            # We add the actual tests after the class definition so we
+            # can give individual names to them, so we can have a
+            # knownfail list.
+            fn = filename.replace(BASEDIR, '').lstrip('/')
+
+            if fn in EXCLUDE_USAGE:
+                print("skipping %s (EXCLUDE_USAGE)" % filename)
+                continue
+
+            if os.path.dirname(fn) in EXCLUDE_DIRS:
+                print("skipping %s (EXCLUDE_DIRS)" % filename)
+                continue
+
+            def _f(self, filename=filename):
+                print(filename)
+                try:
+                    p = subprocess.Popen(['python3', filename],
+                                         stderr=subprocess.PIPE,
+                                         stdout=subprocess.PIPE)
+                    out, err = p.communicate(timeout=5)
+                except OSError as e:
+                    self.fail("Error: %s" % e)
+                except subprocess.SubprocessError as e:
+                    self.fail("Subprocess error: %s" % e)
+
+                err = err.decode('utf-8')
+                out = out.decode('utf-8')
+                self.assertNotIn('Traceback', err)
+
+                self.assertIn('usage', out.lower() + err.lower(),
+                              'stdout:\n%s\nstderr:\n%s' % (out, err))
+
+            setattr(cls, 'test_%s' % name, _f)
+
+
+class HelpTestSuper(TestCase):
+    """Python scripts run with -h or --help should print a help string,
+    and exit with success.
+    """
+    check_return_code = True
+    check_consistency = True
+    check_contains_usage = True
+    check_multiline = True
+    check_merged_out_and_err = False
+
+    interpreter = None
+
+    options_start = None
+    options_end = None
+    def iterator(self):
+        raise NotImplementedError("Subclass this "
+                                  "and add an iterator function!")
+
+    @classmethod
+    def initialise(cls):
+        for name, filename in cls.iterator():
+            # We add the actual tests after the class definition so we
+            # can give individual names to them, so we can have a


-- 
Samba Shared Repository



More information about the samba-cvs mailing list