python:samba:tests: Fix code spelling
[samba.git] / python / samba / tests / source.py
1 # Unix SMB/CIFS implementation.
2 # Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2011
3 #
4 # Loosely based on bzrlib's test_source.py
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 #
19
20 """Source level Python tests."""
21
22 import io
23 import errno
24 import os
25 import re
26 import warnings
27
28 from samba.tests import (
29     TestCase,
30 )
31
32
33 def get_python_source_files():
34     """Iterate over all Python source files."""
35     library_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "samba"))
36     assert os.path.isdir(library_dir), library_dir
37
38     for root, dirs, files in os.walk(library_dir):
39         for f in files:
40             if f.endswith(".py"):
41                 yield os.path.abspath(os.path.join(root, f))
42
43     bindir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "..", "..", "bin"))
44     assert os.path.isdir(bindir), bindir
45     for f in os.listdir(bindir):
46         p = os.path.abspath(os.path.join(bindir, f))
47         if not os.path.islink(p):
48             continue
49         target = os.readlink(p)
50         if os.path.dirname(target).endswith("scripting/bin"):
51             yield p
52     wafsambadir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "..", "..", "buildtools", "wafsamba"))
53     assert os.path.isdir(wafsambadir), wafsambadir
54     for root, dirs, files in os.walk(wafsambadir):
55         for f in files:
56             if f.endswith(".py"):
57                 yield os.path.abspath(os.path.join(root, f))
58
59
60 def get_source_file_contents():
61     """Iterate over the contents of all python files."""
62     for fname in get_python_source_files():
63         try:
64             f = io.open(fname, mode='r', encoding='utf-8')
65         except IOError as e:
66             if e.errno == errno.ENOENT:
67                 warnings.warn("source file %s broken link?" % fname)
68                 continue
69             else:
70                 raise
71         try:
72             text = f.read()
73         finally:
74             f.close()
75         yield fname, text
76
77
78 class TestSource(TestCase):
79
80     def test_copyright(self):
81         """Test that all Python files have a valid copyright statement."""
82         incorrect = []
83
84         copyright_re = re.compile('#\\s*copyright.*(?=\n)', re.I)
85
86         for fname, text in get_source_file_contents():
87             if fname.endswith("ms_schema.py"):
88                 # FIXME: Not sure who holds copyright on ms_schema.py
89                 continue
90             if "wafsamba" in fname:
91                 # FIXME: No copyright headers in wafsamba
92                 continue
93             if fname.endswith("python/samba/tests/krb5/kcrypto.py"):
94                 # Imported from MIT testing repo
95                 continue
96             if fname.endswith("python/samba/tests/krb5/rfc4120_pyasn1.py"):
97                 # Autogenerated
98                 continue
99             match = copyright_re.search(text)
100             if not match:
101                 incorrect.append((fname, 'no copyright line found\n'))
102
103         if incorrect:
104             help_text = [
105                 "Some files have missing or incorrect copyright"
106                 " statements.", ""]
107             for fname, comment in incorrect:
108                 help_text.append(fname)
109                 help_text.append((' ' * 4) + comment)
110
111             self.fail('\n'.join(help_text))
112
113     def test_gpl(self):
114         """Test that all .py files have a GPL disclaimer."""
115         incorrect = []
116
117         gpl_txt = """
118 # This program is free software; you can redistribute it and/or modify
119 # it under the terms of the GNU General Public License as published by
120 # the Free Software Foundation; either version 3 of the License, or
121 # (at your option) any later version.
122 #
123 # This program is distributed in the hope that it will be useful,
124 # but WITHOUT ANY WARRANTY; without even the implied warranty of
125 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
126 # GNU General Public License for more details.
127 #
128 # You should have received a copy of the GNU General Public License
129 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
130 """
131         gpl_re = re.compile(re.escape(gpl_txt), re.MULTILINE)
132
133         for fname, text in get_source_file_contents():
134             if "wafsamba" in fname:
135                 # FIXME: License to wafsamba hasn't been clarified yet
136                 continue
137             if fname.endswith("/python/samba/subunit/run.py"):
138                 # Imported from subunit/testtools, which are dual
139                 # Apache2/BSD-3.
140                 continue
141             if fname.endswith("python/samba/tests/krb5/kcrypto.py"):
142                 # Imported from MIT testing repo
143                 continue
144             if fname.endswith("python/samba/tests/krb5/rfc4120_pyasn1.py"):
145                 # Autogenerated
146                 continue
147             if not gpl_re.search(text):
148                 incorrect.append(fname)
149
150         if incorrect:
151             help_text = ['Some files have missing or incomplete GPL statement',
152                          gpl_txt]
153             for fname in incorrect:
154                 help_text.append((' ' * 4) + fname)
155
156             self.fail('\n'.join(help_text))
157
158     def _push_file(self, dict_, fname, line_no):
159         if fname not in dict_:
160             dict_[fname] = [line_no]
161         else:
162             dict_[fname].append(line_no)
163
164     def _format_message(self, dict_, message):
165         files = ["%s: %s" % (f, ', '.join([str(i + 1) for i in lines]))
166                  for f, lines in dict_.items()]
167         files.sort()
168         return message + '\n\n    %s' % ('\n    '.join(files))
169
170     def _iter_source_files_lines(self):
171         for fname, text in get_source_file_contents():
172             lines = text.splitlines(True)
173             for line_no, line in enumerate(lines):
174                 yield fname, line_no, line
175
176     def test_no_tabs(self):
177         """Check that there are no tabs in Python files."""
178         tabs = {}
179         for fname, line_no, line in self._iter_source_files_lines():
180             if '\t' in line:
181                 self._push_file(tabs, fname, line_no)
182         if tabs:
183             self.fail(self._format_message(tabs,
184                                            'Tab characters were found in the following source files.'
185                                            '\nThey should either be replaced by "\\t" or by spaces:'))
186
187     def test_unix_newlines(self):
188         """Check for unix new lines."""
189         illegal_newlines = {}
190         for fname, line_no, line in self._iter_source_files_lines():
191             if not line.endswith('\n') or line.endswith('\r\n'):
192                 self._push_file(illegal_newlines, fname, line_no)
193         if illegal_newlines:
194             self.fail(self._format_message(illegal_newlines,
195                                            'Non-unix newlines were found in the following source files:'))
196
197     def test_trailing_whitespace(self):
198         """Check that there is not trailing whitespace in Python files."""
199         trailing_whitespace = {}
200         for fname, line_no, line in self._iter_source_files_lines():
201             if line.rstrip("\n").endswith(" "):
202                 self._push_file(trailing_whitespace, fname, line_no)
203         if trailing_whitespace:
204             self.fail(self._format_message(trailing_whitespace,
205                                            'Trailing whitespace was found in the following source files.'))
206
207     def test_shebang_lines(self):
208         """Check that files with shebang lines and only those are executable."""
209         files_with_shebang = {}
210         files_without_shebang = {}
211         for fname, line_no, line in self._iter_source_files_lines():
212             if line_no >= 1:
213                 continue
214             executable = (os.stat(fname).st_mode & 0o111)
215             has_shebang = line.startswith("#!")
216             if has_shebang and not executable:
217                 self._push_file(files_with_shebang, fname, line_no)
218             if not has_shebang and executable:
219                 self._push_file(files_without_shebang, fname, line_no)
220         if files_with_shebang:
221             self.fail(self._format_message(files_with_shebang,
222                                            'Files with shebang line that are not executable:'))
223         if files_without_shebang:
224             self.fail(self._format_message(files_without_shebang,
225                                            'Files without shebang line that are executable:'))