Skip to content

Commit d9869c5

Browse files
committed
Refactor queryparse tests
1 parent af3947a commit d9869c5

1 file changed

Lines changed: 113 additions & 158 deletions

File tree

test/dbcore/test_queryparse.py

Lines changed: 113 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -14,184 +14,139 @@
1414

1515
"""Tests for dbcore query parsing helpers."""
1616

17-
import unittest
18-
1917
import pytest
2018

2119
from beets.dbcore import query, sort
2220
from beets.dbcore.queryparse import ModelQuery, QueryTerm
2321
from beets.test.fixtures import ModelFixture1, SortFixture
2422

25-
26-
class QueryParseTest(unittest.TestCase):
27-
def pqp(self, part):
28-
term = QueryTerm.make(part)
29-
return term.field, term.pattern, term.get_query_cls(ModelFixture1)
30-
31-
def test_one_basic_term(self):
32-
q = "test"
33-
r = (None, "test", query.SubstringQuery)
34-
assert self.pqp(q) == r
35-
36-
def test_one_keyed_term(self):
37-
q = "test:val"
38-
r = ("test", "val", query.SubstringQuery)
39-
assert self.pqp(q) == r
40-
41-
def test_colon_at_end(self):
42-
q = "test:"
43-
r = ("test", "", query.SubstringQuery)
44-
assert self.pqp(q) == r
45-
46-
def test_one_basic_regexp(self):
47-
q = r":regexp"
48-
r = (None, "regexp", query.RegexpQuery)
49-
assert self.pqp(q) == r
50-
51-
def test_keyed_regexp(self):
52-
q = r"test::regexp"
53-
r = ("test", "regexp", query.RegexpQuery)
54-
assert self.pqp(q) == r
55-
56-
def test_escaped_colon(self):
57-
q = r"test\:val"
58-
r = (None, "test:val", query.SubstringQuery)
59-
assert self.pqp(q) == r
60-
61-
def test_escaped_colon_in_regexp(self):
62-
q = r":test\:regexp"
63-
r = (None, "test:regexp", query.RegexpQuery)
64-
assert self.pqp(q) == r
65-
66-
def test_single_year(self):
67-
q = "year:1999"
68-
r = ("year", "1999", query.NumericQuery)
69-
assert self.pqp(q) == r
70-
71-
def test_multiple_years(self):
72-
q = "year:1999..2010"
73-
r = ("year", "1999..2010", query.NumericQuery)
74-
assert self.pqp(q) == r
75-
76-
def test_empty_query_part(self):
77-
q = ""
78-
r = (None, "", query.SubstringQuery)
79-
assert self.pqp(q) == r
80-
81-
def test_implicit_path(self):
82-
q = "/tmp"
83-
r = ("path", "/tmp", query.PathQuery)
84-
assert self.pqp(q) == r
85-
86-
87-
class QueryFromStringsTest(unittest.TestCase):
88-
def qfs(self, strings):
89-
return ModelFixture1.parse_query(strings).query
90-
91-
def test_zero_parts(self):
92-
q = self.qfs([])
93-
assert isinstance(q, query.TrueQuery)
94-
95-
def test_two_parts(self):
96-
q = self.qfs(["foo", "bar:baz"])
23+
_p = pytest.param
24+
25+
26+
def _parse_query_parts(parts: list[str]):
27+
return ModelFixture1.parse_query(parts).query
28+
29+
30+
def _parse_sort_parts(parts: list[str]):
31+
return ModelFixture1.parse_query(parts).sort
32+
33+
34+
class TestQueryTermParsing:
35+
@pytest.mark.parametrize(
36+
"query_string,expected",
37+
[
38+
("test", (None, "test", query.SubstringQuery)),
39+
("test:val", ("test", "val", query.SubstringQuery)),
40+
("test:", ("test", "", query.SubstringQuery)),
41+
(r":regexp", (None, "regexp", query.RegexpQuery)),
42+
(r"test::regexp", ("test", "regexp", query.RegexpQuery)),
43+
(r"test\:val", (None, "test:val", query.SubstringQuery)),
44+
(r":test\:regexp", (None, "test:regexp", query.RegexpQuery)),
45+
("year:1999", ("year", "1999", query.NumericQuery)),
46+
("year:1999..2010", ("year", "1999..2010", query.NumericQuery)),
47+
("", (None, "", query.SubstringQuery)),
48+
("/tmp", ("path", "/tmp", query.PathQuery)),
49+
],
50+
)
51+
def test_query_term_parsing(self, query_string, expected):
52+
"""Test that various query strings are parsed correctly."""
53+
term = QueryTerm.make(query_string)
54+
result = term.field, term.pattern, term.get_query_cls(ModelFixture1)
55+
assert result == expected
56+
57+
58+
class TestQueryFromParts:
59+
@pytest.mark.parametrize(
60+
"query_parts,expected_type",
61+
[
62+
_p([], query.TrueQuery, id="zero_parts"),
63+
_p([""], query.TrueQuery, id="empty_query_part"),
64+
_p(["field_one:2..3"], query.NumericQuery, id="fixed_type_query"),
65+
_p(
66+
["some_float_field:2..3"],
67+
query.NumericQuery,
68+
id="flex_type_query",
69+
),
70+
],
71+
)
72+
def test_query_from_parts_types(self, query_parts, expected_type):
73+
q = _parse_query_parts(query_parts)
74+
assert isinstance(q, expected_type)
75+
76+
def test_query_from_two_parts_builds_and_query(self):
77+
q = _parse_query_parts(["foo", "bar:baz"])
9778
assert isinstance(q, query.AndQuery)
9879
assert len(q.subqueries) == 2
9980
assert isinstance(q.subqueries[0], query.OrQuery)
10081
assert isinstance(q.subqueries[1], query.SubstringQuery)
10182

102-
def test_parse_fixed_type_query(self):
103-
q = self.qfs(["field_one:2..3"])
104-
assert isinstance(q, query.NumericQuery)
105-
106-
def test_parse_flex_type_query(self):
107-
q = self.qfs(["some_float_field:2..3"])
108-
assert isinstance(q, query.NumericQuery)
109-
110-
def test_empty_query_part(self):
111-
q = self.qfs([""])
112-
assert isinstance(q, query.TrueQuery)
11383

114-
115-
class SortFromStringsTest(unittest.TestCase):
116-
def sfs(self, strings):
117-
return ModelFixture1.parse_query(strings).sort
118-
119-
def test_zero_parts(self):
120-
s = self.sfs([])
84+
class TestSortFromParts:
85+
def test_sort_from_zero_parts(self):
86+
s = _parse_sort_parts([])
12187
assert isinstance(s, sort.NullSort)
12288
assert s == sort.NullSort()
12389

124-
def test_one_parts(self):
125-
s = self.sfs(["field+"])
90+
def test_sort_from_one_part(self):
91+
s = _parse_sort_parts(["field+"])
12692
assert isinstance(s, sort.Sort)
12793

128-
def test_two_parts(self):
129-
s = self.sfs(["field+", "another_field-"])
94+
def test_sort_from_two_parts(self):
95+
s = _parse_sort_parts(["field+", "another_field-"])
13096
assert isinstance(s, sort.MultipleSort)
13197
assert len(s.sorts) == 2
13298

133-
def test_fixed_field_sort(self):
134-
s = self.sfs(["field_one+"])
135-
assert isinstance(s, sort.FixedFieldSort)
136-
assert s == sort.FixedFieldSort("field_one")
137-
138-
def test_flex_field_sort(self):
139-
s = self.sfs(["flex_field+"])
140-
assert isinstance(s, sort.SlowFieldSort)
141-
assert s == sort.SlowFieldSort("flex_field")
142-
143-
def test_special_sort(self):
144-
s = self.sfs(["some_sort+"])
145-
assert isinstance(s, SortFixture)
146-
147-
148-
class ParseSortedQueryTest(unittest.TestCase):
149-
def psq(self, parts):
150-
return ModelFixture1.parse_query(parts.split())
151-
152-
def test_and_query(self):
153-
q, s = self.psq("foo bar")
154-
assert isinstance(q, query.AndQuery)
155-
assert isinstance(s, sort.NullSort)
156-
assert len(q.subqueries) == 2
157-
158-
def test_or_query(self):
159-
q, s = self.psq("foo , bar")
160-
assert isinstance(q, query.OrQuery)
161-
assert isinstance(s, sort.NullSort)
162-
assert len(q.subqueries) == 4
163-
164-
def test_no_space_before_comma_or_query(self):
165-
q, s = self.psq("foo, bar")
166-
assert isinstance(q, query.OrQuery)
167-
assert isinstance(s, sort.NullSort)
168-
assert len(q.subqueries) == 4
169-
170-
def test_no_spaces_or_query(self):
171-
q, s = self.psq("foo,bar")
172-
assert isinstance(q, query.OrQuery)
173-
assert isinstance(s, sort.NullSort)
174-
assert len(q.subqueries) == 2
175-
176-
def test_trailing_comma_or_query(self):
177-
q, s = self.psq("foo , bar ,")
178-
assert isinstance(q, query.OrQuery)
179-
assert isinstance(s, sort.NullSort)
180-
assert len(q.subqueries) == 5
181-
182-
def test_leading_comma_or_query(self):
183-
q, s = self.psq(", foo , bar")
184-
assert isinstance(q, query.OrQuery)
185-
assert isinstance(s, sort.NullSort)
186-
assert len(q.subqueries) == 5
187-
188-
def test_only_direction(self):
189-
q, s = self.psq("-")
190-
assert isinstance(q, query.NotQuery)
191-
assert isinstance(s, sort.NullSort)
192-
193-
194-
class ParseQueryTest(unittest.TestCase):
99+
@pytest.mark.parametrize(
100+
"sort_parts,expected_type,expected_sort",
101+
[
102+
_p(
103+
["field_one+"],
104+
sort.FixedFieldSort,
105+
sort.FixedFieldSort("field_one"),
106+
id="fixed_field_sort",
107+
),
108+
_p(
109+
["flex_field+"],
110+
sort.SlowFieldSort,
111+
sort.SlowFieldSort("flex_field"),
112+
id="flex_field_sort",
113+
),
114+
_p(["some_sort+"], SortFixture, None, id="special_sort"),
115+
],
116+
)
117+
def test_sort_from_parts_types(
118+
self, sort_parts, expected_type, expected_sort
119+
):
120+
s = _parse_sort_parts(sort_parts)
121+
assert isinstance(s, expected_type)
122+
if expected_sort is not None:
123+
assert s == expected_sort
124+
125+
126+
class TestParseSortedQuery:
127+
@pytest.mark.parametrize(
128+
"query_str,expected_type,expected_subqueries",
129+
[
130+
_p("foo bar", query.AndQuery, 2, id="and_query"),
131+
_p("foo , bar", query.OrQuery, 4, id="or_query"),
132+
_p("foo, bar", query.OrQuery, 4, id="no_space_before_comma_or_query"),
133+
_p("foo,bar", query.OrQuery, 2, id="no_spaces_or_query"),
134+
_p("foo , bar ,", query.OrQuery, 5, id="trailing_comma_or_query"),
135+
_p(", foo , bar", query.OrQuery, 5, id="leading_comma_or_query"),
136+
_p("-", query.NotQuery, None, id="only_direction"),
137+
],
138+
) # fmt: skip
139+
def test_parse_sorted_query(
140+
self, query_str, expected_type, expected_subqueries
141+
):
142+
"""Verify that query strings are parsed into the correct query type."""
143+
q = _parse_query_parts(query_str.split())
144+
assert isinstance(q, expected_type)
145+
if expected_subqueries is not None:
146+
assert len(q.subqueries) == expected_subqueries
147+
148+
149+
class TestModelQueryErrors:
195150
def test_parse_invalid_query_string(self):
196151
with pytest.raises(query.ParsingError):
197152
ModelQuery.parse(ModelFixture1, 'foo"')

0 commit comments

Comments
 (0)