Coverage for tsfpga/test/lint/file_format_lint.py: 51%
90 statements
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-07 20:51 +0000
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-07 20:51 +0000
1# --------------------------------------------------------------------------------------------------
2# Copyright (c) Lukas Vik. All rights reserved.
3#
4# This file is part of the tsfpga project, a project platform for modern FPGA development.
5# https://tsfpga.com
6# https://github.com/tsfpga/tsfpga
7# --------------------------------------------------------------------------------------------------
9# Standard libraries
10from pathlib import Path
12# Third party libraries
13import pytest
15# First party libraries
16from tsfpga import DEFAULT_FILE_ENCODING
17from tsfpga.system_utils import create_file
20def open_file_with_encoding(file: Path) -> None:
21 """
22 Try to open the ``file`` with ASCII encoding.
23 If that fails, i.e. if it contains non-ASCII characters, print information and raise exception.
24 """
25 try:
26 with open(file, encoding="ascii") as file_handle:
27 file_handle.read()
29 except UnicodeDecodeError as exception:
30 print(file)
31 with open(file, encoding="utf8") as file_handle:
32 lines = file_handle.readlines()
34 for line_idx, line in enumerate(lines):
35 for character in line:
36 try:
37 character.encode("ascii")
38 except UnicodeEncodeError:
39 print(f"Character {character} on line {line_idx + 1} is not ASCII")
41 raise exception
44def check_file_ends_with_newline(file: Path) -> bool:
45 """
46 Return True if ``file`` ends with newline.
47 """
48 test_ok = True
49 with open(file, encoding=DEFAULT_FILE_ENCODING) as file_handle:
50 file_data = file_handle.read()
51 if len(file_data) != 0:
52 if file_data[-1] != "\n":
53 print(f"File {file} didn't end with newline")
54 test_ok = False
56 return test_ok
59def check_file_for_tab_character(file: Path) -> bool:
60 """
61 Return True of ``file`` does not contain any TAB character.
62 """
63 test_ok = True
64 with open(file, encoding=DEFAULT_FILE_ENCODING) as file_handle:
65 for idx, line in enumerate(file_handle.readlines()):
66 if "\t" in line:
67 test_ok = False
68 print(f"TAB character (\\t) on line {idx + 1} in {file}")
69 return test_ok
72def check_file_for_carriage_return(file: Path) -> bool:
73 """
74 Return True if ``file`` does not contain any carriage return (CR).
75 """
76 test_ok = True
77 with open(file, encoding=DEFAULT_FILE_ENCODING, newline="") as file_handle:
78 if "\r" in file_handle.read():
79 test_ok = False
80 print(f"Windows style line breaks (\\r\\n aka CR/LF) in {file}")
82 return test_ok
85def check_file_for_trailing_whitespace(file: Path) -> bool:
86 """
87 Return True if ``file`` does not contain any trailing whitespace.
88 """
89 test_ok = True
90 with open(file, encoding=DEFAULT_FILE_ENCODING) as file_handle:
91 for idx, line in enumerate(file_handle.readlines()):
92 if " \n" in line:
93 test_ok = False
94 print(f"Trailing whitespace on line {idx + 1} in {file}")
96 return test_ok
99def check_file_for_line_length(file_path: Path, max_length: int = 100) -> bool:
100 """
101 Return True if ``file`` does not contain any line that is longer than ``max_length`` characters.
102 """
103 max_length_with_newline = max_length + 1
104 test_ok = True
106 with open(file_path, encoding=DEFAULT_FILE_ENCODING) as file_handle:
107 lines = file_handle.readlines()
108 for line_number, line in enumerate(lines):
109 line_length = len(line)
110 if line_length > max_length_with_newline:
111 print(
112 f"Line {file_path}:{line_number + 1} is too long "
113 f"({line_length - 1} > {max_length_with_newline - 1})"
114 )
115 test_ok = False
117 return test_ok
120def test_open_file_with_encoding_should_raise_exception_on_bad_file(tmp_path: Path) -> None:
121 """
122 Sanity check that the function we use actually triggers on bad files.
123 """
124 file = tmp_path / "temp_file_for_test.txt"
125 with open(file, "w", encoding="utf-8") as file_handle:
126 # Swedish word for island = non-ASCII character
127 data = "\N{LATIN CAPITAL LETTER O WITH DIAERESIS}"
128 file_handle.write(data)
130 with pytest.raises(UnicodeDecodeError):
131 open_file_with_encoding(file)
134def test_check_file_for_tab_character_should_fail_on_bad_file(tmp_path: Path) -> None:
135 """
136 Sanity check that the function we use actually triggers on bad files.
137 """
138 data = "Apa\thest"
139 file = create_file(tmp_path / "temp_file_for_test.txt", data)
140 assert not check_file_for_tab_character(file)
143def test_check_file_for_carriage_return_should_fail_on_bad_file(tmp_path: Path) -> None:
144 """
145 Sanity check that the function we use actually triggers on bad files.
146 """
147 file = tmp_path / "temp_file_for_test.txt"
148 data = b"Apa\r\nhest"
149 with file.open("wb") as file_handle:
150 file_handle.write(data)
151 assert not check_file_for_carriage_return(file)
154def test_check_file_for_trailing_whitespace(tmp_path: Path) -> None:
155 """
156 Sanity check that the function we use actually triggers on bad files.
157 """
158 data = "Apa \nhest \nzebra"
159 file = create_file(tmp_path / "temp_file_for_test.txt", data)
160 assert not check_file_for_trailing_whitespace(file)
163def test_check_file_for_line_length(tmp_path: Path) -> None:
164 """
165 Sanity check that the function we use actually triggers on bad files.
166 """
167 ok_data = """
168asdf
169apa
170hest
171"""
172 ok_file_path = create_file(tmp_path / "ok_data.txt", contents=ok_data)
173 assert check_file_for_line_length(ok_file_path)
175 bad_data = """
176asdf
177apa apa apa apa apa apa apa apa apa apa apa apa apa apa apa apa apa apa apa apa apa apa apa apa
178hest
179"""
180 bad_file_path = create_file(tmp_path / "bad_data.txt", contents=bad_data)
181 assert not check_file_for_line_length(file_path=bad_file_path, max_length=80)