blob: c799c7df0a714cb4333452b0a41aa9304ad78ebb [file] [log] [blame]
Fred Drake8ef67672000-09-27 22:45:25 +00001import ConfigParser
2import StringIO
Fred Drakec6f28912002-10-25 19:40:49 +00003import unittest
Fred Drake8ef67672000-09-27 22:45:25 +00004
Fred Drakec6f28912002-10-25 19:40:49 +00005from test import test_support
Fred Drake3d5f7e82000-12-04 16:30:40 +00006
7
Fred Drakec6f28912002-10-25 19:40:49 +00008class TestCaseBase(unittest.TestCase):
9 def newconfig(self, defaults=None):
10 if defaults is None:
11 self.cf = self.config_class()
12 else:
13 self.cf = self.config_class(defaults)
14 return self.cf
Fred Drake8ef67672000-09-27 22:45:25 +000015
Fred Drakec6f28912002-10-25 19:40:49 +000016 def fromstring(self, string, defaults=None):
17 cf = self.newconfig(defaults)
18 sio = StringIO.StringIO(string)
19 cf.readfp(sio)
20 return cf
Fred Drake8ef67672000-09-27 22:45:25 +000021
Fred Drakec6f28912002-10-25 19:40:49 +000022 def test_basic(self):
23 cf = self.fromstring(
24 "[Foo Bar]\n"
25 "foo=bar\n"
26 "[Spacey Bar]\n"
27 "foo = bar\n"
28 "[Commented Bar]\n"
29 "foo: bar ; comment\n"
30 "[Long Line]\n"
31 "foo: this line is much, much longer than my editor\n"
32 " likes it.\n"
33 "[Section\\with$weird%characters[\t]\n"
34 "[Internationalized Stuff]\n"
35 "foo[bg]: Bulgarian\n"
36 "foo=Default\n"
37 "foo[en]=English\n"
38 "foo[de]=Deutsch\n"
39 "[Spaces]\n"
40 "key with spaces : value\n"
41 "another with spaces = splat!\n"
42 )
43 L = cf.sections()
44 L.sort()
45 eq = self.assertEqual
46 eq(L, [r'Commented Bar',
47 r'Foo Bar',
48 r'Internationalized Stuff',
49 r'Long Line',
50 r'Section\with$weird%characters[' '\t',
51 r'Spaces',
52 r'Spacey Bar',
53 ])
Fred Drake8ef67672000-09-27 22:45:25 +000054
Fred Drakec6f28912002-10-25 19:40:49 +000055 # The use of spaces in the section names serves as a
56 # regression test for SourceForge bug #583248:
57 # http://www.python.org/sf/583248
58 eq(cf.get('Foo Bar', 'foo'), 'bar')
59 eq(cf.get('Spacey Bar', 'foo'), 'bar')
60 eq(cf.get('Commented Bar', 'foo'), 'bar')
61 eq(cf.get('Spaces', 'key with spaces'), 'value')
62 eq(cf.get('Spaces', 'another with spaces'), 'splat!')
Fred Drake3d5f7e82000-12-04 16:30:40 +000063
Fred Drakec6f28912002-10-25 19:40:49 +000064 self.failIf('__name__' in cf.options("Foo Bar"),
65 '__name__ "option" should not be exposed by the API!')
66
67 # Make sure the right things happen for remove_option();
68 # added to include check for SourceForge bug #123324:
69 self.failUnless(cf.remove_option('Foo Bar', 'foo'),
70 "remove_option() failed to report existance of option")
71 self.failIf(cf.has_option('Foo Bar', 'foo'),
72 "remove_option() failed to remove option")
73 self.failIf(cf.remove_option('Foo Bar', 'foo'),
74 "remove_option() failed to report non-existance of option"
75 " that was removed")
76
77 self.assertRaises(ConfigParser.NoSectionError,
78 cf.remove_option, 'No Such Section', 'foo')
79
80 eq(cf.get('Long Line', 'foo'),
Andrew M. Kuchling1bf71172002-03-08 18:10:12 +000081 'this line is much, much longer than my editor\nlikes it.')
Fred Drake3d5f7e82000-12-04 16:30:40 +000082
Fred Drakec6f28912002-10-25 19:40:49 +000083 def test_case_sensitivity(self):
84 cf = self.newconfig()
85 cf.add_section("A")
86 cf.add_section("a")
87 L = cf.sections()
88 L.sort()
89 eq = self.assertEqual
90 eq(L, ["A", "a"])
91 cf.set("a", "B", "value")
92 eq(cf.options("a"), ["b"])
93 eq(cf.get("a", "b"), "value",
Fred Drake3c823aa2001-02-26 21:55:34 +000094 "could not locate option, expecting case-insensitive option names")
Fred Drakec6f28912002-10-25 19:40:49 +000095 self.failUnless(cf.has_option("a", "b"))
96 cf.set("A", "A-B", "A-B value")
97 for opt in ("a-b", "A-b", "a-B", "A-B"):
98 self.failUnless(
99 cf.has_option("A", opt),
100 "has_option() returned false for option which should exist")
101 eq(cf.options("A"), ["a-b"])
102 eq(cf.options("a"), ["b"])
103 cf.remove_option("a", "B")
104 eq(cf.options("a"), [])
Fred Drake3c823aa2001-02-26 21:55:34 +0000105
Fred Drakec6f28912002-10-25 19:40:49 +0000106 # SF bug #432369:
107 cf = self.fromstring(
108 "[MySection]\nOption: first line\n\tsecond line\n")
109 eq(cf.options("MySection"), ["option"])
110 eq(cf.get("MySection", "Option"), "first line\nsecond line")
Fred Drakebeb67132001-07-06 17:22:48 +0000111
Fred Drakec6f28912002-10-25 19:40:49 +0000112 # SF bug #561822:
113 cf = self.fromstring("[section]\nnekey=nevalue\n",
114 defaults={"key":"value"})
115 self.failUnless(cf.has_option("section", "Key"))
Fred Drake309db062002-09-27 15:35:23 +0000116
Fred Drake3c823aa2001-02-26 21:55:34 +0000117
Fred Drakec6f28912002-10-25 19:40:49 +0000118 def test_parse_errors(self):
119 self.newconfig()
120 self.parse_error(ConfigParser.ParsingError,
121 "[Foo]\n extra-spaces: splat\n")
122 self.parse_error(ConfigParser.ParsingError,
123 "[Foo]\n extra-spaces= splat\n")
124 self.parse_error(ConfigParser.ParsingError,
125 "[Foo]\noption-without-value\n")
126 self.parse_error(ConfigParser.ParsingError,
127 "[Foo]\n:value-without-option-name\n")
128 self.parse_error(ConfigParser.ParsingError,
129 "[Foo]\n=value-without-option-name\n")
130 self.parse_error(ConfigParser.MissingSectionHeaderError,
131 "No Section!\n")
Fred Drake168bead2001-10-08 17:13:12 +0000132
Fred Drakec6f28912002-10-25 19:40:49 +0000133 def parse_error(self, exc, src):
134 sio = StringIO.StringIO(src)
135 self.assertRaises(exc, self.cf.readfp, sio)
Fred Drake168bead2001-10-08 17:13:12 +0000136
Fred Drakec6f28912002-10-25 19:40:49 +0000137 def test_query_errors(self):
138 cf = self.newconfig()
139 self.assertEqual(cf.sections(), [],
140 "new ConfigParser should have no defined sections")
141 self.failIf(cf.has_section("Foo"),
142 "new ConfigParser should have no acknowledged sections")
143 self.assertRaises(ConfigParser.NoSectionError,
144 cf.options, "Foo")
145 self.assertRaises(ConfigParser.NoSectionError,
146 cf.set, "foo", "bar", "value")
147 self.get_error(ConfigParser.NoSectionError, "foo", "bar")
148 cf.add_section("foo")
149 self.get_error(ConfigParser.NoOptionError, "foo", "bar")
Fred Drake8ef67672000-09-27 22:45:25 +0000150
Fred Drakec6f28912002-10-25 19:40:49 +0000151 def get_error(self, exc, section, option):
Fred Drake54782192002-12-31 06:57:25 +0000152 try:
153 self.cf.get(section, option)
154 except exc, e:
155 return e
156 else:
157 self.fail("expected exception type %s.%s"
158 % (exc.__module__, exc.__name__))
Fred Drake3af0eb82002-10-25 18:09:24 +0000159
Fred Drakec6f28912002-10-25 19:40:49 +0000160 def test_boolean(self):
161 cf = self.fromstring(
162 "[BOOLTEST]\n"
163 "T1=1\n"
164 "T2=TRUE\n"
165 "T3=True\n"
166 "T4=oN\n"
167 "T5=yes\n"
168 "F1=0\n"
169 "F2=FALSE\n"
170 "F3=False\n"
171 "F4=oFF\n"
172 "F5=nO\n"
173 "E1=2\n"
174 "E2=foo\n"
175 "E3=-1\n"
176 "E4=0.1\n"
177 "E5=FALSE AND MORE"
178 )
179 for x in range(1, 5):
180 self.failUnless(cf.getboolean('BOOLTEST', 't%d' % x))
181 self.failIf(cf.getboolean('BOOLTEST', 'f%d' % x))
182 self.assertRaises(ValueError,
183 cf.getboolean, 'BOOLTEST', 'e%d' % x)
Fred Drake95b96d32001-02-12 17:23:20 +0000184
Fred Drakec6f28912002-10-25 19:40:49 +0000185 def test_weird_errors(self):
186 cf = self.newconfig()
Fred Drake8ef67672000-09-27 22:45:25 +0000187 cf.add_section("Foo")
Fred Drakec6f28912002-10-25 19:40:49 +0000188 self.assertRaises(ConfigParser.DuplicateSectionError,
189 cf.add_section, "Foo")
190
191 def test_write(self):
192 cf = self.fromstring(
193 "[Long Line]\n"
194 "foo: this line is much, much longer than my editor\n"
195 " likes it.\n"
196 "[DEFAULT]\n"
197 "foo: another very\n"
198 " long line"
199 )
200 output = StringIO.StringIO()
201 cf.write(output)
202 self.assertEqual(
203 output.getvalue(),
204 "[DEFAULT]\n"
205 "foo = another very\n"
206 "\tlong line\n"
207 "\n"
208 "[Long Line]\n"
209 "foo = this line is much, much longer than my editor\n"
210 "\tlikes it.\n"
211 "\n"
212 )
213
Fred Drakeabc086f2004-05-18 03:29:52 +0000214 def test_set_string_types(self):
215 cf = self.fromstring("[sect]\n"
216 "option1=foo\n")
217 # Check that we don't get an exception when setting values in
218 # an existing section using strings:
219 class mystr(str):
220 pass
221 cf.set("sect", "option1", "splat")
222 cf.set("sect", "option1", mystr("splat"))
223 cf.set("sect", "option2", "splat")
224 cf.set("sect", "option2", mystr("splat"))
225 try:
226 unicode
227 except NameError:
228 pass
229 else:
230 cf.set("sect", "option1", unicode("splat"))
231 cf.set("sect", "option2", unicode("splat"))
232
233 def test_set_nonstring_types(self):
234 cf = self.fromstring("[sect]\n"
235 "option1=foo\n")
236 # Check that we get a TypeError when setting non-string values
237 # in an existing section:
238 self.assertRaises(TypeError, cf.set, "sect", "option1", 1)
239 self.assertRaises(TypeError, cf.set, "sect", "option1", 1.0)
240 self.assertRaises(TypeError, cf.set, "sect", "option1", object())
241 self.assertRaises(TypeError, cf.set, "sect", "option2", 1)
242 self.assertRaises(TypeError, cf.set, "sect", "option2", 1.0)
243 self.assertRaises(TypeError, cf.set, "sect", "option2", object())
244
Fred Drake82903142004-05-18 04:24:02 +0000245 def test_read_returns_file_list(self):
246 file1 = test_support.findfile("cfgparser.1")
247 # check when we pass a mix of readable and non-readable files:
248 cf = self.newconfig()
249 parsed_files = cf.read([file1, "nonexistant-file"])
250 self.assertEqual(parsed_files, [file1])
251 self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
252 # check when we pass only a filename:
253 cf = self.newconfig()
254 parsed_files = cf.read(file1)
255 self.assertEqual(parsed_files, [file1])
256 self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
257 # check when we pass only missing files:
258 cf = self.newconfig()
259 parsed_files = cf.read(["nonexistant-file"])
260 self.assertEqual(parsed_files, [])
261 # check when we pass no files:
262 cf = self.newconfig()
263 parsed_files = cf.read([])
264 self.assertEqual(parsed_files, [])
265
Fred Drakec6f28912002-10-25 19:40:49 +0000266 # shared by subclasses
267 def get_interpolation_config(self):
268 return self.fromstring(
269 "[Foo]\n"
270 "bar=something %(with1)s interpolation (1 step)\n"
271 "bar9=something %(with9)s lots of interpolation (9 steps)\n"
272 "bar10=something %(with10)s lots of interpolation (10 steps)\n"
273 "bar11=something %(with11)s lots of interpolation (11 steps)\n"
274 "with11=%(with10)s\n"
275 "with10=%(with9)s\n"
276 "with9=%(with8)s\n"
Fred Drakebc12b012004-05-18 02:25:51 +0000277 "with8=%(With7)s\n"
278 "with7=%(WITH6)s\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000279 "with6=%(with5)s\n"
Fred Drakebc12b012004-05-18 02:25:51 +0000280 "With5=%(with4)s\n"
281 "WITH4=%(with3)s\n"
Fred Drakec6f28912002-10-25 19:40:49 +0000282 "with3=%(with2)s\n"
283 "with2=%(with1)s\n"
284 "with1=with\n"
285 "\n"
286 "[Mutual Recursion]\n"
287 "foo=%(bar)s\n"
Fred Drake54782192002-12-31 06:57:25 +0000288 "bar=%(foo)s\n"
289 "\n"
290 "[Interpolation Error]\n"
291 "name=%(reference)s\n",
292 # no definition for 'reference'
Fred Drakec6f28912002-10-25 19:40:49 +0000293 defaults={"getname": "%(__name__)s"})
Fred Drake95b96d32001-02-12 17:23:20 +0000294
Fred Drake98e3b292002-10-25 20:42:44 +0000295 def check_items_config(self, expected):
296 cf = self.fromstring(
297 "[section]\n"
298 "name = value\n"
299 "key: |%(name)s| \n"
300 "getdefault: |%(default)s|\n"
301 "getname: |%(__name__)s|",
302 defaults={"default": "<default>"})
303 L = list(cf.items("section"))
304 L.sort()
305 self.assertEqual(L, expected)
306
Fred Drake8ef67672000-09-27 22:45:25 +0000307
Fred Drakec6f28912002-10-25 19:40:49 +0000308class ConfigParserTestCase(TestCaseBase):
309 config_class = ConfigParser.ConfigParser
310
311 def test_interpolation(self):
312 cf = self.get_interpolation_config()
313 eq = self.assertEqual
314 eq(cf.get("Foo", "getname"), "Foo")
315 eq(cf.get("Foo", "bar"), "something with interpolation (1 step)")
316 eq(cf.get("Foo", "bar9"),
317 "something with lots of interpolation (9 steps)")
318 eq(cf.get("Foo", "bar10"),
319 "something with lots of interpolation (10 steps)")
320 self.get_error(ConfigParser.InterpolationDepthError, "Foo", "bar11")
Fred Drake95b96d32001-02-12 17:23:20 +0000321
Fred Drake54782192002-12-31 06:57:25 +0000322 def test_interpolation_missing_value(self):
323 cf = self.get_interpolation_config()
324 e = self.get_error(ConfigParser.InterpolationError,
325 "Interpolation Error", "name")
326 self.assertEqual(e.reference, "reference")
327 self.assertEqual(e.section, "Interpolation Error")
328 self.assertEqual(e.option, "name")
329
Fred Drake98e3b292002-10-25 20:42:44 +0000330 def test_items(self):
331 self.check_items_config([('default', '<default>'),
332 ('getdefault', '|<default>|'),
333 ('getname', '|section|'),
334 ('key', '|value|'),
335 ('name', 'value')])
336
Fred Drake8ef67672000-09-27 22:45:25 +0000337
Fred Drakec6f28912002-10-25 19:40:49 +0000338class RawConfigParserTestCase(TestCaseBase):
339 config_class = ConfigParser.RawConfigParser
340
341 def test_interpolation(self):
342 cf = self.get_interpolation_config()
343 eq = self.assertEqual
344 eq(cf.get("Foo", "getname"), "%(__name__)s")
345 eq(cf.get("Foo", "bar"),
346 "something %(with1)s interpolation (1 step)")
347 eq(cf.get("Foo", "bar9"),
348 "something %(with9)s lots of interpolation (9 steps)")
349 eq(cf.get("Foo", "bar10"),
350 "something %(with10)s lots of interpolation (10 steps)")
351 eq(cf.get("Foo", "bar11"),
352 "something %(with11)s lots of interpolation (11 steps)")
Fred Drake95b96d32001-02-12 17:23:20 +0000353
Fred Drake98e3b292002-10-25 20:42:44 +0000354 def test_items(self):
355 self.check_items_config([('default', '<default>'),
356 ('getdefault', '|%(default)s|'),
357 ('getname', '|%(__name__)s|'),
358 ('key', '|%(name)s|'),
359 ('name', 'value')])
360
Fred Drake8ef67672000-09-27 22:45:25 +0000361
Fred Drake0eebd5c2002-10-25 21:52:00 +0000362class SafeConfigParserTestCase(ConfigParserTestCase):
363 config_class = ConfigParser.SafeConfigParser
364
365 def test_safe_interpolation(self):
366 # See http://www.python.org/sf/511737
367 cf = self.fromstring("[section]\n"
368 "option1=xxx\n"
369 "option2=%(option1)s/xxx\n"
370 "ok=%(option1)s/%%s\n"
371 "not_ok=%(option2)s/%%s")
372 self.assertEqual(cf.get("section", "ok"), "xxx/%s")
373 self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s")
374
375
Fred Drakec6f28912002-10-25 19:40:49 +0000376def test_main():
Walter Dörwald21d3a322003-05-01 17:45:56 +0000377 test_support.run_unittest(
378 ConfigParserTestCase,
379 RawConfigParserTestCase,
380 SafeConfigParserTestCase
381 )
Fred Drake3af0eb82002-10-25 18:09:24 +0000382
Fred Drakec6f28912002-10-25 19:40:49 +0000383if __name__ == "__main__":
384 test_main()