diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-29 04:21:11 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-29 04:21:11 +0000 |
commit | cdb4a4e19b096cdbf1356e28287238122fc3599c (patch) | |
tree | c5ed3b2b40e4725bbaaae0710d1cbec21b23f3b0 /tests/test_records.py | |
parent | Initial commit. (diff) | |
download | python-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.py | 275 |
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", "", ""), + ] |