1 # Unix SMB/CIFS implementation.
2 # Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2011
4 # Loosely based on bzrlib's test_source.py
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.
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.
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/>.
20 """Source level Python tests."""
27 from samba
.tests
import (
32 def get_python_source_files():
33 """Iterate over all Python source files."""
34 library_dir
= os
.path
.abspath(os
.path
.join(os
.path
.dirname(__file__
), "..", "..", "samba"))
35 assert os
.path
.isdir(library_dir
), library_dir
37 for root
, dirs
, files
in os
.walk(library_dir
):
40 yield os
.path
.abspath(os
.path
.join(root
, f
))
42 bindir
= os
.path
.abspath(os
.path
.join(os
.path
.dirname(__file__
), "..", "..", "..", "..", "bin"))
43 assert os
.path
.isdir(bindir
), bindir
44 for f
in os
.listdir(bindir
):
45 p
= os
.path
.abspath(os
.path
.join(bindir
, f
))
46 if not os
.path
.islink(p
):
48 target
= os
.readlink(p
)
49 if os
.path
.dirname(target
).endswith("scripting/bin"):
51 wafsambadir
= os
.path
.abspath(os
.path
.join(os
.path
.dirname(__file__
), "..", "..", "..", "..", "buildtools", "wafsamba"))
52 assert os
.path
.isdir(wafsambadir
), wafsambadir
53 for root
, dirs
, files
in os
.walk(wafsambadir
):
56 yield os
.path
.abspath(os
.path
.join(root
, f
))
59 def get_source_file_contents():
60 """Iterate over the contents of all python files."""
61 for fname
in get_python_source_files():
65 if e
.errno
== errno
.ENOENT
:
66 warnings
.warn("source file %s broken link?" % fname
)
77 class TestSource(TestCase
):
79 def test_copyright(self
):
80 """Test that all Python files have a valid copyright statement."""
83 copyright_re
= re
.compile('#\\s*copyright.*(?=\n)', re
.I
)
85 for fname
, text
in get_source_file_contents():
86 if fname
.endswith("ms_schema.py"):
87 # FIXME: Not sure who holds copyright on ms_schema.py
89 if "wafsamba" in fname
:
90 # FIXME: No copyright headers in wafsamba
92 match
= copyright_re
.search(text
)
94 incorrect
.append((fname
, 'no copyright line found\n'))
98 "Some files have missing or incorrect copyright"
100 for fname
, comment
in incorrect
:
101 help_text
.append(fname
)
102 help_text
.append((' ' * 4) + comment
)
104 self
.fail('\n'.join(help_text
))
107 """Test that all .py files have a GPL disclaimer."""
111 # This program is free software; you can redistribute it and/or modify
112 # it under the terms of the GNU General Public License as published by
113 # the Free Software Foundation; either version 3 of the License, or
114 # (at your option) any later version.
116 # This program is distributed in the hope that it will be useful,
117 # but WITHOUT ANY WARRANTY; without even the implied warranty of
118 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
119 # GNU General Public License for more details.
121 # You should have received a copy of the GNU General Public License
122 # along with this program. If not, see <http://www.gnu.org/licenses/>.
124 gpl_re
= re
.compile(re
.escape(gpl_txt
), re
.MULTILINE
)
126 for fname
, text
in get_source_file_contents():
127 if "wafsamba" in fname
:
128 # FIXME: License to wafsamba hasn't been clarified yet
130 if fname
.endswith("/python/samba/subunit/run.py"):
131 # Imported from subunit/testtools, which are dual
134 if not gpl_re
.search(text
):
135 incorrect
.append(fname
)
138 help_text
= ['Some files have missing or incomplete GPL statement',
140 for fname
in incorrect
:
141 help_text
.append((' ' * 4) + fname
)
143 self
.fail('\n'.join(help_text
))
145 def _push_file(self
, dict_
, fname
, line_no
):
146 if fname
not in dict_
:
147 dict_
[fname
] = [line_no
]
149 dict_
[fname
].append(line_no
)
151 def _format_message(self
, dict_
, message
):
152 files
= ["%s: %s" % (f
, ', '.join([str(i
+ 1) for i
in lines
]))
153 for f
, lines
in dict_
.items()]
155 return message
+ '\n\n %s' % ('\n '.join(files
))
157 def _iter_source_files_lines(self
):
158 for fname
, text
in get_source_file_contents():
159 lines
= text
.splitlines(True)
160 last_line_no
= len(lines
) - 1
161 for line_no
, line
in enumerate(lines
):
162 yield fname
, line_no
, line
164 def test_no_tabs(self
):
165 """Check that there are no tabs in Python files."""
167 for fname
, line_no
, line
in self
._iter
_source
_files
_lines
():
169 self
._push
_file
(tabs
, fname
, line_no
)
171 self
.fail(self
._format
_message
(tabs
,
172 'Tab characters were found in the following source files.'
173 '\nThey should either be replaced by "\\t" or by spaces:'))
175 def test_unix_newlines(self
):
176 """Check for unix new lines."""
177 illegal_newlines
= {}
178 for fname
, line_no
, line
in self
._iter
_source
_files
_lines
():
179 if not line
.endswith('\n') or line
.endswith('\r\n'):
180 self
._push
_file
(illegal_newlines
, fname
, line_no
)
182 self
.fail(self
._format
_message
(illegal_newlines
,
183 'Non-unix newlines were found in the following source files:'))
185 def test_trailing_whitespace(self
):
186 """Check that there is not trailing whitespace in Python files."""
187 trailing_whitespace
= {}
188 for fname
, line_no
, line
in self
._iter
_source
_files
_lines
():
189 if line
.rstrip("\n").endswith(" "):
190 self
._push
_file
(trailing_whitespace
, fname
, line_no
)
191 if trailing_whitespace
:
192 self
.fail(self
._format
_message
(trailing_whitespace
,
193 'Trailing whitespace was found in the following source files.'))
195 def test_shebang_lines(self
):
196 """Check that files with shebang lines and only those are executable."""
197 files_with_shebang
= {}
198 files_without_shebang
= {}
199 for fname
, line_no
, line
in self
._iter
_source
_files
_lines
():
202 executable
= (os
.stat(fname
).st_mode
& 0111)
203 has_shebang
= line
.startswith("#!")
204 if has_shebang
and not executable
:
205 self
._push
_file
(files_with_shebang
, fname
, line_no
)
206 if not has_shebang
and executable
:
207 self
._push
_file
(files_without_shebang
, fname
, line_no
)
208 if files_with_shebang
:
209 self
.fail(self
._format
_message
(files_with_shebang
,
210 'Files with shebang line that are not executable:'))
211 if files_without_shebang
:
212 self
.fail(self
._format
_message
(files_without_shebang
,
213 'Files without shebang line that are executable:'))