blob: b22159822910493c432c1ad570ac5b23be3eb077 [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):
152 self.assertRaises(exc, self.cf.get, section, option)
Fred Drake3af0eb82002-10-25 18:09:24 +0000153
Fred Drakec6f28912002-10-25 19:40:49 +0000154 def test_boolean(self):
155 cf = self.fromstring(
156 "[BOOLTEST]\n"
157 "T1=1\n"
158 "T2=TRUE\n"
159 "T3=True\n"
160 "T4=oN\n"
161 "T5=yes\n"
162 "F1=0\n"
163 "F2=FALSE\n"
164 "F3=False\n"
165 "F4=oFF\n"
166 "F5=nO\n"
167 "E1=2\n"
168 "E2=foo\n"
169 "E3=-1\n"
170 "E4=0.1\n"
171 "E5=FALSE AND MORE"
172 )
173 for x in range(1, 5):
174 self.failUnless(cf.getboolean('BOOLTEST', 't%d' % x))
175 self.failIf(cf.getboolean('BOOLTEST', 'f%d' % x))
176 self.assertRaises(ValueError,
177 cf.getboolean, 'BOOLTEST', 'e%d' % x)
Fred Drake95b96d32001-02-12 17:23:20 +0000178
Fred Drakec6f28912002-10-25 19:40:49 +0000179 def test_weird_errors(self):
180 cf = self.newconfig()
Fred Drake8ef67672000-09-27 22:45:25 +0000181 cf.add_section("Foo")
Fred Drakec6f28912002-10-25 19:40:49 +0000182 self.assertRaises(ConfigParser.DuplicateSectionError,
183 cf.add_section, "Foo")
184
185 def test_write(self):
186 cf = self.fromstring(
187 "[Long Line]\n"
188 "foo: this line is much, much longer than my editor\n"
189 " likes it.\n"
190 "[DEFAULT]\n"
191 "foo: another very\n"
192 " long line"
193 )
194 output = StringIO.StringIO()
195 cf.write(output)
196 self.assertEqual(
197 output.getvalue(),
198 "[DEFAULT]\n"
199 "foo = another very\n"
200 "\tlong line\n"
201 "\n"
202 "[Long Line]\n"
203 "foo = this line is much, much longer than my editor\n"
204 "\tlikes it.\n"
205 "\n"
206 )
207
208 # shared by subclasses
209 def get_interpolation_config(self):
210 return self.fromstring(
211 "[Foo]\n"
212 "bar=something %(with1)s interpolation (1 step)\n"
213 "bar9=something %(with9)s lots of interpolation (9 steps)\n"
214 "bar10=something %(with10)s lots of interpolation (10 steps)\n"
215 "bar11=something %(with11)s lots of interpolation (11 steps)\n"
216 "with11=%(with10)s\n"
217 "with10=%(with9)s\n"
218 "with9=%(with8)s\n"
219 "with8=%(with7)s\n"
220 "with7=%(with6)s\n"
221 "with6=%(with5)s\n"
222 "with5=%(with4)s\n"
223 "with4=%(with3)s\n"
224 "with3=%(with2)s\n"
225 "with2=%(with1)s\n"
226 "with1=with\n"
227 "\n"
228 "[Mutual Recursion]\n"
229 "foo=%(bar)s\n"
230 "bar=%(foo)s\n",
231 defaults={"getname": "%(__name__)s"})
Fred Drake95b96d32001-02-12 17:23:20 +0000232
Fred Drake98e3b292002-10-25 20:42:44 +0000233 def check_items_config(self, expected):
234 cf = self.fromstring(
235 "[section]\n"
236 "name = value\n"
237 "key: |%(name)s| \n"
238 "getdefault: |%(default)s|\n"
239 "getname: |%(__name__)s|",
240 defaults={"default": "<default>"})
241 L = list(cf.items("section"))
242 L.sort()
243 self.assertEqual(L, expected)
244
Fred Drake8ef67672000-09-27 22:45:25 +0000245
Fred Drakec6f28912002-10-25 19:40:49 +0000246class ConfigParserTestCase(TestCaseBase):
247 config_class = ConfigParser.ConfigParser
248
249 def test_interpolation(self):
250 cf = self.get_interpolation_config()
251 eq = self.assertEqual
252 eq(cf.get("Foo", "getname"), "Foo")
253 eq(cf.get("Foo", "bar"), "something with interpolation (1 step)")
254 eq(cf.get("Foo", "bar9"),
255 "something with lots of interpolation (9 steps)")
256 eq(cf.get("Foo", "bar10"),
257 "something with lots of interpolation (10 steps)")
258 self.get_error(ConfigParser.InterpolationDepthError, "Foo", "bar11")
Fred Drake95b96d32001-02-12 17:23:20 +0000259
Fred Drake98e3b292002-10-25 20:42:44 +0000260 def test_items(self):
261 self.check_items_config([('default', '<default>'),
262 ('getdefault', '|<default>|'),
263 ('getname', '|section|'),
264 ('key', '|value|'),
265 ('name', 'value')])
266
Fred Drake8ef67672000-09-27 22:45:25 +0000267
Fred Drakec6f28912002-10-25 19:40:49 +0000268class RawConfigParserTestCase(TestCaseBase):
269 config_class = ConfigParser.RawConfigParser
270
271 def test_interpolation(self):
272 cf = self.get_interpolation_config()
273 eq = self.assertEqual
274 eq(cf.get("Foo", "getname"), "%(__name__)s")
275 eq(cf.get("Foo", "bar"),
276 "something %(with1)s interpolation (1 step)")
277 eq(cf.get("Foo", "bar9"),
278 "something %(with9)s lots of interpolation (9 steps)")
279 eq(cf.get("Foo", "bar10"),
280 "something %(with10)s lots of interpolation (10 steps)")
281 eq(cf.get("Foo", "bar11"),
282 "something %(with11)s lots of interpolation (11 steps)")
Fred Drake95b96d32001-02-12 17:23:20 +0000283
Fred Drake98e3b292002-10-25 20:42:44 +0000284 def test_items(self):
285 self.check_items_config([('default', '<default>'),
286 ('getdefault', '|%(default)s|'),
287 ('getname', '|%(__name__)s|'),
288 ('key', '|%(name)s|'),
289 ('name', 'value')])
290
Fred Drake8ef67672000-09-27 22:45:25 +0000291
Fred Drake0eebd5c2002-10-25 21:52:00 +0000292class SafeConfigParserTestCase(ConfigParserTestCase):
293 config_class = ConfigParser.SafeConfigParser
294
295 def test_safe_interpolation(self):
296 # See http://www.python.org/sf/511737
297 cf = self.fromstring("[section]\n"
298 "option1=xxx\n"
299 "option2=%(option1)s/xxx\n"
300 "ok=%(option1)s/%%s\n"
301 "not_ok=%(option2)s/%%s")
302 self.assertEqual(cf.get("section", "ok"), "xxx/%s")
303 self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s")
304
305
Fred Drakec6f28912002-10-25 19:40:49 +0000306def test_main():
307 suite = unittest.TestSuite()
308 suite.addTests([unittest.makeSuite(ConfigParserTestCase),
Fred Drake0eebd5c2002-10-25 21:52:00 +0000309 unittest.makeSuite(RawConfigParserTestCase),
310 unittest.makeSuite(SafeConfigParserTestCase)])
Fred Drakec6f28912002-10-25 19:40:49 +0000311 test_support.run_suite(suite)
Fred Drake3af0eb82002-10-25 18:09:24 +0000312
Fred Drakec6f28912002-10-25 19:40:49 +0000313if __name__ == "__main__":
314 test_main()