# Copyright (C) 2009-2012 Lars Wirzenius # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. from __future__ import unicode_literals try: from StringIO import StringIO except ImportError: from io import StringIO import unittest import cliapp class SettingsTests(unittest.TestCase): def setUp(self): self.settings = cliapp.Settings('appname', '1.0') def test_has_progname(self): self.assertEqual(self.settings.progname, 'appname') def test_sets_progname(self): self.settings.progname = 'foo' self.assertEqual(self.settings.progname, 'foo') def test_has_version(self): self.assertEqual(self.settings.version, '1.0') def test_sets_usage_from_func(self): s = cliapp.Settings('appname', '1.0', usage=lambda: 'xyzzy') p = s.build_parser() self.assertTrue('xyzzy' in p.usage) def test_adds_default_options_and_settings(self): self.assertTrue('output' in self.settings) self.assertTrue('log' in self.settings) self.assertTrue('log-level' in self.settings) def test_iterates_over_canonical_settings_names(self): known = ['output', 'log', 'log-level'] self.assertEqual(sorted(x for x in self.settings if x in known), sorted(known)) def test_keys_returns_canonical_names(self): known = ['output', 'log', 'log-level'] self.assertEqual(sorted(x for x in self.settings.keys() if x in known), sorted(known)) def test_parses_options(self): self.settings.string(['foo'], 'foo help', group='foo') self.settings.boolean(['bar'], 'bar help') self.settings.parse_args(['--foo=foovalue', '--bar']) self.assertEqual(self.settings['foo'], 'foovalue') self.assertEqual(self.settings['bar'], True) def test_parses_boolean_negation_option(self): self.settings.boolean(['bar'], 'bar help') self.settings.parse_args(['--bar', '--no-bar']) self.assertEqual(self.settings['bar'], False) def test_parses_boolean_negation_option_in_group(self): self.settings.boolean(['bar'], 'bar help', group='bar') self.settings.parse_args(['--bar', '--no-bar']) self.assertEqual(self.settings['bar'], False) def test_does_not_have_foo_setting_by_default(self): self.assertFalse('foo' in self.settings) def test_raises_keyerror_for_getting_unknown_setting(self): self.assertRaises(KeyError, self.settings.__getitem__, 'foo') def test_raises_keyerror_for_setting_unknown_setting(self): self.assertRaises(KeyError, self.settings.__setitem__, 'foo', 'bar') def test_adds_string_setting(self): self.settings.string(['foo'], 'foo help') self.assertTrue('foo' in self.settings) def test_adds_string_list_setting(self): self.settings.string_list(['foo'], 'foo help') self.assertTrue('foo' in self.settings) def test_string_list_is_empty_list_by_default(self): self.settings.string_list(['foo'], '') self.settings.parse_args([]) self.assertEqual(self.settings['foo'], []) def test_string_list_parses_one_item(self): self.settings.string_list(['foo'], '') self.settings.parse_args(['--foo=foo']) self.assertEqual(self.settings['foo'], ['foo']) def test_string_list_parses_two_items(self): self.settings.string_list(['foo'], '') self.settings.parse_args(['--foo=foo', '--foo', 'bar']) self.assertEqual(self.settings['foo'], ['foo', 'bar']) def test_string_list_uses_nonempty_default_if_given(self): self.settings.string_list(['foo'], '', default=['bar']) self.settings.parse_args([]) self.assertEqual(self.settings['foo'], ['bar']) def test_string_list_uses_ignores_default_if_user_provides_values(self): self.settings.string_list(['foo'], '', default=['bar']) self.settings.parse_args(['--foo=pink', '--foo=punk']) self.assertEqual(self.settings['foo'], ['pink', 'punk']) def test_adds_choice_setting(self): self.settings.choice(['foo'], ['foo', 'bar'], 'foo help') self.assertTrue('foo' in self.settings) def test_choice_defaults_to_first_one(self): self.settings.choice(['foo'], ['foo', 'bar'], 'foo help') self.settings.parse_args([]) self.assertEqual(self.settings['foo'], 'foo') def test_choice_accepts_any_valid_value(self): self.settings.choice(['foo'], ['foo', 'bar'], 'foo help') self.settings.parse_args(['--foo=foo']) self.assertEqual(self.settings['foo'], 'foo') self.settings.parse_args(['--foo=bar']) self.assertEqual(self.settings['foo'], 'bar') def test_choice_raises_error_for_unacceptable_value(self): self.settings.choice(['foo'], ['foo', 'bar'], 'foo help') self.assertRaises(SystemExit, self.settings.parse_args, ['--foo=xyzzy'], suppress_errors=True) def test_adds_boolean_setting(self): self.settings.boolean(['foo'], 'foo help') self.assertTrue('foo' in self.settings) def test_boolean_setting_is_false_by_default(self): self.settings.boolean(['foo'], 'foo help') self.assertFalse(self.settings['foo']) def test_sets_boolean_setting_to_true_for_many_true_values(self): self.settings.boolean(['foo'], 'foo help') self.settings['foo'] = True self.assertTrue(self.settings['foo']) self.settings['foo'] = 1 self.assertTrue(self.settings['foo']) def test_sets_boolean_setting_to_false_for_many_false_values(self): self.settings.boolean(['foo'], 'foo help') self.settings['foo'] = False self.assertFalse(self.settings['foo']) self.settings['foo'] = 0 self.assertFalse(self.settings['foo']) self.settings['foo'] = () self.assertFalse(self.settings['foo']) self.settings['foo'] = [] self.assertFalse(self.settings['foo']) self.settings['foo'] = '' self.assertFalse(self.settings['foo']) def test_sets_boolean_to_true_from_ini_file(self): def fake_open(filename): return StringIO('[config]\nfoo = yes\n') self.settings.boolean(['foo'], 'foo help') self.settings.config_files = ['foo.conf'] self.settings.load_configs(open_file=fake_open) self.assertEqual(self.settings['foo'], True) def test_sets_boolean_to_false_from_ini_file(self): def fake_open(filename): return StringIO('[config]\nfoo = False\n') self.settings.boolean(['foo'], 'foo help') self.settings.config_files = ['foo.conf'] self.settings.load_configs(open_file=fake_open) self.assertEqual(self.settings['foo'], False) def test_sets_boolean_to_true_from_yaml_file(self): def fake_open(filename): return StringIO('config:\n foo: true\n') self.settings.boolean(['foo'], 'foo help') self.settings.config_files = ['foo.yaml'] self.settings.load_configs(open_file=fake_open) self.assertEqual(self.settings['foo'], True) def test_sets_boolean_to_false_from_yaml_file(self): def fake_open(filename): return StringIO('config:\n foo: false\n') self.settings.boolean(['foo'], 'foo help') self.settings.config_files = ['foo.yaml'] self.settings.load_configs(open_file=fake_open) self.assertEqual(self.settings['foo'], False) def test_adds_bytesize_setting(self): self.settings.bytesize(['foo'], 'foo help') self.assertTrue('foo' in self.settings) def test_parses_bytesize_option(self): self.settings.bytesize(['foo'], 'foo help') self.settings.parse_args(args=['--foo=xyzzy']) self.assertEqual(self.settings['foo'], 0) self.settings.parse_args(args=['--foo=123']) self.assertEqual(self.settings['foo'], 123) self.settings.parse_args(args=['--foo=123k']) self.assertEqual(self.settings['foo'], 123 * 1000) self.settings.parse_args(args=['--foo=123m']) self.assertEqual(self.settings['foo'], 123 * 1000 ** 2) self.settings.parse_args(args=['--foo=123g']) self.assertEqual(self.settings['foo'], 123 * 1000 ** 3) self.settings.parse_args(args=['--foo=123t']) self.assertEqual(self.settings['foo'], 123 * 1000 ** 4) self.settings.parse_args(args=['--foo=123kib']) self.assertEqual(self.settings['foo'], 123 * 1024) self.settings.parse_args(args=['--foo=123mib']) self.assertEqual(self.settings['foo'], 123 * 1024 ** 2) self.settings.parse_args(args=['--foo=123gib']) self.assertEqual(self.settings['foo'], 123 * 1024 ** 3) self.settings.parse_args(args=['--foo=123tib']) self.assertEqual(self.settings['foo'], 123 * 1024 ** 4) def test_adds_integer_setting(self): self.settings.integer(['foo'], 'foo help') self.assertTrue('foo' in self.settings) def test_parses_integer_option(self): self.settings.integer(['foo'], 'foo help', default=123) self.settings.parse_args(args=[]) self.assertEqual(self.settings['foo'], 123) self.settings.parse_args(args=['--foo=123']) self.assertEqual(self.settings['foo'], 123) def test_has_list_of_default_config_files(self): defaults = self.settings.default_config_files self.assertTrue(isinstance(defaults, list)) self.assertTrue(len(defaults) > 0) def test_listconfs_returns_empty_list_for_nonexistent_directory(self): self.assertEqual(self.settings.listconfs('notexist'), []) def test_listconfs_lists_config_files_only(self): def mock_listdir(dirname): return ['foo.conf', 'foo.notconf'] names = self.settings.listconfs('.', listdir=mock_listdir) self.assertEqual(names, ['./foo.conf']) def test_listconfs_sorts_names_in_C_locale(self): def mock_listdir(dirname): return ['foo.conf', 'bar.conf'] names = self.settings.listconfs('.', listdir=mock_listdir) self.assertEqual(names, ['./bar.conf', './foo.conf']) def test_has_config_files_attribute(self): self.assertEqual(self.settings.config_files, self.settings.default_config_files) def test_has_config_files_list_can_be_changed(self): self.settings.config_files += ['./foo'] self.assertEqual(self.settings.config_files, self.settings.default_config_files + ['./foo']) def test_loads_ini_files(self): def mock_open(filename, mode=None): return StringIO('''\ [config] foo = yeehaa ''') self.settings.string(['foo'], 'foo help') self.settings.config_files = ['whatever.conf'] self.settings.load_configs(open_file=mock_open) self.assertEqual(self.settings['foo'], 'yeehaa') def test_loads_yaml_files(self): def mock_open(filename, mode=None): return StringIO('''\ config: foo: yeehaa ''') self.settings.string(['foo'], 'foo help') self.settings.config_files = ['whatever.yaml'] self.settings.load_configs(open_file=mock_open) self.assertEqual(self.settings['foo'], 'yeehaa') def test_loads_string_list_from_ini_files(self): def mock_open(filename, mode=None): return StringIO('''\ [config] foo = yeehaa bar = ping, pong comma = ping, pong, "foo,bar" ''') self.settings.string_list(['foo'], 'foo help') self.settings.string_list(['bar'], 'bar help') self.settings.string_list(['comma'], 'comma help') self.settings.config_files = ['whatever.conf'] self.settings.load_configs(open_file=mock_open) self.assertEqual(self.settings['foo'], ['yeehaa']) self.assertEqual(self.settings['bar'], ['ping', 'pong']) self.assertEqual(self.settings['comma'], ['ping', 'pong', 'foo,bar']) def test_loads_string_list_from_yaml_files(self): def mock_open(filename, mode=None): return StringIO('''\ config: foo: yeehaa bar: [ping, pong] comma: [ping, pong, "foo,bar"] ''') self.settings.string_list(['foo'], 'foo help') self.settings.string_list(['bar'], 'bar help') self.settings.string_list(['comma'], 'comma help') self.settings.config_files = ['whatever.yaml'] self.settings.load_configs(open_file=mock_open) self.assertEqual(self.settings['foo'], ['yeehaa']) self.assertEqual(self.settings['bar'], ['ping', 'pong']) self.assertEqual(self.settings['comma'], ['ping', 'pong', 'foo,bar']) def test_handles_defaults_with_ini_files(self): def mock_open(filename, mode=None): return StringIO('''\ [config] ''') self.settings.string(['foo'], 'foo help', default='foo') self.settings.string_list(['bar'], 'bar help', default=['bar']) self.settings.config_files = ['whatever.conf'] self.settings.load_configs(open_file=mock_open) self.assertEqual(self.settings['foo'], 'foo') self.assertEqual(self.settings['bar'], ['bar']) def test_handles_defaults_with_yaml_files(self): def mock_open(filename, mode=None): return StringIO('''\ config: {} ''') self.settings.string(['foo'], 'foo help', default='foo') self.settings.string_list(['bar'], 'bar help', default=['bar']) self.settings.config_files = ['whatever.yaml'] self.settings.load_configs(open_file=mock_open) self.assertEqual(self.settings['foo'], 'foo') self.assertEqual(self.settings['bar'], ['bar']) def test_handles_overridden_defaults_with_ini_files(self): def mock_open(filename, mode=None): return StringIO('''\ [config] foo = yeehaa bar = ping, pong ''') self.settings.string(['foo'], 'foo help', default='foo') self.settings.string_list(['bar'], 'bar help', default=['bar']) self.settings.config_files = ['whatever.conf'] self.settings.load_configs(open_file=mock_open) self.assertEqual(self.settings['foo'], 'yeehaa') self.assertEqual(self.settings['bar'], ['ping', 'pong']) def test_handles_overridden_defaults_with_yaml_files(self): def mock_open(filename, mode=None): return StringIO('''\ config: foo: yeehaa bar: [ping, pong] ''') self.settings.string(['foo'], 'foo help', default='foo') self.settings.string_list(['bar'], 'bar help', default=['bar']) self.settings.config_files = ['whatever.yaml'] self.settings.load_configs(open_file=mock_open) self.assertEqual(self.settings['foo'], 'yeehaa') self.assertEqual(self.settings['bar'], ['ping', 'pong']) def test_handles_values_from_ini_files_overridden_on_command_line(self): def mock_open(filename, mode=None): return StringIO('''\ [config] foo = yeehaa bar = ping, pong ''') self.settings.string(['foo'], 'foo help', default='foo') self.settings.string_list(['bar'], 'bar help', default=['bar']) self.settings.config_files = ['whatever.conf'] self.settings.load_configs(open_file=mock_open) self.settings.parse_args( ['--foo=red', '--bar=blue', '--bar=white,comma']) self.assertEqual(self.settings['foo'], 'red') self.assertEqual(self.settings['bar'], ['blue', 'white,comma']) def test_handles_values_from_yaml_files_overridden_on_command_line(self): def mock_open(filename, mode=None): return StringIO('''\ config: foo: yeehaa bar: [ping, pong] ''') self.settings.string(['foo'], 'foo help', default='foo') self.settings.string_list(['bar'], 'bar help', default=['bar']) self.settings.config_files = ['whatever.yaml'] self.settings.load_configs(open_file=mock_open) self.settings.parse_args( ['--foo=red', '--bar=blue', '--bar=white,comma']) self.assertEqual(self.settings['foo'], 'red') self.assertEqual(self.settings['bar'], ['blue', 'white,comma']) def test_load_configs_raises_error_for_unknown_variable_in_ini(self): def mock_open(filename, mode=None): return StringIO('''\ [config] unknown = variable ''') self.assertRaises( cliapp.UnknownConfigVariable, self.settings.load_configs, open_file=mock_open) def test_load_configs_raises_error_for_unknown_variable_in_yaml(self): def mock_open(filename, mode=None): return StringIO('''\ config: unknown: yeehaa ''') self.settings.string_list(['foo'], 'foo help') self.settings.config_files = ['whatever.yaml'] self.assertRaises( cliapp.UnknownConfigVariable, self.settings.load_configs, open_file=mock_open) def test_load_configs_remembers_extra_sections_in_ini(self): def mock_open(filename, mode=None): return StringIO('''\ [extra] something = else ''') self.settings.string_list(['foo'], 'foo help') self.settings.config_files = ['whatever.conf'] self.settings.load_configs(open_file=mock_open) cp = self.settings.as_cp() self.assertEqual(cp.sections(), ['config', 'extra']) self.assertEqual(cp.get('extra', 'something'), 'else') def test_load_configs_remembers_extra_sections_in_yaml(self): def mock_open(filename, mode=None): return StringIO('''\ config: {} extra: something: else ''') self.settings.string_list(['foo'], 'foo help') self.settings.config_files = ['whatever.yaml'] self.settings.load_configs(open_file=mock_open) cp = self.settings.as_cp() self.assertEqual(cp.sections(), ['config', 'extra']) self.assertEqual(cp.get('extra', 'something'), 'else') def test_load_configs_ignore_errors_opening_a_file(self): def mock_open(filename, mode=None): raise IOError() self.assertEqual(self.settings.load_configs(open_file=mock_open), None) def test_adds_config_file_with_dash_dash_config(self): self.settings.parse_args(['--config=foo.conf']) self.assertEqual(self.settings.config_files, self.settings.default_config_files + ['foo.conf']) def test_ignores_default_configs(self): self.settings.parse_args(['--no-default-configs']) self.assertEqual(self.settings.config_files, []) def test_ignores_then_adds_configs_works(self): self.settings.parse_args(['--no-default-configs', '--config=foo.conf']) self.assertEqual(self.settings.config_files, ['foo.conf']) def test_require_raises_error_if_string_unset(self): self.settings.string(['foo'], 'foo help', default=None) self.assertRaises(cliapp.AppException, self.settings.require, 'foo') def test_require_is_ok_with_set_string(self): self.settings.string(['foo'], 'foo help', default=None) self.settings['foo'] = 'bar' self.assertEqual(self.settings.require('foo'), None) def test_require_is_ok_with_default_string(self): self.settings.string(['foo'], 'foo help', default='foo default') self.assertEqual(self.settings.require('foo'), None) def test_require_raises_error_if_string_list_unset(self): self.settings.string_list(['foo'], 'foo help') self.assertRaises(cliapp.AppException, self.settings.require, 'foo') def test_require_is_ok_with_set_string_list(self): self.settings.string(['foo'], 'foo help') self.settings['foo'] = ['foo', 'bar'] self.assertEqual(self.settings.require('foo'), None) def test_require_is_ok_with_default_string_list(self): self.settings.string(['foo'], 'foo help', default=['foo']) self.assertEqual(self.settings.require('foo'), None) def test_require_is_ok_with_unset_choice(self): self.settings.choice(['foo'], ['foo', 'bar'], 'foo help') self.assertEqual(self.settings.require('foo'), None) def test_require_is_ok_with_unset_boolean(self): self.settings.boolean(['foo'], 'foo help') self.assertEqual(self.settings.require('foo'), None) def test_require_is_ok_with_unset_bytesize(self): self.settings.bytesize(['foo'], 'foo help') self.assertEqual(self.settings.require('foo'), None) def test_require_is_ok_with_unset_integer(self): self.settings.integer(['foo'], 'foo help') self.assertEqual(self.settings.require('foo'), None) def test_require_raises_error_when_one_value_of_several_is_unset(self): self.settings.string(['foo'], 'foo help') self.settings.string(['bar'], 'bar help', default=None) args = ['foo', 'bar'] self.assertRaises(cliapp.AppException, self.settings.require, *args) def test_require_is_ok_with_multiple_values(self): self.settings.string(['foo'], 'foo help') self.settings.string(['bar'], 'bar help') args = ['foo', 'bar'] self.assertEqual(self.settings.require(*args), None) def test_exports_configparser_with_settings(self): self.settings.integer(['foo'], 'foo help', default=1) self.settings.string(['bar'], 'bar help', default='yo') cp = self.settings.as_cp() self.assertEqual(cp.get('config', 'foo'), '1') self.assertEqual(cp.get('config', 'bar'), 'yo') def test_exports_all_config_sections_via_as_cp(self): def mock_open(filename, mode=None): return StringIO('''\ [config] foo = yeehaa [other] bar = dodo ''') self.settings.string(['foo'], 'foo help', default='foo') self.settings.config_files = ['whatever.conf'] self.settings.load_configs(open_file=mock_open) cp = self.settings.as_cp() self.assertEqual(sorted(cp.sections()), ['config', 'other']) self.assertEqual(cp.get('config', 'foo'), 'yeehaa') self.assertEqual(cp.options('other'), ['bar']) self.assertEqual(cp.get('other', 'bar'), 'dodo')