Skip to content

Commit ed6a036

Browse files
committed
tests: cpatch: added
Add basic patching tests for the `cpatch` module. Signed-off-by: Jordan Yates <jordan@embeint.com>
1 parent eb07f0f commit ed6a036

1 file changed

Lines changed: 79 additions & 0 deletions

File tree

tests/test_cpatch.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#!/usr/bin/env python3
2+
3+
import os
4+
import subprocess
5+
import sys
6+
7+
import pytest
8+
9+
from infuse_iot.cpatch import ValidationError, cpatch
10+
11+
assert "TOXTEMPDIR" in os.environ, "you must run these tests using tox"
12+
13+
14+
def apply_generated_patch(tmp_path, original: bytes, expected: bytes) -> bytes:
15+
original_file = tmp_path / "original.bin"
16+
new_file = tmp_path / "new.bin"
17+
patch_file = tmp_path / "update.cpatch"
18+
output_file = tmp_path / "output.bin"
19+
20+
original_file.write_bytes(original)
21+
new_file.write_bytes(expected)
22+
23+
subprocess.run(
24+
[sys.executable, "-m", "infuse_iot.cpatch", "generate", original_file, new_file, patch_file],
25+
check=True,
26+
stdout=subprocess.DEVNULL,
27+
)
28+
subprocess.run(
29+
[sys.executable, "-m", "infuse_iot.cpatch", "patch", original_file, patch_file, output_file],
30+
check=True,
31+
stdout=subprocess.DEVNULL,
32+
)
33+
34+
return output_file.read_bytes()
35+
36+
37+
@pytest.mark.parametrize(
38+
("original", "expected"),
39+
[
40+
pytest.param(bytes(range(64)), bytes(range(64)), id="unchanged"),
41+
pytest.param(bytes(range(64)), bytes(range(16)) + b"HELLO" + bytes(range(21, 64)), id="rewrite"),
42+
pytest.param(bytes(range(64)), bytes(range(64)) + b"TAIL", id="append"),
43+
pytest.param(bytes(range(64)), bytes(range(16)) + bytes(range(24, 64)), id="delete"),
44+
pytest.param(b"abcdefgh" * 8 + b"ijklmnop" * 8, b"ijklmnop" * 8 + b"abcdefgh" * 8, id="reuse"),
45+
],
46+
)
47+
def test_cli_generates_patch_that_reconstructs_expected_output(tmp_path, original, expected):
48+
assert apply_generated_patch(tmp_path, original, expected) == expected
49+
50+
51+
def test_patch_rejects_wrong_original_contents():
52+
original = bytes(range(64))
53+
expected = bytes(range(16)) + b"HELLO" + bytes(range(21, 64))
54+
patch = cpatch.generate(original, expected, verbose=False)
55+
56+
with pytest.raises(ValidationError, match="Original file CRC"):
57+
cpatch.patch(bytes(reversed(original)), patch)
58+
59+
60+
def test_validation_patch_reconstructs_original():
61+
original = bytes(range(256)) * 5
62+
patch = cpatch.validation(original, invalid_length=False, invalid_crc=False)
63+
64+
assert cpatch.patch(original, patch) == original
65+
66+
67+
@pytest.mark.parametrize(
68+
("invalid_length", "invalid_crc", "message"),
69+
[
70+
pytest.param(True, False, "length does not match", id="invalid-length"),
71+
pytest.param(False, True, "CRC does not match", id="invalid-crc"),
72+
],
73+
)
74+
def test_validation_patch_can_generate_invalid_output_metadata(invalid_length, invalid_crc, message):
75+
original = bytes(range(256)) * 5
76+
patch = cpatch.validation(original, invalid_length=invalid_length, invalid_crc=invalid_crc)
77+
78+
with pytest.raises(ValidationError, match=message):
79+
cpatch.patch(original, patch)

0 commit comments

Comments
 (0)