blob: bc0ef5e18dc01853301f7b07d1d5b57ccde2afc4 [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
214 # shared by subclasses
215 def get_interpolation_config(self):
216 return self.fromstring(
217 "[Foo]\n"
218 "bar=something %(with1)s interpolation (1 step)\n"
219 "bar9=something %(with9)s lots of interpolation (9 steps)\n"
220 "bar10=something %(with10)s lots of interpolation (10 steps)\n"
221 "bar11=something %(with11)s lots of interpolation (11 steps)\n"
222 "with11=%(with10)s\n"
223 "with10=%(with9)s\n"
224 "with9=%(with8)s\n"
225 "with8=%(with7)s\n"
226 "with7=%(with6)s\n"
227 "with6=%(with5)s\n"
228 "with5=%(with4)s\n"
229 "with4=%(with3)s\n"
230 "with3=%(with2)s\n"
231 "with2=%(with1)s\n"
232 "with1=with\n"
233 "\n"
234 "[Mutual Recursion]\n"
235 "foo=%(bar)s\n"
Fred Drake54782192002-12-31 06:57:25 +0000236 "bar=%(foo)s\n"
237 "\n"
238 "[Interpolation Error]\n"
239 "name=%(reference)s\n",
240 # no definition for 'reference'
Fred Drakec6f28912002-10-25 19:40:49 +0000241 defaults={"getname": "%(__name__)s"})
Fred Drake95b96d32001-02-12 17:23:20 +0000242
Fred Drake98e3b292002-10-25 20:42:44 +0000243 def check_items_config(self, expected):
244 cf = self.fromstring(
245 "[section]\n"
246 "name = value\n"
247 "key: |%(name)s| \n"
248 "getdefault: |%(default)s|\n"
249 "getname: |%(__name__)s|",
250 defaults={"default": "<default>"})
251 L = list(cf.items("section"))
252 L.sort()
253 self.assertEqual(L, expected)
254
Fred Drake8ef67672000-09-27 22:45:25 +0000255
Fred Drakec6f28912002-10-25 19:40:49 +0000256class ConfigParserTestCase(TestCaseBase):
257 config_class = ConfigParser.ConfigParser
258
259 def test_interpolation(self):
260 cf = self.get_interpolation_config()
261 eq = self.assertEqual
262 eq(cf.get("Foo", "getname"), "Foo")
263 eq(cf.get("Foo", "bar"), "something with interpolation (1 step)")
264 eq(cf.get("Foo", "bar9"),
265 "something with lots of interpolation (9 steps)")
266 eq(cf.get("Foo", "bar10"),
267 "something with lots of interpolation (10 steps)")
268 self.get_error(ConfigParser.InterpolationDepthError, "Foo", "bar11")
Fred Drake95b96d32001-02-12 17:23:20 +0000269
Fred Drake54782192002-12-31 06:57:25 +0000270 def test_interpolation_missing_value(self):
271 cf = self.get_interpolation_config()
272 e = self.get_error(ConfigParser.InterpolationError,
273 "Interpolation Error", "name")
274 self.assertEqual(e.reference, "reference")
275 self.assertEqual(e.section, "Interpolation Error")
276 self.assertEqual(e.option, "name")
277
Fred Drake98e3b292002-10-25 20:42:44 +0000278 def test_items(self):
279 self.check_items_config([('default', '<default>'),
280 ('getdefault', '|<default>|'),
281 ('getname', '|section|'),
282 ('key', '|value|'),
283 ('name', 'value')])
284
Fred Drake8ef67672000-09-27 22:45:25 +0000285
Fred Drakec6f28912002-10-25 19:40:49 +0000286class RawConfigParserTestCase(TestCaseBase):
287 config_class = ConfigParser.RawConfigParser
288
289 def test_interpolation(self):
290 cf = self.get_interpolation_config()
291 eq = self.assertEqual
292 eq(cf.get("Foo", "getname"), "%(__name__)s")
293 eq(cf.get("Foo", "bar"),
294 "something %(with1)s interpolation (1 step)")
295 eq(cf.get("Foo", "bar9"),
296 "something %(with9)s lots of interpolation (9 steps)")
297 eq(cf.get("Foo", "bar10"),
298 "something %(with10)s lots of interpolation (10 steps)")
299 eq(cf.get("Foo", "bar11"),
300 "something %(with11)s lots of interpolation (11 steps)")
Fred Drake95b96d32001-02-12 17:23:20 +0000301
Fred Drake98e3b292002-10-25 20:42:44 +0000302 def test_items(self):
303 self.check_items_config([('default', '<default>'),
304 ('getdefault', '|%(default)s|'),
305 ('getname', '|%(__name__)s|'),
306 ('key', '|%(name)s|'),
307 ('name', 'value')])
308
Fred Drake8ef67672000-09-27 22:45:25 +0000309
Fred Drake0eebd5c2002-10-25 21:52:00 +0000310class SafeConfigParserTestCase(ConfigParserTestCase):
311 config_class = ConfigParser.SafeConfigParser
312
313 def test_safe_interpolation(self):
314 # See http://www.python.org/sf/511737
315 cf = self.fromstring("[section]\n"
316 "option1=xxx\n"
317 "option2=%(option1)s/xxx\n"
318 "ok=%(option1)s/%%s\n"
319 "not_ok=%(option2)s/%%s")
320 self.assertEqual(cf.get("section", "ok"), "xxx/%s")
321 self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s")
322
323
Fred Drakec6f28912002-10-25 19:40:49 +0000324def test_main():
325 suite = unittest.TestSuite()
326 suite.addTests([unittest.makeSuite(ConfigParserTestCase),
Fred Drake0eebd5c2002-10-25 21:52:00 +0000327 unittest.makeSuite(RawConfigParserTestCase),
328 unittest.makeSuite(SafeConfigParserTestCase)])
Fred Drakec6f28912002-10-25 19:40:49 +0000329 test_support.run_suite(suite)
Fred Drake3af0eb82002-10-25 18:09:24 +0000330
Fred Drakec6f28912002-10-25 19:40:49 +0000331if __name__ == "__main__":
332 test_main()