summaryrefslogtreecommitdiffstats
path: root/tests/test_records.py
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-29 04:21:11 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-29 04:21:11 +0000
commitcdb4a4e19b096cdbf1356e28287238122fc3599c (patch)
treec5ed3b2b40e4725bbaaae0710d1cbec21b23f3b0 /tests/test_records.py
parentInitial commit. (diff)
downloadpython-installer-cdb4a4e19b096cdbf1356e28287238122fc3599c.tar.xz
python-installer-cdb4a4e19b096cdbf1356e28287238122fc3599c.zip
Adding upstream version 0.6.0+dfsg1.upstream/0.6.0+dfsg1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/test_records.py')
-rw-r--r--tests/test_records.py275
1 files changed, 275 insertions, 0 deletions
diff --git a/tests/test_records.py b/tests/test_records.py
new file mode 100644
index 0000000..45427ae
--- /dev/null
+++ b/tests/test_records.py
@@ -0,0 +1,275 @@
+import pytest
+
+from installer.records import Hash, InvalidRecordEntry, RecordEntry, parse_record_file
+
+
+#
+# pytest fixture witchcraft
+#
+@pytest.fixture()
+def record_simple_list():
+ return [
+ "file.py,sha256=AVTFPZpEKzuHr7OvQZmhaU3LvwKz06AJw8mT\\_pNh2yI,3144",
+ "distribution-1.0.dist-info/RECORD,,",
+ ]
+
+
+@pytest.fixture()
+def record_simple_iter(record_simple_list):
+ return iter(record_simple_list)
+
+
+@pytest.fixture()
+def record_simple_file(tmpdir, record_simple_list):
+ p = tmpdir.join("RECORD")
+ p.write("\n".join(record_simple_list))
+ with open(str(p)) as f:
+ yield f
+
+
+@pytest.fixture()
+def record_input(request):
+ return request.getfixturevalue(request.param)
+
+
+SAMPLE_RECORDS = [
+ (
+ "purelib",
+ ("test1.py", "sha256=Y0sCextp4SQtQNU-MSs7SsdxD1W-gfKJtUlEbvZ3i-4", 6),
+ b"test1\n",
+ True,
+ ),
+ (
+ "purelib",
+ ("test2.py", "sha256=fW_Xd08Nh2JNptzxbQ09EEwxkedx--LznIau1LK_Gg8", 6),
+ b"test2\n",
+ True,
+ ),
+ (
+ "purelib",
+ ("test3.py", "sha256=qwPDTx7OCCEf4qgDn9ZCQZmz9de1X_E7ETSzZHdsRcU", 6),
+ b"test3\n",
+ True,
+ ),
+ (
+ "purelib",
+ ("test4.py", "sha256=Y0sCextp4SQtQNU-MSs7SsdxD1W-gfKJtUlEbvZ3i-4", 7),
+ b"test1\n",
+ False,
+ ),
+ (
+ "purelib",
+ (
+ "test5.py",
+ "sha256=Y0sCextp4SQtQNU-MSs7SsdxD1W-gfKJtUlEbvZ3i-4",
+ None,
+ ),
+ b"test1\n",
+ True,
+ ),
+ ("purelib", ("test6.py", None, None), b"test1\n", True),
+]
+
+
+#
+# Actual Tests
+#
+class TestRecordEntry:
+ @pytest.mark.parametrize(
+ "path, hash_, size, caused_by",
+ [
+ ("", "", "", ["path"]),
+ ("", "", "non-int", ["path", "size"]),
+ ("a.py", "", "non-int", ["size"]),
+ # Notice that we're explicitly allowing non-compliant hash values
+ ("a.py", "some-random-value", "non-int", ["size"]),
+ ],
+ )
+ def test_invalid_elements(self, path, hash_, size, caused_by):
+ with pytest.raises(InvalidRecordEntry) as exc_info:
+ RecordEntry.from_elements(path, hash_, size)
+
+ assert exc_info.value.elements == (path, hash_, size)
+ for word in caused_by:
+ assert word in str(exc_info.value)
+
+ @pytest.mark.parametrize(
+ "path, hash_, size",
+ [
+ ("a.py", "", ""),
+ ("a.py", "", "3144"),
+ ("a.py", "sha256=AVTFPZpEKzuHr7OvQZmhaU3LvwKz06AJw8mT\\_pNh2yI", ""),
+ ("a.py", "sha256=AVTFPZpEKzuHr7OvQZmhaU3LvwKz06AJw8mT\\_pNh2yI", "3144"),
+ ],
+ )
+ def test_valid_elements(self, path, hash_, size):
+ RecordEntry.from_elements(path, hash_, size)
+
+ @pytest.mark.parametrize(
+ ("scheme", "elements", "data", "passes_validation"), SAMPLE_RECORDS
+ )
+ def test_populates_attributes_correctly(
+ self, scheme, elements, data, passes_validation
+ ):
+ path, hash_string, size = elements
+
+ record = RecordEntry.from_elements(path, hash_string, size)
+
+ assert record.path == path
+ assert record.size == size
+
+ if record.hash_ is not None:
+ assert isinstance(record.hash_, Hash)
+ assert record.hash_.name == "sha256"
+ assert record.hash_.value == hash_string[len("sha256=") :]
+
+ @pytest.mark.parametrize(
+ ("scheme", "elements", "data", "passes_validation"), SAMPLE_RECORDS
+ )
+ def test_validation(self, scheme, elements, data, passes_validation):
+ record = RecordEntry.from_elements(*elements)
+ assert record.validate(data) == passes_validation
+
+ @pytest.mark.parametrize(
+ ("scheme", "elements", "data", "passes_validation"), SAMPLE_RECORDS
+ )
+ def test_string_representation(self, scheme, elements, data, passes_validation):
+ record = RecordEntry.from_elements(*elements)
+
+ expected_row = tuple(
+ [(str(elem) if elem is not None else "") for elem in elements]
+ )
+ assert record.to_row() == expected_row
+
+ @pytest.mark.parametrize(
+ ("scheme", "elements", "data", "passes_validation"), SAMPLE_RECORDS
+ )
+ def test_string_representation_with_prefix(
+ self, scheme, elements, data, passes_validation
+ ):
+ record = RecordEntry.from_elements(*elements)
+
+ expected_row = tuple(
+ [
+ (str(elem) if elem is not None else "")
+ for elem in ("prefix/" + elements[0], elements[1], elements[2])
+ ]
+ )
+ assert record.to_row("prefix/") == expected_row
+
+ def test_equality(self):
+ record = RecordEntry.from_elements(
+ "file.py",
+ "sha256=AVTFPZpEKzuHr7OvQZmhaU3LvwKz06AJw8mT\\_pNh2yI",
+ "3144",
+ )
+ record_same = RecordEntry.from_elements(
+ "file.py",
+ "sha256=AVTFPZpEKzuHr7OvQZmhaU3LvwKz06AJw8mT\\_pNh2yI",
+ "3144",
+ )
+ record_different_name = RecordEntry.from_elements(
+ "file2.py",
+ "sha256=AVTFPZpEKzuHr7OvQZmhaU3LvwKz06AJw8mT\\_pNh2yI",
+ "3144",
+ )
+ record_different_hash_name = RecordEntry.from_elements(
+ "file.py",
+ "md5=AVTFPZpEKzuHr7OvQZmhaU3LvwKz06AJw8mT\\_pNh2yI",
+ "3144",
+ )
+ record_different_hash_value = RecordEntry.from_elements(
+ "file.py",
+ "sha256=qwertyuiodfdsflkgshdlkjghrefawrwerwffsdfflk29",
+ "3144",
+ )
+ record_different_size = RecordEntry.from_elements(
+ "file.py",
+ "sha256=AVTFPZpEKzuHr7OvQZmhaU3LvwKz06AJw8mT\\_pNh2yI",
+ "10",
+ )
+
+ assert record == record_same
+
+ assert record != "random string"
+ assert record != record_different_name
+ assert record != record_different_hash_name
+ assert record != record_different_hash_value
+ assert record != record_different_size
+
+ # Ensure equality is based on current state
+ record_same.hash_ = None
+ assert record != record_same
+
+
+class TestParseRecordFile:
+ def test_accepts_empty_iterable(self):
+ list(parse_record_file([]))
+
+ @pytest.mark.parametrize(
+ "record_input",
+ ["record_simple_list", "record_simple_iter", "record_simple_file"],
+ indirect=True,
+ )
+ def test_accepts_all_kinds_of_iterables(self, record_input):
+ """Should accepts any iterable, e.g. container, iterator, or file object."""
+ records = list(parse_record_file(record_input))
+ assert len(records) == 2
+
+ assert records == [
+ (
+ "file.py",
+ "sha256=AVTFPZpEKzuHr7OvQZmhaU3LvwKz06AJw8mT\\_pNh2yI",
+ "3144",
+ ),
+ ("distribution-1.0.dist-info/RECORD", "", ""),
+ ]
+
+ @pytest.mark.parametrize(
+ "line, element_count",
+ [
+ pytest.param(
+ "file.py,sha256=AVTFPZpEKzuHr7OvQZmhaU3LvwKz06AJw8mT\\_pNh2yI,3144,",
+ 4,
+ id="four",
+ ),
+ pytest.param(
+ "distribution-1.0.dist-info/RECORD,,,,",
+ 5,
+ id="five",
+ ),
+ ],
+ )
+ def test_rejects_wrong_element_count(self, line, element_count):
+ with pytest.raises(InvalidRecordEntry) as exc_info:
+ list(parse_record_file([line]))
+
+ message = f"expected 3 elements, got {element_count}"
+ assert message in str(exc_info.value)
+
+ def test_shows_correct_row_number(self):
+ record_lines = [
+ "file1.py,sha256=AVTFPZpEKzuHr7OvQZmhaU3LvwKz06AJw8mT\\_pNh2yI,3144",
+ "file2.py,sha256=AVTFPZpEKzuHr7OvQZmhaU3LvwKz06AJw8mT\\_pNh2yI,3144",
+ "file3.py,sha256=AVTFPZpEKzuHr7OvQZmhaU3LvwKz06AJw8mT\\_pNh2yI,3144",
+ "distribution-1.0.dist-info/RECORD,,,,",
+ ]
+ with pytest.raises(InvalidRecordEntry) as exc_info:
+ list(parse_record_file(record_lines))
+
+ assert "Row Index 3" in str(exc_info.value)
+
+ def test_parse_record_entry_with_comma(self):
+ record_lines = [
+ '"file1,file2.txt",sha256=AVTFPZpEKzuHr7OvQZmhaU3LvwKz06AJw8mT\\_pNh2yI,3144',
+ "distribution-1.0.dist-info/RECORD,,",
+ ]
+ records = list(parse_record_file(record_lines))
+ assert records == [
+ (
+ "file1,file2.txt",
+ "sha256=AVTFPZpEKzuHr7OvQZmhaU3LvwKz06AJw8mT\\_pNh2yI",
+ "3144",
+ ),
+ ("distribution-1.0.dist-info/RECORD", "", ""),
+ ]