Coverage for tsfpga/test/lint/test_copyright.py: 95%
105 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 re
11import pytest
13import tsfpga
14from tsfpga.system_utils import create_file, read_file
15from tsfpga.git_utils import find_git_files
18class CopyrightHeader:
20 separator_line_length = 100
22 def __init__(self, file, copyright_holder, copyright_text_lines=None):
23 self._file = file
24 self.comment_character = self._get_comment_character()
25 self.separator_line = f"{self.comment_character} " + "-" * (
26 self.separator_line_length - 1 - len(self.comment_character)
27 )
28 self.expected_copyright_header = self._get_expected_copyright_header(
29 copyright_holder, copyright_text_lines
30 )
32 def check_file(self):
33 """
34 Copyright comments should be correct. It should be followed by a blank line or another
35 comment.
36 """
37 copyright_header_re = self.expected_copyright_header.replace("(", "\\(").replace(")", "\\)")
38 regexp = re.compile(copyright_header_re + rf"($|\n|{self.comment_character})")
39 data = read_file(self._file)
40 return regexp.match(data) is not None
42 def fix_file(self):
43 if self._is_suitable_for_insertion():
44 self._insert_copyright_header()
45 else:
46 raise ValueError(f"Can not fix copyright header in file {self._file}")
48 def _get_expected_copyright_header(self, copyright_holder, copyright_text_lines):
49 header = f"{self.separator_line}\n"
50 header += (
51 f"{self.comment_character} Copyright (c) {copyright_holder}. All rights reserved.\n"
52 )
53 if copyright_text_lines:
54 header += f"{self.comment_character}\n"
55 for copyright_text_line in copyright_text_lines:
56 header += f"{self.comment_character} {copyright_text_line}\n"
57 header += f"{self.separator_line}\n"
58 return header
60 def _get_comment_character(self):
61 if self._file.name.endswith(".py"):
62 return "#"
63 if self._file.name.endswith(".vhd"):
64 return "--"
65 if self._file.name.endswith((".xdc", ".tcl")):
66 return "#"
67 if self._file.name.endswith((".c", ".cpp", ".h", ".v")):
68 return "//"
69 raise RuntimeError(f"Could not decide file ending of {self._file}")
71 def _is_suitable_for_insertion(self):
72 """
73 If the file does not begin with a comment, we consired it suitable to insert a new copyright
74 header comment.
75 """
76 return not read_file(self._file).startswith(self.comment_character)
78 def _insert_copyright_header(self):
79 data = read_file(self._file)
80 data = f"{self.expected_copyright_header}\n{data}"
81 create_file(self._file, data)
84def files_to_check_for_copyright_header():
85 file_endings = (".py", ".vhd", ".tcl")
86 exclude_directories = [tsfpga.TSFPGA_EXAMPLE_MODULES / "artyz7" / "tcl"]
87 for file_ending in file_endings:
88 for file in find_git_files(
89 directory=tsfpga.REPO_ROOT,
90 exclude_directories=exclude_directories,
91 file_endings_include=file_ending,
92 ):
93 yield file
96def test_copyright_header_of_all_checked_in_files():
97 test_ok = True
98 for file in files_to_check_for_copyright_header():
99 copyright_lines = [
100 "This file is part of the tsfpga project.",
101 "https://tsfpga.com",
102 "https://gitlab.com/tsfpga/tsfpga",
103 ]
104 copyright_header_checker = CopyrightHeader(file, "Lukas Vik", copyright_lines)
105 if not copyright_header_checker.check_file():
106 test_ok = False
107 print(
108 f"Fail for {file}\nExpected:\n{copyright_header_checker.expected_copyright_header}"
109 )
110 assert test_ok
113def test_check_file(tmp_path):
114 header = "-- " + "-" * 97 + "\n"
115 header += "-- Copyright (c) Apa. All rights reserved.\n"
116 header += "-- " + "-" * 97 + "\n"
118 file = create_file(tmp_path / "header.vhd", header)
119 copyright_header = CopyrightHeader(file, "Apa")
120 assert copyright_header.check_file()
122 file = create_file(tmp_path / "non_comment.vhd", header + "non-comment on line after")
123 copyright_header = CopyrightHeader(file, "Apa")
124 assert not copyright_header.check_file()
126 file = create_file(tmp_path / "empty_line.vhd", header + "\nEmpty line and then non-comment")
127 copyright_header = CopyrightHeader(file, "Apa")
128 assert copyright_header.check_file()
130 file = create_file(tmp_path / "further_comment.vhd", header + "-- Further comment\n")
131 copyright_header = CopyrightHeader(file, "Apa")
132 assert copyright_header.check_file()
135def test_check_file_with_copyright_text(tmp_path):
136 header = "-- " + "-" * 97 + "\n"
137 header += "-- Copyright (c) Apa. All rights reserved.\n"
138 header += "--\n"
139 header += "-- Some more\n"
140 header += "-- text.\n"
141 header += "-- " + "-" * 97 + "\n"
143 file = create_file(tmp_path / "header.vhd", header)
144 copyright_header = CopyrightHeader(file, "Apa", ["Some more", "text."])
145 assert copyright_header.check_file()
148def test_fix_file_comment_insertion(tmp_path):
149 data = "Apa\n"
150 file = create_file(tmp_path / "file_for_test.vhd", data)
152 copyright_header = CopyrightHeader(file, "Hest Hestsson")
153 copyright_header.fix_file()
155 data = read_file(file).split("\n")
156 assert data[0] == "-- " + "-" * 97
157 assert data[1] == "-- Copyright (c) Hest Hestsson. All rights reserved."
158 assert data[2] == "-- " + "-" * 97
159 assert data[3] == ""
160 assert data[4] == "Apa"
163def test_fix_file_should_not_run_on_dirty_file(tmp_path):
164 data = "-- Custom comment line\n\nApa\n"
165 file = create_file(tmp_path / "file_for_test.vhd", data)
166 copyright_header = CopyrightHeader(file, "A")
168 with pytest.raises(ValueError) as exception_info:
169 copyright_header.fix_file()
170 assert str(exception_info.value) == f"Can not fix copyright header in file {file}"