Skip to content

Commit a2b6e57

Browse files
miss-islingtonserhiy-storchakaclaude
authored
[3.13] gh-153741: Harden IDLE GUI tests for newer Tk and display scaling (GH-153742) (#154406)
gh-153741: Harden IDLE GUI tests for newer Tk and display scaling (GH-153742) In test_sidebar.test_mousewheel, only use the X11 <Button-4>/<Button-5> events when testing on x11 Tk before 8.7. Otherwise, use <Mousewheel> as on other systems. In test_configdialog, assert the 'disabled' state flag alone instead of the exact ttk state tuple (which transient pointer states break), and restore the tests' method masks with addCleanup(). (cherry picked from commit a2581eb) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 45d5301 commit a2b6e57

2 files changed

Lines changed: 38 additions & 35 deletions

File tree

Lib/idlelib/idle_test/test_configdialog.py

Lines changed: 31 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ def test_font_set(self):
245245

246246
def test_set_samples(self):
247247
d = self.page
248+
self.addCleanup(setattr, d, 'set_samples', Func()) # Re-mask for other tests.
248249
del d.set_samples # Unmask method for test
249250
orig_samples = d.font_sample, d.highlight_sample
250251
d.font_sample, d.highlight_sample = {}, {}
@@ -258,7 +259,6 @@ def test_set_samples(self):
258259
self.assertTrue(d.font_sample == d.highlight_sample == expected)
259260

260261
d.font_sample, d.highlight_sample = orig_samples
261-
d.set_samples = Func() # Re-mask for other tests.
262262

263263

264264
class HighPageTest(unittest.TestCase):
@@ -308,7 +308,7 @@ def test_load_theme_cfg(self):
308308
# builtinlist sets variable builtin_name to the CurrentTheme default.
309309
eq(d.builtin_name.get(), 'IDLE Classic')
310310
eq(d.custom_name.get(), '- no custom themes -')
311-
eq(d.custom_theme_on.state(), ('disabled',))
311+
self.assertIn('disabled', d.custom_theme_on.state())
312312
eq(d.set_theme_type.called, 1)
313313
eq(d.paint_theme_sample.called, 1)
314314
eq(d.set_highlight_target.called, 1)
@@ -496,23 +496,23 @@ def test_highlight_sample_b1_motion(self):
496496
def test_set_theme_type(self):
497497
eq = self.assertEqual
498498
d = self.page
499+
self.addCleanup(setattr, d, 'set_theme_type', Func()) # Re-mask method.
499500
del d.set_theme_type
500501

501502
# Builtin theme selected.
502503
d.theme_source.set(True)
503504
d.set_theme_type()
504505
eq(d.builtinlist['state'], NORMAL)
505506
eq(d.customlist['state'], DISABLED)
506-
eq(d.button_delete_custom.state(), ('disabled',))
507+
self.assertIn('disabled', d.button_delete_custom.state())
507508

508509
# Custom theme selected.
509510
d.theme_source.set(False)
510511
d.set_theme_type()
511512
eq(d.builtinlist['state'], DISABLED)
512-
eq(d.custom_theme_on.state(), ('selected',))
513+
self.assertNotIn('disabled', d.custom_theme_on.state())
513514
eq(d.customlist['state'], NORMAL)
514-
eq(d.button_delete_custom.state(), ())
515-
d.set_theme_type = Func()
515+
self.assertNotIn('disabled', d.button_delete_custom.state())
516516

517517
def test_get_color(self):
518518
eq = self.assertEqual
@@ -638,24 +638,23 @@ def test_create_new_and_save_new(self):
638638
def test_set_highlight_target(self):
639639
eq = self.assertEqual
640640
d = self.page
641+
self.addCleanup(setattr, d, 'set_highlight_target', Func()) # Re-mask method.
641642
del d.set_highlight_target
642643

643644
# Target is cursor.
644645
d.highlight_target.set('Cursor')
645-
eq(d.fg_on.state(), ('disabled', 'selected'))
646-
eq(d.bg_on.state(), ('disabled',))
646+
self.assertIn('disabled', d.fg_on.state())
647+
self.assertIn('disabled', d.bg_on.state())
647648
self.assertTrue(d.fg_bg_toggle)
648649
eq(d.set_color_sample.called, 1)
649650

650651
# Target is not cursor.
651652
d.highlight_target.set('Comment')
652-
eq(d.fg_on.state(), ('selected',))
653-
eq(d.bg_on.state(), ())
653+
self.assertNotIn('disabled', d.fg_on.state())
654+
self.assertNotIn('disabled', d.bg_on.state())
654655
self.assertTrue(d.fg_bg_toggle)
655656
eq(d.set_color_sample.called, 2)
656657

657-
d.set_highlight_target = Func()
658-
659658
def test_set_color_sample_binding(self):
660659
d = self.page
661660
scs = d.set_color_sample
@@ -668,14 +667,14 @@ def test_set_color_sample_binding(self):
668667

669668
def test_set_color_sample(self):
670669
d = self.page
670+
self.addCleanup(setattr, d, 'set_color_sample', Func()) # Re-mask method.
671671
del d.set_color_sample
672672
d.highlight_target.set('Selected Text')
673673
d.fg_bg_toggle.set(True)
674674
d.set_color_sample()
675675
self.assertEqual(
676676
d.style.lookup(d.frame_color_set['style'], 'background'),
677677
d.highlight_sample.tag_cget('hilite', 'foreground'))
678-
d.set_color_sample = Func()
679678

680679
def test_paint_theme_sample(self):
681680
eq = self.assertEqual
@@ -746,7 +745,7 @@ def test_delete_custom(self):
746745
eq(yesno.called, 2)
747746
self.assertNotIn(theme_name, highpage)
748747
eq(idleConf.GetSectionList('user', 'highlight'), [theme_name2])
749-
eq(d.custom_theme_on.state(), ())
748+
self.assertNotIn('disabled', d.custom_theme_on.state())
750749
eq(d.custom_name.get(), theme_name2)
751750
eq(dialog.deactivate_current_config.called, 1)
752751
eq(dialog.activate_config_changes.called, 1)
@@ -759,7 +758,7 @@ def test_delete_custom(self):
759758
eq(yesno.called, 3)
760759
self.assertNotIn(theme_name, highpage)
761760
eq(idleConf.GetSectionList('user', 'highlight'), [])
762-
eq(d.custom_theme_on.state(), ('disabled',))
761+
self.assertIn('disabled', d.custom_theme_on.state())
763762
eq(d.custom_name.get(), '- no custom themes -')
764763
eq(dialog.deactivate_current_config.called, 2)
765764
eq(dialog.activate_config_changes.called, 2)
@@ -810,7 +809,7 @@ def test_load_key_cfg(self):
810809
# builtinlist sets variable builtin_name to the CurrentKeys default.
811810
eq(d.builtin_name.get(), 'IDLE Classic OSX')
812811
eq(d.custom_name.get(), '- no custom keys -')
813-
eq(d.custom_keyset_on.state(), ('disabled',))
812+
self.assertIn('disabled', d.custom_keyset_on.state())
814813
eq(d.set_keys_type.called, 1)
815814
eq(d.load_keys_list.called, 1)
816815
eq(d.load_keys_list.args, ('IDLE Classic OSX', ))
@@ -931,23 +930,23 @@ def test_keybinding(self):
931930
def test_set_keys_type(self):
932931
eq = self.assertEqual
933932
d = self.page
933+
self.addCleanup(setattr, d, 'set_keys_type', Func()) # Re-mask method.
934934
del d.set_keys_type
935935

936936
# Builtin keyset selected.
937937
d.keyset_source.set(True)
938938
d.set_keys_type()
939939
eq(d.builtinlist['state'], NORMAL)
940940
eq(d.customlist['state'], DISABLED)
941-
eq(d.button_delete_custom_keys.state(), ('disabled',))
941+
self.assertIn('disabled', d.button_delete_custom_keys.state())
942942

943943
# Custom keyset selected.
944944
d.keyset_source.set(False)
945945
d.set_keys_type()
946946
eq(d.builtinlist['state'], DISABLED)
947-
eq(d.custom_keyset_on.state(), ('selected',))
947+
self.assertNotIn('disabled', d.custom_keyset_on.state())
948948
eq(d.customlist['state'], NORMAL)
949-
eq(d.button_delete_custom_keys.state(), ())
950-
d.set_keys_type = Func()
949+
self.assertNotIn('disabled', d.button_delete_custom_keys.state())
951950

952951
def test_get_new_keys(self):
953952
eq = self.assertEqual
@@ -1044,7 +1043,7 @@ def test_on_bindingslist_select(self):
10441043
b.event_generate('<Button-1>', x=x, y=y)
10451044
b.event_generate('<ButtonRelease-1>', x=x, y=y)
10461045
self.assertEqual(b.get('anchor'), 'find')
1047-
self.assertEqual(d.button_new_keys.state(), ())
1046+
self.assertNotIn('disabled', d.button_new_keys.state())
10481047

10491048
def test_create_new_key_set_and_save_new_key_set(self):
10501049
eq = self.assertEqual
@@ -1081,6 +1080,7 @@ def test_load_keys_list(self):
10811080
eq = self.assertEqual
10821081
d = self.page
10831082
gks = idleConf.GetKeySet = Func()
1083+
self.addCleanup(setattr, d, 'load_keys_list', Func()) # Re-mask method.
10841084
del d.load_keys_list
10851085
b = d.bindingslist
10861086

@@ -1116,7 +1116,6 @@ def test_load_keys_list(self):
11161116
eq(b.get(0, 'end'), expected)
11171117
eq(b.get('anchor'), 'spam - <Shift-Key-a>')
11181118
eq(b.curselection(), (2, ))
1119-
d.load_keys_list = Func()
11201119

11211120
del idleConf.GetKeySet
11221121

@@ -1157,7 +1156,7 @@ def test_delete_custom_keys(self):
11571156
eq(yesno.called, 2)
11581157
self.assertNotIn(keyset_name, keyspage)
11591158
eq(idleConf.GetSectionList('user', 'keys'), [keyset_name2])
1160-
eq(d.custom_keyset_on.state(), ())
1159+
self.assertNotIn('disabled', d.custom_keyset_on.state())
11611160
eq(d.custom_name.get(), keyset_name2)
11621161
eq(dialog.deactivate_current_config.called, 1)
11631162
eq(dialog.activate_config_changes.called, 1)
@@ -1170,7 +1169,7 @@ def test_delete_custom_keys(self):
11701169
eq(yesno.called, 3)
11711170
self.assertNotIn(keyset_name, keyspage)
11721171
eq(idleConf.GetSectionList('user', 'keys'), [])
1173-
eq(d.custom_keyset_on.state(), ('disabled',))
1172+
self.assertIn('disabled', d.custom_keyset_on.state())
11741173
eq(d.custom_name.get(), '- no custom keys -')
11751174
eq(dialog.deactivate_current_config.called, 2)
11761175
eq(dialog.activate_config_changes.called, 2)
@@ -1366,25 +1365,25 @@ def test_set_add_delete_state(self):
13661365
# Call with 0 items, 1 unselected item, 1 selected item.
13671366
eq = self.assertEqual
13681367
fr = self.frame
1368+
self.addCleanup(setattr, fr, 'set_add_delete_state', Func()) # Re-mask method.
13691369
del fr.set_add_delete_state # Unmask method.
13701370
sad = fr.set_add_delete_state
13711371
h = fr.helplist
13721372

13731373
h.delete(0, 'end')
13741374
sad()
1375-
eq(fr.button_helplist_edit.state(), ('disabled',))
1376-
eq(fr.button_helplist_remove.state(), ('disabled',))
1375+
self.assertIn('disabled', fr.button_helplist_edit.state())
1376+
self.assertIn('disabled', fr.button_helplist_remove.state())
13771377

13781378
h.insert(0, 'source')
13791379
sad()
1380-
eq(fr.button_helplist_edit.state(), ('disabled',))
1381-
eq(fr.button_helplist_remove.state(), ('disabled',))
1380+
self.assertIn('disabled', fr.button_helplist_edit.state())
1381+
self.assertIn('disabled', fr.button_helplist_remove.state())
13821382

13831383
h.selection_set(0)
13841384
sad()
1385-
eq(fr.button_helplist_edit.state(), ())
1386-
eq(fr.button_helplist_remove.state(), ())
1387-
fr.set_add_delete_state = Func() # Mask method.
1385+
self.assertNotIn('disabled', fr.button_helplist_edit.state())
1386+
self.assertNotIn('disabled', fr.button_helplist_remove.state())
13881387

13891388
def test_helplist_item_add(self):
13901389
# Call without and twice with HelpSource result.
@@ -1462,6 +1461,7 @@ def test_helplist_item_remove(self):
14621461

14631462
def test_update_help_changes(self):
14641463
fr = self.frame
1464+
self.addCleanup(setattr, fr, 'update_help_changes', Func()) # Re-mask method.
14651465
del fr.update_help_changes
14661466
fr.user_helplist.clear()
14671467
fr.user_helplist.append(('name1', 'file1'))
@@ -1470,7 +1470,6 @@ def test_update_help_changes(self):
14701470
fr.update_help_changes()
14711471
self.assertEqual(mainpage['HelpFiles'],
14721472
{'1': 'name1;file1', '2': 'name2;file2'})
1473-
fr.update_help_changes = Func()
14741473

14751474

14761475
class VarTraceTest(unittest.TestCase):

Lib/idlelib/idle_test/test_sidebar.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -689,19 +689,23 @@ def test_mousewheel(self):
689689
last_lineno = get_end_linenumber(text)
690690
self.assertIsNotNone(text.dlineinfo(text.index(f'{last_lineno}.0')))
691691

692-
# Delta for <MouseWheel>, whose meaning is platform-dependent.
692+
# Simulate a mouse wheel notch. Tk 8.7 replaced the X11
693+
# <Button-4>/<Button-5> wheel events with <MouseWheel> (whose delta is
694+
# platform-dependent); older Tk on X11 still uses the button events.
695+
x11_buttons = (sidebar.canvas._windowingsystem == 'x11'
696+
and tk.TkVersion < 8.7)
693697
delta = 1 if sidebar.canvas._windowingsystem == 'aqua' else 120
694698

695699
# Scroll up.
696-
if sidebar.canvas._windowingsystem == 'x11':
700+
if x11_buttons:
697701
sidebar.canvas.event_generate('<Button-4>', x=0, y=0)
698702
else:
699703
sidebar.canvas.event_generate('<MouseWheel>', x=0, y=0, delta=delta)
700704
yield
701705
self.assertIsNone(text.dlineinfo(text.index(f'{last_lineno}.0')))
702706

703707
# Scroll back down.
704-
if sidebar.canvas._windowingsystem == 'x11':
708+
if x11_buttons:
705709
sidebar.canvas.event_generate('<Button-5>', x=0, y=0)
706710
else:
707711
sidebar.canvas.event_generate('<MouseWheel>', x=0, y=0, delta=-delta)

0 commit comments

Comments
 (0)