From e7f9cdc8469d608f790a746948ffeed8363647e8 Mon Sep 17 00:00:00 2001 From: John-Mark Gurney Date: Mon, 12 Sep 2022 11:22:45 -0700 Subject: [PATCH] add tests for the TagCache, fix a bug, docs, drop unneeded sorted.. --- ui/medashare/cli.py | 74 ++++++++++++++++++++++++++++++++++++++++--- ui/medashare/tests.py | 2 +- 2 files changed, 70 insertions(+), 6 deletions(-) diff --git a/ui/medashare/cli.py b/ui/medashare/cli.py index 80d5271..402ccf7 100644 --- a/ui/medashare/cli.py +++ b/ui/medashare/cli.py @@ -749,9 +749,12 @@ def enumeratedir(_dir, created_by_ref): os.path.isdir(os.path.join(_dir, x)) ] class TagCache: + '''Takes tuples, and stores them in a cache where only + the most count recent ones are kept.''' + def __init__(self, tags=(), count=10): self._cache = dict((x, None) for x in tags) - self._count = 10 + self._count = count self._modified = False @property @@ -762,6 +765,9 @@ class TagCache: return self._modified def add(self, tag): + '''Add a tag (tuple) to the cache, possibly dropping ann older + tag if necessary.''' + self._modified = True try: @@ -771,14 +777,19 @@ class TagCache: self._cache[tag] = None - if len(self._cache) > self._count: - del self._cache[next(iter(a.keys()))] + while len(self._cache) > self._count: + del self._cache[next(iter(self._cache.keys()))] def tags(self): + '''Returns the sorted list of tags in the cache.''' + return sorted(self._cache.keys()) @classmethod def load(cls, fname): + '''Load the cache from fname. Must be previously have saved + using the store method.''' + try: with open(fname, 'rb') as fp: cache = _asn1coder.loads(fp.read()) @@ -792,13 +803,66 @@ class TagCache: return cls(**cache) def store(self, fname): + '''Store the cache to fname. The modified property will + be cleared after this.''' + self._modified = False - cache = dict(tags=list(self._cache.keys())) + cache = dict(tags=list(self._cache.keys()), count=self._count) with open(fname, 'wb') as fp: fp.write(_asn1coder.dumps(cache)) +class _TestTagCache(unittest.TestCase): + def setUp(self): + d = pathlib.Path(tempfile.mkdtemp()).resolve() + self.basetempdir = d + + self.tempdir = d / 'subdir' + + self.tempdir.mkdir() + + def tearDown(self): + shutil.rmtree(self.basetempdir) + self.tempdir = None + + def test_cache(self): + # test basic functionality + tc = TagCache(count=2) + + self.assertFalse(tc.modified) + + tc.add(('foo', 'foo')) + + self.assertTrue(tc.modified) + + tc.add(('bar', 'bar')) + + self.assertEqual(tc.tags(), [ ('bar', 'bar'), ('foo', 'foo') ]) + + tc.add(('foo', 'foo')) + + tc.add(('baz', 'baz')) + + tc.add(('foo', 'foo')) + + self.assertEqual(tc.tags(), [ ('baz', 'baz'), ('foo', 'foo') ]) + + cachefile = self.tempdir / 'somecache' + tc.store(cachefile) + + self.assertFalse(tc.modified) + + ntc = TagCache.load(cachefile) + + self.assertFalse(ntc.modified) + + self.assertEqual(tc.tags(), [ ('baz', 'baz'), ('foo', 'foo') ]) + + ntc.add(('whee', 'whee')) + + self.assertEqual(ntc.tags(), [ ('foo', 'foo'), ('whee', 'whee') ]) + def _get_paths(options): fnames = ( '.medashare_identity.pasn1', @@ -1158,7 +1222,7 @@ def cmd_interactive(options, persona, objstr, cache): print('7) Open file.') print('8) Turn auto skip %s' % 'off' if autoskip else 'on') - tags = sorted(cache.tags()) + tags = cache.tags() for pos, (tag, value) in enumerate(tags): print('%s) %s=%s' % (string.ascii_lowercase[pos], tag, value)) diff --git a/ui/medashare/tests.py b/ui/medashare/tests.py index 20d0339..ae5602a 100644 --- a/ui/medashare/tests.py +++ b/ui/medashare/tests.py @@ -2,6 +2,6 @@ from .btv import _TestCases as btv_test_cases from .btv.bencode import _TestCases as bencode_test_cases from .mdb import _TestJSONEncoder from .cli import _TestCononicalCoder, _TestCases as cli_test_cases -from .cli import _TestMigrations +from .cli import _TestMigrations, _TestTagCache from .mtree import Test from .server import _TestCases, _TestPostConfig