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 dataset-type CLI option. 

23""" 

24 

25import abc 

26import click 

27import click.testing 

28import unittest 

29import yaml 

30 

31from lsst.daf.butler.registry import CollectionType 

32from lsst.daf.butler.cli.opt import (collection_type_option, config_file_option, config_option, 

33 dataset_type_option, directory_argument, glob_parameter, verbose_option) 

34from lsst.daf.butler.cli.utils import clickResultMsg 

35 

36 

37class OptionTestBase(unittest.TestCase, abc.ABC): 

38 

39 def setUp(self): 

40 self.runner = click.testing.CliRunner() 

41 

42 def run_command(self, cmd, args): 

43 """ 

44 

45 Parameters 

46 ---------- 

47 cmd : click.Command 

48 The command function to call 

49 args : [`str`] 

50 The arguments to pass to the function call. 

51 

52 Returns 

53 ------- 

54 [type] 

55 [description] 

56 """ 

57 return self.runner.invoke(cmd, args) 

58 

59 def run_test(self, cmd, cmdArgs, verifyFunc, verifyArgs=None): 

60 result = self.run_command(cmd, cmdArgs) 

61 verifyFunc(result, verifyArgs) 

62 

63 def run_help_test(self, cmd, expcectedHelpText): 

64 result = self.runner.invoke(cmd, ["--help"]) 

65 # remove all whitespace to work around line-wrap differences. 

66 self.assertIn("".join(expcectedHelpText.split()), "".join(result.output.split())) 

67 

68 @property 

69 @abc.abstractmethod 

70 def optionClass(self): 

71 pass 

72 

73 def help_test(self): 

74 @click.command() 

75 @self.optionClass() 

76 def cli(): 

77 pass 

78 

79 self.run_help_test(cli, self.optionClass.defaultHelp) 

80 

81 def custom_help_test(self): 

82 @click.command() 

83 @self.optionClass(help="foobarbaz") 

84 def cli(collection_type): 

85 pass 

86 

87 self.run_help_test(cli, "foobarbaz") 

88 

89 

90class CollectionTypeTestCase(OptionTestBase): 

91 

92 optionClass = collection_type_option 

93 

94 def setUp(self): 

95 super().setUp() 

96 CollectionTypeTestCase.collectionType = None 

97 

98 @staticmethod 

99 @click.command() 

100 @collection_type_option() 

101 def cli(collection_type): 

102 CollectionTypeTestCase.collectionType = collection_type 

103 

104 def verify(self, result, verifyArgs): 

105 self.assertEqual(result.exit_code, 0, clickResultMsg(result)) 

106 self.assertEqual(CollectionTypeTestCase.collectionType, verifyArgs) 

107 

108 def test_run(self): 

109 self.run_test(CollectionTypeTestCase.cli, ["--collection-type", "RUN"], 

110 self.verify, CollectionType.RUN) 

111 

112 def test_chained(self): 

113 self.run_test(CollectionTypeTestCase.cli, ["--collection-type", "CHAINED"], 

114 self.verify, CollectionType.CHAINED) 

115 

116 def test_tagged(self): 

117 self.run_test(CollectionTypeTestCase.cli, ["--collection-type", "TAGGED"], 

118 self.verify, CollectionType.TAGGED) 

119 

120 def test_default(self): 

121 self.run_test(CollectionTypeTestCase.cli, [], 

122 self.verify, None) 

123 

124 def test_caseInsensitive(self): 

125 self.run_test(CollectionTypeTestCase.cli, ["--collection-type", "TaGGeD"], 

126 self.verify, CollectionType.TAGGED) 

127 

128 def test_help(self): 

129 self.help_test() 

130 self.custom_help_test() 

131 

132 

133class ConfigTestCase(OptionTestBase): 

134 

135 optionClass = config_option 

136 

137 @staticmethod 

138 @click.command() 

139 @config_option() 

140 def cli(config): 

141 click.echo(yaml.dump(config), nl=False) 

142 

143 def test_basic(self): 

144 """test arguments""" 

145 result = self.runner.invoke(ConfigTestCase.cli, ["--config", "a=1", "-c", "b=2,c=3"]) 

146 self.assertEqual(result.exit_code, 0, f"output: {result.output} exception: {result.exception}") 

147 self.assertEqual(yaml.safe_load(result.stdout), dict(a="1", b="2", c="3")) 

148 

149 def test_missing(self): 

150 @click.command() 

151 @config_option(required=True) 

152 def cli(config): 

153 pass 

154 

155 result = self.runner.invoke(cli, []) 

156 self.assertNotEqual(result.exit_code, 0, f"output: {result.output} exception: {result.exception}") 

157 self.assertIn('Missing option "-c" / "--config"', result.output) 

158 

159 def test_help(self): 

160 self.help_test() 

161 self.custom_help_test() 

162 

163 

164class ConfigFileTestCase(OptionTestBase): 

165 

166 optionClass = config_file_option 

167 

168 @staticmethod 

169 @click.command() 

170 @config_file_option() 

171 def cli(config_file): 

172 click.echo(config_file, nl=False) 

173 

174 def test_basic(self): 

175 """test arguments""" 

176 result = self.runner.invoke(ConfigFileTestCase.cli, ["--config-file", "path/to/file"]) 

177 self.assertEqual(result.exit_code, 0, f"output: {result.output} exception: {result.exception}") 

178 self.assertEqual("path/to/file", result.stdout) 

179 

180 def test_missing(self): 

181 @click.command() 

182 @config_file_option(required=True) 

183 def cli(config): 

184 pass 

185 result = self.runner.invoke(cli, []) 

186 self.assertNotEqual(result.exit_code, 0, f"output: {result.output} exception: {result.exception}") 

187 self.assertIn('Missing option "-C" / "--config-file"', result.output) 

188 

189 def test_help(self): 

190 self.help_test() 

191 self.custom_help_test() 

192 

193 

194class DatasetTypeTestCase(OptionTestBase): 

195 

196 optionClass = dataset_type_option 

197 

198 @staticmethod 

199 @click.command() 

200 @dataset_type_option(help="the dataset type") 

201 def cli(dataset_type): 

202 click.echo(dataset_type, nl=False) 

203 

204 def verify(self, result, verifyArgs): 

205 self.assertEqual(result.exit_code, 0, clickResultMsg(result)) 

206 self.assertEqual(result.stdout, verifyArgs) 

207 

208 def test_single(self): 

209 """test a single argument""" 

210 self.run_test(DatasetTypeTestCase.cli, ["--dataset-type", "one"], self.verify, "['one']") 

211 

212 def test_multiple(self): 

213 """test multiple arguments, using the long and short option names""" 

214 self.run_test(DatasetTypeTestCase.cli, ["--dataset-type", "one", "-d", "two"], 

215 self.verify, "['one', 'two']") 

216 

217 def test_singlePair(self): 

218 """test a single comma-separated value pair""" 

219 self.run_test(DatasetTypeTestCase.cli, ["--dataset-type", "one,two"], 

220 self.verify, "['one', 'two']") 

221 

222 def test_multiplePair(self): 

223 """test multiple comma-separated value pairs""" 

224 self.run_test(DatasetTypeTestCase.cli, ["--dataset-type", "one,two", "-d", "three,four"], 

225 self.verify, "['one', 'two', 'three', 'four']") 

226 

227 def test_help(self): 

228 # dataset_type_option does not have default help 

229 self.custom_help_test() 

230 

231 

232class DirectoryArgumentTestCase(OptionTestBase): 

233 

234 optionClass = directory_argument 

235 

236 def test_required(self): 

237 """test arguments""" 

238 @click.command() 

239 @directory_argument(required=True) 

240 def cli(directory): 

241 click.echo(directory, nl=False) 

242 result = self.runner.invoke(cli, ["this_dir"]) 

243 self.assertEqual(result.exit_code, 0, clickResultMsg(result)) 

244 self.assertEqual("this_dir", result.stdout) 

245 result = self.runner.invoke(cli, []) 

246 self.assertNotEqual(result.exit_code, 0, clickResultMsg(result)) 

247 self.assertIn('Missing argument "DIRECTORY"', result.stdout) 

248 

249 def test_notRequired(self): 

250 """test arguments""" 

251 @click.command() 

252 @directory_argument() 

253 def cli(directory): 

254 click.echo(directory, nl=False) 

255 result = self.runner.invoke(cli, ["this_dir"]) 

256 self.assertEqual(result.exit_code, 0, clickResultMsg(result)) 

257 self.assertEqual("this_dir", result.stdout) 

258 result = self.runner.invoke(cli, []) 

259 self.assertEqual(result.exit_code, 0, clickResultMsg(result)) 

260 self.assertEqual("", result.stdout) 

261 

262 def test_help(self): 

263 # directory_argument does not have default help. 

264 self.custom_help_test() 

265 

266 

267class GlobTestCase(OptionTestBase): 

268 

269 optionClass = glob_parameter 

270 

271 def verify(self, result, verifyArgs): 

272 self.assertEqual(result.exit_code, 0, f"output: {result.output} exception: {result.exception}") 

273 self.assertIn(verifyArgs, result.stdout) 

274 

275 def verifyMissing(self, result, verifyArgs): 

276 self.assertNotEqual(result.exit_code, 0, f"output: {result.output} exception: {result.exception}") 

277 self.assertIn(verifyArgs, result.stdout) 

278 

279 def test_glob_argument(self): 

280 """test argument""" 

281 @click.command() 

282 @glob_parameter(parameterType=glob_parameter.ARGUMENT) 

283 def cli(glob): 

284 if glob is None: 

285 glob = "None" 

286 print(glob) 

287 

288 self.run_test(cli, ["foo*"], self.verify, "foo*") 

289 self.run_test(cli, [], self.verify, "None") 

290 

291 def test_glob_argument_required(self): 

292 """test with argument required""" 

293 @click.command() 

294 @glob_parameter(parameterType=glob_parameter.ARGUMENT, required=True) 

295 def cli(glob): 

296 print(glob) 

297 

298 self.run_test(cli, ["foo*"], self.verify, "foo*") 

299 self.run_test(cli, [], self.verifyMissing, 'Error: Missing argument "GLOB"') 

300 

301 def test_glob_option(self): 

302 """test option""" 

303 @click.command() 

304 @glob_parameter() 

305 def cli(glob): 

306 if glob is None: 

307 glob = "None" 

308 print(glob) 

309 

310 self.run_test(cli, ["--glob", "foo*"], self.verify, "foo*") 

311 self.run_test(cli, [], self.verify, "None") 

312 

313 def test_glob_option_required(self): 

314 """test with argument required""" 

315 @click.command() 

316 @glob_parameter(parameterType=glob_parameter.ARGUMENT, required=True) 

317 def cli(glob): 

318 print(glob) 

319 

320 self.run_test(cli, ["foo*"], self.verify, "foo*") 

321 self.run_test(cli, [], self.verifyMissing, 'Error: Missing argument "GLOB"') 

322 

323 def test_glob_argument_multiple(self): 

324 """test with multiple argument values""" 

325 @click.command() 

326 @glob_parameter(parameterType=glob_parameter.ARGUMENT, multiple=True) 

327 def cli(glob): 

328 print(glob) 

329 

330 self.run_test(cli, ["foo*", "bar", "b?z"], self.verify, "('foo*', 'bar', 'b?z')") 

331 

332 def test_glob_option_multiple(self): 

333 """test with multiple option values""" 

334 @click.command() 

335 @glob_parameter(multiple=True) 

336 def cli(glob): 

337 print(glob) 

338 

339 self.run_test(cli, ["--glob", "foo*", "--glob", "bar", "--glob", "b?z"], self.verify, 

340 "('foo*', 'bar', 'b?z')") 

341 

342 def test_help(self): 

343 self.help_test() 

344 self.custom_help_test() 

345 

346 

347class VerboseTestCase(OptionTestBase): 

348 

349 optionClass = verbose_option 

350 

351 @staticmethod 

352 @click.command() 

353 @verbose_option() 

354 def cli(verbose): 

355 print(verbose) 

356 

357 def verify(self, result, verifyArgs): 

358 self.assertEqual(result.exit_code, 0, f"output: {result.output} exception: {result.exception}") 

359 self.assertIn(verifyArgs, result.stdout) 

360 

361 def test_verbose(self): 

362 """test arguments""" 

363 self.run_test(self.cli, ["--verbose"], self.verify, "True") 

364 

365 def test_notVerbose(self): 

366 """test arguments""" 

367 self.run_test(self.cli, [], self.verify, "False") 

368 

369 def test_help(self): 

370 self.help_test() 

371 self.custom_help_test() 

372 

373 

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

375 unittest.main()