Coverage for tests/test_utils.py: 19%
138 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-01 11:00 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-01 11:00 +0000
1# This file is part of daf_butler.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (http://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This software is dual licensed under the GNU General Public License and also
10# under a 3-clause BSD license. Recipients may choose which of these licenses
11# to use; please see the files gpl-3.0.txt and/or bsd_license.txt,
12# respectively. If you choose the GPL option then the following text applies
13# (but note that there is still no warranty even if you opt for BSD instead):
14#
15# This program is free software: you can redistribute it and/or modify
16# it under the terms of the GNU General Public License as published by
17# the Free Software Foundation, either version 3 of the License, or
18# (at your option) any later version.
19#
20# This program is distributed in the hope that it will be useful,
21# but WITHOUT ANY WARRANTY; without even the implied warranty of
22# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23# GNU General Public License for more details.
24#
25# You should have received a copy of the GNU General Public License
26# along with this program. If not, see <http://www.gnu.org/licenses/>.
28import os
29import re
30import unittest
31from collections import namedtuple
33from lsst.daf.butler import NamedKeyDict, NamedValueSet
34from lsst.daf.butler.utils import globToRegex
36TESTDIR = os.path.dirname(__file__)
39class NamedKeyDictTest(unittest.TestCase):
40 """Tests for NamedKeyDict."""
42 def setUp(self):
43 self.TestTuple = namedtuple("TestTuple", ("name", "id"))
44 self.a = self.TestTuple(name="a", id=1)
45 self.b = self.TestTuple(name="b", id=2)
46 self.dictionary = {self.a: 10, self.b: 20}
47 self.names = {self.a.name, self.b.name}
49 def check(self, nkd):
50 self.assertEqual(len(nkd), 2)
51 self.assertEqual(nkd.names, self.names)
52 self.assertEqual(nkd.keys(), self.dictionary.keys())
53 self.assertEqual(list(nkd.values()), list(self.dictionary.values()))
54 self.assertEqual(list(nkd.items()), list(self.dictionary.items()))
55 self.assertEqual(list(nkd.byName().values()), list(self.dictionary.values()))
56 self.assertEqual(list(nkd.byName().keys()), list(nkd.names))
58 def testConstruction(self):
59 self.check(NamedKeyDict(self.dictionary))
60 self.check(NamedKeyDict(iter(self.dictionary.items())))
62 def testDuplicateNameConstruction(self):
63 self.dictionary[self.TestTuple(name="a", id=3)] = 30
64 with self.assertRaises(AssertionError):
65 NamedKeyDict(self.dictionary)
66 with self.assertRaises(AssertionError):
67 NamedKeyDict(iter(self.dictionary.items()))
69 def testNoNameConstruction(self):
70 self.dictionary["a"] = 30
71 with self.assertRaises(AttributeError):
72 NamedKeyDict(self.dictionary)
73 with self.assertRaises(AttributeError):
74 NamedKeyDict(iter(self.dictionary.items()))
76 def testGetItem(self):
77 nkd = NamedKeyDict(self.dictionary)
78 self.assertEqual(nkd["a"], 10)
79 self.assertEqual(nkd[self.a], 10)
80 self.assertEqual(nkd["b"], 20)
81 self.assertEqual(nkd[self.b], 20)
82 self.assertIn("a", nkd)
83 self.assertIn(self.b, nkd)
85 def testSetItem(self):
86 nkd = NamedKeyDict(self.dictionary)
87 nkd[self.a] = 30
88 self.assertEqual(nkd["a"], 30)
89 nkd["b"] = 40
90 self.assertEqual(nkd[self.b], 40)
91 with self.assertRaises(KeyError):
92 nkd["c"] = 50
93 with self.assertRaises(AssertionError):
94 nkd[self.TestTuple("a", 3)] = 60
96 def testDelItem(self):
97 nkd = NamedKeyDict(self.dictionary)
98 del nkd[self.a]
99 self.assertNotIn("a", nkd)
100 del nkd["b"]
101 self.assertNotIn(self.b, nkd)
102 self.assertEqual(len(nkd), 0)
104 def testIter(self):
105 self.assertEqual(set(iter(NamedKeyDict(self.dictionary))), set(self.dictionary))
107 def testEquality(self):
108 nkd = NamedKeyDict(self.dictionary)
109 self.assertEqual(nkd, self.dictionary)
110 self.assertEqual(self.dictionary, nkd)
113class NamedValueSetTest(unittest.TestCase):
114 """Tests for NamedValueSet."""
116 def setUp(self):
117 self.TestTuple = namedtuple("TestTuple", ("name", "id"))
118 self.a = self.TestTuple(name="a", id=1)
119 self.b = self.TestTuple(name="b", id=2)
120 self.c = self.TestTuple(name="c", id=3)
122 def testConstruction(self):
123 for arg in ({self.a, self.b}, (self.a, self.b)):
124 for nvs in (NamedValueSet(arg), NamedValueSet(arg).freeze()):
125 self.assertEqual(len(nvs), 2)
126 self.assertEqual(nvs.names, {"a", "b"})
127 self.assertCountEqual(nvs, {self.a, self.b})
128 self.assertCountEqual(nvs.asMapping().items(), [(self.a.name, self.a), (self.b.name, self.b)])
130 def testNoNameConstruction(self):
131 with self.assertRaises(AttributeError):
132 NamedValueSet([self.a, "a"])
134 def testGetItem(self):
135 nvs = NamedValueSet({self.a, self.b, self.c})
136 self.assertEqual(nvs["a"], self.a)
137 self.assertEqual(nvs[self.a], self.a)
138 self.assertEqual(nvs["b"], self.b)
139 self.assertEqual(nvs[self.b], self.b)
140 self.assertIn("a", nvs)
141 self.assertIn(self.b, nvs)
143 def testEquality(self):
144 s = {self.a, self.b, self.c}
145 nvs = NamedValueSet(s)
146 self.assertEqual(nvs, s)
147 self.assertEqual(s, nvs)
149 def checkOperator(self, result, expected):
150 self.assertIsInstance(result, NamedValueSet)
151 self.assertEqual(result, expected)
153 def testOperators(self):
154 ab = NamedValueSet({self.a, self.b})
155 bc = NamedValueSet({self.b, self.c})
156 self.checkOperator(ab & bc, {self.b})
157 self.checkOperator(ab | bc, {self.a, self.b, self.c})
158 self.checkOperator(ab ^ bc, {self.a, self.c})
159 self.checkOperator(ab - bc, {self.a})
161 def testPop(self):
162 # Construct with list for repeatable ordering.
163 nvs = NamedValueSet([self.a, self.b, self.c])
164 self.assertEqual(nvs.pop("c"), self.c)
165 self.assertEqual(nvs.pop(), self.a)
166 self.assertEqual(nvs.pop(), self.b)
167 self.assertEqual(nvs.pop("d", self.c), self.c)
168 with self.assertRaises(KeyError):
169 nvs.pop()
171 def testRemove(self):
172 nvs = NamedValueSet([self.a, self.b, self.c])
173 nvs.remove("b")
174 self.assertIn("a", nvs)
175 self.assertNotIn("b", nvs)
176 with self.assertRaises(KeyError):
177 nvs.remove("d")
178 nvs.discard("d")
179 nvs.discard("a")
180 self.assertNotIn("a", nvs)
183class GlobToRegexTestCase(unittest.TestCase):
184 """Tests for glob to regex."""
186 def testStarInList(self):
187 """Test that if a one of the items in the expression list is a star
188 (stand-alone) then ``...`` is returned (which implies no restrictions)
189 """
190 self.assertIs(globToRegex(["foo", "*", "bar"]), ...)
192 def testGlobList(self):
193 """Test that a list of glob strings converts as expected to a regex and
194 returns in the expected list.
195 """
196 # These strings should be returned unchanged.
197 strings = ["bar", "😺", "ingésτ", "ex]", "[xe", "[!no", "e[x"]
198 self.assertEqual(globToRegex(strings), strings)
200 # Globs with strings that match the glob and strings that do not.
201 tests = (
202 ("bar", ["bar"], ["baz"]),
203 ("ba*", ["bar", "baz"], ["az"]),
204 ("ba[rz]", ["bar", "baz"], ["bat"]),
205 ("ba[rz]x[y", ["barx[y", "bazx[y"], ["batx[y"]),
206 ("ba[!rz]", ["bat", "baτ"], ["bar", "baz"]),
207 ("b?r", ["bor", "bar", "b😺r"], ["bat"]),
208 ("*.fits", ["boz.fits"], ["boz.fits.gz", "boz.hdf5"]),
209 )
211 for glob, matches, no_matches in tests:
212 patterns = globToRegex(glob)
213 for match in matches:
214 self.assertTrue(bool(re.fullmatch(patterns[0], match)))
215 for no_match in no_matches:
216 self.assertIsNone(re.fullmatch(patterns[0], no_match))
219if __name__ == "__main__":
220 unittest.main()