Skip to content

Commit 58fd9ec

Browse files
gh-151678: Add tests for tkinter.filedialog (GH-151781)
Exercise the native dialogs (Open, SaveAs and Directory) through the _test_callback seam without opening them, and test the pure-Python FileDialog selection, filter and ok/cancel logic without entering its modal loop. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 2a126a5 commit 58fd9ec

1 file changed

Lines changed: 73 additions & 0 deletions

File tree

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import os
2+
import unittest
3+
from tkinter import filedialog
4+
from tkinter.commondialog import Dialog
5+
from test.support import requires, swap_attr
6+
from test.test_tkinter.support import setUpModule # noqa: F401
7+
from test.test_tkinter.support import AbstractTkTest
8+
9+
requires('gui')
10+
11+
12+
class NativeDialogTest(AbstractTkTest, unittest.TestCase):
13+
# Open, SaveAs and Directory wrap modal native dialogs. The _test_callback
14+
# seam is called by show() just before the dialog would open; replacing it
15+
# with a function that raises exercises show() without blocking on the
16+
# dialog.
17+
18+
def check(self, dialog_class, command):
19+
self.assertEqual(dialog_class.command, command)
20+
master = None
21+
def test_callback(dialog, parent):
22+
nonlocal master
23+
master = parent
24+
raise ZeroDivisionError
25+
with swap_attr(Dialog, '_test_callback', test_callback):
26+
d = dialog_class(self.root, title='Test')
27+
self.assertRaises(ZeroDivisionError, d.show)
28+
self.assertIs(master, self.root)
29+
30+
def test_open(self):
31+
self.check(filedialog.Open, 'tk_getOpenFile')
32+
33+
def test_saveas(self):
34+
self.check(filedialog.SaveAs, 'tk_getSaveFile')
35+
36+
def test_directory(self):
37+
self.check(filedialog.Directory, 'tk_chooseDirectory')
38+
39+
40+
class FileDialogTest(AbstractTkTest, unittest.TestCase):
41+
# The pure-Python FileDialog runs its own modal loop in go(); its logic is
42+
# exercised here without entering the loop.
43+
44+
def test_selection(self):
45+
d = filedialog.FileDialog(self.root)
46+
d.directory = os.path.abspath(os.sep)
47+
d.set_selection('spam.txt')
48+
self.assertEqual(os.path.basename(d.get_selection()), 'spam.txt')
49+
50+
def test_filter(self):
51+
d = filedialog.FileDialog(self.root)
52+
d.set_filter(os.getcwd(), '*.py')
53+
self.assertEqual(d.get_filter(), (os.getcwd(), '*.py'))
54+
55+
def test_ok_cancel(self):
56+
d = filedialog.FileDialog(self.root)
57+
d.directory = os.getcwd()
58+
d.set_selection('spam.txt')
59+
d.ok_command() # Accepts the current selection.
60+
self.assertEqual(os.path.basename(d.how), 'spam.txt')
61+
d.cancel_command() # Returns no selection.
62+
self.assertIsNone(d.how)
63+
64+
def test_subclasses(self):
65+
for cls in filedialog.LoadFileDialog, filedialog.SaveFileDialog:
66+
with self.subTest(cls=cls.__name__):
67+
d = cls(self.root)
68+
self.assertIsInstance(d, filedialog.FileDialog)
69+
self.assertEqual(d.top.title(), cls.title)
70+
71+
72+
if __name__ == "__main__":
73+
unittest.main()

0 commit comments

Comments
 (0)