diff -r 5fd1f8271e8a Lib/idlelib/Checker.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Lib/idlelib/Checker.py Wed Aug 13 20:42:53 2014 +0530 @@ -0,0 +1,465 @@ +import os +import sys +import traceback +from subprocess import Popen +from tempfile import NamedTemporaryFile + +import tkinter as tk +import tkinter.messagebox as tkMessageBox + +from idlelib.OutputWindow import OutputWindow +from idlelib.configHandler import idleConf + + +def get_checkers(): + """ + Return list of checkers defined in users config file. + """ + return idleConf.GetSectionList('user', 'checker') + + +def get_enabled_checkers(): + """ + Return list of currently enabled checkers. + """ + return [c for c in get_checkers() if idleConf.GetOption('checker', c, + 'enabled', default=False, type='bool')] + + +def get_checker_config(checker): + """ + Return configuration of checker as dict. + """ + if checker == '': + raise ValueError('Checker name cannot be empty') + get = idleConf.GetOption + return {'name': checker, + 'enabled': get('checker', checker, 'enabled', default=False, + type='bool',), + 'command': get('checker', checker, 'command', + default='', raw=True), + 'additional': get('checker', checker, 'additional', + default=''), + 'reload_source': get('checker', checker, 'reload_source', + default=True, type='bool'), + 'show_result': get('checker', checker, 'show_result', + default=True, type='bool'), + } + + +def run_checker(editwin, checker): + def run(): + """Run the 3rd party checker 'checker' and display result in a new + CheckerWindow. + Return True if successful, False otherwise.""" + filename = editwin.extensions.get('ScriptBinding').getfilename() + if not filename: + return False + config = get_checker_config(checker) + command = config['command'] + if not command: + location = 'Config Checkers' + menu = 'Run' + message = ("'Command' option for '{checker}' checker is empty.\n" + "Please update the 'Command' option for '{checker}' " + "in {location} in {menu} menu, before running " + "'{checker}' again.".format(checker=checker, + location=location, + menu=menu)) + tkMessageBox.showerror(title="Empty Command", message=message, + parent=editwin.top) + return False + additional = config['additional'] + reload_source = config['reload_source'] + show_result = config['show_result'] + dirname, _file = os.path.split(filename) + args = [os.path.expanduser(arg) for arg in + command.split() + additional.split() + [_file] if arg] + # CheckerWindow closes file if no exception + with NamedTemporaryFile(delete=False) as error_file, \ + NamedTemporaryFile(delete=False) as output_file: + try: + process = Popen(args, stdout=output_file, stderr=error_file, + cwd=dirname) + if show_result: + CheckerWindow(editwin, filename, checker, output_file, + error_file, process, reload_source) + elif reload_source: + while process.poll() is None: + continue + editwin.io.loadfile(filename) + return True + except: + *_, value, tb = sys.exc_info() + message = ("File: {}\n" + "Checker: {}\n" + "Command: {}\n" + "Additional Args: {}\n" + "Call details: {}\n\n\n" + "Traceback: {}".format(filename, checker, command, + additional, ' '.join(args), + traceback.format_exc(limit=1) + )) + tkMessageBox.showerror(title=value, + message=message, + parent=editwin.top) + return False + return run + + +class Checker: + + menudefs = [ + ('run', [None, + ('Config Checkers', '<>'), ], ), ] + + def __init__(self, editwin): + self.editwin = editwin + self.parent = self.editwin.top + self.update_menu() + + def config_checker_event(self, event): + dialog = self.dialog = tk.Toplevel(self.parent) + dialog.grab_set() + dialog.transient(self.parent) + dialog.wm_title('Config Checkers') + dialog.geometry('+%d+%d' % (self.parent.winfo_rootx() + 30, + self.parent.winfo_rooty() + 30)) + titleLabel = tk.Label(dialog, text='Configure Checkers') + self.listbox = tk.Listbox(dialog, selectmode=tk.SINGLE) + self.update_listbox() + addButton = tk.Button(dialog, text='Add checker', + command=self.add_checker) + editButton = tk.Button(dialog, text='Edit Checker', + command=self.edit_checker) + removeButton = tk.Button(dialog, text='Remove Checker', + command=self.remove_checker) + titleLabel.pack() + self.listbox.pack() + addButton.pack(side=tk.LEFT) + editButton.pack(side=tk.LEFT) + removeButton.pack(side=tk.LEFT) + + def update_listbox(self): + self.listbox.delete(0, tk.END) + for checker in get_checkers(): + self.listbox.insert(tk.END, checker) + + def add_checker(self): + ConfigCheckerDialog(self, '') + + def _selected_checker(self, error_title=None, error_message=None, + parent=None): + """ + Return name of currently selected checker, None if nothing is + selected. Show error dialog to user if nothing is selected. + """ + index = self.listbox.curselection() + if index: + checker = self.listbox.get(index) + return checker + else: + tkMessageBox.showerror(title=error_title, message=error_message, + parent=parent) + + return None + + def edit_checker(self): + error_title = 'No Checker Selected' + error_message = 'Select an existing checker to edit' + checker = self._selected_checker(error_title=error_title, + error_message=error_message, + parent=self.dialog) + if checker: + ConfigCheckerDialog(self, checker) + + def remove_checker(self): + error_title = 'No Checker Selected' + error_message = 'Select an existing checker to remove' + checker = self._selected_checker(error_title=error_title, + error_message=error_message, + parent=self.dialog) + if not checker: + return + title = 'Confirm to remove checker {}'.format(checker) + message = ('Removing {checker} will remove all configuration ' + 'values for {checker} from all versions of IDLE.\n ' + 'Please confirm your decision to remove {checker} ' + 'from IDLE.'.format(checker=checker)) + confirm = tkMessageBox.askyesno(title=title, message=message, + parent=self.editwin.top) + if confirm: + for option in ('enabled', 'command', 'additional', 'reload_source', + 'show_result'): + idleConf.userCfg['checker'].remove_option(checker, option) + idleConf.userCfg['checker'].Save() + self.update_listbox() + self.update_menu() + else: + return + + def update_menu(self): + """ + Utility method to update Run menu to display currently enabled + checkers. + """ + editwin_instances = self.editwin.top.instance_dict.keys() + for editwin in editwin_instances: + menu = editwin.menudict.get('run') + if not menu: # A Shell window + continue + start = menu.index('Config Checkers') + 1 + end = menu.index(tk.END) + if start < end: + menu.delete(start, end) + elif start == end: + menu.delete(start) + for checker in get_enabled_checkers(): + menu.add_command( + label='Run {}'.format(checker), + command=run_checker(editwin, checker)) + + +class ConfigCheckerDialog(tk.Toplevel): + def __init__(self, _checker, checker_name=None): + tk.Toplevel.__init__(self, _checker.editwin.top) + self._checker = _checker + self.editwin = _checker.editwin + self.checker_name = checker_name + self.parent = parent = self.editwin.top + + self.name = tk.StringVar(parent) + self.command = tk.StringVar(parent) + self.additional = tk.StringVar(parent) + self.reload_source = tk.StringVar(parent) + self.show_result = tk.StringVar(parent) + self.enabled = tk.StringVar(parent) + self.call_string = tk.StringVar(parent) + self.command.trace('w', self.update_call_string) + self.additional.trace('w', self.update_call_string) + + if checker_name: + config = get_checker_config(checker_name) + self.name.set(config['name'] if checker_name else '') + self.command.set(config['command'] if checker_name else '') + self.additional.set(config['additional'] if checker_name else '') + self.reload_source.set(config['reload_source'] if checker_name else 0) + self.show_result.set(config['show_result'] if checker_name else 1) + self.enabled.set(config['enabled'] if checker_name else 1) + + self.grab_set() + self.resizable(width=False, height=False) + self.create_widgets() + + def create_widgets(self): + parent = self.parent + self.configure(borderwidth=5) + if self.checker_name: + title = 'Edit {} checker'.format(self.checker_name) + else: + title = 'Config new checker' + self.wm_title(title) + self.geometry('+%d+%d' % (parent.winfo_rootx() + 30, + parent.winfo_rooty() + 30)) + self.transient(parent) + self.focus_set() + # frames creation + optionsFrame = tk.Frame(self) + buttonFrame = tk.Frame(self) + + # optionsFrame + nameLabel = tk.Label(optionsFrame, text='Name of Checker') + commandLabel = tk.Label(optionsFrame, text='Command') + additionalLabel = tk.Label(optionsFrame, text='Additional Args') + currentCallStringLabel = tk.Label(optionsFrame, + text='Call Command string') + + self.nameEntry = tk.Entry(optionsFrame, textvariable=self.name, + width=40) + self.commandEntry = tk.Entry(optionsFrame, textvariable=self.command, + width=40) + self.additionalEntry = tk.Entry(optionsFrame, + textvariable=self.additional, width=40) + reload_sourceCheckbutton = tk.Checkbutton(optionsFrame, + variable=self.reload_source, + text='Reload file?') + showResultCheckbutton = tk.Checkbutton(optionsFrame, + variable=self.show_result, + text='Show result after run?') + self.currentCallStringEntry = tk.Entry(optionsFrame, state='readonly', + textvariable=self.call_string, + width=40) + enabledCheckbutton = tk.Checkbutton(optionsFrame, + variable=self.enabled, + text='Enable Checker?') + + # buttonFrame + okButton = tk.Button(buttonFrame, text='Ok', command=self.ok) + cancelButton = tk.Button(buttonFrame, text='Cancel', + command=self.cancel) + + # frames packing + optionsFrame.pack() + buttonFrame.pack() + # optionsFrame packing + nameLabel.pack() + self.nameEntry.pack() + commandLabel.pack() + self.commandEntry.pack() + additionalLabel.pack() + self.additionalEntry.pack() + reload_sourceCheckbutton.pack() + showResultCheckbutton.pack() + currentCallStringLabel.pack() + self.currentCallStringEntry.pack() + enabledCheckbutton.pack() + # buttonFrame packing + okButton.pack(side=tk.LEFT) + cancelButton.pack() + + def update_call_string(self, *args, **kwargs): + filename = self.editwin.io.filename or '' + call_string = ' '.join([self.command.get(), self.additional.get(), + os.path.split(filename)[1] or '']) + self.call_string.set(call_string) + + def name_ok(self): + name = self.name.get() + ok = True + if name.strip() == '': + tkMessageBox.showerror(title='Name Error', + message='No Name Specified', parent=self) + ok = False + return ok + + def command_ok(self): + command = self.command.get() + ok = True + if command.strip() == '': + message = ('No command specified. \nCommand is name or full path' + ' to the program that IDLE has to execute') + tkMessageBox.showerror(title='Command Error', + message=message, parent=self) + ok = False + return ok + + def additional_ok(self): + ok = True + return ok + + def ok(self): + _ok = self.name_ok() and self.command_ok() and self.additional_ok() + if _ok: + name = self.name.get() + idleConf.userCfg['checker'].SetOption(name, 'enabled', + self.enabled.get()) + idleConf.userCfg['checker'].SetOption(name, 'command', + self.command.get()) + idleConf.userCfg['checker'].SetOption(name, 'additional', + self.additional.get()) + idleConf.userCfg['checker'].SetOption(name, 'reload_source', + self.reload_source.get()), + idleConf.userCfg['checker'].SetOption(name, 'show_result', + self.show_result.get()) + + idleConf.userCfg['checker'].Save() + self.close() + + def cancel(self): + self.close() + + def close(self): + self._checker.update_listbox() + self._checker.update_menu() + self._checker.dialog.grab_set() + self.destroy() + + +class CheckerWindow(OutputWindow): + def __init__(self, editwin, filename, checker, output_file, error_file, + process, reload_source): + """ + editwin - EditorWindow instance + filename - string + checker - name of checker + output_file, error_file - Temporary file objects + process - Popen object + reload_source - bool, reload original file after checker finished + """ + self.editwin = editwin + self.filename = filename + self.checker = checker + self.process = process + self.reload_source = reload_source + OutputWindow.__init__(self, self.editwin.flist) + self.error_file = open(error_file.name, 'r') + self.output_file = open(output_file.name, 'r') + + theme = idleConf.CurrentTheme() + stderr_fg = idleConf.GetHighlight(theme, 'stderr', fgBg='fg') + stdout_fg = idleConf.GetHighlight(theme, 'stdout', fgBg='fg') + tagdefs = {'stderr': {'foreground': stderr_fg}, + 'stdout': {'foreground': stdout_fg}, } + for tag, cnf in tagdefs.items(): + self.text.tag_configure(tag, **cnf) + + self.text.mark_set('stderr_index', '1.0') + self.text.mark_set('stdout_index', tk.END) + self.stderr_index = self.text.index('stderr_index') + self.stdout_index = self.text.index('stdout_index') + self.status_bar.set_label('Checker status', 'Processing..!', + side=tk.RIGHT) + self.update() + + def short_title(self): + return '{} - {}'.format(self.checker, self.filename) + + def update(self): + self.update_error() + self.update_output() + if self.process.poll() is None: + self.text.after(10, self.update) + else: + if self.reload_source: + self.editwin.io.loadfile(self.filename) + self.update_error() + self.update_output() + self.status_bar.set_label('Checker status', 'Done', side=tk.RIGHT) + self._clean_tempfiles() + + def update_error(self): + for line in self.error_file.read().splitlines(True): + self.text.insert(self.stderr_index, line, 'stderr') + self.stderr_index = self.text.index('stderr_index') + + def update_output(self): + for line in self.output_file.read().splitlines(True): + self.text.insert(self.stdout_index, line, 'stdout') + self.stdout_index = self.text.index('stdout_index') + + file_line_pats = [r':\s*(\d+)\s*(:|,)'] + + def _file_line_helper(self, line): + for prog in self.file_line_progs: + match = prog.search(line) + if match: + lineno = match.group(1) + else: + return None + try: + return self.filename, int(lineno) + except TypeError: + return None + + def _clean_tempfiles(self): + self.output_file.close() + self.error_file.close() + try: + os.unlink(self.error_file.name) + os.unlink(self.output_file.name) + except OSError: + pass + + def close(self): + self._clean_tempfiles() + OutputWindow.close(self) diff -r 5fd1f8271e8a Lib/idlelib/config-extensions.def --- a/Lib/idlelib/config-extensions.def Wed Aug 13 09:35:21 2014 +0300 +++ b/Lib/idlelib/config-extensions.def Wed Aug 13 20:42:53 2014 +0530 @@ -94,3 +94,9 @@ enable_shell=0 enable_editor=1 +[Checker] +enable=1 +enable_shell=0 +enable_editor=1 +[Checker_bindings] +config-checker= diff -r 5fd1f8271e8a Lib/idlelib/configHandler.py --- a/Lib/idlelib/configHandler.py Wed Aug 13 09:35:21 2014 +0300 +++ b/Lib/idlelib/configHandler.py Wed Aug 13 20:42:53 2014 +0530 @@ -162,6 +162,7 @@ (user home dir)/.idlerc/config-extensions.cfg (user home dir)/.idlerc/config-highlight.cfg (user home dir)/.idlerc/config-keys.cfg + (user home dir)/.idlerc/config-checker.cfg """ def __init__(self): self.defaultCfg={} @@ -182,7 +183,7 @@ else: # we were exec'ed (for testing only) idleDir=os.path.abspath(sys.path[0]) userDir=self.GetUserCfgDir() - configTypes=('main','extensions','highlight','keys') + configTypes=('main','extensions','highlight','keys', 'checker') defCfgFiles={} usrCfgFiles={} for cfgType in configTypes: #build config file names @@ -282,9 +283,11 @@ Get a list of sections from either the user or default config for the given config type. configSet must be either 'user' or 'default' - configType must be one of ('main','extensions','highlight','keys') + configType must be one of ('main','extensions','highlight','keys', + 'checker') """ - if not (configType in ('main','extensions','highlight','keys')): + if not (configType in ('main','extensions','highlight','keys', + 'checker')): raise InvalidConfigType('Invalid configType specified') if configSet == 'user': cfgParser=self.userCfg[configType] diff -r 5fd1f8271e8a Lib/idlelib/idle_test/test_checker.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Lib/idlelib/idle_test/test_checker.py Wed Aug 13 20:42:53 2014 +0530 @@ -0,0 +1,331 @@ +import unittest +from test.support import requires +requires('gui') +from unittest.mock import Mock, call +from idlelib.idle_test.mock_tk import Var, Mbox +from tkinter import Listbox, END, Tk +import idlelib.Checker as checker_module + + +class Dummy_editwin: + io = Mock() + top = None + extensions = {'ScriptBinding': Mock()} + flist = None + + def __init__(self, *args, **kwargs): + self.filename = None + + +class Dummy_tempfile: + def __init__(self, delete=False): + pass + + def __enter__(self, *args, **kwargs): + pass + + def __exit__(self, *args, **kwargs): + pass + +checker_dialog = checker_module.Checker +config_checker_dialog = checker_module.ConfigCheckerDialog +editwin = Dummy_editwin() +run = checker_module.run_checker(editwin, 'three') + +# methods call Mbox.showerror if values are not ok +orig_mbox = checker_module.tkMessageBox +orig_idleConf = checker_module.idleConf +orig_config_checker_dialog = checker_module.ConfigCheckerDialog +orig_get_checker_config = checker_module.get_checker_config +orig_named_temporary_file = checker_module.NamedTemporaryFile +orig_popen = checker_module.Popen +orig_checker_window = checker_module.CheckerWindow +showerror = Mbox.showerror +askyesno = Mbox.askyesno + + +def setUpModule(): + checker_module.idleConf = idleConf = Mock() + idleConf.GetSectionList = Mock(return_value=['one', 'two', 'three']) + attrs = {'userCfg': {'checker': Mock(), 'Save': Mock()}, + 'SetOption': Mock()} + idleConf.configure_mock(**attrs) + checker_module.tkMessageBox = Mbox + + +def tearDownModule(): + checker_module.idleConf = orig_idleConf + checker_module.tkMessageBox = orig_mbox + + +class Dummy_checker: + # Mock for testing methods of Checker + add_checker = checker_dialog.add_checker + edit_checker = checker_dialog.edit_checker + remove_checker = checker_dialog.remove_checker + _selected_checker = checker_dialog._selected_checker + update_listbox = checker_dialog.update_listbox + update_menu = Mock() + editwin = editwin + + +class Dummy_config_checker_dialog: + # Mock for testing methods of ConfigCheckerDialog + name_ok = config_checker_dialog.name_ok + command_ok = config_checker_dialog.command_ok + additional_ok = config_checker_dialog.additional_ok + update_call_string = config_checker_dialog.update_call_string + ok = config_checker_dialog.ok + cancel = config_checker_dialog.cancel + + name = Var() + command = Var() + additional = Var() + reload_source = Var() + show_result = Var() + enabled = Var() + call_string = Var() + destroyed = False + editwin = editwin + + def destroy(cls): + cls.destroyed = True + + def close(cls): + cls.destroy() + + +class CheckerUtilityTest(unittest.TestCase): + def test_get_checkers(self): + self.assertIsInstance(checker_module.get_checkers(), list) + + def test_get_enabled_checkers(self): + checkers_list = checker_module.get_checkers() + enabled_checkers = checker_module.get_enabled_checkers() + self.assertIsInstance(enabled_checkers, list) + self.assertTrue(set(enabled_checkers) <= set(checkers_list)) + + def test_checker_config(self): + get = checker_module.get_checker_config + with self.assertRaises(ValueError) as ve: + get('') + self.assertIn('empty', str(ve.exception)) + cfg_list = list(get(checker_module.get_enabled_checkers()[0])) + for item in ('enabled', 'name', 'command', 'additional', + 'reload_source', 'show_result'): + self.assertIn(item, cfg_list, '{} config not found'.format(item)) + + +class RunCheckerTest(unittest.TestCase): + + @classmethod + def setUpClass(cls): + checker_module.get_checker_config = Mock() + checker_module.NamedTemporaryFile = Dummy_tempfile + checker_module.CheckerWindow = Mock() + cls.get_config = checker_module.get_checker_config + script_binding = editwin.extensions.get('ScriptBinding') + script_binding.getfilename = lambda: editwin.filename + + @classmethod + def tearDownClass(cls): + checker_module.get_checker_config = orig_get_checker_config + checker_module.NamedTemporaryFile = Mock() + checker_module.CheckerWindow = orig_checker_window + checker_module.Popen = orig_popen + + def setUp(self): + self.checker_config = {'name': 'three', 'enabled': True, + 'command': 'python -m three', + 'additional': '-v 2 format=True o', + 'reload_source': 1, 'show_result': 1} + self.get_config.configure_mock(return_value=self.checker_config) + editwin.filename = 'foo/bar/filename.py' + checker_module.Popen = Mock() + + def test_blank_filename(self): + editwin.filename = '' + self.assertFalse(run()) + + def test_blank_command(self): + self.checker_config['command'] = '' + self.get_config.configure_mock(return_value=self.checker_config) + self.assertFalse(run()) + self.assertEqual('Empty Command', showerror.title) + self.assertIn('three', showerror.message) + self.assertIn('Command', showerror.message) + + def test_bad_run(self): + editwin.filename = 'foo/bar/imaginary_file.py' + error_message = 'No such file or directory' + error_filename = 'imaginary_file.py' + checker_module.Popen = Mock(side_effect=OSError(2, + error_message, + error_filename)) + self.assertFalse(run()) + self.assertIn('imaginary_file.py', str(showerror.title)) + self.assertIn('No such file or directory', showerror.message) + self.assertIn('Traceback', showerror.message) + + def test_good_run(self): + self.assertTrue(run()) + call_args = checker_module.Popen.call_args + args = call_args[0][0] + cwd = call_args[1]['cwd'] + self.assertListEqual(args, ['python', '-m', 'three', '-v', '2', + 'format=True', 'o', 'filename.py']) + self.assertEqual(cwd, 'foo/bar') + + +class CheckerTest(unittest.TestCase): + dialog = Dummy_checker() + + @classmethod + def setUpClass(cls): + cls.dialog.dialog = cls.dialog + checker_module.tkMessageBox = Mbox + checker_module.ConfigCheckerDialog = Mock() + cls.dialog.root = Tk() + cls.dialog.listbox = Listbox(cls.dialog.root) + + @classmethod + def tearDownClass(cls): + checker_module.ConfigCheckerDialog = orig_config_checker_dialog + cls.dialog.listbox.destroy() + cls.dialog.root.destroy() + del cls.dialog.listbox, cls.dialog.root + + def tearDown(self): + self.dialog.update_listbox() + + def test_add_checker(self): + self.dialog.add_checker() + checker_module.ConfigCheckerDialog.assert_called_with(self.dialog, '') + + def test_bad_edit(self): + showerror.title = '' + showerror.message = '' + self.dialog.listbox.selection_clear(0, END) + self.dialog.edit_checker() + self.assertEqual(showerror.title, 'No Checker Selected') + self.assertIn('existing', showerror.message) + + def test_good_edit(self): + self.dialog.listbox.selection_set(END) + self.dialog.edit_checker() + checker_module.ConfigCheckerDialog.assert_called_with(self.dialog, + 'three') + + def test_bad_remove(self): + self.dialog.listbox.selection_clear(0, END) + showerror.title = '' + showerror.message = '' + self.dialog.remove_checker() + self.assertEqual(showerror.title, 'No Checker Selected') + self.assertIn('existing', showerror.message) + + def test_dont_confirm_remove(self): + self.dialog.listbox.selection_set(END) + askyesno.result = False + self.assertIsNone(self.dialog.remove_checker()) + self.assertIn('Confirm', askyesno.title) + self.assertIn('three', askyesno.title) + self.assertIn('three', askyesno.message) + self.assertIn('remove', askyesno.message) + + def test_good_remove(self): + self.dialog.listbox.selection_set(END) + askyesno.result = True + self.dialog.remove_checker() + self.assertIn('Confirm', askyesno.title) + self.assertIn('three', askyesno.title) + self.assertIn('three', askyesno.message) + self.assertIn('remove', askyesno.message) + idleConf = checker_module.idleConf + remove = idleConf.userCfg['checker'].remove_option + remove.assert_has_calls([call('three', 'enabled'), + call('three', 'command'), + call('three', 'additional'), + call('three', 'reload_source'), + call('three', 'show_result'), + ]) + save = idleConf.userCfg['checker'].Save + save.assert_called_with() + + def test_update_listbox(self): + self.dialog.listbox.delete(0, END) + self.dialog.update_listbox() + list_items = self.dialog.listbox.get(0, END) + self.assertTupleEqual(list_items, ('one', 'two', 'three')) + + def test_selected_checker(self): + self.dialog.listbox.selection_clear(0, END) + self.assertIsNone(self.dialog._selected_checker()) + self.dialog.listbox.selection_set("end") + self.assertEqual(self.dialog._selected_checker(), 'three') + + +class ConfigCheckerDialogTest(unittest.TestCase): + dialog = Dummy_config_checker_dialog() + + def test_blank_name(self): + for name in ('', ' '): + self.dialog.name.set(name) + self.assertFalse(self.dialog.name_ok()) + self.assertEqual(showerror.title, 'Name Error') + self.assertIn('No', showerror.message) + + self.dialog.name.set(' ') + self.assertFalse(self.dialog.name_ok()) + self.assertEqual(showerror.title, 'Name Error') + self.assertIn('No', showerror.message) + + def test_good_name(self): + self.dialog.name.set('pyflakes') + self.assertTrue(self.dialog.name_ok()) + + def test_blank_command(self): + for command in ('', ' '): + self.dialog.command.set(command) + self.assertFalse(self.dialog.command_ok()) + self.assertEqual(showerror.title, 'Command Error') + self.assertIn('No', showerror.message) + + def test_good_command(self): + self.dialog.command.set('/bin/pyflakes') + self.assertTrue(self.dialog.command_ok()) + + def test_good_ok(self): + self.dialog.name.set('bar') + self.dialog.enabled.set(0) + self.dialog.command.set('foo') + self.dialog.additional.set('') + self.dialog.reload_source.set(0) + self.dialog.show_result.set(1) + self.dialog.ok() + idleConf = checker_module.idleConf + set_option = idleConf.userCfg['checker'].SetOption + set_option.assert_has_calls([call('bar', 'enabled', 0), + call('bar', 'command', 'foo'), + call('bar', 'additional', ''), + call('bar', 'reload_source', 0), + call('bar', 'show_result', 1), + ]) + save = idleConf.userCfg['checker'].Save + save.assert_called_with() + + def test_update_call_string(self): + self.dialog.editwin.io.filename = '/foo/bar/filename.py' + self.dialog.command.set('checker') + self.dialog.additional.set('--help') + self.dialog.update_call_string() + self.assertEqual(self.dialog.call_string.get(), + 'checker --help filename.py') + + self.dialog.editwin.io.filename = None + self.dialog.update_call_string() + self.assertEqual(self.dialog.call_string.get(), + 'checker --help ') + +if __name__ == '__main__': + unittest.main(verbosity=2)