diff options
Diffstat (limited to 'test_pyproject_save_files.py')
-rwxr-xr-x | test_pyproject_save_files.py | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/test_pyproject_save_files.py b/test_pyproject_save_files.py new file mode 100755 index 0000000..5dd0b27 --- /dev/null +++ b/test_pyproject_save_files.py @@ -0,0 +1,263 @@ +import pytest +import yaml + +from pathlib import Path +from pprint import pprint + +from pyproject_preprocess_record import parse_record, read_record, save_parsed_record + +from pyproject_save_files import argparser, generate_file_list, BuildrootPath +from pyproject_save_files import main as save_files_main +from pyproject_save_files import module_names_from_path + +DIR = Path(__file__).parent +PREFIX = Path("/usr") +BINDIR = BuildrootPath("/usr/bin") +DATADIR = BuildrootPath("/usr/share") +SITELIB = BuildrootPath("/usr/lib/python3.7/site-packages") +SITEARCH = BuildrootPath("/usr/lib64/python3.7/site-packages") + +yaml_file = DIR / "pyproject_save_files_test_data.yaml" +yaml_data = yaml.safe_load(yaml_file.read_text()) +EXPECTED_DICT = yaml_data["classified"] +EXPECTED_FILES = yaml_data["dumped"] +TEST_RECORDS = yaml_data["records"] +TEST_METADATAS = yaml_data["metadata"] + + +@pytest.fixture +def tldr_root(tmp_path): + prepare_pyproject_record(tmp_path, package="tldr") + return tmp_path + + +@pytest.fixture +def pyproject_record(tmp_path): + return tmp_path / "pyproject-record" + + +def prepare_pyproject_record(tmp_path, package=None, content=None): + """ + Creates RECORD from test data and then uses + functions from pyproject_process_record to convert + it to pyproject-record file which is then + further processed by functions from pyproject_save_files. + """ + record_file = tmp_path / "RECORD" + pyproject_record = tmp_path / "pyproject-record" + + if package is not None: + # Get test data and write dist-info/RECORD file + record_path = BuildrootPath(TEST_RECORDS[package]["path"]) + record_file.write_text(TEST_RECORDS[package]["content"]) + if package in TEST_METADATAS: + metadata_path = BuildrootPath(TEST_METADATAS[package]["path"]).to_real(tmp_path) + metadata_path.parent.mkdir(parents=True, exist_ok=True) + metadata_path.write_text(TEST_METADATAS[package]["content"]) + # Parse RECORD file + parsed_record = parse_record(record_path, read_record(record_file)) + # Save JSON content to pyproject-record + save_parsed_record(record_path, parsed_record, pyproject_record) + elif content is not None: + save_parsed_record(*content, output_file=pyproject_record) + + +@pytest.fixture +def output_files(tmp_path): + return tmp_path / "pyproject_files" + +@pytest.fixture +def output_modules(tmp_path): + return tmp_path / "pyproject_modules" + + +def test_parse_record_tldr(): + record_path = BuildrootPath(TEST_RECORDS["tldr"]["path"]) + record_content = read_record(DIR / "test_RECORD") + output = list(parse_record(record_path, record_content)) + pprint(output) + expected = [ + str(BINDIR / "__pycache__/tldr.cpython-37.pyc"), + str(BINDIR / "tldr"), + str(BINDIR / "tldr.py"), + str(SITELIB / "__pycache__/tldr.cpython-37.pyc"), + str(SITELIB / "tldr-0.5.dist-info/INSTALLER"), + str(SITELIB / "tldr-0.5.dist-info/LICENSE"), + str(SITELIB / "tldr-0.5.dist-info/METADATA"), + str(SITELIB / "tldr-0.5.dist-info/RECORD"), + str(SITELIB / "tldr-0.5.dist-info/WHEEL"), + str(SITELIB / "tldr-0.5.dist-info/top_level.txt"), + str(SITELIB / "tldr.py"), + ] + assert output == expected + + +def test_parse_record_tensorflow(): + long = "tensorflow_core/include/tensorflow/core/common_runtime/base_collective_executor.h" + record_path = SITEARCH / "tensorflow-2.1.0.dist-info/RECORD" + record_content = [ + ["../../../bin/toco_from_protos", "sha256=hello", "289"], + [f"../../../lib/python3.7/site-packages/{long}", "sha256=darkness", "1024"], + ["tensorflow-2.1.0.dist-info/METADATA", "sha256=friend", "2859"], + ] + output = list(parse_record(record_path, record_content)) + pprint(output) + expected = [ + str(BINDIR / "toco_from_protos"), + str(SITELIB / long), + str(SITEARCH / "tensorflow-2.1.0.dist-info/METADATA"), + ] + assert output == expected + + +def remove_others(expected): + return [ + p for p in expected + if not ( + p.startswith(str(BINDIR)) or + p.endswith(".pth") or + p.endswith("*") or + p.rpartition(' ')[-1].startswith(str(DATADIR)) + ) + ] + + +@pytest.mark.parametrize("include_auto", (True, False)) +@pytest.mark.parametrize("package, glob, expected_files, expected_modules", EXPECTED_FILES) +def test_generate_file_list(package, glob, expected_files, include_auto, expected_modules): + paths_dict = EXPECTED_DICT[package] + modules_glob = {glob} + if not include_auto: + expected_files = remove_others(expected_files) + tested = generate_file_list(paths_dict, modules_glob, include_auto) + + assert tested == expected_files + + +def test_generate_file_list_unused_glob(): + paths_dict = EXPECTED_DICT["kerberos"] + modules_glob = {"kerberos", "unused_glob1", "unused_glob2", "kerb*"} + with pytest.raises(ValueError) as excinfo: + generate_file_list(paths_dict, modules_glob, True) + + assert "unused_glob1, unused_glob2" in str(excinfo.value) + assert "kerb" not in str(excinfo.value) + + +@pytest.mark.parametrize( + "path, expected", + [ + ("foo/bar/baz.py", {"foo", "foo.bar", "foo.bar.baz"}), + ("foo/bar.py", {"foo", "foo.bar"}), + ("foo.py", {"foo"}), + ("foo/bar.so.2", set()), + ("foo.cpython-37m-x86_64-linux-gnu.so", {"foo"}), + ("foo/_api/v2/__init__.py", set()), + ("foo/__init__.py", {"foo"}), + ("foo/_priv.py", set()), + ("foo/_bar/lib.so", set()), + ("foo/bar/baz.so", {"foo", "foo.bar", "foo.bar.baz"}), + ("foo/bar/baz.pth", set()), + ("foo/bar/baz.pyc", set()), + ("def.py", set()), + ("foo-bar/baz.py", set()), + ("foobar/12baz.py", set()), + ("foo/\nbar/baz.py", set()), + ("foo/+bar/baz.py", set()), + ("foo/__init__.cpython-39-x86_64-linux-gnu.so", {"foo"}), + ("foo/bar/__pycache__/abc.cpython-37.pyc", set()), + ], +) +def test_module_names_from_path(path, expected): + tested = Path(path) + assert module_names_from_path(tested) == expected + + +def default_options(output_files, output_modules, mock_root, pyproject_record): + return [ + "--output-files", + str(output_files), + "--output-modules", + str(output_modules), + "--buildroot", + str(mock_root), + "--sitelib", + str(SITELIB), + "--sitearch", + str(SITEARCH), + "--python-version", + "3.7", # test data are for 3.7, + "--pyproject-record", + str(pyproject_record), + "--prefix", + str(PREFIX), + ] + + +@pytest.mark.parametrize("include_auto", (True, False)) +@pytest.mark.parametrize("package, glob, expected_files, expected_modules", EXPECTED_FILES) +def test_cli(tmp_path, package, glob, expected_files, expected_modules, include_auto, pyproject_record): + prepare_pyproject_record(tmp_path, package) + output_files = tmp_path / "files" + output_modules = tmp_path / "modules" + globs = [glob, "+auto"] if include_auto else [glob] + cli_args = argparser().parse_args([*default_options(output_files, output_modules, tmp_path, pyproject_record), *globs]) + save_files_main(cli_args) + + if not include_auto: + expected_files = remove_others(expected_files) + tested_files = output_files.read_text() + assert tested_files == "\n".join(expected_files) + "\n" + + tested_modules = output_modules.read_text().split() + + assert tested_modules == expected_modules + + +def test_cli_no_pyproject_record(tmp_path, pyproject_record): + output_files = tmp_path / "files" + output_modules = tmp_path / "modules" + cli_args = argparser().parse_args([*default_options(output_files, output_modules, tmp_path, pyproject_record), "tldr*"]) + + with pytest.raises(FileNotFoundError): + save_files_main(cli_args) + + +def test_cli_too_many_RECORDS(tldr_root, output_files, output_modules, pyproject_record): + # Two calls to simulate how %pyproject_install process more than one RECORD file + prepare_pyproject_record(tldr_root, + content=("foo/bar/dist-info/RECORD", [])) + prepare_pyproject_record(tldr_root, + content=("foo/baz/dist-info/RECORD", [])) + cli_args = argparser().parse_args([*default_options(output_files, output_modules, tldr_root, pyproject_record), "tldr*"]) + + with pytest.raises(FileExistsError): + save_files_main(cli_args) + + +def test_cli_bad_argument(tldr_root, output_files, output_modules, pyproject_record): + cli_args = argparser().parse_args( + [*default_options(output_files, output_modules, tldr_root, pyproject_record), "tldr*", "+foodir"] + ) + + with pytest.raises(ValueError): + save_files_main(cli_args) + + +def test_cli_bad_option(tldr_root, output_files, output_modules, pyproject_record): + prepare_pyproject_record(tldr_root.parent, content=("RECORD1", [])) + cli_args = argparser().parse_args( + [*default_options(output_files, output_modules, tldr_root, pyproject_record), "tldr*", "you_cannot_have_this"] + ) + + with pytest.raises(ValueError): + save_files_main(cli_args) + + +def test_cli_bad_namespace(tldr_root, output_files, output_modules, pyproject_record): + cli_args = argparser().parse_args( + [*default_options(output_files, output_modules, tldr_root, pyproject_record), "tldr.didntread"] + ) + + with pytest.raises(ValueError): + save_files_main(cli_args) |