Coverage for tsfpga/test/test_system_utils.py: 97%
114 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-08-29 20:51 +0000
« prev ^ index » next coverage.py v7.10.6, created at 2025-08-29 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# --------------------------------------------------------------------------------------------------
9import subprocess
10from pathlib import Path
12import pytest
14from tsfpga.system_utils import (
15 create_directory,
16 create_file,
17 delete,
18 file_is_in_directory,
19 path_relative_to,
20 prepend_file,
21 read_file,
22 read_last_lines_of_file,
23 run_command,
24 system_is_windows,
25)
28def test_delete_files_and_folders(tmp_path):
29 # Test deleting a file, with and without wait
30 path = create_file(tmp_path / "temp.txt")
31 assert path.exists()
32 delete(path)
33 assert not path.exists()
35 path = create_file(tmp_path / "temp.txt")
36 assert path.exists()
37 delete(path, wait_until_deleted=True)
38 assert not path.exists()
40 # Test deleting a directory, with and without wait
41 path = create_directory(tmp_path / "temp_dir")
42 assert path.exists()
43 delete(path)
44 assert not path.exists()
46 path = create_directory(tmp_path / "temp_dir")
47 assert path.exists()
48 delete(path, wait_until_deleted=True)
49 assert not path.exists()
52def test_create_directory_plain(tmp_path):
53 path = tmp_path / "temp_dir"
54 assert not path.exists()
56 create_directory(path)
57 assert path.exists()
58 assert path.is_dir()
61def test_create_directory_that_exists_without_empty(tmp_path):
62 path = tmp_path / "temp_dir"
63 sub_path = create_directory(path / "sub")
65 create_directory(path, empty=False)
66 assert sub_path.exists()
69def test_create_directory_that_exists_with_empty(tmp_path):
70 path = tmp_path / "temp_dir"
71 sub_path = create_directory(path / "sub")
73 create_directory(path)
74 assert path.exists()
75 assert not sub_path.exists()
78def test_create_directory_without_empty_when_path_is_a_file(tmp_path):
79 path = create_file(tmp_path / "file.txt", contents="data")
81 with pytest.raises(FileExistsError) as exception_info:
82 create_directory(path, empty=False)
83 assert str(exception_info.value) == f"Requested directory path already exists as a file: {path}"
85 assert read_file(path) == "data"
88def test_file_is_in_directory(tmp_path):
89 assert file_is_in_directory(tmp_path / "file.txt", [tmp_path])
90 assert not file_is_in_directory(tmp_path / "file.txt", [tmp_path / "sub"])
92 assert file_is_in_directory(
93 tmp_path / "sub" / "file.txt", [tmp_path / "sub", tmp_path / "sub2"]
94 )
95 assert not file_is_in_directory(tmp_path / "file.txt", [tmp_path / "sub", tmp_path / "sub2"])
96 assert not file_is_in_directory(
97 tmp_path / "sub" / "file.txt", [tmp_path / "sub2", tmp_path / "sub3"]
98 )
101def test_path_relative_to():
102 this_file = Path(__file__)
103 this_dir = this_file.parent
104 parent = this_dir.parent
106 assert path_relative_to(this_file, this_dir) == Path(this_file.name)
107 assert path_relative_to(this_file, parent) == Path(this_dir.name) / this_file.name
108 assert (
109 path_relative_to(this_file, parent / "whatever")
110 == Path("..") / this_dir.name / this_file.name
111 )
114@pytest.mark.skipif(not system_is_windows(), reason="Path manipulation is different on Windows")
115def test_path_relative_to_on_different_windows_drive():
116 path = Path("C:/apa/hest.vhd")
117 other = Path("D:/zebra")
119 assert path_relative_to(path, other) == path
122def test_path_relative_to_on_different_linux_mount():
123 path = Path("/home/apa/hest.vhd")
124 other = Path("/mnt/zebra")
126 assert path_relative_to(path, other) == Path("../../home/apa/hest.vhd")
129def test_read_last_lines_of_file_with_short_file(tmp_path):
130 # A file that is smaller than the buffer size
131 data = "a\nb\nc"
132 file = create_file(tmp_path / "data.txt", contents=data)
133 assert read_last_lines_of_file(file, num_lines=10) == data
136def test_read_last_lines_of_file_with_long_file(tmp_path):
137 # A file that is larger than the buffer size
138 data_trash = (("a" * 700) + "\n") * 3000
139 data_last_lines = (("b" * 700) + "\n") * 10
140 file = create_file(tmp_path / "data.txt", contents=data_trash + data_last_lines)
141 assert read_last_lines_of_file(file, num_lines=10) == data_last_lines
144def test_read_last_lines_of_file_with_trailing_newlines(tmp_path):
145 # A file that is smaller than the buffer size
146 data = "a\nb\n\n \n\n"
147 file = create_file(tmp_path / "data.txt", contents=data)
148 assert read_last_lines_of_file(file, num_lines=10) == data
151def test_read_last_lines_of_file_with_empty_file(tmp_path):
152 data = ""
153 file = create_file(tmp_path / "data.txt", contents=data)
154 assert read_last_lines_of_file(file, num_lines=10) == data
156 data = "\n"
157 file = create_file(tmp_path / "data.txt", contents=data)
158 assert read_last_lines_of_file(file, num_lines=10) == data
161def test_prepend_file(tmp_path):
162 assert (
163 read_file(
164 prepend_file(
165 file_path=create_file(tmp_path / "data.txt", contents="data"), text="hello\nmy_"
166 )
167 )
168 == "hello\nmy_data"
169 )
172def test_prepend_file_with_empty_file(tmp_path):
173 assert read_file(prepend_file(file_path=create_file(tmp_path / "data.txt"), text="a")) == "a"
176def test_run_command_called_with_nonexisting_binary_should_raise_exception():
177 cmd = ["/apa/hest/zebra.exe", "foobar"]
178 with pytest.raises(FileNotFoundError):
179 run_command(cmd)
182def test_run_command_with_non_zero_return_code_should_raise_exception():
183 cmd = ["ls", "/apa/hest/zebra"]
184 with pytest.raises(subprocess.CalledProcessError):
185 run_command(cmd)
188def test_run_command_called_with_non_list_should_raise_exception():
189 cmd = ["ls", "-la"]
190 run_command(cmd)
192 cmd = "ls -la"
193 with pytest.raises(TypeError) as exception_info:
194 run_command(cmd)
195 assert str(exception_info.value).startswith("Must be called with a list")
198def test_run_command_should_capture_output_as_strings():
199 this_dir = Path(__file__).parent.resolve()
201 cmd = ["ls", str(this_dir)]
202 result = run_command(cmd, capture_output=True)
204 assert isinstance(result.stdout, str)
205 assert isinstance(result.stderr, str)
207 assert result.stderr == ""
209 # Show that it is regular text with regular newlines.
210 assert "\ntest_system_utils.py\n" in result.stdout
211 assert "\ntest_ip_core_file.py\n" in result.stdout