def test_cli_invalid_version(capsys, invalid_version): """Checks that invalid version strings are handled properly""" # Ensure that invalid_version cannot be a semantic_version.Version with pytest.raises(ValueError): Version(invalid_version) cli = Cli() cli._setup_settings() matcher = re.compile(r"^INFO : aqtinstall\(aqt\) v.* on Python 3.*\n" r"(.*\n)*" r"ERROR :.*Invalid version: '" + invalid_version + r"'! Please use the form '5\.X\.Y'\.\n.*") for cmd in ( ("install", invalid_version, "mac", "desktop"), ("doc", invalid_version, "mac", "desktop"), ("list-qt", "mac", "desktop", "--arch", invalid_version), ): cli = Cli() assert cli.run(cmd) == 1 out, err = capsys.readouterr() sys.stdout.write(out) sys.stderr.write(err) assert matcher.match(err)
def test_list_archives(monkeypatch, capsys, version: str, arch: str, modules_to_query: List[str], modules_failed_query: List[str]): archive_id = ArchiveId("qt", "windows", "desktop") in_file = f"{archive_id.host}-{version.replace('.', '')}-update.xml" expect_out_file = f"{archive_id.host}-{version.replace('.', '')}-expect.json" _xml = (Path(__file__).parent / "data" / in_file).read_text("utf-8") monkeypatch.setattr(MetadataFactory, "fetch_http", lambda self, _: _xml) expect = json.loads( (Path(__file__).parent / "data" / expect_out_file).read_text("utf-8")) if not modules_to_query: expected_qt_archives = expect["qt_base_pkgs_by_arch"][arch][ "DownloadableArchives"] expected = set([arc.split("-")[0] for arc in expected_qt_archives]) else: expected_mod_metadata = expect["modules_metadata_by_arch"][arch] if "all" not in modules_to_query: expected_mod_metadata = filter( lambda mod: mod["Name"].split(".")[-2] in modules_to_query, expected_mod_metadata) expected = set([ arc.split("-")[0] for mod in expected_mod_metadata for arc in mod["DownloadableArchives"] ]) archives_query = [version, arch, *modules_to_query] cli_args = ["list-qt", "windows", "desktop", "--archives", *archives_query] if not modules_failed_query: meta = set( MetadataFactory(archive_id, archives_query=archives_query).getList()) assert meta == expected cli = Cli() assert 0 == cli.run(cli_args) out, err = capsys.readouterr() assert out.rstrip() == " ".join(sorted(expected)) return expected_err_msg = f"The requested modules were not located: {sorted(modules_failed_query)}" with pytest.raises(CliInputError) as err: MetadataFactory(archive_id, archives_query=archives_query).getList() assert err.type == CliInputError assert format(err.value).startswith(expected_err_msg) cli = Cli() assert 1 == cli.run(cli_args) out, err = capsys.readouterr() assert expected_err_msg in err
def test_cli_determine_qt_version(monkeypatch, host, target, arch, version_or_spec: str, expected_version: Version, is_bad_spec: bool): _html = (Path(__file__).parent / "data" / f"{host}-{target}.html").read_text("utf-8") monkeypatch.setattr(MetadataFactory, "fetch_http", lambda *args, **kwargs: _html) cli = Cli() cli._setup_settings() if is_bad_spec: with pytest.raises(CliInputError) as e: Cli._determine_qt_version(version_or_spec, host, target, arch) assert e.type == CliInputError assert format( e.value ) == f"Invalid version or SimpleSpec: '{version_or_spec}'\n" + SimpleSpec.usage( ) elif not expected_version: with pytest.raises(CliInputError) as e: Cli._determine_qt_version(version_or_spec, host, target, arch) assert e.type == CliInputError expect_msg = f"No versions of Qt exist for spec={version_or_spec} with host={host}, target={target}, arch={arch}" actual_msg = format(e.value) assert actual_msg == expect_msg else: ver = Cli._determine_qt_version(version_or_spec, host, target, arch) assert ver == expected_version
def test_cli_set_7zip(monkeypatch): cli = Cli() cli._setup_settings() with pytest.raises(CliInputError) as err: cli._set_sevenzip("some_nonexistent_binary") assert err.type == CliInputError assert format(err.value) == "Specified 7zip command executable does not exist: 'some_nonexistent_binary'"
def test_cli_check_module(): cli = Cli() cli._setup_settings() assert cli._check_modules_arg("5.11.3", ["qtcharts", "qtwebengine"]) assert not cli._check_modules_arg("5.7", ["not_exist"]) assert cli._check_modules_arg("5.14.0", None) assert not cli._check_modules_arg("5.15.0", ["Unknown"])
def test_install_nonexistent_archives(monkeypatch, capsys, cmd, xml_file: Optional[str], expected): xml = (Path(__file__).parent / "data" / xml_file).read_text("utf-8") if xml_file else "" def mock_get_url(url, *args, **kwargs): if not xml_file: raise ArchiveDownloadError( f"Failed to retrieve file at {url}\nServer response code: 404, reason: Not Found" ) return xml monkeypatch.setattr("aqt.archives.getUrl", mock_get_url) monkeypatch.setattr( "aqt.archives.get_hash", lambda *args, **kwargs: hashlib.sha256( bytes(xml, "utf-8")).hexdigest()) monkeypatch.setattr( "aqt.metadata.get_hash", lambda *args, **kwargs: hashlib.sha256( bytes(xml, "utf-8")).hexdigest()) monkeypatch.setattr("aqt.metadata.getUrl", mock_get_url) cli = Cli() cli._setup_settings() assert cli.run(cmd.split()) == 1 out, err = capsys.readouterr() actual = err[err.index("\n") + 1:] assert actual == expected, "{0} != {1}".format(actual, expected)
def test_cli_check_mirror(): cli = Cli() cli._setup_settings() assert cli._check_mirror(None) arg = ["install-qt", "linux", "desktop", "5.11.3", "-b", "https://download.qt.io/"] args = cli.parser.parse_args(arg) assert args.base == "https://download.qt.io/" assert cli._check_mirror(args.base)
def test_list_wrong_target(capsys, cmd: str, host: str, target: str): expect = f"ERROR : '{target}' is not a valid target for host '{host}'" cli = Cli() return_code = cli.run([cmd, host, target]) out, err = capsys.readouterr() assert return_code == 1 assert err.strip() == expect
def test_invalid_spec(capsys, cmd: str, spec: str): expect_prefix = f"ERROR : Invalid version specification: '{spec}'" host, target = "linux", "desktop" cli = Cli() return_code = cli.run([cmd, host, target, "--spec", spec]) out, err = capsys.readouterr() assert return_code == 1 assert err.strip().startswith(expect_prefix)
def test_cli_legacy_commands_with_correct_syntax(monkeypatch, cmd): # Pretend to install correctly when any command is run for func in ("run_install_qt", "run_install_src", "run_install_doc", "run_install_example", "run_install_tool"): monkeypatch.setattr(Cli, func, lambda *args, **kwargs: 0) cli = Cli() cli._setup_settings() assert 0 == cli.run(cmd.split())
def test_cli_check_combination(): cli = Cli() cli._setup_settings() assert cli._check_qt_arg_combination("5.11.3", "linux", "desktop", "gcc_64") assert cli._check_qt_arg_combination("5.11.3", "mac", "desktop", "clang_64") assert not cli._check_qt_arg_combination("5.14.0", "android", "desktop", "clang_64")
def test_list_invalid_extensions(capsys, monkeypatch, target, ext, version, expected_msg): host = "windows" extension_params = ["--extension", ext] if ext else [] cli = Cli() cli.run(["list-qt", host, target, *extension_params, "--arch", version]) out, err = capsys.readouterr() sys.stdout.write(out) sys.stderr.write(err) assert expected_msg in err
def test_cli_input_errors(capsys, cmd, expect_msg, should_show_help): cli = Cli() cli._setup_settings() assert 1 == cli.run(cmd.split()) out, err = capsys.readouterr() if should_show_help: assert expected_help(out) else: assert out == "" assert err.rstrip().endswith(expect_msg)
def test_list_src_doc_examples_cli(monkeypatch, capsys, win_5152_sde_xml_file, command: str, expected: Set[str]): monkeypatch.setattr(MetadataFactory, "fetch_http", lambda self, _: win_5152_sde_xml_file) cli = Cli() assert 0 == cli.run(command.split()) out, err = capsys.readouterr() assert not err out_set = set(out.strip().split()) assert out_set == expected
def test_install( monkeypatch, capsys, cmd: List[str], host: str, target: str, version: str, arch: str, arch_dir: str, updates_url: str, archives: List[MockArchive], expect_out, # type: re.Pattern ): # For convenience, fill in version and arch dir: prevents repetitive data declarations for i in range(len(archives)): archives[i].version = version archives[i].arch_dir = arch_dir mock_get_url, mock_download_archive = make_mock_geturl_download_archive( archives, arch, host, updates_url) monkeypatch.setattr("aqt.archives.getUrl", mock_get_url) monkeypatch.setattr("aqt.installer.getUrl", mock_get_url) monkeypatch.setattr("aqt.installer.downloadBinaryFile", mock_download_archive) with TemporaryDirectory() as output_dir: cli = Cli() cli._setup_settings() assert 0 == cli.run(cmd + ["--outputdir", output_dir]) out, err = capsys.readouterr() sys.stdout.write(out) sys.stderr.write(err) assert expect_out.match(err) installed_path = Path(output_dir) / version / arch_dir if version == "5.9.0": installed_path = Path(output_dir) / "5.9" / arch_dir assert installed_path.is_dir() for archive in archives: if not archive.should_install: continue for patched_file in archive.contents: file_path = installed_path / patched_file.filename assert file_path.is_file() expect_content = patched_file.expected_content( base_dir=output_dir, sep=os.sep) actual_content = file_path.read_text(encoding="utf_8") assert actual_content == expect_content
def test_list_tool_cli(monkeypatch, capsys, host: str, target: str, tool_name: str): html_file = f"{host}-{target}.html" xml_file = f"{host}-{target}-{tool_name}-update.xml" html_expect = f"{host}-{target}-expect.json" xml_expect = f"{host}-{target}-{tool_name}-expect.json" htmltext, xmltext, htmljson, xmljson = [ (Path(__file__).parent / "data" / filename).read_text("utf-8") for filename in (html_file, xml_file, html_expect, xml_expect) ] expected_tools = set(json.loads(htmljson)["tools"]) xml_data = json.loads(xmljson) expected_tool_modules = set(xml_data["modules"]) def _mock_fetch_http(_, rest_of_url, *args, **kwargs: str) -> str: if not rest_of_url.endswith("Updates.xml"): return htmltext folder = urlparse(rest_of_url).path.split("/")[-2] assert folder.startswith("tools_") return xmltext monkeypatch.setattr(MetadataFactory, "fetch_http", _mock_fetch_http) cli = Cli() cli.run(["list-tool", host, target]) out, err = capsys.readouterr() output_set = set(out.strip().split()) assert output_set == expected_tools cli.run(["list-tool", host, target, tool_name]) out, err = capsys.readouterr() output_set = set(out.strip().split()) assert output_set == expected_tool_modules # Test abbreviated tool name: "aqt list-tool mac desktop ifw" assert tool_name.startswith("tools_") short_tool_name = tool_name[6:] cli.run(["list-tool", host, target, short_tool_name]) out, err = capsys.readouterr() output_set = set(out.strip().split()) assert output_set == expected_tool_modules cli.run(["list-tool", host, target, tool_name, "-l"]) out, err = capsys.readouterr() expected_tooldata = format(fetch_expected_tooldata(xml_expect)) assert out.strip() == expected_tooldata
def test_cli_unexpected_error(monkeypatch, capsys): def _mocked_run(*args): raise RuntimeError("Some unexpected error") monkeypatch.setattr("aqt.installer.Cli.run_install_qt", _mocked_run) cli = Cli() cli._setup_settings() assert Cli.UNHANDLED_EXCEPTION_CODE == cli.run(["install-qt", "mac", "ios", "6.2.0"]) out, err = capsys.readouterr() assert err.startswith("Some unexpected error") assert err.rstrip().endswith( "===========================PLEASE FILE A BUG REPORT===========================\n" "You have discovered a bug in aqt.\n" "Please file a bug report at https://github.com/miurahr/aqtinstall/issues.\n" "Please remember to include a copy of this program's output in your report." )
def test_cli_legacy_tool_new_syntax(monkeypatch, capsys, cmd): # These incorrect commands cannot be filtered out directly by argparse because # they have the correct number of arguments. command = cmd.split() expected = ( "WARNING : The command 'tool' is deprecated and marked for removal in a future version of aqt.\n" "In the future, please use the command 'install-tool' instead.\n" "ERROR : Invalid version: 'tools_ifw'! Please use the form '5.X.Y'.\n" ) cli = Cli() cli._setup_settings() assert 1 == cli.run(command) out, err = capsys.readouterr() actual = err[err.index("\n") + 1:] assert actual == expected
def test_list_qt_cli( monkeypatch, capsys, expected_windows_desktop_5140: Dict[str, Set[str]], args: str, expect: Union[Set[str], List[str]], ): htmlfile, xmlfile = "windows-desktop.html", "windows-5140-update.xml" version_string_to_replace = "qt5.5140" if isinstance(expect, list): # In this case, 'expect' is a list of keys to follow to the expected values. expected_dict = expected_windows_desktop_5140 for key in expect: # Follow the chain of keys to the list of values. expected_dict = expected_dict[key] assert isinstance(expected_dict, list) expect_set = set(expected_dict) else: expect_set = expect assert isinstance(expect_set, set) def _mock_fetch_http(_, rest_of_url, *args, **kwargs: str) -> str: htmltext = (Path(__file__).parent / "data" / htmlfile).read_text("utf-8") if not rest_of_url.endswith("Updates.xml"): return htmltext xmltext = (Path(__file__).parent / "data" / xmlfile).read_text("utf-8") # If we are serving an Updates.xml, `aqt list` will look for a Qt version number. # We will replace the version numbers in the file with the requested version. match = re.search(r"qt(\d)_(\d+)", rest_of_url) assert match major, version_nodot = match.groups() desired_version_string = f"qt{major}.{version_nodot}" return xmltext.replace(version_string_to_replace, desired_version_string) monkeypatch.setattr(MetadataFactory, "fetch_http", _mock_fetch_http) cli = Cli() cli.run(["list-qt", "windows", "desktop", *args.split()]) out, err = capsys.readouterr() output_set = set(out.strip().split()) assert output_set == expect_set
def test_install_pool_exception(monkeypatch, capsys, make_exception, settings_file, expect_end_msg, expect_return): def mock_installer_func(*args): raise eval(make_exception) host, target, ver, arch = "windows", "desktop", "6.1.0", "win64_mingw81" updates_url = "windows_x86/desktop/qt6_610/Updates.xml" archives = [ plain_qtbase_archive("qt.qt6.610.win64_mingw81", "win64_mingw81") ] cmd = ["install-qt", host, target, ver, arch] mock_get_url, mock_download_archive = make_mock_geturl_download_archive( archives, arch, host, updates_url) monkeypatch.setattr("aqt.archives.getUrl", mock_get_url) monkeypatch.setattr("aqt.installer.getUrl", mock_get_url) monkeypatch.setattr("aqt.installer.installer", mock_installer_func) Settings.load_settings(str(Path(__file__).parent / settings_file)) cli = Cli() assert expect_return == cli.run(cmd) out, err = capsys.readouterr() assert err.rstrip().endswith(expect_end_msg)
def test_list_targets(capsys, cmd: str, host: str, expect: Set[str]): cli = Cli() cli.run([cmd, host]) out, err = capsys.readouterr() output_set = set(out.strip().split()) assert output_set == expect
def test_list_archives_insufficient_args(capsys): cli = Cli() assert 1 == cli.run("list-qt mac desktop --archives 5.14.0".split()) out, err = capsys.readouterr() assert err.strip( ) == "ERROR : The '--archives' flag requires a 'QT_VERSION' and an 'ARCHITECTURE' parameter."
def test_cli_legacy_commands_with_wrong_syntax(cmd): cli = Cli() cli._setup_settings() with pytest.raises(SystemExit) as e: cli.run(cmd.split()) assert e.type == SystemExit
def main(): # For Windows standalone binaries, this is a noop on all other environments. freeze_support() cli = Cli() return cli.run()
def test_cli_help(capsys): cli = Cli() cli.run(["help"]) out, err = capsys.readouterr() assert expected_help(out)
def main(): cli = Cli() return cli.run()
def test_cli_check_version(): cli = Cli() cli._setup_settings() assert cli._check_qt_arg_versions("5.12.0") assert not cli._check_qt_arg_versions("5.12")