bpo-35598: IDLE: Increase test coverage for config_key.py (#11360) · python/cpython@b0a6196

1-

"Test config_key, coverage 82%"

1+

"""Test config_key, coverage 98%.

2+3+

Coverage is effectively 100%. Tkinter dialog is mocked, Mac-only line

4+

may be skipped, and dummy function in bind test should not be called.

5+

Not tested: exit with 'self.advanced or self.keys_ok(keys)) ...' False.

6+

"""

2738

from idlelib import config_key

49

from test.support import requires

510

import unittest

6-

from tkinter import Tk

11+

from unittest import mock

12+

from tkinter import Tk, TclError

713

from idlelib.idle_test.mock_idle import Func

814

from idlelib.idle_test.mock_tk import Mbox_func

91516+

gkd = config_key.GetKeysDialog

17+10181119

class ValidationTest(unittest.TestCase):

1220

"Test validation methods: ok, keys_ok, bind_ok."

132114-

class Validator(config_key.GetKeysDialog):

22+

class Validator(gkd):

1523

def __init__(self, *args, **kwargs):

1624

config_key.GetKeysDialog.__init__(self, *args, **kwargs)

1725

class list_keys_final:

@@ -95,5 +103,186 @@ def test_bind_not_ok(self):

95103

self.assertIn('not accepted', self.dialog.showerror.message)

9610497105106+

class ToggleLevelTest(unittest.TestCase):

107+

"Test toggle between Basic and Advanced frames."

108+109+

@classmethod

110+

def setUpClass(cls):

111+

requires('gui')

112+

cls.root = Tk()

113+

cls.root.withdraw()

114+

cls.dialog = gkd(cls.root, 'Title', '<<Test>>', [], _utest=True)

115+116+

@classmethod

117+

def tearDownClass(cls):

118+

cls.dialog.cancel()

119+

cls.root.update_idletasks()

120+

cls.root.destroy()

121+

del cls.dialog, cls.root

122+123+

def test_toggle_level(self):

124+

dialog = self.dialog

125+126+

def stackorder():

127+

"""Get the stack order of the children of the frame.

128+129+

winfo_children() stores the children in stack order, so

130+

this can be used to check whether a frame is above or

131+

below another one.

132+

"""

133+

for index, child in enumerate(dialog.frame.winfo_children()):

134+

if child._name == 'keyseq_basic':

135+

basic = index

136+

if child._name == 'keyseq_advanced':

137+

advanced = index

138+

return basic, advanced

139+140+

# New window starts at basic level.

141+

self.assertFalse(dialog.advanced)

142+

self.assertIn('Advanced', dialog.button_level['text'])

143+

basic, advanced = stackorder()

144+

self.assertGreater(basic, advanced)

145+146+

# Toggle to advanced.

147+

dialog.toggle_level()

148+

self.assertTrue(dialog.advanced)

149+

self.assertIn('Basic', dialog.button_level['text'])

150+

basic, advanced = stackorder()

151+

self.assertGreater(advanced, basic)

152+153+

# Toggle to basic.

154+

dialog.button_level.invoke()

155+

self.assertFalse(dialog.advanced)

156+

self.assertIn('Advanced', dialog.button_level['text'])

157+

basic, advanced = stackorder()

158+

self.assertGreater(basic, advanced)

159+160+161+

class KeySelectionTest(unittest.TestCase):

162+

"Test selecting key on Basic frames."

163+164+

class Basic(gkd):

165+

def __init__(self, *args, **kwargs):

166+

super().__init__(*args, **kwargs)

167+

class list_keys_final:

168+

get = Func()

169+

select_clear = Func()

170+

yview = Func()

171+

self.list_keys_final = list_keys_final

172+

def set_modifiers_for_platform(self):

173+

self.modifiers = ['foo', 'bar', 'BAZ']

174+

self.modifier_label = {'BAZ': 'ZZZ'}

175+

showerror = Mbox_func()

176+177+

@classmethod

178+

def setUpClass(cls):

179+

requires('gui')

180+

cls.root = Tk()

181+

cls.root.withdraw()

182+

cls.dialog = cls.Basic(cls.root, 'Title', '<<Test>>', [], _utest=True)

183+184+

@classmethod

185+

def tearDownClass(cls):

186+

cls.dialog.cancel()

187+

cls.root.update_idletasks()

188+

cls.root.destroy()

189+

del cls.dialog, cls.root

190+191+

def setUp(self):

192+

self.dialog.clear_key_seq()

193+194+

def test_get_modifiers(self):

195+

dialog = self.dialog

196+

gm = dialog.get_modifiers

197+

eq = self.assertEqual

198+199+

# Modifiers are set by selecting/deselecting the checkbutton.

200+

dialog.modifier_checkbuttons['foo'].select()

201+

eq(gm(), ['foo'])

202+203+

dialog.modifier_checkbuttons['BAZ'].select()

204+

eq(gm(), ['foo', 'BAZ'])

205+206+

dialog.modifier_checkbuttons['foo'].deselect()

207+

eq(gm(), ['BAZ'])

208+209+

def test_translate_key(self):

210+

dialog = self.dialog

211+

tr = dialog.translate_key

212+

eq = self.assertEqual

213+214+

# Letters return unchanged with no 'Shift'.

215+

eq(tr('q', []), 'Key-q')

216+

eq(tr('q', ['Control', 'Alt']), 'Key-q')

217+218+

# 'Shift' uppercases single lowercase letters.

219+

eq(tr('q', ['Shift']), 'Key-Q')

220+

eq(tr('q', ['Control', 'Shift']), 'Key-Q')

221+

eq(tr('q', ['Control', 'Alt', 'Shift']), 'Key-Q')

222+223+

# Convert key name to keysym.

224+

eq(tr('Page Up', []), 'Key-Prior')

225+

# 'Shift' doesn't change case.

226+

eq(tr('Page Down', ['Shift']), 'Key-Next')

227+228+

@mock.patch.object(gkd, 'get_modifiers')

229+

def test_build_key_string(self, mock_modifiers):

230+

dialog = self.dialog

231+

key = dialog.list_keys_final

232+

string = dialog.key_string.get

233+

eq = self.assertEqual

234+235+

key.get.result = 'a'

236+

mock_modifiers.return_value = []

237+

dialog.build_key_string()

238+

eq(string(), '<Key-a>')

239+240+

mock_modifiers.return_value = ['mymod']

241+

dialog.build_key_string()

242+

eq(string(), '<mymod-Key-a>')

243+244+

key.get.result = ''

245+

mock_modifiers.return_value = ['mymod', 'test']

246+

dialog.build_key_string()

247+

eq(string(), '<mymod-test>')

248+249+

@mock.patch.object(gkd, 'get_modifiers')

250+

def test_final_key_selected(self, mock_modifiers):

251+

dialog = self.dialog

252+

key = dialog.list_keys_final

253+

string = dialog.key_string.get

254+

eq = self.assertEqual

255+256+

mock_modifiers.return_value = ['Shift']

257+

key.get.result = '{'

258+

dialog.final_key_selected()

259+

eq(string(), '<Shift-Key-braceleft>')

260+261+262+

class CancelTest(unittest.TestCase):

263+

"Simulate user clicking [Cancel] button."

264+265+

@classmethod

266+

def setUpClass(cls):

267+

requires('gui')

268+

cls.root = Tk()

269+

cls.root.withdraw()

270+

cls.dialog = gkd(cls.root, 'Title', '<<Test>>', [], _utest=True)

271+272+

@classmethod

273+

def tearDownClass(cls):

274+

cls.dialog.cancel()

275+

cls.root.update_idletasks()

276+

cls.root.destroy()

277+

del cls.dialog, cls.root

278+279+

def test_cancel(self):

280+

self.assertEqual(self.dialog.winfo_class(), 'Toplevel')

281+

self.dialog.button_cancel.invoke()

282+

with self.assertRaises(TclError):

283+

self.dialog.winfo_class()

284+

self.assertEqual(self.dialog.result, '')

285+286+98287

if __name__ == '__main__':

99288

unittest.main(verbosity=2)