"""Tests for the query parser, including the required @maintainer syntax.""" from __future__ import annotations from sjaur.query import OPERATORS, SearchQuery, parse_query def test_plain_query(): query = parse_query("firefox") assert query.text == "firefox" assert query.maintainer is None assert query.filters == () def test_maintainer_only(): query = parse_query("@max_musterman") assert query.maintainer == "max_musterman" assert query.text == "" def test_maintainer_with_package_query(): query = parse_query("@max_musterman firefox") assert query.maintainer == "max_musterman" assert query.text == "firefox" def test_only_first_word_is_maintainer_query(): query = parse_query("@john python editor") assert query.maintainer == "john" assert query.text == "python editor" def test_separated_operator_token(): query = parse_query("@ john firefox") assert query.maintainer == "john" assert query.text == "firefox" def test_multiple_at_tokens_uses_first(): query = parse_query("@alice @bob firefox") assert query.maintainer == "alice" assert query.text == "firefox" def test_separated_operator_alone_takes_next_word(): # "@ word" behaves like "@word": the next token is the maintainer query. query = parse_query("@ firefox") assert query.maintainer == "firefox" assert query.text == "" def test_trailing_operator_without_value_is_ignored(): query = parse_query("firefox @") assert query.maintainer is None assert query.text == "firefox" def test_at_inside_word_is_not_an_operator(): query = parse_query("user@example.com") assert query.maintainer is None assert query.text == "user@example.com" def test_empty_query(): query = parse_query("") assert query == SearchQuery() def test_whitespace_is_normalized(): query = parse_query(" firefox nightly ") assert query.text == "firefox nightly" def test_operator_registry_is_extensible(): # Future operators must only need a table entry plus a SearchQuery field. assert "@" in OPERATORS assert OPERATORS["@"] == "maintainer"