• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

miurahr / aqtinstall / 6152502796

11 Sep 2023 10:35PM UTC coverage: 94.143% (+0.2%) from 93.946%
6152502796

push

github

web-flow
Merge pull request #705 from ddalcino/topic/ddalcino/cli/warn-ext7zr

Log a warning when aqtinstall falls back to an external 7z extraction tool

1133 of 1226 branches covered (0.0%)

Branch coverage included in aggregate %.

54 of 54 new or added lines in 2 files covered. (100.0%)

3464 of 3657 relevant lines covered (94.72%)

0.95 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.47
/tests/test_cli.py
1
import re
1✔
2
import sys
1✔
3
from pathlib import Path
1✔
4
from tempfile import TemporaryDirectory
1✔
5
from typing import Dict, List, Optional
1✔
6

7
import pytest
1✔
8

9
from aqt.exceptions import CliInputError
1✔
10
from aqt.helper import Settings
1✔
11
from aqt.installer import Cli
1✔
12
from aqt.metadata import MetadataFactory, SimpleSpec, Version
1✔
13

14

15
def expected_help(actual, prefix=None):
1✔
16
    expected = (
1✔
17
        "usage: aqt [-h] [-c CONFIG]\n"
18
        "           {install-qt,install-tool,install-doc,install-example,install-src,"
19
        "list-qt,list-tool,list-doc,list-example,list-src,"
20
        "install,tool,doc,examples,src,help,version}\n"
21
        "           ...\n"
22
        "\n"
23
        "Another unofficial Qt Installer.\n"
24
        "aqt helps you install Qt SDK, tools, examples and others\n"
25
        "\n"
26
        "option",
27
        "  -h, --help            show this help message and exit\n"
28
        "  -c CONFIG, --config CONFIG\n"
29
        "                        Configuration ini file.\n"
30
        "\n"
31
        "subcommands:\n"
32
        "  aqt accepts several subcommands:\n"
33
        "  install-* subcommands are commands that install components\n"
34
        "  list-* subcommands are commands that show available components\n"
35
        "  \n"
36
        "  commands {install|tool|src|examples|doc} are deprecated and marked for "
37
        "removal\n"
38
        "\n"
39
        "  {install-qt,install-tool,install-doc,install-example,install-src,list-qt,"
40
        "list-tool,list-doc,list-example,list-src,"
41
        "install,tool,doc,examples,src,help,version}\n"
42
        "                        Please refer to each help message by using '--help' "
43
        "with each subcommand\n",
44
    )
45
    if prefix is not None:
1!
46
        return actual.startswith(prefix + expected[0]) and actual.endswith(expected[1])
×
47
    return actual.startswith(expected[0]) and actual.endswith(expected[1])
1✔
48

49

50
def test_cli_help(capsys):
1✔
51
    cli = Cli()
1✔
52
    cli.run(["help"])
1✔
53
    out, err = capsys.readouterr()
1✔
54
    assert expected_help(out)
1✔
55

56

57
@pytest.mark.parametrize(
1✔
58
    "qt_version, modules, unexpected_modules",
59
    (
60
        ("5.11.3", ["qtcharts", "qtwebengine"], []),
61
        ("5.11.3", ["not_exist"], ["not_exist"]),
62
        ("5.11.3", ["qtcharts", "qtwebengine", "not_exist"], ["not_exist"]),
63
        ("5.11.3", None, []),
64
        ("5.15.0", ["Unknown"], ["Unknown"]),
65
    ),
66
)
67
def test_cli_select_unexpected_modules(qt_version: str, modules: Optional[List[str]], unexpected_modules: List[str]):
1✔
68
    cli = Cli()
1✔
69
    cli._setup_settings()
1✔
70
    assert cli._select_unexpected_modules(qt_version, modules) == unexpected_modules
1✔
71

72
    nonexistent_qt = "5.16.0"
1✔
73
    assert cli._select_unexpected_modules(nonexistent_qt, modules) == sorted(modules or [])
1✔
74

75

76
def test_cli_check_combination():
1✔
77
    cli = Cli()
1✔
78
    cli._setup_settings()
1✔
79
    assert cli._check_qt_arg_combination("5.11.3", "linux", "desktop", "gcc_64")
1✔
80
    assert cli._check_qt_arg_combination("5.11.3", "mac", "desktop", "clang_64")
1✔
81
    assert not cli._check_qt_arg_combination("5.14.0", "android", "desktop", "clang_64")
1✔
82

83

84
def test_cli_check_version():
1✔
85
    cli = Cli()
1✔
86
    cli._setup_settings()
1✔
87
    assert cli._check_qt_arg_versions("5.12.0")
1✔
88
    assert not cli._check_qt_arg_versions("5.12")
1✔
89

90

91
@pytest.mark.parametrize(
1✔
92
    "host, target, arch, version_or_spec, expected_version, is_bad_spec",
93
    (
94
        ("windows", "desktop", "wasm_32", "6.1", None, False),
95
        ("windows", "desktop", "wasm_32", "5.12", None, False),
96
        ("windows", "desktop", "wasm_32", "5.13", Version("5.13.2"), False),
97
        ("windows", "desktop", "wasm_32", "5", Version("5.15.2"), False),
98
        ("windows", "desktop", "wasm_32", "<5.14.5", Version("5.14.2"), False),
99
        ("windows", "desktop", "mingw32", "6.0", Version("6.0.3"), False),
100
        ("windows", "winrt", "mingw32", "6", None, False),
101
        ("windows", "winrt", "mingw32", "bad spec", None, True),
102
        ("windows", "android", "android_x86", "6", Version("6.1.0"), False),
103
        ("windows", "desktop", "android_x86", "6", Version("6.5.0"), False),  # does not validate arch
104
        ("windows", "desktop", "android_fake", "6", Version("6.5.0"), False),  # does not validate arch
105
    ),
106
)
107
def test_cli_determine_qt_version(
1✔
108
    monkeypatch, host, target, arch, version_or_spec: str, expected_version: Version, is_bad_spec: bool
109
):
110
    _html = (Path(__file__).parent / "data" / f"{host}-{target}.html").read_text("utf-8")
1✔
111
    monkeypatch.setattr(MetadataFactory, "fetch_http", lambda *args, **kwargs: _html)
1✔
112
    cli = Cli()
1✔
113
    cli._setup_settings()
1✔
114

115
    if is_bad_spec:
1✔
116
        with pytest.raises(CliInputError) as e:
1✔
117
            Cli._determine_qt_version(version_or_spec, host, target, arch)
1✔
118
        assert e.type == CliInputError
1✔
119
        assert format(e.value) == f"Invalid version or SimpleSpec: '{version_or_spec}'\n" + SimpleSpec.usage()
1✔
120
    elif not expected_version:
1✔
121
        with pytest.raises(CliInputError) as e:
1✔
122
            Cli._determine_qt_version(version_or_spec, host, target, arch)
1✔
123
        assert e.type == CliInputError
1✔
124
        expect_msg = f"No versions of Qt exist for spec={version_or_spec} with host={host}, target={target}, arch={arch}"
1✔
125
        actual_msg = format(e.value)
1✔
126
        assert actual_msg == expect_msg
1✔
127
    else:
128
        ver = Cli._determine_qt_version(version_or_spec, host, target, arch)
1✔
129
        assert ver == expected_version
1✔
130

131

132
@pytest.mark.parametrize(
1✔
133
    "invalid_version",
134
    ("5.15", "five-dot-fifteen", "5", "5.5.5.5"),
135
)
136
def test_cli_invalid_version(capsys, invalid_version):
1✔
137
    """Checks that invalid version strings are handled properly"""
138

139
    # Ensure that invalid_version cannot be a semantic_version.Version
140
    with pytest.raises(ValueError):
1✔
141
        Version(invalid_version)
1✔
142

143
    cli = Cli()
1✔
144
    cli._setup_settings()
1✔
145

146
    matcher = re.compile(
1✔
147
        r"^INFO    : aqtinstall\(aqt\) v.* on Python 3.*\n"
148
        r"(.*\n)*"
149
        r"ERROR   :.*Invalid version: '" + invalid_version + r"'! Please use the form '5\.X\.Y'\.\n.*"
150
    )
151

152
    for cmd in (
1✔
153
        ("install", invalid_version, "mac", "desktop"),
154
        ("doc", invalid_version, "mac", "desktop"),
155
        ("list-qt", "mac", "desktop", "--arch", invalid_version),
156
    ):
157
        cli = Cli()
1✔
158
        assert cli.run(cmd) == 1
1✔
159
        out, err = capsys.readouterr()
1✔
160
        sys.stdout.write(out)
1✔
161
        sys.stderr.write(err)
1✔
162
        assert matcher.match(err)
1✔
163

164

165
@pytest.mark.parametrize(
1✔
166
    "version, allow_latest, allow_empty, allow_minus, expect_ok",
167
    (
168
        ("1.2.3", False, False, False, True),
169
        ("1.2.", False, False, False, False),
170
        ("latest", True, False, False, True),
171
        ("latest", False, False, False, False),
172
        ("", False, True, False, True),
173
        ("", False, False, False, False),
174
        ("1.2.3-0-123", False, False, True, True),
175
        ("1.2.3-0-123", False, False, False, False),
176
    ),
177
)
178
def test_cli_validate_version(version: str, allow_latest: bool, allow_empty: bool, allow_minus: bool, expect_ok: bool):
1✔
179
    if expect_ok:
1✔
180
        Cli._validate_version_str(version, allow_latest=allow_latest, allow_empty=allow_empty, allow_minus=allow_minus)
1✔
181
    else:
182
        with pytest.raises(CliInputError) as err:
1✔
183
            Cli._validate_version_str(version, allow_latest=allow_latest, allow_empty=allow_empty, allow_minus=allow_minus)
1✔
184
        assert err.type == CliInputError
1✔
185

186

187
def test_cli_check_mirror():
1✔
188
    cli = Cli()
1✔
189
    cli._setup_settings()
1✔
190
    assert cli._check_mirror(None)
1✔
191
    arg = ["install-qt", "linux", "desktop", "5.11.3", "-b", "https://download.qt.io/"]
1✔
192
    args = cli.parser.parse_args(arg)
1✔
193
    assert args.base == "https://download.qt.io/"
1✔
194
    assert cli._check_mirror(args.base)
1✔
195

196

197
@pytest.mark.parametrize(
1✔
198
    "arch, host, target, version, expect",
199
    (
200
        ("impossible_arch", "windows", "desktop", "6.2.0", "impossible_arch"),
201
        ("", "windows", "desktop", "6.2.0", None),
202
        (None, "windows", "desktop", "6.2.0", None),
203
        (None, "linux", "desktop", "6.2.0", "gcc_64"),
204
        (None, "mac", "desktop", "6.2.0", "clang_64"),
205
        (None, "mac", "ios", "6.2.0", "ios"),
206
        (None, "mac", "android", "6.2.0", "android"),
207
        (None, "mac", "android", "5.12.0", None),
208
        # SimpleSpec instead of Version
209
        ("impossible_arch", "windows", "desktop", "6.2", "impossible_arch"),
210
        ("", "windows", "desktop", "6.2", None),
211
        (None, "windows", "desktop", "6.2", None),
212
        (None, "linux", "desktop", "6.2", "gcc_64"),
213
        (None, "mac", "desktop", "6.2", "clang_64"),
214
        (None, "mac", "ios", "6.2", "ios"),
215
        (None, "mac", "android", "6.2", None),  # No way to determine arch for android target w/o version
216
    ),
217
)
218
def test_set_arch(arch: Optional[str], host: str, target: str, version: str, expect: Optional[str]):
1✔
219
    if not expect:
1✔
220
        with pytest.raises(CliInputError) as e:
1✔
221
            Cli._set_arch(arch, host, target, version)
1✔
222
        assert e.type == CliInputError
1✔
223
        assert format(e.value) == "Please supply a target architecture."
1✔
224
        assert e.value.should_show_help is True
1✔
225
    else:
226
        assert Cli._set_arch(arch, host, target, version) == expect
1✔
227

228

229
@pytest.mark.parametrize(
1✔
230
    "cmd, expect_msg, should_show_help",
231
    (
232
        (
233
            "install-qt mac ios 6.2.0 --base not_a_url",
234
            "The `--base` option requires a url where the path `online/qtsdkrepository` exists.",
235
            True,
236
        ),
237
        (
238
            "install-qt mac ios 6.2.0 --noarchives",
239
            "When `--noarchives` is set, the `--modules` option is mandatory.",
240
            False,
241
        ),
242
        (
243
            "install-qt mac ios 6.2.0 --noarchives --archives",
244
            "When `--noarchives` is set, the `--modules` option is mandatory.",
245
            False,
246
        ),
247
        (
248
            "install-qt mac ios 6.2.0 --noarchives --archives --modules qtcharts",
249
            "Options `--archives` and `--noarchives` are mutually exclusive.",
250
            False,
251
        ),
252
        (
253
            "install-src mac ios 6.2.0 --kde",
254
            "KDE patch: unsupported version!!",
255
            False,
256
        ),
257
    ),
258
)
259
def test_cli_input_errors(capsys, cmd, expect_msg, should_show_help):
1✔
260
    cli = Cli()
1✔
261
    cli._setup_settings()
1✔
262
    assert 1 == cli.run(cmd.split())
1✔
263
    out, err = capsys.readouterr()
1✔
264
    if should_show_help:
1✔
265
        assert expected_help(out)
1✔
266
    else:
267
        assert out == ""
1✔
268
    assert err.rstrip().endswith(expect_msg)
1✔
269

270

271
# These commands use the new syntax with the legacy commands
272
@pytest.mark.parametrize(
1✔
273
    "cmd",
274
    (
275
        "install linux desktop 5.10.0",
276
        "install linux desktop 5.10.0 gcc_64",
277
        "src linux desktop 5.10.0",
278
        "doc linux desktop 5.10.0",
279
        "example linux desktop 5.10.0",
280
        "tool windows desktop tools_ifw",
281
    ),
282
)
283
def test_cli_legacy_commands_with_wrong_syntax(cmd):
1✔
284
    cli = Cli()
1✔
285
    cli._setup_settings()
1✔
286
    with pytest.raises(SystemExit) as e:
1✔
287
        cli.run(cmd.split())
1✔
288
    assert e.type == SystemExit
1✔
289

290

291
@pytest.mark.parametrize(
1✔
292
    "cmd",
293
    (
294
        "tool windows desktop tools_ifw qt.tools.ifw.31",  # New syntax
295
        "tool windows desktop tools_ifw 1.2.3",
296
    ),
297
)
298
def test_cli_legacy_tool_new_syntax(monkeypatch, capsys, cmd):
1✔
299
    # These incorrect commands cannot be filtered out directly by argparse because
300
    # they have the correct number of arguments.
301
    command = cmd.split()
1✔
302

303
    expected = (
1✔
304
        "WARNING : The command 'tool' is deprecated and marked for removal in a future version of aqt.\n"
305
        "In the future, please use the command 'install-tool' instead.\n"
306
        "ERROR   : Invalid version: 'tools_ifw'! Please use the form '5.X.Y'.\n"
307
    )
308

309
    cli = Cli()
1✔
310
    cli._setup_settings()
1✔
311
    assert 1 == cli.run(command)
1✔
312
    out, err = capsys.readouterr()
1✔
313
    actual = err[err.index("\n") + 1 :]
1✔
314
    assert actual == expected
1✔
315

316

317
@pytest.mark.parametrize(
1✔
318
    "cmd, expect_err",
319
    (
320
        (
321
            "list-qt mac --extension wasm",
322
            "WARNING : The parameter 'extension' with value 'wasm' is deprecated "
323
            "and marked for removal in a future version of aqt.\n"
324
            "In the future, please omit this parameter.\n"
325
            "WARNING : The '--extension' flag will be ignored.\n",
326
        ),
327
        (
328
            "list-qt mac desktop --extensions 6.2.0",
329
            "WARNING : The parameter 'extensions' with value '6.2.0' is deprecated "
330
            "and marked for removal in a future version of aqt.\n"
331
            "In the future, please omit this parameter.\n"
332
            "WARNING : The '--extensions' flag will always return an empty list, "
333
            "because there are no useful arguments for the '--extension' flag.\n",
334
        ),
335
    ),
336
)
337
def test_cli_list_qt_deprecated_flags(capsys, cmd: str, expect_err: str):
1✔
338
    cli = Cli()
1✔
339
    cli._setup_settings()
1✔
340
    assert 0 == cli.run(cmd.split())
1✔
341
    out, err = capsys.readouterr()
1✔
342
    assert err == expect_err
1✔
343

344

345
# These commands come directly from examples in the legacy documentation
346
@pytest.mark.parametrize(
1✔
347
    "cmd",
348
    (
349
        "install 5.10.0 linux desktop",  # default arch
350
        "install 5.10.2 linux android android_armv7",
351
        "src 5.15.2 windows desktop --archives qtbase --kde",
352
        "doc 5.15.2 windows desktop -m qtcharts qtnetworkauth",
353
        "examples 5.15.2 windows desktop -m qtcharts qtnetworkauth",
354
        "tool linux tools_ifw 4.0 qt.tools.ifw.40",
355
    ),
356
)
357
def test_cli_legacy_commands_with_correct_syntax(monkeypatch, cmd):
1✔
358
    # Pretend to install correctly when any command is run
359
    for func in ("run_install_qt", "run_install_src", "run_install_doc", "run_install_example", "run_install_tool"):
1✔
360
        monkeypatch.setattr(Cli, func, lambda *args, **kwargs: 0)
1✔
361

362
    cli = Cli()
1✔
363
    cli._setup_settings()
1✔
364
    assert 0 == cli.run(cmd.split())
1✔
365

366

367
def test_cli_unexpected_error(monkeypatch, capsys):
1✔
368
    def _mocked_run(*args):
1✔
369
        raise RuntimeError("Some unexpected error")
1✔
370

371
    monkeypatch.setattr("aqt.installer.Cli.run_install_qt", _mocked_run)
1✔
372

373
    cli = Cli()
1✔
374
    cli._setup_settings()
1✔
375
    assert Cli.UNHANDLED_EXCEPTION_CODE == cli.run(["install-qt", "mac", "ios", "6.2.0"])
1✔
376
    out, err = capsys.readouterr()
1✔
377
    assert err.startswith("ERROR   : Some unexpected error")
1✔
378
    assert err.rstrip().endswith(
1✔
379
        "===========================PLEASE FILE A BUG REPORT===========================\n"
380
        "You have discovered a bug in aqt.\n"
381
        "Please file a bug report at https://github.com/miurahr/aqtinstall/issues\n"
382
        "Please remember to include a copy of this program's output in your report."
383
    )
384

385

386
@pytest.mark.parametrize("external_tool_exists", (True, False))
1✔
387
def test_set_7zip_checks_external_tool_when_specified(monkeypatch, capsys, external_tool_exists: bool):
1✔
388
    cli = Cli()
1✔
389
    cli._setup_settings()
1✔
390
    external = "my_7z_extractor"
1✔
391

392
    def mock_subprocess_run(args, **kwargs):
1✔
393
        assert args[0] == external
1✔
394
        if not external_tool_exists:
1✔
395
            raise FileNotFoundError()
1✔
396

397
    monkeypatch.setattr("aqt.installer.subprocess.run", mock_subprocess_run)
1✔
398
    monkeypatch.setattr("aqt.installer.EXT7Z", False)
1✔
399
    if external_tool_exists:
1✔
400
        assert external == cli._set_sevenzip(external)
1✔
401
    else:
402
        with pytest.raises(CliInputError) as err:
1✔
403
            cli._set_sevenzip(external)
1✔
404
        assert format(err.value) == format(f"Specified 7zip command executable does not exist: '{external}'")
1✔
405
    assert capsys.readouterr()[1] == ""
1✔
406

407

408
@pytest.mark.parametrize("fallback_exists", (True, False))
1✔
409
def test_set_7zip_uses_fallback_when_py7zr_missing(monkeypatch, capsys, fallback_exists: bool):
1✔
410
    cli = Cli()
1✔
411
    cli._setup_settings()
1✔
412
    external, fallback = None, Settings.zipcmd
1✔
413

414
    def mock_subprocess_run(args, **kwargs):
1✔
415
        assert args[0] == fallback
1✔
416
        if not fallback_exists:
1✔
417
            raise FileNotFoundError()
1✔
418

419
    monkeypatch.setattr("aqt.installer.subprocess.run", mock_subprocess_run)
1✔
420
    monkeypatch.setattr("aqt.installer.EXT7Z", True)
1✔
421
    if fallback_exists:
1✔
422
        assert fallback == cli._set_sevenzip(external)
1✔
423
    else:
424
        with pytest.raises(CliInputError) as err:
1✔
425
            cli._set_sevenzip(external)
1✔
426
        assert format(err.value) == format(f"Fallback 7zip command executable does not exist: '{fallback}'")
1✔
427
    assert f"Falling back to '{fallback}'" in capsys.readouterr()[1]
1✔
428

429

430
@pytest.mark.parametrize("fallback_exists", (True, False))
1✔
431
def test_set_7zip_chooses_p7zr_when_ext_missing(monkeypatch, capsys, fallback_exists: bool):
1✔
432
    cli = Cli()
1✔
433
    cli._setup_settings()
1✔
434
    external = None
1✔
435

436
    def mock_subprocess_run(args, **kwargs):
1✔
437
        assert False, "Should not try to run anything"
×
438

439
    monkeypatch.setattr("aqt.installer.subprocess.run", mock_subprocess_run)
1✔
440
    monkeypatch.setattr("aqt.installer.EXT7Z", False)
1✔
441
    assert cli._set_sevenzip(external) is None
1✔
442
    assert capsys.readouterr()[1] == ""
1✔
443

444

445
@pytest.mark.parametrize(
1✔
446
    "archive_dest, keep, temp_dir, expect, should_make_dir",
447
    (
448
        (None, False, "temp", "temp", False),
449
        (None, True, "temp", ".", False),
450
        ("my_archives", False, "temp", "my_archives", True),
451
        ("my_archives", True, "temp", "my_archives", True),
452
    ),
453
)
454
def test_cli_choose_archive_dest(
1✔
455
    monkeypatch, archive_dest: Optional[str], keep: bool, temp_dir: str, expect: str, should_make_dir: bool
456
):
457
    enclosed = {"made_dir": False}
1✔
458

459
    def mock_mkdir(*args, **kwargs):
1✔
460
        enclosed["made_dir"] = True
1✔
461

462
    monkeypatch.setattr("aqt.installer.Path.mkdir", mock_mkdir)
1✔
463

464
    assert Cli.choose_archive_dest(archive_dest, keep, temp_dir) == Path(expect)
1✔
465
    assert enclosed["made_dir"] == should_make_dir
1✔
466

467

468
@pytest.mark.parametrize(
1✔
469
    "host, target, arch, is_auto, mocked_arches, existing_arch_dirs, expect",
470
    (
471
        (  # not installed
472
            "windows",
473
            "android",
474
            "android_armv7",
475
            False,
476
            ["win64_mingw99"],
477
            ["not_mingw"],
478
            {"install": None, "instruct": "win64_mingw99", "use_dir": "mingw99_64"},
479
        ),
480
        (  # Alt Desktop Qt already installed
481
            "windows",
482
            "android",
483
            "android_armv7",
484
            False,
485
            ["win64_mingw99"],
486
            ["mingw128_32"],
487
            {"install": None, "instruct": None, "use_dir": "mingw128_32"},
488
        ),
489
        # not installed
490
        (
491
            "linux",
492
            "android",
493
            "android_armv7",
494
            False,
495
            [],
496
            ["gcc_32"],
497
            {"install": None, "instruct": "gcc_64", "use_dir": "gcc_64"},
498
        ),
499
        (  # Desktop Qt already installed
500
            "linux",
501
            "android",
502
            "android_armv7",
503
            False,
504
            [],
505
            ["gcc_64"],
506
            {"install": None, "instruct": None, "use_dir": "gcc_64"},
507
        ),
508
        (  # not installed
509
            "windows",
510
            "android",
511
            "android_armv7",
512
            True,
513
            ["win64_mingw99"],
514
            ["not_mingw"],
515
            {"install": "win64_mingw99", "instruct": None, "use_dir": "mingw99_64"},
516
        ),
517
        (  # Alt Desktop Qt already installed
518
            "windows",
519
            "android",
520
            "android_armv7",
521
            True,
522
            ["win64_mingw99"],
523
            ["mingw128_32"],
524
            {"install": None, "instruct": None, "use_dir": "mingw128_32"},
525
        ),
526
        # not installed
527
        (
528
            "linux",
529
            "android",
530
            "android_armv7",
531
            True,
532
            [],
533
            ["gcc_32"],
534
            {"install": "gcc_64", "instruct": None, "use_dir": "gcc_64"},
535
        ),
536
        (  # Desktop Qt already installed
537
            "linux",
538
            "android",
539
            "android_armv7",
540
            True,
541
            [],
542
            ["gcc_64"],
543
            {"install": None, "instruct": None, "use_dir": "gcc_64"},
544
        ),
545
        (  # MSVC arm64 with --autodesktop: should install min64_msvc2019_64
546
            "windows",
547
            "desktop",
548
            "win64_msvc2019_arm64",
549
            True,
550
            ["win64_mingw", "win64_msvc2019_64", "win64_msvc2019_arm64", "wasm_singlethread", "wasm_multithread"],
551
            ["mingw128_32"],
552
            {"install": "win64_msvc2019_64", "instruct": None, "use_dir": "msvc2019_64"},
553
        ),
554
        (  # MSVC arm64 without --autodesktop: should point to min64_msvc2019_64
555
            "windows",
556
            "desktop",
557
            "win64_msvc2019_arm64",
558
            False,
559
            ["win64_mingw", "win64_msvc2019_64", "win64_msvc2019_arm64", "wasm_singlethread", "wasm_multithread"],
560
            ["mingw128_32"],
561
            {"install": None, "instruct": "win64_msvc2019_64", "use_dir": "msvc2019_64"},
562
        ),
563
        (  # MSVC arm64 without --autodesktop, with correct target already installed
564
            "windows",
565
            "desktop",
566
            "win64_msvc2019_arm64",
567
            False,
568
            ["win64_mingw", "win64_msvc2019_64", "win64_msvc2019_arm64", "wasm_singlethread", "wasm_multithread"],
569
            ["msvc2019_64"],
570
            {"install": None, "instruct": None, "use_dir": "msvc2019_64"},
571
        ),
572
        (  # MSVC arm64 without --autodesktop, with wrong target already installed
573
            "windows",
574
            "desktop",
575
            "win64_msvc2019_arm64",
576
            False,
577
            ["win64_mingw", "win64_msvc2019_64", "win64_msvc2019_arm64", "wasm_singlethread", "wasm_multithread"],
578
            ["mingw128_32"],
579
            {"install": None, "instruct": "win64_msvc2019_64", "use_dir": "msvc2019_64"},
580
        ),
581
    ),
582
)
583
def test_get_autodesktop_dir_and_arch_non_android(
1✔
584
    monkeypatch,
585
    capsys,
586
    host: str,
587
    target: str,
588
    arch: str,
589
    is_auto: bool,
590
    mocked_arches: List[str],
591
    existing_arch_dirs: List[str],
592
    expect: Dict[str, str],
593
):
594
    """
595
    :is_auto:               Simulates passing `--autodesktop` to aqt
596
    :mocked_mingw:          When we ask MetadataFactory for a list of available architectures, we return this value
597
    :existing_arch_dirs:    Directories that contain an existing file at `arch_dir/bin/qmake`
598
    :expect[install]:       The archdir we expect aqt to install
599
    :expect[instruct]:      The architecture we expect aqt to ask the user to install
600
    :expect[use_dir]:       The directory that includes `bin/qmake`; we will patch files in the mobile installation
601
                            with this value
602
    """
603
    monkeypatch.setattr(MetadataFactory, "fetch_arches", lambda *args: mocked_arches)
1✔
604
    monkeypatch.setattr(Cli, "run", lambda *args: 0)
1!
605

606
    version = "6.2.3"
1✔
607
    cli = Cli()
1✔
608
    cli._setup_settings()
1✔
609

610
    flavor = "MSVC Arm64" if arch == "win64_msvc2019_arm64" else target
1✔
611
    expect_msg_prefix = (
1✔
612
        f"You are installing the {flavor} version of Qt, "
613
        f"which requires that the desktop version of Qt is also installed."
614
    )
615

616
    with TemporaryDirectory() as temp_dir:
1✔
617
        base_dir = Path(temp_dir)
1✔
618
        for arch_dir in existing_arch_dirs:
1✔
619
            qmake = base_dir / version / arch_dir / f"bin/qmake{'.exe' if host == 'windows' else ''}"
1✔
620
            qmake.parent.mkdir(parents=True)
1✔
621
            qmake.write_text("exe file")
1✔
622
        autodesktop_arch_dir, autodesktop_arch_to_install = cli._get_autodesktop_dir_and_arch(
1✔
623
            is_auto, host, target, base_dir, Version(version), arch
624
        )
625
        # It should choose the correct desktop arch directory for updates
626
        assert autodesktop_arch_dir == expect["use_dir"]
1✔
627

628
        out, err = capsys.readouterr()
1✔
629
        if expect["install"]:
1✔
630
            assert err.strip() == f"INFO    : {expect_msg_prefix} Now installing Qt: desktop {version} {expect['install']}"
1✔
631
        elif expect["instruct"]:
1✔
632
            assert (
1✔
633
                err.strip() == f"WARNING : {expect_msg_prefix} You can install it with the following command:\n"
634
                f"          `aqt install-qt {host} desktop {version} {expect['instruct']}`"
635
            )
636
        else:
637
            assert err.strip() == f"INFO    : Found installed {host}-desktop Qt at {base_dir / version / expect['use_dir']}"
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc