Update version number and release date.
[python/dscho.git] / Lib / test / test_cfgparser.py
blobbc0ef5e18dc01853301f7b07d1d5b57ccde2afc4
1 import ConfigParser
2 import StringIO
3 import unittest
5 from test import test_support
8 class 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
16 def fromstring(self, string, defaults=None):
17 cf = self.newconfig(defaults)
18 sio = StringIO.StringIO(string)
19 cf.readfp(sio)
20 return cf
22 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"
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',
55 # 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!')
64 self.failIf('__name__' in cf.options("Foo Bar"),
65 '__name__ "option" should not be exposed by the API!')
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")
77 self.assertRaises(ConfigParser.NoSectionError,
78 cf.remove_option, 'No Such Section', 'foo')
80 eq(cf.get('Long Line', 'foo'),
81 'this line is much, much longer than my editor\nlikes it.')
83 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",
94 "could not locate option, expecting case-insensitive option names")
95 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"), [])
106 # 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")
112 # SF bug #561822:
113 cf = self.fromstring("[section]\nnekey=nevalue\n",
114 defaults={"key":"value"})
115 self.failUnless(cf.has_option("section", "Key"))
118 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")
133 def parse_error(self, exc, src):
134 sio = StringIO.StringIO(src)
135 self.assertRaises(exc, self.cf.readfp, sio)
137 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")
151 def get_error(self, exc, section, option):
152 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__))
160 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"
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)
185 def test_weird_errors(self):
186 cf = self.newconfig()
187 cf.add_section("Foo")
188 self.assertRaises(ConfigParser.DuplicateSectionError,
189 cf.add_section, "Foo")
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"
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"
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"
236 "bar=%(foo)s\n"
237 "\n"
238 "[Interpolation Error]\n"
239 "name=%(reference)s\n",
240 # no definition for 'reference'
241 defaults={"getname": "%(__name__)s"})
243 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)
256 class ConfigParserTestCase(TestCaseBase):
257 config_class = ConfigParser.ConfigParser
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")
270 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")
278 def test_items(self):
279 self.check_items_config([('default', '<default>'),
280 ('getdefault', '|<default>|'),
281 ('getname', '|section|'),
282 ('key', '|value|'),
283 ('name', 'value')])
286 class RawConfigParserTestCase(TestCaseBase):
287 config_class = ConfigParser.RawConfigParser
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)")
302 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')])
310 class SafeConfigParserTestCase(ConfigParserTestCase):
311 config_class = ConfigParser.SafeConfigParser
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")
324 def test_main():
325 suite = unittest.TestSuite()
326 suite.addTests([unittest.makeSuite(ConfigParserTestCase),
327 unittest.makeSuite(RawConfigParserTestCase),
328 unittest.makeSuite(SafeConfigParserTestCase)])
329 test_support.run_suite(suite)
331 if __name__ == "__main__":
332 test_main()