0001 import ConfigParser 0002 import StringIO 0003 import unittest 0004 0005 from test import test_support 0006 0007 0008 class TestCaseBase(unittest.TestCase): 0009 def newconfig(self, defaults=None): 0010 if defaults is None: 0011 self.cf = self.config_class() 0012 else: 0013 self.cf = self.config_class(defaults) 0014 return self.cf 0015 0016 def fromstring(self, string, defaults=None): 0017 cf = self.newconfig(defaults) 0018 sio = StringIO.StringIO(string) 0019 cf.readfp(sio) 0020 return cf 0021 0022 def test_basic(self): 0023 cf = self.fromstring( 0024 "[Foo Bar]\n" 0025 "foo=bar\n" 0026 "[Spacey Bar]\n" 0027 "foo = bar\n" 0028 "[Commented Bar]\n" 0029 "foo: bar ; comment\n" 0030 "[Long Line]\n" 0031 "foo: this line is much, much longer than my editor\n" 0032 " likes it.\n" 0033 "[Section\\with$weird%characters[\t]\n" 0034 "[Internationalized Stuff]\n" 0035 "foo[bg]: Bulgarian\n" 0036 "foo=Default\n" 0037 "foo[en]=English\n" 0038 "foo[de]=Deutsch\n" 0039 "[Spaces]\n" 0040 "key with spaces : value\n" 0041 "another with spaces = splat!\n" 0042 ) 0043 L = cf.sections() 0044 L.sort() 0045 eq = self.assertEqual 0046 eq(L, [r'Commented Bar', 0047 r'Foo Bar', 0048 r'Internationalized Stuff', 0049 r'Long Line', 0050 r'Section\with$weird%characters[' '\t', 0051 r'Spaces', 0052 r'Spacey Bar', 0053 ]) 0054 0055 # The use of spaces in the section names serves as a 0056 # regression test for SourceForge bug #583248: 0057 # http://www.python.org/sf/583248 0058 eq(cf.get('Foo Bar', 'foo'), 'bar') 0059 eq(cf.get('Spacey Bar', 'foo'), 'bar') 0060 eq(cf.get('Commented Bar', 'foo'), 'bar') 0061 eq(cf.get('Spaces', 'key with spaces'), 'value') 0062 eq(cf.get('Spaces', 'another with spaces'), 'splat!') 0063 0064 self.failIf('__name__' in cf.options("Foo Bar"), 0065 '__name__ "option" should not be exposed by the API!') 0066 0067 # Make sure the right things happen for remove_option(); 0068 # added to include check for SourceForge bug #123324: 0069 self.failUnless(cf.remove_option('Foo Bar', 'foo'), 0070 "remove_option() failed to report existance of option") 0071 self.failIf(cf.has_option('Foo Bar', 'foo'), 0072 "remove_option() failed to remove option") 0073 self.failIf(cf.remove_option('Foo Bar', 'foo'), 0074 "remove_option() failed to report non-existance of option" 0075 " that was removed") 0076 0077 self.assertRaises(ConfigParser.NoSectionError, 0078 cf.remove_option, 'No Such Section', 'foo') 0079 0080 eq(cf.get('Long Line', 'foo'), 0081 'this line is much, much longer than my editor\nlikes it.') 0082 0083 def test_case_sensitivity(self): 0084 cf = self.newconfig() 0085 cf.add_section("A") 0086 cf.add_section("a") 0087 L = cf.sections() 0088 L.sort() 0089 eq = self.assertEqual 0090 eq(L, ["A", "a"]) 0091 cf.set("a", "B", "value") 0092 eq(cf.options("a"), ["b"]) 0093 eq(cf.get("a", "b"), "value", 0094 "could not locate option, expecting case-insensitive option names") 0095 self.failUnless(cf.has_option("a", "b")) 0096 cf.set("A", "A-B", "A-B value") 0097 for opt in ("a-b", "A-b", "a-B", "A-B"): 0098 self.failUnless( 0099 cf.has_option("A", opt), 0100 "has_option() returned false for option which should exist") 0101 eq(cf.options("A"), ["a-b"]) 0102 eq(cf.options("a"), ["b"]) 0103 cf.remove_option("a", "B") 0104 eq(cf.options("a"), []) 0105 0106 # SF bug #432369: 0107 cf = self.fromstring( 0108 "[MySection]\nOption: first line\n\tsecond line\n") 0109 eq(cf.options("MySection"), ["option"]) 0110 eq(cf.get("MySection", "Option"), "first line\nsecond line") 0111 0112 # SF bug #561822: 0113 cf = self.fromstring("[section]\nnekey=nevalue\n", 0114 defaults={"key":"value"}) 0115 self.failUnless(cf.has_option("section", "Key")) 0116 0117 0118 def test_default_case_sensitivity(self): 0119 cf = self.newconfig({"foo": "Bar"}) 0120 self.assertEqual( 0121 cf.get("DEFAULT", "Foo"), "Bar", 0122 "could not locate option, expecting case-insensitive option names") 0123 cf = self.newconfig({"Foo": "Bar"}) 0124 self.assertEqual( 0125 cf.get("DEFAULT", "Foo"), "Bar", 0126 "could not locate option, expecting case-insensitive defaults") 0127 0128 def test_parse_errors(self): 0129 self.newconfig() 0130 self.parse_error(ConfigParser.ParsingError, 0131 "[Foo]\n extra-spaces: splat\n") 0132 self.parse_error(ConfigParser.ParsingError, 0133 "[Foo]\n extra-spaces= splat\n") 0134 self.parse_error(ConfigParser.ParsingError, 0135 "[Foo]\noption-without-value\n") 0136 self.parse_error(ConfigParser.ParsingError, 0137 "[Foo]\n:value-without-option-name\n") 0138 self.parse_error(ConfigParser.ParsingError, 0139 "[Foo]\n=value-without-option-name\n") 0140 self.parse_error(ConfigParser.MissingSectionHeaderError, 0141 "No Section!\n") 0142 0143 def parse_error(self, exc, src): 0144 sio = StringIO.StringIO(src) 0145 self.assertRaises(exc, self.cf.readfp, sio) 0146 0147 def test_query_errors(self): 0148 cf = self.newconfig() 0149 self.assertEqual(cf.sections(), [], 0150 "new ConfigParser should have no defined sections") 0151 self.failIf(cf.has_section("Foo"), 0152 "new ConfigParser should have no acknowledged sections") 0153 self.assertRaises(ConfigParser.NoSectionError, 0154 cf.options, "Foo") 0155 self.assertRaises(ConfigParser.NoSectionError, 0156 cf.set, "foo", "bar", "value") 0157 self.get_error(ConfigParser.NoSectionError, "foo", "bar") 0158 cf.add_section("foo") 0159 self.get_error(ConfigParser.NoOptionError, "foo", "bar") 0160 0161 def get_error(self, exc, section, option): 0162 try: 0163 self.cf.get(section, option) 0164 except exc, e: 0165 return e 0166 else: 0167 self.fail("expected exception type %s.%s" 0168 % (exc.__module__, exc.__name__)) 0169 0170 def test_boolean(self): 0171 cf = self.fromstring( 0172 "[BOOLTEST]\n" 0173 "T1=1\n" 0174 "T2=TRUE\n" 0175 "T3=True\n" 0176 "T4=oN\n" 0177 "T5=yes\n" 0178 "F1=0\n" 0179 "F2=FALSE\n" 0180 "F3=False\n" 0181 "F4=oFF\n" 0182 "F5=nO\n" 0183 "E1=2\n" 0184 "E2=foo\n" 0185 "E3=-1\n" 0186 "E4=0.1\n" 0187 "E5=FALSE AND MORE" 0188 ) 0189 for x in range(1, 5): 0190 self.failUnless(cf.getboolean('BOOLTEST', 't%d' % x)) 0191 self.failIf(cf.getboolean('BOOLTEST', 'f%d' % x)) 0192 self.assertRaises(ValueError, 0193 cf.getboolean, 'BOOLTEST', 'e%d' % x) 0194 0195 def test_weird_errors(self): 0196 cf = self.newconfig() 0197 cf.add_section("Foo") 0198 self.assertRaises(ConfigParser.DuplicateSectionError, 0199 cf.add_section, "Foo") 0200 0201 def test_write(self): 0202 cf = self.fromstring( 0203 "[Long Line]\n" 0204 "foo: this line is much, much longer than my editor\n" 0205 " likes it.\n" 0206 "[DEFAULT]\n" 0207 "foo: another very\n" 0208 " long line" 0209 ) 0210 output = StringIO.StringIO() 0211 cf.write(output) 0212 self.assertEqual( 0213 output.getvalue(), 0214 "[DEFAULT]\n" 0215 "foo = another very\n" 0216 "\tlong line\n" 0217 "\n" 0218 "[Long Line]\n" 0219 "foo = this line is much, much longer than my editor\n" 0220 "\tlikes it.\n" 0221 "\n" 0222 ) 0223 0224 def test_set_string_types(self): 0225 cf = self.fromstring("[sect]\n" 0226 "option1=foo\n") 0227 # Check that we don't get an exception when setting values in 0228 # an existing section using strings: 0229 class mystr(str): 0230 pass 0231 cf.set("sect", "option1", "splat") 0232 cf.set("sect", "option1", mystr("splat")) 0233 cf.set("sect", "option2", "splat") 0234 cf.set("sect", "option2", mystr("splat")) 0235 try: 0236 unicode 0237 except NameError: 0238 pass 0239 else: 0240 cf.set("sect", "option1", unicode("splat")) 0241 cf.set("sect", "option2", unicode("splat")) 0242 0243 def test_read_returns_file_list(self): 0244 file1 = test_support.findfile("cfgparser.1") 0245 # check when we pass a mix of readable and non-readable files: 0246 cf = self.newconfig() 0247 parsed_files = cf.read([file1, "nonexistant-file"]) 0248 self.assertEqual(parsed_files, [file1]) 0249 self.assertEqual(cf.get("Foo Bar", "foo"), "newbar") 0250 # check when we pass only a filename: 0251 cf = self.newconfig() 0252 parsed_files = cf.read(file1) 0253 self.assertEqual(parsed_files, [file1]) 0254 self.assertEqual(cf.get("Foo Bar", "foo"), "newbar") 0255 # check when we pass only missing files: 0256 cf = self.newconfig() 0257 parsed_files = cf.read(["nonexistant-file"]) 0258 self.assertEqual(parsed_files, []) 0259 # check when we pass no files: 0260 cf = self.newconfig() 0261 parsed_files = cf.read([]) 0262 self.assertEqual(parsed_files, []) 0263 0264 # shared by subclasses 0265 def get_interpolation_config(self): 0266 return self.fromstring( 0267 "[Foo]\n" 0268 "bar=something %(with1)s interpolation (1 step)\n" 0269 "bar9=something %(with9)s lots of interpolation (9 steps)\n" 0270 "bar10=something %(with10)s lots of interpolation (10 steps)\n" 0271 "bar11=something %(with11)s lots of interpolation (11 steps)\n" 0272 "with11=%(with10)s\n" 0273 "with10=%(with9)s\n" 0274 "with9=%(with8)s\n" 0275 "with8=%(With7)s\n" 0276 "with7=%(WITH6)s\n" 0277 "with6=%(with5)s\n" 0278 "With5=%(with4)s\n" 0279 "WITH4=%(with3)s\n" 0280 "with3=%(with2)s\n" 0281 "with2=%(with1)s\n" 0282 "with1=with\n" 0283 "\n" 0284 "[Mutual Recursion]\n" 0285 "foo=%(bar)s\n" 0286 "bar=%(foo)s\n" 0287 "\n" 0288 "[Interpolation Error]\n" 0289 "name=%(reference)s\n", 0290 # no definition for 'reference' 0291 defaults={"getname": "%(__name__)s"}) 0292 0293 def check_items_config(self, expected): 0294 cf = self.fromstring( 0295 "[section]\n" 0296 "name = value\n" 0297 "key: |%(name)s| \n" 0298 "getdefault: |%(default)s|\n" 0299 "getname: |%(__name__)s|", 0300 defaults={"default": "<default>"}) 0301 L = list(cf.items("section")) 0302 L.sort() 0303 self.assertEqual(L, expected) 0304 0305 0306 class ConfigParserTestCase(TestCaseBase): 0307 config_class = ConfigParser.ConfigParser 0308 0309 def test_interpolation(self): 0310 cf = self.get_interpolation_config() 0311 eq = self.assertEqual 0312 eq(cf.get("Foo", "getname"), "Foo") 0313 eq(cf.get("Foo", "bar"), "something with interpolation (1 step)") 0314 eq(cf.get("Foo", "bar9"), 0315 "something with lots of interpolation (9 steps)") 0316 eq(cf.get("Foo", "bar10"), 0317 "something with lots of interpolation (10 steps)") 0318 self.get_error(ConfigParser.InterpolationDepthError, "Foo", "bar11") 0319 0320 def test_interpolation_missing_value(self): 0321 cf = self.get_interpolation_config() 0322 e = self.get_error(ConfigParser.InterpolationError, 0323 "Interpolation Error", "name") 0324 self.assertEqual(e.reference, "reference") 0325 self.assertEqual(e.section, "Interpolation Error") 0326 self.assertEqual(e.option, "name") 0327 0328 def test_items(self): 0329 self.check_items_config([('default', '<default>'), 0330 ('getdefault', '|<default>|'), 0331 ('getname', '|section|'), 0332 ('key', '|value|'), 0333 ('name', 'value')]) 0334 0335 def test_set_nonstring_types(self): 0336 cf = self.newconfig() 0337 cf.add_section('non-string') 0338 cf.set('non-string', 'int', 1) 0339 cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13, '%(']) 0340 cf.set('non-string', 'dict', {'pi': 3.14159, '%(': 1, 0341 '%(list)': '%(list)'}) 0342 cf.set('non-string', 'string_with_interpolation', '%(list)s') 0343 self.assertEqual(cf.get('non-string', 'int', raw=True), 1) 0344 self.assertRaises(TypeError, cf.get, 'non-string', 'int') 0345 self.assertEqual(cf.get('non-string', 'list', raw=True), 0346 [0, 1, 1, 2, 3, 5, 8, 13, '%(']) 0347 self.assertRaises(TypeError, cf.get, 'non-string', 'list') 0348 self.assertEqual(cf.get('non-string', 'dict', raw=True), 0349 {'pi': 3.14159, '%(': 1, '%(list)': '%(list)'}) 0350 self.assertRaises(TypeError, cf.get, 'non-string', 'dict') 0351 self.assertEqual(cf.get('non-string', 'string_with_interpolation', 0352 raw=True), '%(list)s') 0353 self.assertRaises(ValueError, cf.get, 'non-string', 0354 'string_with_interpolation', raw=False) 0355 0356 0357 class RawConfigParserTestCase(TestCaseBase): 0358 config_class = ConfigParser.RawConfigParser 0359 0360 def test_interpolation(self): 0361 cf = self.get_interpolation_config() 0362 eq = self.assertEqual 0363 eq(cf.get("Foo", "getname"), "%(__name__)s") 0364 eq(cf.get("Foo", "bar"), 0365 "something %(with1)s interpolation (1 step)") 0366 eq(cf.get("Foo", "bar9"), 0367 "something %(with9)s lots of interpolation (9 steps)") 0368 eq(cf.get("Foo", "bar10"), 0369 "something %(with10)s lots of interpolation (10 steps)") 0370 eq(cf.get("Foo", "bar11"), 0371 "something %(with11)s lots of interpolation (11 steps)") 0372 0373 def test_items(self): 0374 self.check_items_config([('default', '<default>'), 0375 ('getdefault', '|%(default)s|'), 0376 ('getname', '|%(__name__)s|'), 0377 ('key', '|%(name)s|'), 0378 ('name', 'value')]) 0379 0380 def test_set_nonstring_types(self): 0381 cf = self.newconfig() 0382 cf.add_section('non-string') 0383 cf.set('non-string', 'int', 1) 0384 cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13]) 0385 cf.set('non-string', 'dict', {'pi': 3.14159}) 0386 self.assertEqual(cf.get('non-string', 'int'), 1) 0387 self.assertEqual(cf.get('non-string', 'list'), 0388 [0, 1, 1, 2, 3, 5, 8, 13]) 0389 self.assertEqual(cf.get('non-string', 'dict'), {'pi': 3.14159}) 0390 0391 0392 class SafeConfigParserTestCase(ConfigParserTestCase): 0393 config_class = ConfigParser.SafeConfigParser 0394 0395 def test_safe_interpolation(self): 0396 # See http://www.python.org/sf/511737 0397 cf = self.fromstring("[section]\n" 0398 "option1=xxx\n" 0399 "option2=%(option1)s/xxx\n" 0400 "ok=%(option1)s/%%s\n" 0401 "not_ok=%(option2)s/%%s") 0402 self.assertEqual(cf.get("section", "ok"), "xxx/%s") 0403 self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s") 0404 0405 def test_set_nonstring_types(self): 0406 cf = self.fromstring("[sect]\n" 0407 "option1=foo\n") 0408 # Check that we get a TypeError when setting non-string values 0409 # in an existing section: 0410 self.assertRaises(TypeError, cf.set, "sect", "option1", 1) 0411 self.assertRaises(TypeError, cf.set, "sect", "option1", 1.0) 0412 self.assertRaises(TypeError, cf.set, "sect", "option1", object()) 0413 self.assertRaises(TypeError, cf.set, "sect", "option2", 1) 0414 self.assertRaises(TypeError, cf.set, "sect", "option2", 1.0) 0415 self.assertRaises(TypeError, cf.set, "sect", "option2", object()) 0416 0417 0418 def test_main(): 0419 test_support.run_unittest( 0420 ConfigParserTestCase, 0421 RawConfigParserTestCase, 0422 SafeConfigParserTestCase 0423 ) 0424 0425 if __name__ == "__main__": 0426 test_main() 0427
Generated by PyXR 0.9.4