Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

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 program is free software: you can redistribute it and/or modify 

10# it under the terms of the GNU General Public License as published by 

11# the Free Software Foundation, either version 3 of the License, or 

12# (at your option) any later version. 

13# 

14# This program is distributed in the hope that it will be useful, 

15# but WITHOUT ANY WARRANTY; without even the implied warranty of 

16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

17# GNU General Public License for more details. 

18# 

19# You should have received a copy of the GNU General Public License 

20# along with this program. If not, see <http://www.gnu.org/licenses/>. 

21 

22"""Unit tests for the daf_butler shared CLI options. 

23""" 

24 

25import click 

26from functools import partial 

27import unittest 

28from unittest.mock import MagicMock 

29 

30from lsst.daf.butler.cli.utils import clickResultMsg, LogCliRunner, split_kv 

31 

32 

33class SplitKvTestCase(unittest.TestCase): 

34 """Tests that call split_kv directly.""" 

35 

36 def test_single(self): 

37 self.assertEqual(split_kv("context", "param", "first=1"), {"first": "1"}) 

38 

39 def test_multiple(self): 

40 self.assertEqual(split_kv("context", "param", "first=1,second=2"), {"first": "1", "second": "2"}) 

41 

42 def test_unseparated(self): 

43 self.assertEqual(split_kv("context", "param", "first,second=2", unseparated_okay=True), 

44 {"": "first", "second": "2"}) 

45 

46 def test_notMultiple(self): 

47 with self.assertRaisesRegex(click.ClickException, "Could not parse key-value pair " 

48 "'first=1,second=2' using separator '=', with multiple values not " 

49 "allowed."): 

50 split_kv("context", "param", "first=1,second=2", multiple=False) 

51 

52 def test_wrongSeparator(self): 

53 with self.assertRaises(click.ClickException): 

54 split_kv("context", "param", "first-1") 

55 

56 def test_missingSeparator(self): 

57 with self.assertRaises(click.ClickException): 

58 split_kv("context", "param", "first 1") 

59 

60 def test_duplicateKeys(self): 

61 with self.assertRaises(click.ClickException): 

62 split_kv("context", "param", "first=1,first=2") 

63 

64 def test_dashSeparator(self): 

65 self.assertEqual(split_kv("context", "param", "first-1,second-2", separator="-"), 

66 {"first": "1", "second": "2"}) 

67 

68 

69class SplitKvCmdTestCase(unittest.TestCase): 

70 """Tests using split_kv with a command.""" 

71 

72 def setUp(self): 

73 self.runner = LogCliRunner() 

74 

75 def test_cli(self): 

76 mock = MagicMock() 

77 @click.command() 

78 @click.option("--value", callback=split_kv, multiple=True) 

79 def cli(value): 

80 mock(value) 

81 

82 result = self.runner.invoke(cli, ["--value", "first=1"]) 

83 self.assertEqual(result.exit_code, 0, msg=clickResultMsg(result)) 

84 mock.assert_called_with({'first': '1'}) 

85 

86 result = self.runner.invoke(cli, ["--value", "first=1,second=2"]) 

87 self.assertEqual(result.exit_code, 0, msg=clickResultMsg(result)) 

88 mock.assert_called_with({'first': '1', 'second': '2'}) 

89 

90 result = self.runner.invoke(cli, ["--value", "first=1", "--value", "second=2"]) 

91 self.assertEqual(result.exit_code, 0, msg=clickResultMsg(result)) 

92 mock.assert_called_with({'first': '1', 'second': '2'}) 

93 

94 # double separator "==" should fail: 

95 result = self.runner.invoke(cli, ["--value", "first==1"]) 

96 self.assertEqual(result.exit_code, 1) 

97 self.assertEqual(result.output, 

98 "Error: Could not parse key-value pair 'first==1' using separator '=', with " 

99 "multiple values allowed.\n") 

100 

101 def test_choice(self): 

102 choices = ["FOO", "BAR", "BAZ"] 

103 mock = MagicMock() 

104 @click.command() 

105 @click.option("--metasyntactic-var", 

106 callback=partial(split_kv, 

107 unseparated_okay=True, 

108 choice=click.Choice(choices, case_sensitive=False), 

109 normalize=True)) 

110 def cli(metasyntactic_var): 

111 mock(metasyntactic_var) 

112 

113 # check a valid choice without a kv separator 

114 result = self.runner.invoke(cli, ["--metasyntactic-var", "FOO"]) 

115 self.assertEqual(result.exit_code, 0, msg=clickResultMsg(result)) 

116 mock.assert_called_with({"": "FOO"}) 

117 

118 # check a valid choice with a kv separator 

119 result = self.runner.invoke(cli, ["--metasyntactic-var", "lsst.daf.butler=BAR"]) 

120 self.assertEqual(result.exit_code, 0, msg=clickResultMsg(result)) 

121 mock.assert_called_with({"lsst.daf.butler": "BAR"}) 

122 

123 # check invalid choices with and wihtout kv separators 

124 for val in ("BOZ", "lsst.daf.butler=BOZ"): 

125 result = self.runner.invoke(cli, ["--metasyntactic-var", val]) 

126 self.assertNotEqual(result.exit_code, 0, msg=clickResultMsg(result)) 

127 self.assertIn('Error: Invalid value for "--metasyntactic-var": invalid choice: BOZ. ' 

128 f'(choose from {", ".join(choices)})', 

129 result.output) 

130 

131 # check value normalization (lower case "foo" should become "FOO") 

132 result = self.runner.invoke(cli, ["--metasyntactic-var", "lsst.daf.butler=foo"]) 

133 self.assertEqual(result.exit_code, 0, msg=clickResultMsg(result)) 

134 mock.assert_called_with({"lsst.daf.butler": "FOO"}) 

135 

136 def test_separatorDash(self): 

137 def split_kv_dash(context, param, values): 

138 return split_kv(context, param, values, separator="-") 

139 

140 mock = MagicMock() 

141 @click.command() 

142 @click.option("--value", callback=split_kv_dash, multiple=True) 

143 def cli(value): 

144 mock(value) 

145 

146 result = self.runner.invoke(cli, ["--value", "first-1"]) 

147 self.assertEqual(result.exit_code, 0, msg=clickResultMsg(result)) 

148 mock.assert_called_with({'first': '1'}) 

149 

150 def test_separatorFunctoolsDash(self): 

151 mock = MagicMock() 

152 @click.command() 

153 @click.option("--value", callback=partial(split_kv, separator="-"), multiple=True) 

154 def cli(value): 

155 mock(value) 

156 result = self.runner.invoke(cli, ["--value", "first-1", "--value", "second-2"]) 

157 self.assertEqual(result.exit_code, 0, msg=clickResultMsg(result)) 

158 mock.assert_called_with({'first': '1', 'second': '2'}) 

159 

160 def test_separatorSpace(self): 

161 @click.command() 

162 @click.option("--value", callback=partial(split_kv, separator=" "), multiple=True) 

163 def cli(value): 

164 pass 

165 result = self.runner.invoke(cli, ["--value", "first 1"]) 

166 self.assertEqual(str(result.exception), 

167 "' ' is not a supported separator for key-value pairs.") 

168 

169 def test_separatorComma(self): 

170 @click.command() 

171 @click.option("--value", callback=partial(split_kv, separator=","), multiple=True) 

172 def cli(value): 

173 pass 

174 result = self.runner.invoke(cli, ["--value", "first,1"]) 

175 self.assertEqual(str(result.exception), 

176 "',' is not a supported separator for key-value pairs.") 

177 

178 def test_normalizeWithoutChoice(self): 

179 """Test that normalize=True without Choice fails gracefully. 

180 

181 Normalize uses values in the provided Choice to create the normalized 

182 value. Without a provided Choice, it can't normalize. Verify that this 

183 does not cause a crash or other bad behavior, it just doesn't normalize 

184 anything. 

185 """ 

186 mock = MagicMock() 

187 @click.command() 

188 @click.option("--value", callback=partial(split_kv, normalize=True)) 

189 def cli(value): 

190 mock(value) 

191 result = self.runner.invoke(cli, ["--value", "foo=bar"]) 

192 self.assertEqual(result.exit_code, 0, msg=clickResultMsg(result)) 

193 mock.assert_called_with(dict(foo="bar")) 

194 

195 

196if __name__ == "__main__": 196 ↛ 197line 196 didn't jump to line 197, because the condition on line 196 was never true

197 unittest.main()