Skip to content

Commit 5f80c0e

Browse files
miss-islingtonserhiy-storchakaclaude
authored
[3.14] gh-153741: Harden IDLE GUI tests for newer Tk and display scaling (GH-153742) (#154405)
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 f838462 commit 5f80c0e

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
@@ -244,6 +244,7 @@ def test_font_set(self):
244244

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

259260
d.font_sample, d.highlight_sample = orig_samples
260-
d.set_samples = Func() # Re-mask for other tests.
261261

262262

263263
class HighPageTest(unittest.TestCase):
@@ -307,7 +307,7 @@ def test_load_theme_cfg(self):
307307
# builtinlist sets variable builtin_name to the CurrentTheme default.
308308
eq(d.builtin_name.get(), 'IDLE Classic')
309309
eq(d.custom_name.get(), '- no custom themes -')
310-
eq(d.custom_theme_on.state(), ('disabled',))
310+
self.assertIn('disabled', d.custom_theme_on.state())
311311
eq(d.set_theme_type.called, 1)
312312
eq(d.paint_theme_sample.called, 1)
313313
eq(d.set_highlight_target.called, 1)
@@ -495,23 +495,23 @@ def test_highlight_sample_b1_motion(self):
495495
def test_set_theme_type(self):
496496
eq = self.assertEqual
497497
d = self.page
498+
self.addCleanup(setattr, d, 'set_theme_type', Func()) # Re-mask method.
498499
del d.set_theme_type
499500

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

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

516516
def test_get_color(self):
517517
eq = self.assertEqual
@@ -637,24 +637,23 @@ def test_create_new_and_save_new(self):
637637
def test_set_highlight_target(self):
638638
eq = self.assertEqual
639639
d = self.page
640+
self.addCleanup(setattr, d, 'set_highlight_target', Func()) # Re-mask method.
640641
del d.set_highlight_target
641642

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

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

656-
d.set_highlight_target = Func()
657-
658657
def test_set_color_sample_binding(self):
659658
d = self.page
660659
scs = d.set_color_sample
@@ -667,14 +666,14 @@ def test_set_color_sample_binding(self):
667666

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

679678
def test_paint_theme_sample(self):
680679
eq = self.assertEqual
@@ -745,7 +744,7 @@ def test_delete_custom(self):
745744
eq(yesno.called, 2)
746745
self.assertNotIn(theme_name, highpage)
747746
eq(idleConf.GetSectionList('user', 'highlight'), [theme_name2])
748-
eq(d.custom_theme_on.state(), ())
747+
self.assertNotIn('disabled', d.custom_theme_on.state())
749748
eq(d.custom_name.get(), theme_name2)
750749
eq(dialog.deactivate_current_config.called, 1)
751750
eq(dialog.activate_config_changes.called, 1)
@@ -758,7 +757,7 @@ def test_delete_custom(self):
758757
eq(yesno.called, 3)
759758
self.assertNotIn(theme_name, highpage)
760759
eq(idleConf.GetSectionList('user', 'highlight'), [])
761-
eq(d.custom_theme_on.state(), ('disabled',))
760+
self.assertIn('disabled', d.custom_theme_on.state())
762761
eq(d.custom_name.get(), '- no custom themes -')
763762
eq(dialog.deactivate_current_config.called, 2)
764763
eq(dialog.activate_config_changes.called, 2)
@@ -809,7 +808,7 @@ def test_load_key_cfg(self):
809808
# builtinlist sets variable builtin_name to the CurrentKeys default.
810809
eq(d.builtin_name.get(), 'IDLE Classic OSX')
811810
eq(d.custom_name.get(), '- no custom keys -')
812-
eq(d.custom_keyset_on.state(), ('disabled',))
811+
self.assertIn('disabled', d.custom_keyset_on.state())
813812
eq(d.set_keys_type.called, 1)
814813
eq(d.load_keys_list.called, 1)
815814
eq(d.load_keys_list.args, ('IDLE Classic OSX', ))
@@ -930,23 +929,23 @@ def test_keybinding(self):
930929
def test_set_keys_type(self):
931930
eq = self.assertEqual
932931
d = self.page
932+
self.addCleanup(setattr, d, 'set_keys_type', Func()) # Re-mask method.
933933
del d.set_keys_type
934934

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

942942
# Custom keyset selected.
943943
d.keyset_source.set(False)
944944
d.set_keys_type()
945945
eq(d.builtinlist['state'], DISABLED)
946-
eq(d.custom_keyset_on.state(), ('selected',))
946+
self.assertNotIn('disabled', d.custom_keyset_on.state())
947947
eq(d.customlist['state'], NORMAL)
948-
eq(d.button_delete_custom_keys.state(), ())
949-
d.set_keys_type = Func()
948+
self.assertNotIn('disabled', d.button_delete_custom_keys.state())
950949

951950
def test_get_new_keys(self):
952951
eq = self.assertEqual
@@ -1043,7 +1042,7 @@ def test_on_bindingslist_select(self):
10431042
b.event_generate('<Button-1>', x=x, y=y)
10441043
b.event_generate('<ButtonRelease-1>', x=x, y=y)
10451044
self.assertEqual(b.get('anchor'), 'find')
1046-
self.assertEqual(d.button_new_keys.state(), ())
1045+
self.assertNotIn('disabled', d.button_new_keys.state())
10471046

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

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

11201119
del idleConf.GetKeySet
11211120

@@ -1156,7 +1155,7 @@ def test_delete_custom_keys(self):
11561155
eq(yesno.called, 2)
11571156
self.assertNotIn(keyset_name, keyspage)
11581157
eq(idleConf.GetSectionList('user', 'keys'), [keyset_name2])
1159-
eq(d.custom_keyset_on.state(), ())
1158+
self.assertNotIn('disabled', d.custom_keyset_on.state())
11601159
eq(d.custom_name.get(), keyset_name2)
11611160
eq(dialog.deactivate_current_config.called, 1)
11621161
eq(dialog.activate_config_changes.called, 1)
@@ -1169,7 +1168,7 @@ def test_delete_custom_keys(self):
11691168
eq(yesno.called, 3)
11701169
self.assertNotIn(keyset_name, keyspage)
11711170
eq(idleConf.GetSectionList('user', 'keys'), [])
1172-
eq(d.custom_keyset_on.state(), ('disabled',))
1171+
self.assertIn('disabled', d.custom_keyset_on.state())
11731172
eq(d.custom_name.get(), '- no custom keys -')
11741173
eq(dialog.deactivate_current_config.called, 2)
11751174
eq(dialog.activate_config_changes.called, 2)
@@ -1365,25 +1364,25 @@ def test_set_add_delete_state(self):
13651364
# Call with 0 items, 1 unselected item, 1 selected item.
13661365
eq = self.assertEqual
13671366
fr = self.frame
1367+
self.addCleanup(setattr, fr, 'set_add_delete_state', Func()) # Re-mask method.
13681368
del fr.set_add_delete_state # Unmask method.
13691369
sad = fr.set_add_delete_state
13701370
h = fr.helplist
13711371

13721372
h.delete(0, 'end')
13731373
sad()
1374-
eq(fr.button_helplist_edit.state(), ('disabled',))
1375-
eq(fr.button_helplist_remove.state(), ('disabled',))
1374+
self.assertIn('disabled', fr.button_helplist_edit.state())
1375+
self.assertIn('disabled', fr.button_helplist_remove.state())
13761376

13771377
h.insert(0, 'source')
13781378
sad()
1379-
eq(fr.button_helplist_edit.state(), ('disabled',))
1380-
eq(fr.button_helplist_remove.state(), ('disabled',))
1379+
self.assertIn('disabled', fr.button_helplist_edit.state())
1380+
self.assertIn('disabled', fr.button_helplist_remove.state())
13811381

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

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

14621461
def test_update_help_changes(self):
14631462
fr = self.frame
1463+
self.addCleanup(setattr, fr, 'update_help_changes', Func()) # Re-mask method.
14641464
del fr.update_help_changes
14651465
fr.user_helplist.clear()
14661466
fr.user_helplist.append(('name1', 'file1'))
@@ -1469,7 +1469,6 @@ def test_update_help_changes(self):
14691469
fr.update_help_changes()
14701470
self.assertEqual(mainpage['HelpFiles'],
14711471
{'1': 'name1;file1', '2': 'name2;file2'})
1472-
fr.update_help_changes = Func()
14731472

14741473

14751474
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)