mirror of
https://github.com/miurahr/aqtinstall.git
synced 2025-12-16 20:27:05 +03:00
* Add authentication flags for list-qt-commercial, add tests for coverage * Add dry run * Make tests really use auth since secrets have been added, fix some indents * Fix auth issue, rename user 'email, and password 'pw' * Fix modules param type * Update commands names
1339 lines
54 KiB
Python
1339 lines
54 KiB
Python
import hashlib
|
|
import json
|
|
import os
|
|
import re
|
|
import shutil
|
|
import sys
|
|
from pathlib import Path
|
|
from tempfile import TemporaryDirectory
|
|
from typing import Dict, List, Optional, Set, Union
|
|
from urllib.parse import urlparse
|
|
|
|
import pytest
|
|
|
|
from aqt.exceptions import (
|
|
AqtException,
|
|
ArchiveConnectionError,
|
|
ArchiveDownloadError,
|
|
ArchiveListError,
|
|
CliInputError,
|
|
EmptyMetadata,
|
|
)
|
|
from aqt.helper import Settings
|
|
from aqt.installer import Cli
|
|
from aqt.metadata import (
|
|
ArchiveId,
|
|
MetadataFactory,
|
|
QtRepoProperty,
|
|
SimpleSpec,
|
|
ToolData,
|
|
Version,
|
|
Versions,
|
|
show_list,
|
|
suggested_follow_up,
|
|
)
|
|
|
|
ModulesQuery = MetadataFactory.ModulesQuery
|
|
|
|
Settings.load_settings()
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"arch, version, expect",
|
|
(
|
|
("wasm_32", Version("5.13.1"), "wasm"),
|
|
("mingw", Version("5.13.1"), ""),
|
|
("android_fake", Version("5.13.1"), ""),
|
|
("android_x86", Version("5.13.1"), ""),
|
|
("android_x86", Version("6.13.1"), "x86"),
|
|
("android_x86", Version("6.0.0"), "x86"),
|
|
),
|
|
)
|
|
def test_list_extension_for_arch(arch: str, version: Version, expect: str):
|
|
ext = QtRepoProperty.extension_for_arch(arch, version >= Version("6.0.0"))
|
|
assert ext == expect
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"arch, expect",
|
|
(
|
|
("wasm_32", ["wasm"]),
|
|
("mingw", [""]),
|
|
("android_fake", [""]),
|
|
("android", [""]),
|
|
("android_x86", ["", "x86"]),
|
|
),
|
|
)
|
|
def test_list_possible_extension_for_arch(arch: str, expect: List[str]):
|
|
exts = QtRepoProperty.possible_extensions_for_arch(arch)
|
|
assert set(exts) == set(expect)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"init_data, expect_str, expect_fmt, expect_flat, expect_last, expect_bool",
|
|
(
|
|
(
|
|
[
|
|
(1, [Version("1.1.1"), Version("1.1.2")]),
|
|
(2, [Version("1.2.1"), Version("1.2.2")]),
|
|
],
|
|
"[[Version('1.1.1'), Version('1.1.2')], [Version('1.2.1'), Version('1.2.2')]]",
|
|
"1.1.1 1.1.2\n1.2.1 1.2.2",
|
|
[Version("1.1.1"), Version("1.1.2"), Version("1.2.1"), Version("1.2.2")],
|
|
Version("1.2.2"),
|
|
True,
|
|
),
|
|
(
|
|
[],
|
|
"[]",
|
|
"",
|
|
[],
|
|
None,
|
|
False,
|
|
),
|
|
(
|
|
Version("1.2.3"),
|
|
"[[Version('1.2.3')]]",
|
|
"1.2.3",
|
|
[Version("1.2.3")],
|
|
Version("1.2.3"),
|
|
True,
|
|
),
|
|
),
|
|
)
|
|
def test_versions(init_data, expect_str, expect_fmt, expect_flat, expect_last, expect_bool):
|
|
versions = Versions(init_data)
|
|
assert str(versions) == expect_str
|
|
assert format(versions) == expect_fmt
|
|
assert format(versions, "s") == expect_str
|
|
assert versions.flattened() == expect_flat
|
|
assert versions.latest() == expect_last
|
|
assert bool(versions) == expect_bool
|
|
|
|
with pytest.raises(TypeError) as pytest_wrapped_e:
|
|
format(versions, "x")
|
|
assert pytest_wrapped_e.type == TypeError
|
|
|
|
|
|
@pytest.fixture
|
|
def spec_regex():
|
|
return re.compile(r"^(\d+\.\d+)")
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"os_name,target,in_file,expect_out_file",
|
|
[
|
|
("windows", "android", "windows-android.html", "windows-android-expect.json"),
|
|
("windows", "desktop", "windows-desktop.html", "windows-desktop-expect.json"),
|
|
("windows", "winrt", "windows-winrt.html", "windows-winrt-expect.json"),
|
|
("linux", "android", "linux-android.html", "linux-android-expect.json"),
|
|
("linux", "desktop", "linux-desktop.html", "linux-desktop-expect.json"),
|
|
("linux_arm64", "desktop", "linux_arm64-desktop.html", "linux_arm64-desktop-expect.json"),
|
|
("mac", "android", "mac-android.html", "mac-android-expect.json"),
|
|
("mac", "desktop", "mac-desktop.html", "mac-desktop-expect.json"),
|
|
("mac", "ios", "mac-ios.html", "mac-ios-expect.json"),
|
|
("windows", "android", "mirror-pre-a.html", "mirror-expect.json"),
|
|
("windows", "android", "mirror-table-before-pre-a.html", "mirror-expect.json"),
|
|
("windows", "android", "mirror-first-td.html", "mirror-expect.json"),
|
|
("windows", "android", "mirror-tag-in-a.html", "mirror-expect.json"),
|
|
],
|
|
)
|
|
def test_list_versions_tools(monkeypatch, spec_regex, os_name, target, in_file, expect_out_file):
|
|
_html = (Path(__file__).parent / "data" / in_file).read_text("utf-8")
|
|
monkeypatch.setattr(MetadataFactory, "fetch_http", lambda *args, **kwargs: _html)
|
|
|
|
expected = json.loads((Path(__file__).parent / "data" / expect_out_file).read_text("utf-8"))
|
|
|
|
# Test 'aqt list-tool'
|
|
tools = MetadataFactory(ArchiveId("tools", os_name, target)).getList()
|
|
assert tools == expected["tools"]
|
|
|
|
# Test 'aqt list-qt'
|
|
expected_output = expected["qt"]["qt"]
|
|
archive_id = ArchiveId("qt", os_name, target)
|
|
all_versions = MetadataFactory(archive_id).getList()
|
|
assert f"{all_versions}" == "\n".join(expected_output)
|
|
|
|
# Filter for the latest version only
|
|
latest_ver = MetadataFactory(archive_id, is_latest_version=True).getList()
|
|
assert f"{latest_ver}" == expected_output[-1].split(" ")[-1]
|
|
|
|
for row in expected_output:
|
|
spec = SimpleSpec(spec_regex.search(row).group(1))
|
|
|
|
# Find the latest version for a particular spec
|
|
latest_ver_for_spec = MetadataFactory(
|
|
archive_id,
|
|
spec=spec,
|
|
is_latest_version=True,
|
|
).getList()
|
|
assert f"{latest_ver_for_spec}" == row.split(" ")[-1]
|
|
|
|
# Find all versions for a particular spec
|
|
all_ver_for_spec = MetadataFactory(
|
|
archive_id,
|
|
spec=spec,
|
|
).getList()
|
|
assert f"{all_ver_for_spec}" == row
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"version,extension,in_file,expect_out_file",
|
|
[
|
|
("5.14.0", "", "windows-5140-update.xml", "windows-5140-expect.json"),
|
|
("5.15.0", "", "windows-5150-update.xml", "windows-5150-expect.json"),
|
|
(
|
|
"5.15.2",
|
|
"src_doc_examples",
|
|
"windows-5152-src-doc-example-update.xml",
|
|
"windows-5152-src-doc-example-expect.json",
|
|
),
|
|
("6.2.0", "", "windows-620-update.xml", "windows-620-expect.json"),
|
|
],
|
|
)
|
|
def test_list_qt_modules(monkeypatch, version: str, extension: str, in_file: str, expect_out_file: str):
|
|
archive_id = ArchiveId("qt", "windows", "desktop")
|
|
_xml = (Path(__file__).parent / "data" / in_file).read_text("utf-8")
|
|
expect = json.loads((Path(__file__).parent / "data" / expect_out_file).read_text("utf-8"))
|
|
|
|
monkeypatch.setattr(MetadataFactory, "fetch_http", lambda self, _: _xml)
|
|
|
|
for arch in expect["architectures"]:
|
|
modules = MetadataFactory(archive_id).fetch_modules(Version(version), arch)
|
|
assert modules == sorted(expect["modules_by_arch"][arch])
|
|
|
|
|
|
@pytest.fixture
|
|
def win_5152_sde_xml_file() -> str:
|
|
return (Path(__file__).parent / "data" / "windows-5152-src-doc-example-update.xml").read_text("utf-8")
|
|
|
|
|
|
def win_sde_expected(cmd_type: str, query_type: str, expect_out_file: str) -> Set[str]:
|
|
assert cmd_type in ("src", "doc", "examples")
|
|
assert query_type in ("archives", "modules")
|
|
_json = json.loads((Path(__file__).parent / "data" / expect_out_file).read_text("utf-8"))
|
|
return set(_json[cmd_type][query_type])
|
|
|
|
|
|
def win_5152_sde_expected(cmd_type: str, query_type: str) -> Set[str]:
|
|
return win_sde_expected(cmd_type, query_type, "windows-5152-src-doc-example-expect.json")
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"cmd_type, host, version, expected",
|
|
[
|
|
(
|
|
_cmd_type,
|
|
"windows",
|
|
"5.15.2",
|
|
win_5152_sde_expected(_cmd_type, "archives"),
|
|
)
|
|
for _cmd_type in ("src", "doc", "examples")
|
|
],
|
|
)
|
|
def test_list_src_doc_examples_archives(
|
|
monkeypatch, win_5152_sde_xml_file, cmd_type: str, host: str, version: str, expected: Set[str]
|
|
):
|
|
monkeypatch.setattr(MetadataFactory, "fetch_http", lambda self, _: win_5152_sde_xml_file)
|
|
|
|
archive_id = ArchiveId("qt", host, "desktop")
|
|
archives = set(MetadataFactory(archive_id).fetch_archives_sde(cmd_type, Version(version)))
|
|
assert archives == expected
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"cmd_type, host, version, expected",
|
|
[
|
|
(
|
|
_cmd_type,
|
|
"windows",
|
|
"5.15.2",
|
|
win_5152_sde_expected(_cmd_type, "modules"),
|
|
)
|
|
for _cmd_type in ("doc", "examples")
|
|
],
|
|
)
|
|
def test_list_src_doc_examples_modules(
|
|
monkeypatch, win_5152_sde_xml_file, cmd_type: str, host: str, version: str, expected: Set[str]
|
|
):
|
|
monkeypatch.setattr(MetadataFactory, "fetch_http", lambda self, _: win_5152_sde_xml_file)
|
|
|
|
archive_id = ArchiveId("qt", host, "desktop")
|
|
modules = set(MetadataFactory(archive_id).fetch_modules_sde(cmd_type, Version(version)))
|
|
assert modules == expected
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"command, updates_file, url, expected",
|
|
(
|
|
(
|
|
"list-src windows 5.15.2",
|
|
"windows-5152-src-doc-example-update.xml",
|
|
re.compile(r"/windows_x86/desktop/qt5_5152_src_doc_examples/Updates\.xml$"),
|
|
win_5152_sde_expected("src", "archives"),
|
|
),
|
|
(
|
|
"list-doc windows 5.15.2",
|
|
"windows-5152-src-doc-example-update.xml",
|
|
re.compile(r"/windows_x86/desktop/qt5_5152_src_doc_examples/Updates\.xml$"),
|
|
win_5152_sde_expected("doc", "archives"),
|
|
),
|
|
(
|
|
"list-example windows 5.15.2",
|
|
"windows-5152-src-doc-example-update.xml",
|
|
re.compile(r"/windows_x86/desktop/qt5_5152_src_doc_examples/Updates\.xml$"),
|
|
win_5152_sde_expected("examples", "archives"),
|
|
),
|
|
(
|
|
"list-doc windows 5.15.2 --modules",
|
|
"windows-5152-src-doc-example-update.xml",
|
|
re.compile(r"/windows_x86/desktop/qt5_5152_src_doc_examples/Updates\.xml$"),
|
|
win_5152_sde_expected("doc", "modules"),
|
|
),
|
|
(
|
|
"list-example windows 5.15.2 --modules",
|
|
"windows-5152-src-doc-example-update.xml",
|
|
re.compile(r"/windows_x86/desktop/qt5_5152_src_doc_examples/Updates\.xml$"),
|
|
win_5152_sde_expected("examples", "modules"),
|
|
),
|
|
(
|
|
"list-src windows 6.8.1",
|
|
"all_os-681-src-doc-example-update.xml",
|
|
re.compile(r"/all_os/qt/qt6_681_(?:unix|windows)_line_endings_src/Updates\.xml$"),
|
|
win_sde_expected("src", "archives", "all_os-681-src-doc-example-expect.json"),
|
|
),
|
|
(
|
|
"list-doc windows 6.8.1",
|
|
"all_os-681-src-doc-example-update.xml",
|
|
re.compile(r"/all_os/qt/qt6_681_(?:unix|windows)_line_endings_src/Updates\.xml$"),
|
|
win_sde_expected("doc", "archives", "all_os-681-src-doc-example-expect.json"),
|
|
),
|
|
(
|
|
"list-example windows 6.8.1",
|
|
"all_os-681-src-doc-example-update.xml",
|
|
re.compile(r"/all_os/qt/qt6_681_(?:unix|windows)_line_endings_src/Updates\.xml$"),
|
|
win_sde_expected("examples", "archives", "all_os-681-src-doc-example-expect.json"),
|
|
),
|
|
(
|
|
"list-src all_os 6.8.1",
|
|
"all_os-681-src-doc-example-update.xml",
|
|
re.compile(r"/all_os/qt/qt6_681_(?:unix|windows)_line_endings_src/Updates\.xml$"),
|
|
win_sde_expected("src", "archives", "all_os-681-src-doc-example-expect.json"),
|
|
),
|
|
(
|
|
"list-doc all_os 6.8.1",
|
|
"all_os-681-src-doc-example-update.xml",
|
|
re.compile(r"/all_os/qt/qt6_681_(?:unix|windows)_line_endings_src/Updates\.xml$"),
|
|
win_sde_expected("doc", "archives", "all_os-681-src-doc-example-expect.json"),
|
|
),
|
|
(
|
|
"list-example all_os 6.8.1",
|
|
"all_os-681-src-doc-example-update.xml",
|
|
re.compile(r"/all_os/qt/qt6_681_(?:unix|windows)_line_endings_src/Updates\.xml$"),
|
|
win_sde_expected("examples", "archives", "all_os-681-src-doc-example-expect.json"),
|
|
),
|
|
),
|
|
)
|
|
def test_list_src_doc_examples_cli(
|
|
monkeypatch, capsys, command: str, updates_file: str, url: re.Pattern, expected: Set[str]
|
|
):
|
|
def mock_fetch(self, rest_of_url):
|
|
assert url.search(rest_of_url), f"Unexpected URL: {rest_of_url}"
|
|
return (Path(__file__).parent / "data" / updates_file).read_text("utf-8")
|
|
|
|
monkeypatch.setattr(MetadataFactory, "fetch_http", mock_fetch)
|
|
|
|
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
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"version, arch, modules_to_query, modules_failed_query",
|
|
(
|
|
("5.14.0", "win32_mingw73", [], []),
|
|
("5.14.0", "win32_mingw73", ["qtcharts"], []),
|
|
("5.14.0", "win32_mingw73", ["all"], []),
|
|
("5.14.0", "win32_mingw73", ["debug_info"], ["debug_info"]),
|
|
("5.14.0", "win64_msvc2017_64", [], []),
|
|
("5.14.0", "win64_msvc2017_64", ["debug_info"], []),
|
|
),
|
|
)
|
|
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 = [mod for mod in expected_mod_metadata if mod["Name"].split(".")[-2] in modules_to_query]
|
|
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_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."
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"xml_content",
|
|
(
|
|
"<Updates><PackageUpdate><badname></badname></PackageUpdate></Updates>",
|
|
"<Updates><PackageUpdate><Name></Name></PackageUpdate></Updates>",
|
|
"<Updates></PackageUpdate><PackageUpdate></Updates><Name></Name>",
|
|
),
|
|
)
|
|
def test_list_archives_bad_xml(monkeypatch, xml_content: str):
|
|
archive_id = ArchiveId("qt", "windows", "desktop")
|
|
archives_query = ["5.15.2", "win32_mingw81", "qtcharts"]
|
|
|
|
monkeypatch.setattr(MetadataFactory, "fetch_http", lambda self, _: xml_content)
|
|
with pytest.raises(ArchiveListError) as e:
|
|
MetadataFactory(archive_id, archives_query=archives_query).getList()
|
|
assert e.type == ArchiveListError
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"host, target, tool_name",
|
|
[
|
|
("mac", "desktop", "tools_cmake"),
|
|
("mac", "desktop", "tools_ifw"),
|
|
("mac", "desktop", "tools_qtcreator"),
|
|
],
|
|
)
|
|
def test_tool_modules(monkeypatch, host: str, target: str, tool_name: str):
|
|
archive_id = ArchiveId("tools", host, target)
|
|
in_file = "{}-{}-{}-update.xml".format(host, target, tool_name)
|
|
expect_out_file = "{}-{}-{}-expect.json".format(host, target, tool_name)
|
|
_xml = (Path(__file__).parent / "data" / in_file).read_text("utf-8")
|
|
expect = json.loads((Path(__file__).parent / "data" / expect_out_file).read_text("utf-8"))
|
|
|
|
monkeypatch.setattr(MetadataFactory, "fetch_http", lambda self, _: _xml)
|
|
|
|
modules = MetadataFactory(archive_id, tool_name=tool_name).getList()
|
|
assert modules == expect["modules"]
|
|
|
|
table = MetadataFactory(archive_id, tool_name=tool_name, is_long_listing=True).getList()
|
|
assert table._rows(table.long_heading_keys) == expect["long_listing"]
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"host, target, version, arch",
|
|
[
|
|
["windows", "desktop", "5.14.0", arch]
|
|
for arch in ["win32_mingw73", "win32_msvc2017", "win64_mingw73", "win64_msvc2015_64", "win64_msvc2017_64"]
|
|
],
|
|
)
|
|
def test_long_qt_modules(monkeypatch, host: str, target: str, version: str, arch: str):
|
|
archive_id = ArchiveId("qt", host, target)
|
|
in_file = f"{host}-{version.replace('.', '')}-update.xml"
|
|
expect_out_file = f"{host}-{version.replace('.', '')}-expect.json"
|
|
_xml = (Path(__file__).parent / "data" / in_file).read_text("utf-8")
|
|
expect = json.loads((Path(__file__).parent / "data" / expect_out_file).read_text("utf-8"))
|
|
|
|
monkeypatch.setattr(MetadataFactory, "fetch_http", lambda self, _: _xml)
|
|
|
|
table = MetadataFactory(archive_id, modules_query=ModulesQuery(version, arch), is_long_listing=True).getList()
|
|
assert table._rows(table.long_heading_keys) == expect["modules_long_by_arch"][arch]
|
|
|
|
|
|
def expected_windows_desktop_plus_wasm_5140(is_wasm_threaded: bool) -> Dict:
|
|
if is_wasm_threaded:
|
|
input_filenames = (
|
|
"windows-5140-expect.json",
|
|
"windows-650-wasm-single-expect.json",
|
|
"windows-650-wasm-multi-expect.json",
|
|
)
|
|
else:
|
|
input_filenames = "windows-5140-expect.json", "windows-5140-wasm-expect.json"
|
|
|
|
to_join = [json.loads((Path(__file__).parent / "data" / f).read_text("utf-8")) for f in input_filenames]
|
|
|
|
result = {"architectures": [], "modules_by_arch": {}}
|
|
|
|
# Gather architectures from all sources
|
|
for source in to_join:
|
|
result["architectures"].extend(source["architectures"])
|
|
if "modules_by_arch" in source:
|
|
result["modules_by_arch"].update(source["modules_by_arch"])
|
|
|
|
# Remove duplicates while preserving order
|
|
seen = set()
|
|
result["architectures"] = [x for x in result["architectures"] if not (x in seen or seen.add(x))]
|
|
|
|
return result
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"host, target, version, arch, expect_arches",
|
|
[
|
|
("all_os", "wasm", "6.7.3", "", {"wasm_singlethread", "wasm_multithread"}),
|
|
("all_os", "wasm", "6.8.0", "", {"wasm_singlethread", "wasm_multithread"}),
|
|
],
|
|
)
|
|
def test_list_wasm_arches(monkeypatch, capsys, host: str, target: str, version: str, arch: str, expect_arches: Set[str]):
|
|
def _mock_fetch_http(_, rest_of_url: str, *args, **kwargs) -> str:
|
|
|
|
if rest_of_url.endswith("wasm_singlethread/Updates.xml"):
|
|
if version >= "6.8.0":
|
|
return (Path(__file__).parent / "data" / "all_os-680-wasm-single-update.xml").read_text("utf-8")
|
|
else:
|
|
return (Path(__file__).parent / "data" / "all_os-673-wasm-single-update.xml").read_text("utf-8")
|
|
elif rest_of_url.endswith("wasm_multithread/Updates.xml"):
|
|
if version >= "6.8.0":
|
|
return (Path(__file__).parent / "data" / "all_os-680-wasm-multi-update.xml").read_text("utf-8")
|
|
else:
|
|
return (Path(__file__).parent / "data" / "all_os-673-wasm-multi-update.xml").read_text("utf-8")
|
|
return "" # Return empty HTML since we don't need it
|
|
|
|
monkeypatch.setattr("aqt.metadata.getUrl", _mock_fetch_http)
|
|
monkeypatch.setattr(MetadataFactory, "fetch_http", _mock_fetch_http)
|
|
|
|
cli = Cli()
|
|
cli._setup_settings()
|
|
assert 0 == cli.run(["list-qt", host, target, "--arch", version])
|
|
out, err = capsys.readouterr()
|
|
assert set(out.strip().split()) == expect_arches
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"args, is_wasm_threaded, expect",
|
|
(
|
|
("--modules latest win64_msvc2017_64", False, ["modules_by_arch", "win64_msvc2017_64"]),
|
|
("--spec 5.14 --modules latest win64_msvc2017_64", False, ["modules_by_arch", "win64_msvc2017_64"]),
|
|
("--modules 5.14.0 win32_mingw73", False, ["modules_by_arch", "win32_mingw73"]),
|
|
("--modules 5.14.0 win32_msvc2017", False, ["modules_by_arch", "win32_msvc2017"]),
|
|
("--modules 5.14.0 win64_mingw73", False, ["modules_by_arch", "win64_mingw73"]),
|
|
("--modules 5.14.0 win64_msvc2015_64", False, ["modules_by_arch", "win64_msvc2015_64"]),
|
|
("--modules 5.14.0 win64_msvc2017_64", False, ["modules_by_arch", "win64_msvc2017_64"]),
|
|
("--modules 6.5.0 wasm_singlethread", True, ["modules_by_arch", "wasm_singlethread"]),
|
|
("--modules 6.5.0 wasm_multithread", True, ["modules_by_arch", "wasm_multithread"]),
|
|
("--spec 5.14 --arch latest", False, ["architectures"]),
|
|
("--arch 5.14.0", False, ["architectures"]),
|
|
),
|
|
)
|
|
def test_list_qt_cli(
|
|
monkeypatch,
|
|
capsys,
|
|
args: str,
|
|
is_wasm_threaded: bool,
|
|
expect: Union[Set[str], List[str]],
|
|
):
|
|
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_plus_wasm_5140(is_wasm_threaded)
|
|
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" / "windows-desktop.html").read_text("utf-8")
|
|
if not rest_of_url.endswith("Updates.xml"):
|
|
return htmltext
|
|
|
|
def get_xml_filename() -> str:
|
|
if rest_of_url.endswith("_wasm/Updates.xml"):
|
|
return "windows-5140-wasm-update.xml"
|
|
elif rest_of_url.endswith("_wasm_singlethread/Updates.xml"):
|
|
return "windows-650-wasm-single-update.xml"
|
|
elif rest_of_url.endswith("_wasm_multithread/Updates.xml"):
|
|
return "windows-650-wasm-multi-update.xml"
|
|
else:
|
|
return "windows-5140-update.xml"
|
|
|
|
xmltext = (Path(__file__).parent / "data" / get_xml_filename()).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_list_missing_wasm_updates_for_windows(monkeypatch, capsys):
|
|
"""Require that MetadataFactory is resilient to missing wasm updates.xml files"""
|
|
data_dir = Path(__file__).parent / "data"
|
|
expect = set(json.loads((data_dir / "windows-620-expect.json").read_text("utf-8"))["architectures"])
|
|
|
|
def _mock_fetch_http(_, rest_of_url, *args, **kwargs: str) -> str:
|
|
htmltext = (Path(__file__).parent / "data" / "windows-desktop.html").read_text("utf-8")
|
|
if rest_of_url.endswith("windows_x86/desktop/"):
|
|
return htmltext
|
|
elif rest_of_url.endswith("windows_x86/desktop/qt6_620/Updates.xml"):
|
|
return (data_dir / "windows-620-update.xml").read_text("utf-8")
|
|
else:
|
|
raise ArchiveDownloadError(f"No such file at {rest_of_url}")
|
|
|
|
monkeypatch.setattr(MetadataFactory, "fetch_http", _mock_fetch_http)
|
|
|
|
cli = Cli()
|
|
rv = cli.run("list-qt windows desktop --arch 6.2.0".split())
|
|
assert rv == 0
|
|
out, err = capsys.readouterr()
|
|
assert set(out.strip().split()) == expect
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"qt_ver_str, expect_set", (("6.2.0", {"android_x86", "android_x86_64", "android_armv7", "android_arm64_v8a"}),)
|
|
)
|
|
def test_list_android_arches(monkeypatch, capsys, qt_ver_str: str, expect_set: Set[str]):
|
|
host, target = "windows", "android"
|
|
|
|
def _mock_fetch_http(_, rest_of_url, *args, **kwargs: str) -> str:
|
|
assert rest_of_url.endswith("Updates.xml"), f"Fetched unexpected file at {rest_of_url}"
|
|
|
|
xmltext = (Path(__file__).parent / "data" / "windows-620-android-armv7-update.xml").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+_(?P<arch>\w+)/Updates\.xml$", rest_of_url)
|
|
assert match
|
|
return xmltext.replace("armv7", match.group("arch"))
|
|
|
|
monkeypatch.setattr(MetadataFactory, "fetch_http", _mock_fetch_http)
|
|
|
|
# Unit test:
|
|
archive_id = ArchiveId("qt", host, target)
|
|
actual_arches = MetadataFactory(archive_id).fetch_arches(Version(qt_ver_str))
|
|
assert set(actual_arches) == expect_set
|
|
|
|
# Integration test:
|
|
cli = Cli()
|
|
cli.run(["list-qt", host, target, "--arch", qt_ver_str])
|
|
out, err = capsys.readouterr()
|
|
output_set = set(out.strip().split())
|
|
assert output_set == expect_set
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"host, has_wasm",
|
|
(("linux", True), ("windows", False), ("mac", False)),
|
|
)
|
|
def test_list_desktop_arches_qt5130(monkeypatch, capsys, host: str, has_wasm: bool):
|
|
"""Tests the edge case of desktop Qt 5.13.0, in which "wasm_32" is a valid arch for Linux but not win/mac."""
|
|
|
|
# Generate some mock Updates.xml files. The host mismatch is not important; we just want to check for arch==wasm
|
|
updates_xmltext, wasm_updates_xmltext = [
|
|
(Path(__file__).parent / "data" / filename).read_text("utf-8").replace("qt5.5140", "qt5.5130")
|
|
for filename in ("windows-5140-update.xml", "windows-5140-wasm-update.xml")
|
|
]
|
|
|
|
def _mock_fetch_http(_, rest_of_url, *args, **kwargs: str) -> str:
|
|
if rest_of_url == "online/qtsdkrepository/linux_x64/desktop/qt5_5130_wasm/Updates.xml":
|
|
return wasm_updates_xmltext
|
|
elif rest_of_url.endswith("/desktop/qt5_5130/Updates.xml"):
|
|
return updates_xmltext
|
|
else:
|
|
assert False, f"Fetched an unexpected file at '{rest_of_url}'"
|
|
|
|
monkeypatch.setattr(MetadataFactory, "fetch_http", _mock_fetch_http)
|
|
|
|
cli = Cli()
|
|
cli.run(["list-qt", host, "desktop", "--arch", "5.13.0"])
|
|
out, err = capsys.readouterr()
|
|
output_set = set(out.strip().split())
|
|
if has_wasm:
|
|
assert "wasm_32" in output_set
|
|
else:
|
|
assert "wasm_32" not in output_set
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"cmd, host, expect",
|
|
(
|
|
("list-qt", "windows", {"desktop", "android", "winrt"}),
|
|
("list-qt", "linux", {"desktop", "android"}),
|
|
("list-qt", "mac", {"desktop", "android", "ios"}),
|
|
("list-tool", "windows", {"desktop", "android", "winrt"}),
|
|
("list-tool", "linux", {"desktop", "android"}),
|
|
("list-tool", "mac", {"desktop", "android", "ios"}),
|
|
),
|
|
)
|
|
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
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"cmd, host, target",
|
|
(
|
|
("list-qt", "windows", "ios"),
|
|
("list-qt", "linux", "ios"),
|
|
("list-qt", "linux", "winrt"),
|
|
("list-qt", "mac", "winrt"),
|
|
("list-tool", "windows", "ios"),
|
|
("list-tool", "linux", "ios"),
|
|
("list-tool", "linux", "winrt"),
|
|
("list-tool", "mac", "winrt"),
|
|
),
|
|
)
|
|
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
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"cmd, spec",
|
|
(
|
|
("list-qt", "not a spec"),
|
|
("list-qt", "1...3"),
|
|
("list-qt", ""),
|
|
("list-qt", ">3 <5"),
|
|
),
|
|
)
|
|
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)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"simple_spec, expected_name",
|
|
(
|
|
(SimpleSpec("*"), "mytool.999"),
|
|
(SimpleSpec(">3.5"), "mytool.999"),
|
|
(SimpleSpec("3.5.5"), "mytool.355"),
|
|
(SimpleSpec("<3.5"), "mytool.300"),
|
|
(SimpleSpec("<=3.5"), "mytool.355"),
|
|
(SimpleSpec("<=3.5.0"), "mytool.350"),
|
|
(SimpleSpec(">10"), None),
|
|
),
|
|
)
|
|
def test_list_choose_tool_by_version(simple_spec, expected_name):
|
|
tools_data = {
|
|
"mytool.999": {"Version": "9.9.9", "Name": "mytool.999"},
|
|
"mytool.355": {"Version": "3.5.5", "Name": "mytool.355"},
|
|
"mytool.350": {"Version": "3.5.0", "Name": "mytool.350"},
|
|
"mytool.300": {"Version": "3.0.0", "Name": "mytool.300"},
|
|
}
|
|
item = MetadataFactory.choose_highest_version_in_spec(tools_data, simple_spec)
|
|
if item is not None:
|
|
assert item["Name"] == expected_name
|
|
else:
|
|
assert expected_name is None
|
|
|
|
|
|
mac_qt = ArchiveId("qt", "mac", "desktop")
|
|
wrong_tool_name_msg = "Please use 'aqt list-tool mac desktop' to check what tools are available."
|
|
wrong_qt_version_msg = "Please use 'aqt list-qt mac desktop' to show versions of Qt available."
|
|
wrong_arch_msg = "Please use 'aqt list-qt mac desktop --arch <QT_VERSION>' to list valid architectures."
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"meta, expected_message",
|
|
(
|
|
(MetadataFactory(mac_qt), []),
|
|
(
|
|
MetadataFactory(mac_qt, spec=SimpleSpec("5.0")),
|
|
["Please use 'aqt list-qt mac desktop' to check that versions of qt exist within the spec '5.0'."],
|
|
),
|
|
(
|
|
MetadataFactory(ArchiveId("tools", "mac", "desktop"), tool_name="ifw"),
|
|
[wrong_tool_name_msg],
|
|
),
|
|
(
|
|
MetadataFactory(mac_qt, architectures_ver="1.2.3"),
|
|
[wrong_qt_version_msg],
|
|
),
|
|
(
|
|
MetadataFactory(mac_qt, modules_query=ModulesQuery("1.2.3", "clang_64")),
|
|
[wrong_qt_version_msg, wrong_arch_msg],
|
|
),
|
|
(
|
|
MetadataFactory(mac_qt, archives_query=["1.2.3", "clang_64", "a module", "another module"]),
|
|
[
|
|
"Please use 'aqt list-qt mac desktop' to show versions of Qt available.",
|
|
"Please use 'aqt list-qt mac desktop --arch <QT_VERSION>' to show architectures available.",
|
|
"Please use 'aqt list-qt mac desktop --modules <QT_VERSION>' to show modules available.",
|
|
],
|
|
),
|
|
(
|
|
MetadataFactory(mac_qt, archives_query=["1.2.3", "clang_64"]),
|
|
[
|
|
"Please use 'aqt list-qt mac desktop' to show versions of Qt available.",
|
|
"Please use 'aqt list-qt mac desktop --arch <QT_VERSION>' to show architectures available.",
|
|
],
|
|
),
|
|
(
|
|
MetadataFactory(mac_qt, spec=SimpleSpec("<5.9")),
|
|
["Please use 'aqt list-qt mac desktop' to check that versions of qt exist within the spec '<5.9'."],
|
|
),
|
|
(
|
|
MetadataFactory(ArchiveId("tools", "mac", "desktop"), tool_name="ifw"),
|
|
[wrong_tool_name_msg],
|
|
),
|
|
(
|
|
MetadataFactory(mac_qt, architectures_ver="1.2.3"),
|
|
[wrong_qt_version_msg],
|
|
),
|
|
(
|
|
MetadataFactory(mac_qt, modules_query=ModulesQuery("1.2.3", "clang_64")),
|
|
[wrong_qt_version_msg, wrong_arch_msg],
|
|
),
|
|
),
|
|
)
|
|
def test_suggested_follow_up(meta: MetadataFactory, expected_message: str):
|
|
assert suggested_follow_up(meta) == expected_message
|
|
|
|
|
|
def test_format_suggested_follow_up():
|
|
suggestions = [
|
|
"Please use 'aqt list-tool mac desktop --modules <QT_VERSION>' to list valid modules.",
|
|
"Please use 'aqt list-tool mac desktop' to check what tools are available.",
|
|
]
|
|
expected = (
|
|
"==============================Suggested follow-up:==============================\n"
|
|
"* Please use 'aqt list-tool mac desktop --modules <QT_VERSION>' to list valid modules.\n"
|
|
"* Please use 'aqt list-tool mac desktop' to check what tools are available."
|
|
)
|
|
ex = AqtException("msg", suggested_action=suggestions)
|
|
assert ex._format_suggested_follow_up() == expected
|
|
|
|
|
|
def test_format_suggested_follow_up_empty():
|
|
ex = AqtException("msg", suggested_action=[])
|
|
assert format(ex) == "msg"
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"meta, expect",
|
|
(
|
|
(
|
|
MetadataFactory(ArchiveId("qt", "mac", "desktop"), spec=SimpleSpec("5.42")),
|
|
"qt/mac/desktop with spec 5.42",
|
|
),
|
|
(
|
|
MetadataFactory(ArchiveId("qt", "mac", "desktop"), spec=SimpleSpec("5.42")),
|
|
"qt/mac/desktop with spec 5.42",
|
|
),
|
|
(MetadataFactory(ArchiveId("qt", "mac", "desktop")), "qt/mac/desktop"),
|
|
(
|
|
MetadataFactory(ArchiveId("qt", "mac", "desktop")),
|
|
"qt/mac/desktop",
|
|
),
|
|
),
|
|
)
|
|
def test_list_describe_filters(meta: MetadataFactory, expect: str):
|
|
assert meta.describe_filters() == expect
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"archive_id, spec, version_str, arch, expect",
|
|
(
|
|
(mac_qt, None, "5.12.42", None, Version("5.12.42")),
|
|
(
|
|
mac_qt,
|
|
None,
|
|
"not a version",
|
|
None,
|
|
CliInputError("Invalid version string: 'not a version'"),
|
|
),
|
|
(mac_qt, SimpleSpec("5"), "latest", None, Version("5.15.2")),
|
|
(
|
|
mac_qt,
|
|
SimpleSpec("5.0"),
|
|
"latest",
|
|
None,
|
|
CliInputError("There is no latest version of Qt with the criteria 'qt/mac/desktop with spec 5.0'"),
|
|
),
|
|
(mac_qt, SimpleSpec("<6.2.0"), "latest", "wasm_32", Version("5.15.2")),
|
|
),
|
|
)
|
|
def test_list_to_version(monkeypatch, archive_id, spec, version_str, arch: Optional[str], expect):
|
|
_html = (Path(__file__).parent / "data" / "mac-desktop.html").read_text("utf-8")
|
|
monkeypatch.setattr(MetadataFactory, "fetch_http", lambda *args, **kwargs: _html)
|
|
|
|
if isinstance(expect, Exception):
|
|
with pytest.raises(CliInputError) as error:
|
|
MetadataFactory(archive_id, spec=spec)._to_version(version_str, arch)
|
|
assert error.type == CliInputError
|
|
assert str(expect) == str(error.value)
|
|
else:
|
|
assert MetadataFactory(archive_id, spec=spec)._to_version(version_str, arch) == expect
|
|
|
|
|
|
def test_list_fetch_tool_by_simple_spec(monkeypatch):
|
|
update_xml = (Path(__file__).parent / "data" / "windows-desktop-tools_vcredist-update.xml").read_text("utf-8")
|
|
monkeypatch.setattr(MetadataFactory, "fetch_http", lambda self, _: update_xml)
|
|
|
|
expect_json = (Path(__file__).parent / "data" / "windows-desktop-tools_vcredist-expect.json").read_text("utf-8")
|
|
expected = json.loads(expect_json)["modules_data"]
|
|
|
|
def check(actual, expect):
|
|
for key in (
|
|
"Description",
|
|
"DisplayName",
|
|
"DownloadableArchives",
|
|
"ReleaseDate",
|
|
"SHA1",
|
|
"Version",
|
|
"Virtual",
|
|
):
|
|
assert actual[key] == expect[key]
|
|
|
|
meta = MetadataFactory(ArchiveId("tools", "windows", "desktop"))
|
|
check(
|
|
meta.fetch_tool_by_simple_spec(tool_name="tools_vcredist", simple_spec=SimpleSpec("2011")),
|
|
expected["qt.tools.vcredist"],
|
|
)
|
|
check(
|
|
meta.fetch_tool_by_simple_spec(tool_name="tools_vcredist", simple_spec=SimpleSpec("2014")),
|
|
expected["qt.tools.vcredist_msvc2013_x86"],
|
|
)
|
|
nonexistent = meta.fetch_tool_by_simple_spec(tool_name="tools_vcredist", simple_spec=SimpleSpec("1970"))
|
|
assert nonexistent is None
|
|
|
|
# Simulate a broken Updates.xml file, with invalid versions
|
|
highest_module_info = MetadataFactory.choose_highest_version_in_spec(
|
|
all_tools_data={"some_module": {"Version": "not_a_version"}},
|
|
simple_spec=SimpleSpec("*"),
|
|
)
|
|
assert highest_module_info is None
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"columns, expect",
|
|
(
|
|
(
|
|
120,
|
|
(
|
|
"Tool Variant Name Version Release Date Display Name "
|
|
" Description \n"
|
|
"====================================================================================="
|
|
"===================================\n"
|
|
"qt.tools.ifw.41 4.1.1-202105261132 2021-05-26 Qt Installer Framework 4.1 "
|
|
"The Qt Installer Framework provides\n"
|
|
" "
|
|
"a set of tools and utilities to \n"
|
|
" "
|
|
"create installers for the supported\n"
|
|
" "
|
|
"desktop Qt platforms: Linux, \n"
|
|
" "
|
|
"Microsoft Windows, and macOS. \n"
|
|
),
|
|
),
|
|
(
|
|
80,
|
|
"Tool Variant Name Version Release Date\n"
|
|
"=====================================================\n"
|
|
"qt.tools.ifw.41 4.1.1-202105261132 2021-05-26 \n",
|
|
),
|
|
(
|
|
0,
|
|
"Tool Variant Name Version Release Date Display Name "
|
|
" Descriptio"
|
|
"n \n"
|
|
"====================================================================================="
|
|
"====================================================================================="
|
|
"=============================================================================\n"
|
|
"qt.tools.ifw.41 4.1.1-202105261132 2021-05-26 Qt Installer Framework 4.1 "
|
|
"The Qt Installer Framework provides a set of tools and utilities to create installers"
|
|
" for the supported desktop Qt platforms: Linux, Microsoft Windows, and macOS.\n",
|
|
),
|
|
),
|
|
)
|
|
def test_show_list_tools_long_ifw(capsys, monkeypatch, columns, expect):
|
|
update_xml = (Path(__file__).parent / "data" / "mac-desktop-tools_ifw-update.xml").read_text("utf-8")
|
|
monkeypatch.setattr(MetadataFactory, "fetch_http", lambda self, _: update_xml)
|
|
|
|
monkeypatch.setattr(shutil, "get_terminal_size", lambda fallback: os.terminal_size((columns, 24)))
|
|
|
|
meta = MetadataFactory(
|
|
ArchiveId("tools", "mac", "desktop"),
|
|
tool_name="tools_ifw",
|
|
is_long_listing=True,
|
|
)
|
|
show_list(meta)
|
|
out, err = capsys.readouterr()
|
|
sys.stdout.write(out)
|
|
sys.stderr.write(err)
|
|
assert out == expect
|
|
|
|
|
|
LONG_MODULES_WIN_5140_120 = (
|
|
" Module Name Display Name Release Date Download Size Installed Size\n"
|
|
"====================================================================================================================\n"
|
|
"qtcharts Qt Charts for MinGW 7.3.0 32-bit 2019-12-11 772.7K 7.8M \n"
|
|
"qtdatavis3d Qt Data Visualization for MinGW 7.3.0 32-bit 2019-12-11 620.2K 5.0M \n"
|
|
"qtlottie Qt Lottie Animation for MinGW 7.3.0 32-bit 2019-12-11 153.5K 968.4K \n"
|
|
"qtnetworkauth Qt Network Authorization for MinGW 7.3.0 32-bit 2019-12-11 98.7K 638.6K \n"
|
|
"qtpurchasing Qt Purchasing for MinGW 7.3.0 32-bit 2019-12-11 50.9K 306.8K \n"
|
|
"qtquick3d Qt Quick 3D for MinGW 7.3.0 32-bit 2019-12-11 9.8M 21.2M \n"
|
|
"qtquicktimeline Qt Quick Timeline for MinGW 7.3.0 32-bit 2019-12-11 35.3K 154.1K \n"
|
|
"qtscript Qt Script for MinGW 7.3.0 32-bit 2019-12-11 1.0M 5.5M \n"
|
|
"qtvirtualkeyboard Qt Virtual Keyboard for MinGW 7.3.0 32-bit 2019-12-11 2.1M 6.8M \n"
|
|
"qtwebglplugin Qt WebGL Streaming Plugin for MinGW 7.3.0 32-bit 2019-12-11 201.7K 1.0M \n"
|
|
)
|
|
LONG_MODULES_WIN_5140_80 = (
|
|
" Module Name Display Name \n"
|
|
"====================================================================\n"
|
|
"qtcharts Qt Charts for MinGW 7.3.0 32-bit \n"
|
|
"qtdatavis3d Qt Data Visualization for MinGW 7.3.0 32-bit \n"
|
|
"qtlottie Qt Lottie Animation for MinGW 7.3.0 32-bit \n"
|
|
"qtnetworkauth Qt Network Authorization for MinGW 7.3.0 32-bit \n"
|
|
"qtpurchasing Qt Purchasing for MinGW 7.3.0 32-bit \n"
|
|
"qtquick3d Qt Quick 3D for MinGW 7.3.0 32-bit \n"
|
|
"qtquicktimeline Qt Quick Timeline for MinGW 7.3.0 32-bit \n"
|
|
"qtscript Qt Script for MinGW 7.3.0 32-bit \n"
|
|
"qtvirtualkeyboard Qt Virtual Keyboard for MinGW 7.3.0 32-bit \n"
|
|
"qtwebglplugin Qt WebGL Streaming Plugin for MinGW 7.3.0 32-bit\n"
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"columns, use_cli, expect",
|
|
(
|
|
(120, False, LONG_MODULES_WIN_5140_120),
|
|
(80, False, LONG_MODULES_WIN_5140_80),
|
|
(120, True, LONG_MODULES_WIN_5140_120),
|
|
(80, True, LONG_MODULES_WIN_5140_80),
|
|
),
|
|
)
|
|
def test_show_list_long_qt_modules(capsys, monkeypatch, columns: int, use_cli: bool, expect: str):
|
|
update_xml = (Path(__file__).parent / "data" / "windows-5140-update.xml").read_text("utf-8")
|
|
monkeypatch.setattr(MetadataFactory, "fetch_http", lambda self, _: update_xml)
|
|
|
|
cli = Cli()
|
|
|
|
# Patching get_terminal_size prevents successful instantiation of Cli, so do it afterwards:
|
|
monkeypatch.setattr(shutil, "get_terminal_size", lambda fallback: os.terminal_size((columns, 24)))
|
|
|
|
if use_cli:
|
|
return_code = cli.run("list-qt windows desktop --long-modules 5.14.0 win32_mingw73".split())
|
|
assert return_code == 0
|
|
else:
|
|
meta = MetadataFactory(
|
|
ArchiveId("qt", "windows", "desktop"),
|
|
modules_query=ModulesQuery("5.14.0", "win32_mingw73"),
|
|
is_long_listing=True,
|
|
)
|
|
show_list(meta)
|
|
out, err = capsys.readouterr()
|
|
sys.stdout.write(out)
|
|
sys.stderr.write(err)
|
|
assert out == expect
|
|
|
|
|
|
def test_show_list_versions(monkeypatch, capsys):
|
|
_html = (Path(__file__).parent / "data" / "mac-desktop.html").read_text("utf-8")
|
|
monkeypatch.setattr(MetadataFactory, "fetch_http", lambda *args: _html)
|
|
|
|
expect_file = Path(__file__).parent / "data" / "mac-desktop-expect.json"
|
|
expected = "\n".join(json.loads(expect_file.read_text("utf-8"))["qt"]["qt"]) + "\n"
|
|
|
|
show_list(MetadataFactory(mac_qt))
|
|
out, err = capsys.readouterr()
|
|
assert out == expected
|
|
|
|
|
|
def test_show_list_tools(monkeypatch, capsys):
|
|
page = (Path(__file__).parent / "data" / "mac-desktop.html").read_text("utf-8")
|
|
monkeypatch.setattr(MetadataFactory, "fetch_http", lambda *args, **kwargs: page)
|
|
|
|
expect_file = Path(__file__).parent / "data" / "mac-desktop-expect.json"
|
|
expect = "\n".join(json.loads(expect_file.read_text("utf-8"))["tools"]) + "\n"
|
|
|
|
meta = MetadataFactory(ArchiveId("tools", "mac", "desktop"))
|
|
show_list(meta)
|
|
out, err = capsys.readouterr()
|
|
sys.stdout.write(out)
|
|
sys.stderr.write(err)
|
|
assert out == expect
|
|
|
|
|
|
def test_show_list_empty(monkeypatch, capsys):
|
|
monkeypatch.setattr(MetadataFactory, "getList", lambda self: [])
|
|
meta = MetadataFactory(ArchiveId("tools", "mac", "desktop"))
|
|
with pytest.raises(EmptyMetadata) as error:
|
|
show_list(meta)
|
|
assert error.type == EmptyMetadata
|
|
assert format(error.value) == "No tools available for this request."
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"exception_class, error_msg, source",
|
|
(
|
|
(ArchiveConnectionError, "Failure to connect to some url", "aqt.metadata.getUrl"),
|
|
(ArchiveDownloadError, "Failure to download some xml file", "aqt.metadata.getUrl"),
|
|
),
|
|
)
|
|
def test_show_list_bad_connection(monkeypatch, capsys, exception_class, error_msg, source):
|
|
def mock(*args, **kwargs):
|
|
raise exception_class(error_msg)
|
|
|
|
monkeypatch.setattr(source, mock)
|
|
meta = MetadataFactory(mac_qt, spec=SimpleSpec("<5.9"))
|
|
with pytest.raises(exception_class) as error:
|
|
show_list(meta)
|
|
assert error.type == exception_class
|
|
assert format(error.value) == (
|
|
f"{error_msg}\n"
|
|
"==============================Suggested follow-up:==============================\n"
|
|
"* Please use 'aqt list-qt mac desktop' to check that versions of qt exist within the spec '<5.9'."
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"exception_class, error_msg, source", ((ArchiveConnectionError, "Failure to connect", "aqt.helper.getUrl"),)
|
|
)
|
|
def test_show_list_bad_connection_for_checksum(monkeypatch, capsys, exception_class, error_msg, source):
|
|
def mock(*args, **kwargs):
|
|
raise exception_class(error_msg)
|
|
|
|
monkeypatch.setattr(source, mock)
|
|
|
|
cli = Cli()
|
|
cli.run("list-qt linux desktop --arch 6.4.0".split())
|
|
out, err = capsys.readouterr()
|
|
sys.stdout.write(out)
|
|
sys.stderr.write(err)
|
|
|
|
assert (
|
|
err == "ERROR : Failed to download checksum for the file 'Updates.xml' from mirrors "
|
|
"'['https://download.qt.io']\n"
|
|
"==============================Suggested follow-up:==============================\n"
|
|
"* Check your internet connection\n"
|
|
"* Consider modifying `requests.max_retries_to_retrieve_hash` in settings.ini\n"
|
|
"* Consider modifying `mirrors.trusted_mirrors` in settings.ini "
|
|
"(see https://aqtinstall.readthedocs.io/en/stable/configuration.html#configuration)\n"
|
|
"* Please use 'aqt list-qt linux desktop' to show versions of Qt available.\n"
|
|
)
|
|
|
|
|
|
def fetch_expected_tooldata(json_filename: str) -> ToolData:
|
|
text = (Path(__file__).parent / "data" / json_filename).read_text("utf-8")
|
|
raw_tooldata: List[List[str]] = json.loads(text)["long_listing"]
|
|
keys = ("Version", "ReleaseDate", "DisplayName", "Description")
|
|
|
|
tools: Dict[str, Dict[str, str]] = {}
|
|
for variant_name, *values in raw_tooldata:
|
|
assert len(keys) == len(values)
|
|
tools[variant_name] = {k: v for k, v in zip(keys, values)}
|
|
|
|
return ToolData(tools)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"host, target, tool_name",
|
|
(
|
|
("mac", "desktop", "tools_cmake"),
|
|
("mac", "desktop", "sdktool"),
|
|
),
|
|
)
|
|
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_") or folder in ["sdktool"]
|
|
return xmltext
|
|
|
|
monkeypatch.setattr(MetadataFactory, "fetch_http", _mock_fetch_http)
|
|
|
|
cli = Cli()
|
|
cli.run(["list-tool", host, target])
|
|
out, err = capsys.readouterr()
|
|
assert not err
|
|
output_set = set(out.strip().split())
|
|
assert output_set == expected_tools
|
|
|
|
cli.run(["list-tool", host, target, tool_name])
|
|
out, err = capsys.readouterr()
|
|
assert not err
|
|
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_") or tool_name in ["sdktool"]
|
|
short_tool_name = tool_name[6:] if tool_name.startswith("tools_") else tool_name
|
|
cli.run(["list-tool", host, target, short_tool_name])
|
|
out, err = capsys.readouterr()
|
|
assert not err
|
|
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()
|
|
assert not err
|
|
|
|
expected_tooldata = format(fetch_expected_tooldata(xml_expect))
|
|
assert out.strip() == expected_tooldata.strip()
|
|
|
|
|
|
def test_fetch_http_ok(monkeypatch):
|
|
html_content = b"some_html_content"
|
|
base_url = "https://alt.baseurl.com"
|
|
|
|
def mock_getUrl(url: str, *args, **kwargs) -> str:
|
|
assert url.startswith(base_url)
|
|
return str(html_content)
|
|
|
|
monkeypatch.setattr("aqt.metadata.get_hash", lambda *args, **kwargs: hashlib.sha256(html_content).hexdigest())
|
|
monkeypatch.setattr("aqt.metadata.getUrl", mock_getUrl)
|
|
assert MetadataFactory(mac_qt, base_url=base_url).fetch_http("some_url") == str(html_content)
|
|
|
|
|
|
def test_fetch_http_failover(monkeypatch):
|
|
urls_requested = set()
|
|
|
|
def _mock(url, **kwargs):
|
|
urls_requested.add(url)
|
|
if len(urls_requested) <= 1:
|
|
raise ArchiveDownloadError()
|
|
return "some_html_content"
|
|
|
|
monkeypatch.setattr("aqt.metadata.get_hash", lambda *args, **kwargs: hashlib.sha256(b"some_html_content").hexdigest())
|
|
monkeypatch.setattr("aqt.metadata.getUrl", _mock)
|
|
|
|
# Require that the first attempt failed, but the second did not
|
|
assert MetadataFactory(mac_qt).fetch_http("some_url") == "some_html_content"
|
|
assert len(urls_requested) == 2
|
|
|
|
|
|
@pytest.mark.parametrize("exception_on_error", (ArchiveDownloadError, ArchiveConnectionError))
|
|
def test_fetch_http_download_error(monkeypatch, exception_on_error):
|
|
urls_requested = set()
|
|
|
|
def _mock(url, **kwargs):
|
|
urls_requested.add(url)
|
|
raise exception_on_error()
|
|
|
|
monkeypatch.setattr("aqt.metadata.get_hash", lambda *args, **kwargs: hashlib.sha256(b"some_html_content").hexdigest())
|
|
monkeypatch.setattr("aqt.metadata.getUrl", _mock)
|
|
with pytest.raises(exception_on_error) as e:
|
|
MetadataFactory(mac_qt).fetch_http("some_url")
|
|
assert e.type == exception_on_error
|
|
|
|
# Require that a fallback url was tried
|
|
assert len(urls_requested) == 2
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"host, expected, all_arches",
|
|
(
|
|
("windows", "win32_mingw", ["win64_msvc2013_64", "win32_mingw", "win16_mingw"]),
|
|
("windows", "win32_mingw", ["win64_msvc2013_64", "win32_mingw"]),
|
|
("windows", "win1_mingw0", ["win64_msvc2013_64", "win_mingw900", "win1_mingw0"]),
|
|
("windows", "win32_mingw1", ["win64_msvc2013_64", "win32_mingw", "win32_mingw1"]),
|
|
("windows", "win64_mingw", ["win64_msvc2013_64", "win32_mingw900", "win64_mingw"]),
|
|
("windows", "win64_mingw81", ["win64_msvc2013_64", "win64_mingw81", "win64_mingw"]),
|
|
("windows", "win64_mingw73", ["win64_msvc2013_64", "win64_mingw53", "win64_mingw73"]),
|
|
("windows", "win64_mingw", ["win64_msvc2013_64", "win64_mingw", "win64_mingw"]),
|
|
("windows", EmptyMetadata(), []),
|
|
("linux", "gcc_64", ["should not fetch arches"]),
|
|
("mac", "clang_64", ["should not fetch arches"]),
|
|
),
|
|
)
|
|
def test_select_default_mingw(monkeypatch, host: str, expected: Union[str, Exception], all_arches: List[str]):
|
|
monkeypatch.setattr("aqt.metadata.MetadataFactory.fetch_arches", lambda *args, **kwargs: all_arches)
|
|
|
|
if isinstance(expected, Exception):
|
|
with pytest.raises(type(expected)) as e:
|
|
MetadataFactory(ArchiveId("qt", host, "desktop")).fetch_default_desktop_arch(Version("1.2.3"))
|
|
assert e.type == type(expected)
|
|
else:
|
|
actual_arch = MetadataFactory(ArchiveId("qt", host, "desktop")).fetch_default_desktop_arch(Version("1.2.3"))
|
|
assert actual_arch == expected
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"expected_result, installed_files",
|
|
(
|
|
("mingw73_32", ["mingw73_32/bin/qmake.exe", "msvc2017/bin/qmake.exe"]),
|
|
(None, ["msvc2017/bin/qmake.exe"]),
|
|
(None, ["mingw73_win/bin/qmake.exe"]), # Bad directory: mingw73_win does not fit the mingw naming convention
|
|
(None, ["mingw73_32/bin/qmake", "msvc2017/bin/qmake.exe"]),
|
|
("mingw81_32", ["mingw73_32/bin/qmake.exe", "mingw81_32/bin/qmake.exe"]),
|
|
("mingw73_64", ["mingw73_64/bin/qmake.exe", "mingw73_32/bin/qmake.exe"]),
|
|
),
|
|
)
|
|
def test_find_installed_qt_mingw_dir(expected_result: str, installed_files: List[str]):
|
|
qt_ver = "6.3.0"
|
|
host = "windows"
|
|
|
|
# Setup a mock install directory that includes some installed files
|
|
with TemporaryDirectory() as base_dir:
|
|
base_path = Path(base_dir)
|
|
for file in installed_files:
|
|
path = base_path / qt_ver / file
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
path.write_text("Mock installed file")
|
|
|
|
actual_result = QtRepoProperty.find_installed_desktop_qt_dir(host, base_path, Version(qt_ver))
|
|
assert (actual_result.name if actual_result else None) == expected_result
|