blob: d79773b07c676560df1d6f4828f2184bccf33adf [file] [log] [blame]
Harrison Mutai19dc4f92024-05-10 16:54:29 +00001#!/usr/bin/env python3
2# type: ignore[attr-defined]
3
4#
5# Copyright (c) 2024, Arm Limited. All rights reserved.
6#
7# SPDX-License-Identifier: BSD-3-Clause
8#
9
10"""Contains unit tests for the CLI functionality."""
11
12from pathlib import Path
13from unittest import mock
14
15import pytest
16from click.testing import CliRunner
17
18from tlc.cli import cli
19from tlc.te import TransferEntry
20from tlc.tl import TransferList
21
22
23def test_create_empty_tl(tmpdir):
24 runner = CliRunner()
25 test_file = tmpdir.join("tl.bin")
26
27 result = runner.invoke(cli, ["create", test_file.strpath])
28 assert result.exit_code == 0
29 assert TransferList.fromfile(test_file) is not None
30
31
32def test_create_with_fdt(tmpdir):
33 runner = CliRunner()
34 fdt = tmpdir.join("fdt.dtb")
35 fdt.write_binary(b"\x00" * 100)
36
37 result = runner.invoke(
38 cli,
39 [
40 "create",
41 "--fdt",
42 fdt.strpath,
43 "--size",
44 "1000",
45 tmpdir.join("tl.bin").strpath,
46 ],
47 )
48 assert result.exit_code == 0
49
50
51def test_add_single_entry(tlcrunner, tmptlstr):
52 tlcrunner.invoke(cli, ["add", "--entry", "0", "/dev/null", tmptlstr])
53
54 tl = TransferList.fromfile(tmptlstr)
55 assert tl is not None
56 assert len(tl.entries) == 1
57 assert tl.entries[0].id == 0
58
59
60def test_add_multiple_entries(tlcrunner, tlc_entries, tmptlstr):
61 for id, path in tlc_entries:
62 tlcrunner.invoke(cli, ["add", "--entry", id, path, tmptlstr])
63
64 tl = TransferList.fromfile(tmptlstr)
65 assert tl is not None
66 assert len(tl.entries) == len(tlc_entries)
67
68
69def test_info(tlcrunner, tmptlstr, tmpfdt):
70 tlcrunner.invoke(cli, ["add", "--entry", "0", "/dev/null", tmptlstr])
71 tlcrunner.invoke(cli, ["add", "--fdt", tmpfdt.strpath, tmptlstr])
72
73 result = tlcrunner.invoke(cli, ["info", tmptlstr])
74 assert result.exit_code == 0
75 assert "signature" in result.stdout
76 assert "id" in result.stdout
77
78 result = tlcrunner.invoke(cli, ["info", "--header", tmptlstr])
79 assert result.exit_code == 0
80 assert "signature" in result.stdout
81 assert "id" not in result.stdout
82
83 result = tlcrunner.invoke(cli, ["info", "--entries", tmptlstr])
84 assert result.exit_code == 0
85 assert "signature" not in result.stdout
86 assert "id" in result.stdout
87
88
89def test_raises_max_size_error(tmptlstr, tmpfdt):
90 tmpfdt.write_binary(bytes(6000))
91
92 runner = CliRunner()
93 result = runner.invoke(cli, ["create", "--fdt", tmpfdt, tmptlstr])
94
95 assert result.exception
96 assert isinstance(result.exception, MemoryError)
97 assert "TL max size exceeded, consider increasing with the option -s" in str(
98 result.exception
99 )
100 assert "TL size has exceeded the maximum allocation" in str(
101 result.exception.__cause__
102 )
103
104
105def test_info_get_fdt_offset(tmptlstr, tmpfdt):
106 runner = CliRunner()
107 with runner.isolated_filesystem():
108 runner.invoke(cli, ["create", "--size", "1000", tmptlstr])
109 runner.invoke(cli, ["add", "--entry", "1", tmpfdt.strpath, tmptlstr])
110 result = runner.invoke(cli, ["info", "--fdt-offset", tmptlstr])
111
112 assert result.exit_code == 0
113 assert result.output.strip("\n").isdigit()
114
115
116def test_remove_tag(tlcrunner, tmptlstr):
117 tlcrunner.invoke(cli, ["add", "--entry", "0", "/dev/null", tmptlstr])
118 result = tlcrunner.invoke(cli, ["info", tmptlstr])
119
120 assert result.exit_code == 0
121 assert "signature" in result.stdout
122
123 tlcrunner.invoke(cli, ["remove", "--tags", "0", tmptlstr])
124 tl = TransferList.fromfile(tmptlstr)
125
126 assert result.exit_code == 0
127 assert len(tl.entries) == 0
128
129
130def test_unpack_tl(tlcrunner, tmptlstr, tmpfdt, tmpdir):
131 with tlcrunner.isolated_filesystem(temp_dir=tmpdir):
132 tlcrunner.invoke(cli, ["add", "--entry", 1, tmpfdt.strpath, tmptlstr])
133 tlcrunner.invoke(cli, ["unpack", tmptlstr])
134 assert Path("te_0_1.bin").exists()
135
136
137def test_unpack_multiple_tes(tlcrunner, tlc_entries, tmptlstr, tmpdir):
138 with tlcrunner.isolated_filesystem(temp_dir=tmpdir):
139 for id, path in tlc_entries:
140 tlcrunner.invoke(cli, ["add", "--entry", id, path, tmptlstr])
141
142 assert all(
143 filter(
144 lambda te: (Path(tmpdir.strpath) / f"te_{te[0]}.bin").exists(), tlc_entries
145 )
146 )
147
148
149def test_unpack_into_dir(tlcrunner, tmpdir, tmptlstr, tmpfdt):
150 tlcrunner.invoke(cli, ["add", "--entry", 1, tmpfdt.strpath, tmptlstr])
151 tlcrunner.invoke(cli, ["unpack", "-C", tmpdir.strpath, tmptlstr])
152
153 assert (Path(tmpdir.strpath) / "te_0_1.bin").exists()
154
155
156def test_unpack_into_dir_with_conflicting_tags(tlcrunner, tmpdir, tmptlstr, tmpfdt):
157 tlcrunner.invoke(cli, ["add", "--entry", 1, tmpfdt.strpath, tmptlstr])
158 tlcrunner.invoke(cli, ["add", "--entry", 1, tmpfdt.strpath, tmptlstr])
159 tlcrunner.invoke(cli, ["unpack", "-C", tmpdir.strpath, tmptlstr])
160
161 assert (Path(tmpdir.strpath) / "te_0_1.bin").exists()
162 assert (Path(tmpdir.strpath) / "te_1_1.bin").exists()
163
164
165def test_validate_invalid_signature(tmptlstr, tlcrunner, monkeypatch):
166 tl = TransferList()
167 tl.signature = 0xDEADBEEF
168
169 mock_open = lambda tmptlstr, mode: mock.mock_open(read_data=tl.header_to_bytes())()
170 monkeypatch.setattr("builtins.open", mock_open)
171
172 result = tlcrunner.invoke(cli, ["validate", tmptlstr])
173 assert result.exit_code != 0
174
175
176def test_validate_misaligned_entries(tmptlstr, tlcrunner, monkeypatch):
177 """Base address of a TE must be 8-byte aligned."""
178 mock_open = lambda tmptlstr, mode: mock.mock_open(
179 read_data=TransferList().header_to_bytes()
180 + bytes(5)
181 + TransferEntry(0, 0, bytes(0)).header_to_bytes
182 )()
183 monkeypatch.setattr("builtins.open", mock_open)
184
185 result = tlcrunner.invoke(cli, ["validate", tmptlstr])
186
187 assert result.exit_code == 1
188
189
190@pytest.mark.parametrize(
191 "version", [0, TransferList.version, TransferList.version + 1, 1 << 8]
192)
193def test_validate_unsupported_version(version, tmptlstr, tlcrunner, monkeypatch):
194 tl = TransferList()
195 tl.version = version
196
197 mock_open = lambda tmptlstr, mode: mock.mock_open(read_data=tl.header_to_bytes())()
198 monkeypatch.setattr("builtins.open", mock_open)
199
200 result = tlcrunner.invoke(cli, ["validate", tmptlstr])
201
202 if version >= TransferList.version and version <= 0xFF:
203 assert result.exit_code == 0
204 else:
205 assert result.exit_code == 1