mirror of https://github.com/python/cpython
Issue #28572: Add 10% to coverage of IDLE's test_configdialog.
Update and augment description of the configuration system.
This commit is contained in:
parent
f5df73025d
commit
f46b7823e6
|
@ -4,44 +4,50 @@
|
||||||
# When IDLE starts, it will look in
|
# When IDLE starts, it will look in
|
||||||
# the following two sets of files, in order:
|
# the following two sets of files, in order:
|
||||||
#
|
#
|
||||||
# default configuration
|
# default configuration files in idlelib
|
||||||
# ---------------------
|
# --------------------------------------
|
||||||
# config-main.def the default general config file
|
# config-main.def default general config file
|
||||||
# config-extensions.def the default extension config file
|
# config-extensions.def default extension config file
|
||||||
# config-highlight.def the default highlighting config file
|
# config-highlight.def default highlighting config file
|
||||||
# config-keys.def the default keybinding config file
|
# config-keys.def default keybinding config file
|
||||||
#
|
#
|
||||||
# user configuration
|
# user configuration files in ~/.idlerc
|
||||||
# -------------------
|
# -------------------------------------
|
||||||
# ~/.idlerc/config-main.cfg the user general config file
|
# config-main.cfg user general config file
|
||||||
# ~/.idlerc/config-extensions.cfg the user extension config file
|
# config-extensions.cfg user extension config file
|
||||||
# ~/.idlerc/config-highlight.cfg the user highlighting config file
|
# config-highlight.cfg user highlighting config file
|
||||||
# ~/.idlerc/config-keys.cfg the user keybinding config file
|
# config-keys.cfg user keybinding config file
|
||||||
#
|
#
|
||||||
# On Windows2000 and Windows XP the .idlerc directory is at
|
# On Windows, the default location of the home directory ('~' above)
|
||||||
# Documents and Settings\<username>\.idlerc
|
# depends on the version. For Windows 10, it is C:\Users\<username>.
|
||||||
#
|
|
||||||
# On Windows98 it is at c:\.idlerc
|
|
||||||
#
|
#
|
||||||
# Any options the user saves through the config dialog will be saved to
|
# Any options the user saves through the config dialog will be saved to
|
||||||
# the relevant user config file. Reverting any general setting to the
|
# the relevant user config file. Reverting any general or extension
|
||||||
# default causes that entry to be wiped from the user file and re-read
|
# setting to the default causes that entry to be wiped from the user
|
||||||
# from the default file. User highlighting themes or keybinding sets are
|
# file and re-read from the default file. This rule applies to each
|
||||||
# retained unless specifically deleted within the config dialog. Choosing
|
# item, except that the three editor font items are saved as a group.
|
||||||
# one of the default themes or keysets just applies the relevant settings
|
#
|
||||||
# from the default file.
|
# User highlighting themes and keybinding sets must have (section) names
|
||||||
|
# distinct from the default names. All items are added and saved as a
|
||||||
|
# group. They are retained unless specifically deleted within the config
|
||||||
|
# dialog. Choosing one of the default themes or keysets just applies the
|
||||||
|
# relevant settings from the default file.
|
||||||
|
#
|
||||||
|
# Additional help sources are listed in the [HelpFiles] section below
|
||||||
|
# and should be viewable by a web browser (or the Windows Help viewer in
|
||||||
|
# the case of .chm files). These sources will be listed on the Help
|
||||||
|
# menu. The pattern, and two examples, are
|
||||||
#
|
#
|
||||||
# Additional help sources are listed in the [HelpFiles] section and must be
|
|
||||||
# viewable by a web browser (or the Windows Help viewer in the case of .chm
|
|
||||||
# files). These sources will be listed on the Help menu. The pattern is
|
|
||||||
# <sequence_number = menu item;/path/to/help/source>
|
# <sequence_number = menu item;/path/to/help/source>
|
||||||
# You can't use a semi-colon in a menu item or path. The path will be platform
|
# 1 = IDLE;C:/Programs/Python36/Lib/idlelib/help.html
|
||||||
# specific because of path separators, drive specs etc.
|
# 2 = Pillow;https://pillow.readthedocs.io/en/latest/
|
||||||
#
|
#
|
||||||
# It is best to use the Configuration GUI to set up additional help sources!
|
# You can't use a semi-colon in a menu item or path. The path will be
|
||||||
# Example:
|
# platform specific because of path separators, drive specs etc.
|
||||||
#1 = My Extra Help Source;/usr/share/doc/foo/index.html
|
#
|
||||||
#2 = Another Help Source;/path/to/another.pdf
|
# The default files should not be edited except to add new sections to
|
||||||
|
# config-extensions.def for added extensions . The user files should be
|
||||||
|
# modified through the Settings dialog.
|
||||||
|
|
||||||
[General]
|
[General]
|
||||||
editor-on-startup= 0
|
editor-on-startup= 0
|
||||||
|
|
|
@ -1,13 +1,20 @@
|
||||||
"""Provides access to stored IDLE configuration information.
|
"""idlelib.config -- Manage IDLE configuration information.
|
||||||
|
|
||||||
Refer to the comments at the beginning of config-main.def for a description of
|
The comments at the beginning of config-main.def describe the
|
||||||
the available configuration files and the design implemented to update user
|
configuration files and the design implemented to update user
|
||||||
configuration information. In particular, user configuration choices which
|
configuration information. In particular, user configuration choices
|
||||||
duplicate the defaults will be removed from the user's configuration files,
|
which duplicate the defaults will be removed from the user's
|
||||||
and if a file becomes empty, it will be deleted.
|
configuration files, and if a user file becomes empty, it will be
|
||||||
|
deleted.
|
||||||
|
|
||||||
The contents of the user files may be altered using the Options/Configure IDLE
|
The configuration database maps options to values. Comceptually, the
|
||||||
menu to access the configuration GUI (configdialog.py), or manually.
|
database keys are tuples (config-type, section, item). As implemented,
|
||||||
|
there are separate dicts for default and user values. Each has
|
||||||
|
config-type keys 'main', 'extensions', 'highlight', and 'keys'. The
|
||||||
|
value for each key is a ConfigParser instance that maps section and item
|
||||||
|
to values. For 'main' and 'extenstons', user values override
|
||||||
|
default values. For 'highlight' and 'keys', user sections augment the
|
||||||
|
default sections (and must, therefore, have distinct names).
|
||||||
|
|
||||||
Throughout this module there is an emphasis on returning useable defaults
|
Throughout this module there is an emphasis on returning useable defaults
|
||||||
when a problem occurs in returning a requested configuration value back to
|
when a problem occurs in returning a requested configuration value back to
|
||||||
|
|
|
@ -392,28 +392,28 @@ class ConfigDialog(Toplevel):
|
||||||
text=' Additional Help Sources ')
|
text=' Additional Help Sources ')
|
||||||
#frameRun
|
#frameRun
|
||||||
labelRunChoiceTitle = Label(frameRun, text='At Startup')
|
labelRunChoiceTitle = Label(frameRun, text='At Startup')
|
||||||
radioStartupEdit = Radiobutton(
|
self.radioStartupEdit = Radiobutton(
|
||||||
frameRun, variable=self.startupEdit, value=1,
|
frameRun, variable=self.startupEdit, value=1,
|
||||||
command=self.SetKeysType, text="Open Edit Window")
|
text="Open Edit Window")
|
||||||
radioStartupShell = Radiobutton(
|
self.radioStartupShell = Radiobutton(
|
||||||
frameRun, variable=self.startupEdit, value=0,
|
frameRun, variable=self.startupEdit, value=0,
|
||||||
command=self.SetKeysType, text='Open Shell Window')
|
text='Open Shell Window')
|
||||||
#frameSave
|
#frameSave
|
||||||
labelRunSaveTitle = Label(frameSave, text='At Start of Run (F5) ')
|
labelRunSaveTitle = Label(frameSave, text='At Start of Run (F5) ')
|
||||||
radioSaveAsk = Radiobutton(
|
self.radioSaveAsk = Radiobutton(
|
||||||
frameSave, variable=self.autoSave, value=0,
|
frameSave, variable=self.autoSave, value=0,
|
||||||
command=self.SetKeysType, text="Prompt to Save")
|
text="Prompt to Save")
|
||||||
radioSaveAuto = Radiobutton(
|
self.radioSaveAuto = Radiobutton(
|
||||||
frameSave, variable=self.autoSave, value=1,
|
frameSave, variable=self.autoSave, value=1,
|
||||||
command=self.SetKeysType, text='No Prompt')
|
text='No Prompt')
|
||||||
#frameWinSize
|
#frameWinSize
|
||||||
labelWinSizeTitle = Label(
|
labelWinSizeTitle = Label(
|
||||||
frameWinSize, text='Initial Window Size (in characters)')
|
frameWinSize, text='Initial Window Size (in characters)')
|
||||||
labelWinWidthTitle = Label(frameWinSize, text='Width')
|
labelWinWidthTitle = Label(frameWinSize, text='Width')
|
||||||
entryWinWidth = Entry(
|
self.entryWinWidth = Entry(
|
||||||
frameWinSize, textvariable=self.winWidth, width=3)
|
frameWinSize, textvariable=self.winWidth, width=3)
|
||||||
labelWinHeightTitle = Label(frameWinSize, text='Height')
|
labelWinHeightTitle = Label(frameWinSize, text='Height')
|
||||||
entryWinHeight = Entry(
|
self.entryWinHeight = Entry(
|
||||||
frameWinSize, textvariable=self.winHeight, width=3)
|
frameWinSize, textvariable=self.winHeight, width=3)
|
||||||
#frameHelp
|
#frameHelp
|
||||||
frameHelpList = Frame(frameHelp)
|
frameHelpList = Frame(frameHelp)
|
||||||
|
@ -443,17 +443,17 @@ class ConfigDialog(Toplevel):
|
||||||
frameHelp.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
|
frameHelp.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
|
||||||
#frameRun
|
#frameRun
|
||||||
labelRunChoiceTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
|
labelRunChoiceTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
|
||||||
radioStartupShell.pack(side=RIGHT, anchor=W, padx=5, pady=5)
|
self.radioStartupShell.pack(side=RIGHT, anchor=W, padx=5, pady=5)
|
||||||
radioStartupEdit.pack(side=RIGHT, anchor=W, padx=5, pady=5)
|
self.radioStartupEdit.pack(side=RIGHT, anchor=W, padx=5, pady=5)
|
||||||
#frameSave
|
#frameSave
|
||||||
labelRunSaveTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
|
labelRunSaveTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
|
||||||
radioSaveAuto.pack(side=RIGHT, anchor=W, padx=5, pady=5)
|
self.radioSaveAuto.pack(side=RIGHT, anchor=W, padx=5, pady=5)
|
||||||
radioSaveAsk.pack(side=RIGHT, anchor=W, padx=5, pady=5)
|
self.radioSaveAsk.pack(side=RIGHT, anchor=W, padx=5, pady=5)
|
||||||
#frameWinSize
|
#frameWinSize
|
||||||
labelWinSizeTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
|
labelWinSizeTitle.pack(side=LEFT, anchor=W, padx=5, pady=5)
|
||||||
entryWinHeight.pack(side=RIGHT, anchor=E, padx=10, pady=5)
|
self.entryWinHeight.pack(side=RIGHT, anchor=E, padx=10, pady=5)
|
||||||
labelWinHeightTitle.pack(side=RIGHT, anchor=E, pady=5)
|
labelWinHeightTitle.pack(side=RIGHT, anchor=E, pady=5)
|
||||||
entryWinWidth.pack(side=RIGHT, anchor=E, padx=10, pady=5)
|
self.entryWinWidth.pack(side=RIGHT, anchor=E, padx=10, pady=5)
|
||||||
labelWinWidthTitle.pack(side=RIGHT, anchor=E, pady=5)
|
labelWinWidthTitle.pack(side=RIGHT, anchor=E, pady=5)
|
||||||
#frameHelp
|
#frameHelp
|
||||||
frameHelpListButtons.pack(side=RIGHT, padx=5, pady=5, fill=Y)
|
frameHelpListButtons.pack(side=RIGHT, padx=5, pady=5, fill=Y)
|
||||||
|
|
|
@ -1,30 +1,123 @@
|
||||||
'''Test idlelib.configdialog.
|
"""Test idlelib.configdialog.
|
||||||
|
|
||||||
Coverage: 46% just by creating dialog.
|
Half the class creates dialog, half works with user customizations.
|
||||||
The other half is code for working with user customizations.
|
Coverage: 46% just by creating dialog, 56% with current tests.
|
||||||
'''
|
"""
|
||||||
from idlelib.configdialog import ConfigDialog # always test import
|
from idlelib.configdialog import ConfigDialog, idleConf # test import
|
||||||
from test.support import requires
|
from test.support import requires
|
||||||
requires('gui')
|
requires('gui')
|
||||||
from tkinter import Tk
|
from tkinter import Tk
|
||||||
import unittest
|
import unittest
|
||||||
|
import idlelib.config as config
|
||||||
|
|
||||||
class ConfigDialogTest(unittest.TestCase):
|
# Tests should not depend on fortuitous user configurations.
|
||||||
|
# They must not affect actual user .cfg files.
|
||||||
|
# Use solution from test_config: empty parsers with no filename.
|
||||||
|
usercfg = idleConf.userCfg
|
||||||
|
testcfg = {
|
||||||
|
'main': config.IdleUserConfParser(''),
|
||||||
|
'highlight': config.IdleUserConfParser(''),
|
||||||
|
'keys': config.IdleUserConfParser(''),
|
||||||
|
'extensions': config.IdleUserConfParser(''),
|
||||||
|
}
|
||||||
|
|
||||||
@classmethod
|
# ConfigDialog.changedItems is a 3-level hierarchical dictionary of
|
||||||
def setUpClass(cls):
|
# pending changes that mirrors the multilevel user config dict.
|
||||||
cls.root = Tk()
|
# For testing, record args in a list for comparison with expected.
|
||||||
cls.root.withdraw()
|
changes = []
|
||||||
|
class TestDialog(ConfigDialog):
|
||||||
|
def AddChangedItem(self, *args):
|
||||||
|
changes.append(args)
|
||||||
|
|
||||||
@classmethod
|
def setUpModule():
|
||||||
def tearDownClass(cls):
|
global root, configure
|
||||||
cls.root.update_idletasks()
|
idleConf.userCfg = testcfg
|
||||||
cls.root.destroy()
|
root = Tk()
|
||||||
del cls.root
|
root.withdraw()
|
||||||
|
configure = TestDialog(root, 'Test', _utest=True)
|
||||||
|
|
||||||
def test_configdialog(self):
|
|
||||||
d = ConfigDialog(self.root, 'Test', _utest=True)
|
def tearDownModule():
|
||||||
d.remove_var_callbacks()
|
global root, configure
|
||||||
|
idleConf.userCfg = testcfg
|
||||||
|
configure.remove_var_callbacks()
|
||||||
|
del configure
|
||||||
|
root.update_idletasks()
|
||||||
|
root.destroy()
|
||||||
|
del root
|
||||||
|
|
||||||
|
|
||||||
|
class FontTabTest(unittest.TestCase):
|
||||||
|
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
changes.clear()
|
||||||
|
|
||||||
|
def test_font(self):
|
||||||
|
configure.fontName.set('Test Font')
|
||||||
|
expected = [
|
||||||
|
('main', 'EditorWindow', 'font', 'Test Font'),
|
||||||
|
('main', 'EditorWindow', 'font-size', '10'),
|
||||||
|
('main', 'EditorWindow', 'font-bold', False)]
|
||||||
|
self.assertEqual(changes, expected)
|
||||||
|
changes.clear()
|
||||||
|
configure.fontSize.set(12)
|
||||||
|
expected = [
|
||||||
|
('main', 'EditorWindow', 'font', 'Test Font'),
|
||||||
|
('main', 'EditorWindow', 'font-size', '12'),
|
||||||
|
('main', 'EditorWindow', 'font-bold', False)]
|
||||||
|
self.assertEqual(changes, expected)
|
||||||
|
changes.clear()
|
||||||
|
configure.fontBold.set(True)
|
||||||
|
expected = [
|
||||||
|
('main', 'EditorWindow', 'font', 'Test Font'),
|
||||||
|
('main', 'EditorWindow', 'font-size', '12'),
|
||||||
|
('main', 'EditorWindow', 'font-bold', True)]
|
||||||
|
self.assertEqual(changes, expected)
|
||||||
|
|
||||||
|
#def test_sample(self): pass # TODO
|
||||||
|
|
||||||
|
def test_tabspace(self):
|
||||||
|
configure.spaceNum.set(6)
|
||||||
|
self.assertEqual(changes, [('main', 'Indent', 'num-spaces', 6)])
|
||||||
|
|
||||||
|
|
||||||
|
class HighlightTest(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
changes.clear()
|
||||||
|
|
||||||
|
#def test_colorchoose(self): pass # TODO
|
||||||
|
|
||||||
|
|
||||||
|
class KeysTest(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
changes.clear()
|
||||||
|
|
||||||
|
|
||||||
|
class GeneralTest(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
changes.clear()
|
||||||
|
|
||||||
|
def test_startup(self):
|
||||||
|
configure.radioStartupEdit.invoke()
|
||||||
|
self.assertEqual(changes,
|
||||||
|
[('main', 'General', 'editor-on-startup', 1)])
|
||||||
|
|
||||||
|
def test_autosave(self):
|
||||||
|
configure.radioSaveAuto.invoke()
|
||||||
|
self.assertEqual(changes, [('main', 'General', 'autosave', 1)])
|
||||||
|
|
||||||
|
def test_editor_size(self):
|
||||||
|
configure.entryWinHeight.insert(0, '1')
|
||||||
|
self.assertEqual(changes, [('main', 'EditorWindow', 'height', '140')])
|
||||||
|
changes.clear()
|
||||||
|
configure.entryWinWidth.insert(0, '1')
|
||||||
|
self.assertEqual(changes, [('main', 'EditorWindow', 'width', '180')])
|
||||||
|
|
||||||
|
#def test_help_sources(self): pass # TODO
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
Loading…
Reference in New Issue