Coverage for tsfpga/test/lint/test_file_format.py: 98%
110 statements
« prev ^ index » next coverage.py v6.4, created at 2022-05-28 04:01 +0000
« prev ^ index » next coverage.py v6.4, created at 2022-05-28 04:01 +0000
1# --------------------------------------------------------------------------------------------------
2# Copyright (c) Lukas Vik. All rights reserved.
3#
4# This file is part of the tsfpga project.
5# https://tsfpga.com
6# https://gitlab.com/tsfpga/tsfpga
7# --------------------------------------------------------------------------------------------------
9import pytest
11from tsfpga import DEFAULT_FILE_ENCODING, REPO_ROOT, TSFPGA_DOC, TSFPGA_EXAMPLE_MODULES, TSFPGA_TCL
12from tsfpga.git_utils import find_git_files
13from tsfpga.system_utils import create_file
16def open_file_with_encoding(file):
17 print(file)
18 with open(file, encoding="ascii") as file_handle:
19 file_handle.read()
22def test_all_checked_in_files_are_properly_encoded():
23 """
24 To avoid problems with different editors and different file encodings, all checked in files
25 should contain only ASCII characters.
27 Avoid one of the documentation files that uses wonky characters to illustrate a directory tree.
28 """
29 for file in files_to_test(exclude_directories=[TSFPGA_DOC / "sphinx" / "module_structure.rst"]):
30 open_file_with_encoding(file)
33def check_file_ends_with_newline(file):
34 test_ok = True
35 with open(file, encoding=DEFAULT_FILE_ENCODING) as file_handle:
36 file_data = file_handle.read()
37 if len(file_data) != 0:
38 if file_data[-1] != "\n":
39 print(f"File {file} didn't end with newline")
40 test_ok = False
41 return test_ok
44def test_all_checked_in_files_end_with_newline():
45 """
46 All checked in non-empty files should end with a UNIX style line break (\n).
47 Otherwise UNIX doesn't consider them actual text files.
48 """
49 test_ok = True
50 for file in files_to_test():
51 test_ok &= check_file_ends_with_newline(file)
52 assert test_ok
55def check_file_for_tab_character(file):
56 test_ok = True
57 with open(file, encoding=DEFAULT_FILE_ENCODING) as file_handle:
58 for idx, line in enumerate(file_handle.readlines()):
59 if "\t" in line:
60 test_ok = False
61 print(f"TAB charatcher (\\t) on line {idx + 1} in {file}")
62 return test_ok
65def test_no_checked_in_files_contain_tabs():
66 """
67 To avoid problems with files looking different in different editors, no checked in files may
68 contain TAB characters.
69 """
70 test_ok = True
71 for file in files_to_test():
72 test_ok &= check_file_for_tab_character(file)
73 assert test_ok
76def check_file_for_carriage_return(file):
77 test_ok = True
78 with open(file, encoding=DEFAULT_FILE_ENCODING, newline="") as file_handle:
79 if "\r" in file_handle.read():
80 test_ok = False
81 print(f"Windows style line breaks (\\r\\n aka CR/LF) in {file}")
82 return test_ok
85def test_no_checked_in_files_contain_carriage_return():
86 """
87 All checked in files should use UNIX style line breaks (\n not \r\n).
88 Some Linux editors and tools will display or interpret the \r as something other than a line
89 break.
90 """
91 test_ok = True
92 for file in files_to_test():
93 test_ok &= check_file_for_carriage_return(file)
94 assert test_ok
97def check_file_for_trailing_whitespace(file):
98 test_ok = True
99 with open(file, encoding=DEFAULT_FILE_ENCODING) as file_handle:
100 for idx, line in enumerate(file_handle.readlines()):
101 if " \n" in line:
102 test_ok = False
103 print(f"Trailing whitespace on line {idx + 1} in {file}")
104 return test_ok
107def test_no_checked_in_files_contain_trailing_whitespace():
108 """
109 Trailing whitespace is not allowed. Some motivation here:
110 https://softwareengineering.stackexchange.com/questions/121555/
111 """
112 test_ok = True
113 for file in files_to_test():
114 test_ok &= check_file_for_trailing_whitespace(file)
115 assert test_ok
118def check_file_for_line_length(file_path, max_length=100):
119 max_length_with_newline = max_length + 1
120 test_ok = True
122 with open(file_path, encoding=DEFAULT_FILE_ENCODING) as file_handle:
123 lines = file_handle.readlines()
124 for line_number, line in enumerate(lines):
125 line_length = len(line)
126 if line_length > max_length_with_newline:
127 print(
128 f"Line {file_path}:{line_number + 1} is too long "
129 f"({line_length - 1} > {max_length_with_newline - 1})"
130 )
131 test_ok = False
133 return test_ok
136def test_no_checked_in_files_have_too_long_lines():
137 test_ok = True
138 excludes = [
139 # YAML format seems hard to break lines in
140 REPO_ROOT / ".gitlab-ci.yml",
141 # We list the license text exactly as the original, with no line breaks
142 REPO_ROOT / "license.rst",
143 # Impossible RST syntax to break
144 TSFPGA_DOC / "release_notes" / "5.0.0.rst",
145 TSFPGA_DOC / "sphinx" / "hdl_modules.rst",
146 TSFPGA_DOC / "sphinx" / "hdl_registers.rst",
147 TSFPGA_DOC / "sphinx" / "simulation.rst",
148 # Impossible dockerfile syntax to break
149 REPO_ROOT / "docker" / "ci" / "Dockerfile",
150 # Impossible TCL syntax to break
151 TSFPGA_TCL / "check_timing.tcl",
152 # From Vivado, not modified by us
153 TSFPGA_EXAMPLE_MODULES / "artyz7" / "tcl" / "block_design.tcl",
154 ]
155 for file_path in files_to_test(exclude_directories=excludes):
156 test_ok &= check_file_for_line_length(file_path=file_path)
158 assert test_ok
161def files_to_test(exclude_directories=None):
162 # Do not test binary image files
163 return find_git_files(
164 directory=REPO_ROOT,
165 exclude_directories=exclude_directories,
166 file_endings_avoid=("png", "svg"),
167 )
170def test_open_file_with_encoding_should_raise_exception_on_bad_file(tmp_path):
171 """
172 Sanity check that the function we use actually triggers on bad files.
173 """
174 file = tmp_path / "temp_file_for_test.txt"
175 with open(file, "w", encoding="utf-8") as file_handle:
176 # Swedish word for island = non-ASCII character
177 data = "\N{LATIN CAPITAL LETTER O WITH DIAERESIS}"
178 file_handle.write(data)
180 with pytest.raises(UnicodeDecodeError):
181 open_file_with_encoding(file)
184def test_check_file_for_tab_character_should_fail_on_bad_file(tmp_path):
185 """
186 Sanity check that the function we use actually triggers on bad files.
187 """
188 data = "Apa\thest"
189 file = create_file(tmp_path / "temp_file_for_test.txt", data)
190 assert not check_file_for_tab_character(file)
193def test_check_file_for_carriage_return_should_fail_on_bad_file(tmp_path):
194 """
195 Sanity check that the function we use actually triggers on bad files.
196 """
197 file = tmp_path / "temp_file_for_test.txt"
198 data = b"Apa\r\nhest"
199 with file.open("wb") as file_handle:
200 file_handle.write(data)
201 assert not check_file_for_carriage_return(file)
204def test_check_file_for_trailing_whitespace(tmp_path):
205 """
206 Sanity check that the function we use actually triggers on bad files.
207 """
208 data = "Apa \nhest \nzebra"
209 file = create_file(tmp_path / "temp_file_for_test.txt", data)
210 assert not check_file_for_trailing_whitespace(file)
213def test_check_file_for_line_length(tmp_path):
214 """
215 Sanity check that the function we use actually triggers on bad files.
216 """
217 ok_data = """
218asdf
219apa
220hest
221"""
222 ok_file_path = create_file(tmp_path / "ok_data.txt", contents=ok_data)
223 assert check_file_for_line_length(ok_file_path)
225 bad_data = """
226asdf
227apa apa apa apa apa apa apa apa apa apa apa apa apa apa apa apa apa apa apa apa apa apa apa apa
228hest
229"""
230 bad_file_path = create_file(tmp_path / "bad_data.txt", contents=bad_data)
231 assert not check_file_for_line_length(file_path=bad_file_path, max_length=80)