Skip to content

Commit c288300

Browse files
committed
Refactor queryparse tests
1 parent 55f4e7a commit c288300

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
@@ -1,183 +1,138 @@
11
"""Tests for dbcore query parsing helpers."""
22

3-
import unittest
4-
53
import pytest
64

75
from beets.dbcore import ModelQuery, query, sort
86
from beets.dbcore.queryparse import QueryTerm
97
from beets.test.fixtures import ModelFixture1, SortFixture
108

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

88-
def test_parse_fixed_type_query(self):
89-
q = self.qfs(["field_one:2..3"])
90-
assert isinstance(q, query.NumericQuery)
91-
92-
def test_parse_flex_type_query(self):
93-
q = self.qfs(["some_float_field:2..3"])
94-
assert isinstance(q, query.NumericQuery)
95-
96-
def test_empty_query_part(self):
97-
q = self.qfs([""])
98-
assert isinstance(q, query.TrueQuery)
9969

100-
101-
class SortFromStringsTest(unittest.TestCase):
102-
def sfs(self, strings):
103-
return ModelQuery.get_sort(ModelFixture1, strings)
104-
105-
def test_zero_parts(self):
106-
s = self.sfs([])
70+
class TestSortFromParts:
71+
def test_sort_from_zero_parts(self):
72+
s = _parse_sort_parts([])
10773
assert isinstance(s, sort.NullSort)
10874
assert s == sort.NullSort()
10975

110-
def test_one_parts(self):
111-
s = self.sfs(["field+"])
76+
def test_sort_from_one_part(self):
77+
s = _parse_sort_parts(["field+"])
11278
assert isinstance(s, sort.Sort)
11379

114-
def test_two_parts(self):
115-
s = self.sfs(["field+", "another_field-"])
80+
def test_sort_from_two_parts(self):
81+
s = _parse_sort_parts(["field+", "another_field-"])
11682
assert isinstance(s, sort.MultipleSort)
11783
assert len(s.sorts) == 2
11884

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

0 commit comments

Comments
 (0)