# Copyright Kevin Deldycke <[email protected]> and contributors.
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
from __future__ import annotations
import pytest
from extra_platforms.pytest import unless_macos
from meta_package_manager.pool import pool
from meta_package_manager.tables import SEARCH_COLUMNS
from .test_cli import CLITableTests, check_packages_payload
_MAS_UNICODE_SEARCH = (
'{"adamID":1435447041,"name":"้้ - AIๆถไปฃ็ๅทฅไฝๆนๅผ","version":"8.5.5"}\n'
'{"adamID":1189898970,"name":"WeCom-Business IM & Work Tools","version":"5.0.10"}\n'
)
"""A `mas search ้ --json` answer, captured on macOS against `mas` 7.0.0.
One JSON object per line, which is the stream shape
{meth}`~meta_package_manager.managers.mas.MAS._parse_json_stream` reads. The
second entry is kept so the highlighter has a non-matching row to leave alone.
"""
[docs]
@pytest.fixture
def subcmd():
# "excel" deterministically surfaces an upstream `mas` record whose
# `description` carries an unescaped U+0010 byte and two U+2028 line
# separators (`PDF to Excel OCR Converter`, adamID 1316315027). Searching
# for it gives real-world coverage of the parser workaround in
# `meta_package_manager.managers.mas._parse_json_stream`. Upstream bug:
# https://github.com/mas-cli/mas/issues/1248
return "search", "excel"
[docs]
class TestSearch(CLITableTests):
columns_registry = SEARCH_COLUMNS
[docs]
def test_description_column_selection(self, invoke, fake_pool):
"""The description column hides by default, and shows with `--description`.
An explicit `--columns` selection is authoritative either way.
"""
# Hidden by default.
result = invoke("search", "match-me", color=False)
assert result.exit_code == 0
assert "Description" not in result.stdout
# The --description shorthand adds the column.
result = invoke("--description", "search", "match-me", color=False)
assert result.exit_code == 0
assert "Description" in result.stdout
# An explicit --columns selection surfaces it without the shorthand...
result = invoke(
"search", "match-me", "--columns", "package_id,description", color=False
)
assert result.exit_code == 0
header = next(line for line in result.stdout.splitlines() if "โ" in line)
assert "Description" in header
assert "Manager" not in header
# ...and wins over the shorthand when it leaves the column out.
result = invoke(
"--description",
"search",
"match-me",
"--columns",
"package_id",
color=False,
)
assert result.exit_code == 0
assert "Description" not in result.stdout
[docs]
def test_json_parsing(self, invoke, subcmd):
result = invoke("--table-format", "json", subcmd)
check_packages_payload(result)
[docs]
@unless_macos
def test_unicode_search(self, invoke, monkeypatch):
"""Check `mpm` is accepting unicode as search query.
`mas` is the only manager we have that is accepting unicode characters for
its package names. We perform a search with it so we can prove `mpm` is
supporting it too:
```{code-block} shell-session
$ mpm --mas search ้
โญโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโฌโโโโโโโโโโโโโโโโโฎ
โ Package ID โ Name โ Manager โ Latest version โ
โโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโผโโโโโโโโโโโโโโโโโค
โ 1435447041 โ ้้ - ่ฎฉ่ฟๆญฅๅ็ โ mas โ 7.6.57 โ
โฐโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโดโโโโโโโโโโโโโโโโโฏ
```
Test originates from #16.
```{note}
The search answer is canned, so the assertions below run on every macOS
host instead of only a lucky one. `mas search` queries
`itunes.apple.com` over the network for every call, and an unreachable
API returns the same empty table as a query mpm mangled: asserting
through the live call reports a unicode bug whenever the host is
offline, firewalled or signed out of the App Store, which is why this
test used to be skipped on GitHub Actions. Only the search is canned,
every other call reaching the real binary, so `mas` still has to be
installed and answer its version probe for the selector to resolve it.
```
"""
mas = pool["mas"]
real_run_cli = mas.run_cli
def canned_search(*args, **kwargs):
if "search" in args:
return _MAS_UNICODE_SEARCH
return real_run_cli(*args, **kwargs)
monkeypatch.setattr(mas, "run_cli", canned_search)
result = invoke("--color", "--mas", "search", "้")
assert result.exit_code == 0
assert "้้" in result.stdout
# The match is emphasized with the theme's search style (green since
# click-extra 8.4.0, which dropped the bold).
assert " \x1b[32m้้\x1b[0m " in result.stdout
[docs]
def test_search_highlight(self, invoke):
"""We search on cargo as it is available on all platforms.
The search on the small `co` string is producing all variations of multiple
`co` substring matches and highlights.
"""
# `--verbosity INFO` keeps the selection narration in the captured
# stderr, so a failure names the reason cargo was dropped (probe
# failure, version parse, timeout) instead of a bare exit 2.
result = invoke("--color", "--cargo", "--verbosity", "INFO", "search", "co")
assert result.exit_code == 0, result.stderr
# crates.io intermittently throttles CI runners into empty search
# results: an empty table means there is nothing to highlight, not a
# highlighting bug.
data_rows = [
line for line in result.stdout.splitlines() if line.startswith("โ")
]
if len(data_rows) <= 1: # Header row only: the search came back empty.
pytest.skip("cargo search returned no results (registry throttling)")
# Check that the highlight ANSI sequence for "co" appears in the output.
# Cargo search results change over time, so we only verify that
# highlighting is applied, not which specific packages are returned.
# click-extra 7.19 dropped the bold code from theme().search, leaving
# the green color as the only highlight style.
highlight_pattern = "\x1b[32mco\x1b[0m"
assert highlight_pattern in result.stdout