diff --git a/beetsplug/limit.py b/beetsplug/limit.py index 5e5ee16be..3942ced0f 100644 --- a/beetsplug/limit.py +++ b/beetsplug/limit.py @@ -28,7 +28,7 @@ from itertools import islice def lslimit(lib, opts, args): - """Query command with head/tail""" + """Query command with head/tail.""" if (opts.head is not None) and (opts.tail is not None): raise ValueError("Only use one of --head and --tail") @@ -56,15 +56,15 @@ lslimit_cmd = Subcommand( ) lslimit_cmd.parser.add_option( - '--head', - action='store', + "--head", + action="store", type="int", default=None ) lslimit_cmd.parser.add_option( - '--tail', - action='store', + "--tail", + action="store", type="int", default=None ) @@ -74,28 +74,25 @@ lslimit_cmd.func = lslimit class LimitPlugin(BeetsPlugin): - """Query limit functionality via command and query prefix - """ + """Query limit functionality via command and query prefix.""" def commands(self): + """Expose `lslimit` subcommand.""" return [lslimit_cmd] def queries(self): class HeadQuery(FieldQuery): - """This inner class pattern allows the query to track state - """ + """This inner class pattern allows the query to track state.""" n = 0 N = None @classmethod def value_match(cls, pattern, value): - if cls.N is None: cls.N = int(pattern) if cls.N < 0: raise ValueError("Limit value must be non-negative") - cls.n += 1 return cls.n <= cls.N diff --git a/setup.cfg b/setup.cfg index 6aab6b7e6..31deba4b1 100644 --- a/setup.cfg +++ b/setup.cfg @@ -69,6 +69,7 @@ per-file-ignores = ./beetsplug/permissions.py:D ./beetsplug/spotify.py:D ./beetsplug/lastgenre/__init__.py:D + ./beetsplug/limit.py:D ./beetsplug/mbcollection.py:D ./beetsplug/metasync/amarok.py:D ./beetsplug/metasync/itunes.py:D diff --git a/test/test_limit.py b/test/test_limit.py index d5a3d60af..35c01c41a 100644 --- a/test/test_limit.py +++ b/test/test_limit.py @@ -18,60 +18,83 @@ import unittest from test.helper import TestHelper -class LsLimitPluginTest(unittest.TestCase, TestHelper): +class LimitPluginTest(unittest.TestCase, TestHelper): + """Unit tests for LimitPlugin + + Note: query prefix tests do not work correctly with `run_with_output`. + """ def setUp(self): + self.setup_beets() self.load_plugins("limit") + + # we'll create an even number of tracks in the library self.num_test_items = 10 assert self.num_test_items % 2 == 0 - self.num_limit = self.num_test_items // 2 - self.num_limit_prefix = "'<" + str(self.num_limit) + "'" - self.track_head_range = "track:.." + str(self.num_limit) - self.track_tail_range = "track:" + str(self.num_limit + 1) + ".." for item_no, item in \ enumerate(self.add_item_fixtures(count=self.num_test_items)): item.track = item_no + 1 item.store() + # our limit tests will use half of this number + self.num_limit = self.num_test_items // 2 + self.num_limit_prefix = "".join(["'", "<", str(self.num_limit), "'"]) + + # a subset of tests has only `num_limit` results, identified by a + # range filter on the track number + self.track_head_range = "track:.." + str(self.num_limit) + self.track_tail_range = "track:" + str(self.num_limit + 1) + ".." + def tearDown(self): + self.unload_plugins() self.teardown_beets() def test_no_limit(self): + """Returns all when there is no limit or filter.""" result = self.run_with_output("lslimit") self.assertEqual(result.count("\n"), self.num_test_items) def test_lslimit_head(self): + """Returns the expected number with `lslimit --head`.""" result = self.run_with_output("lslimit", "--head", str(self.num_limit)) self.assertEqual(result.count("\n"), self.num_limit) def test_lslimit_tail(self): + """Returns the expected number with `lslimit --tail`.""" result = self.run_with_output("lslimit", "--tail", str(self.num_limit)) self.assertEqual(result.count("\n"), self.num_limit) def test_lslimit_head_invariant(self): + """Returns the expected number with `lslimit --head` and a filter.""" result = self.run_with_output( "lslimit", "--head", str(self.num_limit), self.track_tail_range) self.assertEqual(result.count("\n"), self.num_limit) def test_lslimit_tail_invariant(self): + """Returns the expected number with `lslimit --tail` and a filter.""" result = self.run_with_output( "lslimit", "--tail", str(self.num_limit), self.track_head_range) self.assertEqual(result.count("\n"), self.num_limit) def test_prefix(self): - result = self.run_with_output("ls", self.num_limit_prefix) - self.assertEqual(result.count("\n"), self.num_limit) + """Returns the expected number with the query prefix.""" + result = self.lib.items(self.num_limit_prefix) + self.assertEqual(len(result), self.num_limit) def test_prefix_when_correctly_ordered(self): - result = self.run_with_output( - "ls", self.track_tail_range, self.num_limit_prefix) - self.assertEqual(result.count("\n"), self.num_limit) + """Returns the expected number with the query prefix and filter when + the prefix portion (correctly) appears last.""" + correct_order = self.track_tail_range + " " + self.num_limit_prefix + result = self.lib.items(correct_order) + self.assertEqual(len(result), self.num_limit) def test_prefix_when_incorrectly_ordred(self): - result = self.run_with_output( - "ls", self.num_limit_prefix, self.track_tail_range) - self.assertEqual(result.count("\n"), 0) + """Returns no results with the query prefix and filter when the prefix + portion (incorrectly) appears first.""" + incorrect_order = self.num_limit_prefix + " " + self.track_tail_range + result = self.lib.items(incorrect_order) + self.assertEqual(len(result), 0) def suite():