Coverage for tests/test_dataid_match.py: 13%
52 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-11-30 12:09 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-11-30 12:09 +0000
1# This file is part of ctrl_mpexec.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://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 <https://www.gnu.org/licenses/>.
28import unittest
30from lsst.pipe.base.tests.mocks import DataIdMatch
33class DataIdMatchTestCase(unittest.TestCase):
34 """A test case for DataidMatch class"""
36 dataIds = (
37 {"instrument": "INSTR", "detector": 1, "number": 4},
38 {"instrument": "INSTR", "detector": 2, "number": 3},
39 {"instrument": "LSST", "detector": 3, "number": 2},
40 {"instrument": "LSST", "detector": 4, "number": 1},
41 )
43 def test_strings(self):
44 """Tests for string comparisons method"""
45 tests = (
46 ("instrument = 'INSTR'", [True, True, False, False]),
47 ("instrument = 'LSST'", [False, False, True, True]),
48 ("instrument < 'LSST'", [True, True, False, False]),
49 ("instrument IN ('LSST', 'INSTR')", [True, True, True, True]),
50 )
52 for expr, result in tests:
53 dataIdMatch = DataIdMatch(expr)
54 self.assertEqual([dataIdMatch.match(dataId) for dataId in self.dataIds], result)
56 def test_comparisons(self):
57 """Test all supported comparison operators"""
58 tests = (
59 ("detector = 1", [True, False, False, False]),
60 ("detector != 1", [False, True, True, True]),
61 ("detector > 2", [False, False, True, True]),
62 ("2 <= detector", [False, True, True, True]),
63 ("2 > detector", [True, False, False, False]),
64 ("2 >= detector", [True, True, False, False]),
65 )
67 for expr, result in tests:
68 dataIdMatch = DataIdMatch(expr)
69 self.assertEqual([dataIdMatch.match(dataId) for dataId in self.dataIds], result)
71 def test_arith(self):
72 """Test all supported arithmetical operators"""
73 tests = (
74 ("detector + number = 5", [True, True, True, True]),
75 ("detector - number = 1", [False, False, True, False]),
76 ("detector * number = 6", [False, True, True, False]),
77 ("detector / number = 1.5", [False, False, True, False]),
78 ("detector % number = 1", [True, False, True, False]),
79 ("+detector = 1", [True, False, False, False]),
80 ("-detector = -4", [False, False, False, True]),
81 )
83 for expr, result in tests:
84 dataIdMatch = DataIdMatch(expr)
85 self.assertEqual([dataIdMatch.match(dataId) for dataId in self.dataIds], result)
87 def test_logical(self):
88 """Test all supported logical operators"""
89 tests = (
90 ("detector = 1 OR instrument = 'LSST'", [True, False, True, True]),
91 ("detector = 1 AND instrument = 'INSTR'", [True, False, False, False]),
92 ("NOT detector = 1", [False, True, True, True]),
93 )
95 for expr, result in tests:
96 dataIdMatch = DataIdMatch(expr)
97 self.assertEqual([dataIdMatch.match(dataId) for dataId in self.dataIds], result)
99 def test_parens(self):
100 """Test parentheses"""
101 tests = (("(detector = 1 OR number = 1) AND instrument = 'LSST'", [False, False, False, True]),)
103 for expr, result in tests:
104 dataIdMatch = DataIdMatch(expr)
105 self.assertEqual([dataIdMatch.match(dataId) for dataId in self.dataIds], result)
107 def test_in(self):
108 """Test IN expression"""
109 tests = (
110 ("detector in (1, 3, 2)", [True, True, True, False]),
111 ("detector not in (1, 3, 2)", [False, False, False, True]),
112 ("detector in (1..4:2)", [True, False, True, False]),
113 ("detector in (1..4:2, 4)", [True, False, True, True]),
114 )
116 for expr, result in tests:
117 dataIdMatch = DataIdMatch(expr)
118 self.assertEqual([dataIdMatch.match(dataId) for dataId in self.dataIds], result)
120 def test_errors(self):
121 """Test for errors in expressions"""
122 dataId = {"instrument": "INSTR", "detector": 1}
124 # Unknown identifier
125 expr = "INSTRUMENT = 'INSTR'"
126 dataIdMatch = DataIdMatch(expr)
127 with self.assertRaisesRegex(KeyError, "INSTRUMENT"):
128 dataIdMatch.match(dataId)
130 # non-boolean expression
131 expr = "instrument"
132 dataIdMatch = DataIdMatch(expr)
133 with self.assertRaisesRegex(TypeError, "Expression 'instrument' returned non-boolean object"):
134 dataIdMatch.match(dataId)
136 # operations on unsupported combination of types
137 expr = "instrument - detector = 0"
138 dataIdMatch = DataIdMatch(expr)
139 with self.assertRaisesRegex(TypeError, "unsupported operand type"):
140 dataIdMatch.match(dataId)
142 # function calls are not implemented
143 expr = "POINT(2, 1) != POINT(1, 2)"
144 dataIdMatch = DataIdMatch(expr)
145 with self.assertRaises(NotImplementedError):
146 dataIdMatch.match(dataId)
149if __name__ == "__main__":
150 unittest.main()