]>
Commit | Line | Data |
---|---|---|
4710c53d | 1 | import ConfigParser\r |
2 | import StringIO\r | |
3 | import os\r | |
4 | import unittest\r | |
5 | import UserDict\r | |
6 | \r | |
7 | from test import test_support\r | |
8 | \r | |
9 | \r | |
10 | class SortedDict(UserDict.UserDict):\r | |
11 | def items(self):\r | |
12 | result = self.data.items()\r | |
13 | result.sort()\r | |
14 | return result\r | |
15 | \r | |
16 | def keys(self):\r | |
17 | result = self.data.keys()\r | |
18 | result.sort()\r | |
19 | return result\r | |
20 | \r | |
21 | def values(self):\r | |
22 | # XXX never used?\r | |
23 | result = self.items()\r | |
24 | return [i[1] for i in result]\r | |
25 | \r | |
26 | def iteritems(self): return iter(self.items())\r | |
27 | def iterkeys(self): return iter(self.keys())\r | |
28 | __iter__ = iterkeys\r | |
29 | def itervalues(self): return iter(self.values())\r | |
30 | \r | |
31 | \r | |
32 | class TestCaseBase(unittest.TestCase):\r | |
33 | allow_no_value = False\r | |
34 | \r | |
35 | def newconfig(self, defaults=None):\r | |
36 | if defaults is None:\r | |
37 | self.cf = self.config_class(allow_no_value=self.allow_no_value)\r | |
38 | else:\r | |
39 | self.cf = self.config_class(defaults,\r | |
40 | allow_no_value=self.allow_no_value)\r | |
41 | return self.cf\r | |
42 | \r | |
43 | def fromstring(self, string, defaults=None):\r | |
44 | cf = self.newconfig(defaults)\r | |
45 | sio = StringIO.StringIO(string)\r | |
46 | cf.readfp(sio)\r | |
47 | return cf\r | |
48 | \r | |
49 | def test_basic(self):\r | |
50 | config_string = (\r | |
51 | "[Foo Bar]\n"\r | |
52 | "foo=bar\n"\r | |
53 | "[Spacey Bar]\n"\r | |
54 | "foo = bar\n"\r | |
55 | "[Commented Bar]\n"\r | |
56 | "foo: bar ; comment\n"\r | |
57 | "[Long Line]\n"\r | |
58 | "foo: this line is much, much longer than my editor\n"\r | |
59 | " likes it.\n"\r | |
60 | "[Section\\with$weird%characters[\t]\n"\r | |
61 | "[Internationalized Stuff]\n"\r | |
62 | "foo[bg]: Bulgarian\n"\r | |
63 | "foo=Default\n"\r | |
64 | "foo[en]=English\n"\r | |
65 | "foo[de]=Deutsch\n"\r | |
66 | "[Spaces]\n"\r | |
67 | "key with spaces : value\n"\r | |
68 | "another with spaces = splat!\n"\r | |
69 | )\r | |
70 | if self.allow_no_value:\r | |
71 | config_string += (\r | |
72 | "[NoValue]\n"\r | |
73 | "option-without-value\n"\r | |
74 | )\r | |
75 | \r | |
76 | cf = self.fromstring(config_string)\r | |
77 | L = cf.sections()\r | |
78 | L.sort()\r | |
79 | E = [r'Commented Bar',\r | |
80 | r'Foo Bar',\r | |
81 | r'Internationalized Stuff',\r | |
82 | r'Long Line',\r | |
83 | r'Section\with$weird%characters[' '\t',\r | |
84 | r'Spaces',\r | |
85 | r'Spacey Bar',\r | |
86 | ]\r | |
87 | if self.allow_no_value:\r | |
88 | E.append(r'NoValue')\r | |
89 | E.sort()\r | |
90 | eq = self.assertEqual\r | |
91 | eq(L, E)\r | |
92 | \r | |
93 | # The use of spaces in the section names serves as a\r | |
94 | # regression test for SourceForge bug #583248:\r | |
95 | # http://www.python.org/sf/583248\r | |
96 | eq(cf.get('Foo Bar', 'foo'), 'bar')\r | |
97 | eq(cf.get('Spacey Bar', 'foo'), 'bar')\r | |
98 | eq(cf.get('Commented Bar', 'foo'), 'bar')\r | |
99 | eq(cf.get('Spaces', 'key with spaces'), 'value')\r | |
100 | eq(cf.get('Spaces', 'another with spaces'), 'splat!')\r | |
101 | if self.allow_no_value:\r | |
102 | eq(cf.get('NoValue', 'option-without-value'), None)\r | |
103 | \r | |
104 | self.assertNotIn('__name__', cf.options("Foo Bar"),\r | |
105 | '__name__ "option" should not be exposed by the API!')\r | |
106 | \r | |
107 | # Make sure the right things happen for remove_option();\r | |
108 | # added to include check for SourceForge bug #123324:\r | |
109 | self.assertTrue(cf.remove_option('Foo Bar', 'foo'),\r | |
110 | "remove_option() failed to report existence of option")\r | |
111 | self.assertFalse(cf.has_option('Foo Bar', 'foo'),\r | |
112 | "remove_option() failed to remove option")\r | |
113 | self.assertFalse(cf.remove_option('Foo Bar', 'foo'),\r | |
114 | "remove_option() failed to report non-existence of option"\r | |
115 | " that was removed")\r | |
116 | \r | |
117 | self.assertRaises(ConfigParser.NoSectionError,\r | |
118 | cf.remove_option, 'No Such Section', 'foo')\r | |
119 | \r | |
120 | eq(cf.get('Long Line', 'foo'),\r | |
121 | 'this line is much, much longer than my editor\nlikes it.')\r | |
122 | \r | |
123 | def test_case_sensitivity(self):\r | |
124 | cf = self.newconfig()\r | |
125 | cf.add_section("A")\r | |
126 | cf.add_section("a")\r | |
127 | L = cf.sections()\r | |
128 | L.sort()\r | |
129 | eq = self.assertEqual\r | |
130 | eq(L, ["A", "a"])\r | |
131 | cf.set("a", "B", "value")\r | |
132 | eq(cf.options("a"), ["b"])\r | |
133 | eq(cf.get("a", "b"), "value",\r | |
134 | "could not locate option, expecting case-insensitive option names")\r | |
135 | self.assertTrue(cf.has_option("a", "b"))\r | |
136 | cf.set("A", "A-B", "A-B value")\r | |
137 | for opt in ("a-b", "A-b", "a-B", "A-B"):\r | |
138 | self.assertTrue(\r | |
139 | cf.has_option("A", opt),\r | |
140 | "has_option() returned false for option which should exist")\r | |
141 | eq(cf.options("A"), ["a-b"])\r | |
142 | eq(cf.options("a"), ["b"])\r | |
143 | cf.remove_option("a", "B")\r | |
144 | eq(cf.options("a"), [])\r | |
145 | \r | |
146 | # SF bug #432369:\r | |
147 | cf = self.fromstring(\r | |
148 | "[MySection]\nOption: first line\n\tsecond line\n")\r | |
149 | eq(cf.options("MySection"), ["option"])\r | |
150 | eq(cf.get("MySection", "Option"), "first line\nsecond line")\r | |
151 | \r | |
152 | # SF bug #561822:\r | |
153 | cf = self.fromstring("[section]\nnekey=nevalue\n",\r | |
154 | defaults={"key":"value"})\r | |
155 | self.assertTrue(cf.has_option("section", "Key"))\r | |
156 | \r | |
157 | \r | |
158 | def test_default_case_sensitivity(self):\r | |
159 | cf = self.newconfig({"foo": "Bar"})\r | |
160 | self.assertEqual(\r | |
161 | cf.get("DEFAULT", "Foo"), "Bar",\r | |
162 | "could not locate option, expecting case-insensitive option names")\r | |
163 | cf = self.newconfig({"Foo": "Bar"})\r | |
164 | self.assertEqual(\r | |
165 | cf.get("DEFAULT", "Foo"), "Bar",\r | |
166 | "could not locate option, expecting case-insensitive defaults")\r | |
167 | \r | |
168 | def test_parse_errors(self):\r | |
169 | self.newconfig()\r | |
170 | self.parse_error(ConfigParser.ParsingError,\r | |
171 | "[Foo]\n extra-spaces: splat\n")\r | |
172 | self.parse_error(ConfigParser.ParsingError,\r | |
173 | "[Foo]\n extra-spaces= splat\n")\r | |
174 | self.parse_error(ConfigParser.ParsingError,\r | |
175 | "[Foo]\n:value-without-option-name\n")\r | |
176 | self.parse_error(ConfigParser.ParsingError,\r | |
177 | "[Foo]\n=value-without-option-name\n")\r | |
178 | self.parse_error(ConfigParser.MissingSectionHeaderError,\r | |
179 | "No Section!\n")\r | |
180 | \r | |
181 | def parse_error(self, exc, src):\r | |
182 | sio = StringIO.StringIO(src)\r | |
183 | self.assertRaises(exc, self.cf.readfp, sio)\r | |
184 | \r | |
185 | def test_query_errors(self):\r | |
186 | cf = self.newconfig()\r | |
187 | self.assertEqual(cf.sections(), [],\r | |
188 | "new ConfigParser should have no defined sections")\r | |
189 | self.assertFalse(cf.has_section("Foo"),\r | |
190 | "new ConfigParser should have no acknowledged "\r | |
191 | "sections")\r | |
192 | self.assertRaises(ConfigParser.NoSectionError,\r | |
193 | cf.options, "Foo")\r | |
194 | self.assertRaises(ConfigParser.NoSectionError,\r | |
195 | cf.set, "foo", "bar", "value")\r | |
196 | self.get_error(ConfigParser.NoSectionError, "foo", "bar")\r | |
197 | cf.add_section("foo")\r | |
198 | self.get_error(ConfigParser.NoOptionError, "foo", "bar")\r | |
199 | \r | |
200 | def get_error(self, exc, section, option):\r | |
201 | try:\r | |
202 | self.cf.get(section, option)\r | |
203 | except exc, e:\r | |
204 | return e\r | |
205 | else:\r | |
206 | self.fail("expected exception type %s.%s"\r | |
207 | % (exc.__module__, exc.__name__))\r | |
208 | \r | |
209 | def test_boolean(self):\r | |
210 | cf = self.fromstring(\r | |
211 | "[BOOLTEST]\n"\r | |
212 | "T1=1\n"\r | |
213 | "T2=TRUE\n"\r | |
214 | "T3=True\n"\r | |
215 | "T4=oN\n"\r | |
216 | "T5=yes\n"\r | |
217 | "F1=0\n"\r | |
218 | "F2=FALSE\n"\r | |
219 | "F3=False\n"\r | |
220 | "F4=oFF\n"\r | |
221 | "F5=nO\n"\r | |
222 | "E1=2\n"\r | |
223 | "E2=foo\n"\r | |
224 | "E3=-1\n"\r | |
225 | "E4=0.1\n"\r | |
226 | "E5=FALSE AND MORE"\r | |
227 | )\r | |
228 | for x in range(1, 5):\r | |
229 | self.assertTrue(cf.getboolean('BOOLTEST', 't%d' % x))\r | |
230 | self.assertFalse(cf.getboolean('BOOLTEST', 'f%d' % x))\r | |
231 | self.assertRaises(ValueError,\r | |
232 | cf.getboolean, 'BOOLTEST', 'e%d' % x)\r | |
233 | \r | |
234 | def test_weird_errors(self):\r | |
235 | cf = self.newconfig()\r | |
236 | cf.add_section("Foo")\r | |
237 | self.assertRaises(ConfigParser.DuplicateSectionError,\r | |
238 | cf.add_section, "Foo")\r | |
239 | \r | |
240 | def test_write(self):\r | |
241 | config_string = (\r | |
242 | "[Long Line]\n"\r | |
243 | "foo: this line is much, much longer than my editor\n"\r | |
244 | " likes it.\n"\r | |
245 | "[DEFAULT]\n"\r | |
246 | "foo: another very\n"\r | |
247 | " long line\n"\r | |
248 | )\r | |
249 | if self.allow_no_value:\r | |
250 | config_string += (\r | |
251 | "[Valueless]\n"\r | |
252 | "option-without-value\n"\r | |
253 | )\r | |
254 | \r | |
255 | cf = self.fromstring(config_string)\r | |
256 | output = StringIO.StringIO()\r | |
257 | cf.write(output)\r | |
258 | expect_string = (\r | |
259 | "[DEFAULT]\n"\r | |
260 | "foo = another very\n"\r | |
261 | "\tlong line\n"\r | |
262 | "\n"\r | |
263 | "[Long Line]\n"\r | |
264 | "foo = this line is much, much longer than my editor\n"\r | |
265 | "\tlikes it.\n"\r | |
266 | "\n"\r | |
267 | )\r | |
268 | if self.allow_no_value:\r | |
269 | expect_string += (\r | |
270 | "[Valueless]\n"\r | |
271 | "option-without-value\n"\r | |
272 | "\n"\r | |
273 | )\r | |
274 | self.assertEqual(output.getvalue(), expect_string)\r | |
275 | \r | |
276 | def test_set_string_types(self):\r | |
277 | cf = self.fromstring("[sect]\n"\r | |
278 | "option1=foo\n")\r | |
279 | # Check that we don't get an exception when setting values in\r | |
280 | # an existing section using strings:\r | |
281 | class mystr(str):\r | |
282 | pass\r | |
283 | cf.set("sect", "option1", "splat")\r | |
284 | cf.set("sect", "option1", mystr("splat"))\r | |
285 | cf.set("sect", "option2", "splat")\r | |
286 | cf.set("sect", "option2", mystr("splat"))\r | |
287 | try:\r | |
288 | unicode\r | |
289 | except NameError:\r | |
290 | pass\r | |
291 | else:\r | |
292 | cf.set("sect", "option1", unicode("splat"))\r | |
293 | cf.set("sect", "option2", unicode("splat"))\r | |
294 | \r | |
295 | def test_read_returns_file_list(self):\r | |
296 | file1 = test_support.findfile("cfgparser.1")\r | |
297 | # check when we pass a mix of readable and non-readable files:\r | |
298 | cf = self.newconfig()\r | |
299 | parsed_files = cf.read([file1, "nonexistent-file"])\r | |
300 | self.assertEqual(parsed_files, [file1])\r | |
301 | self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")\r | |
302 | # check when we pass only a filename:\r | |
303 | cf = self.newconfig()\r | |
304 | parsed_files = cf.read(file1)\r | |
305 | self.assertEqual(parsed_files, [file1])\r | |
306 | self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")\r | |
307 | # check when we pass only missing files:\r | |
308 | cf = self.newconfig()\r | |
309 | parsed_files = cf.read(["nonexistent-file"])\r | |
310 | self.assertEqual(parsed_files, [])\r | |
311 | # check when we pass no files:\r | |
312 | cf = self.newconfig()\r | |
313 | parsed_files = cf.read([])\r | |
314 | self.assertEqual(parsed_files, [])\r | |
315 | \r | |
316 | # shared by subclasses\r | |
317 | def get_interpolation_config(self):\r | |
318 | return self.fromstring(\r | |
319 | "[Foo]\n"\r | |
320 | "bar=something %(with1)s interpolation (1 step)\n"\r | |
321 | "bar9=something %(with9)s lots of interpolation (9 steps)\n"\r | |
322 | "bar10=something %(with10)s lots of interpolation (10 steps)\n"\r | |
323 | "bar11=something %(with11)s lots of interpolation (11 steps)\n"\r | |
324 | "with11=%(with10)s\n"\r | |
325 | "with10=%(with9)s\n"\r | |
326 | "with9=%(with8)s\n"\r | |
327 | "with8=%(With7)s\n"\r | |
328 | "with7=%(WITH6)s\n"\r | |
329 | "with6=%(with5)s\n"\r | |
330 | "With5=%(with4)s\n"\r | |
331 | "WITH4=%(with3)s\n"\r | |
332 | "with3=%(with2)s\n"\r | |
333 | "with2=%(with1)s\n"\r | |
334 | "with1=with\n"\r | |
335 | "\n"\r | |
336 | "[Mutual Recursion]\n"\r | |
337 | "foo=%(bar)s\n"\r | |
338 | "bar=%(foo)s\n"\r | |
339 | "\n"\r | |
340 | "[Interpolation Error]\n"\r | |
341 | "name=%(reference)s\n",\r | |
342 | # no definition for 'reference'\r | |
343 | defaults={"getname": "%(__name__)s"})\r | |
344 | \r | |
345 | def check_items_config(self, expected):\r | |
346 | cf = self.fromstring(\r | |
347 | "[section]\n"\r | |
348 | "name = value\n"\r | |
349 | "key: |%(name)s| \n"\r | |
350 | "getdefault: |%(default)s|\n"\r | |
351 | "getname: |%(__name__)s|",\r | |
352 | defaults={"default": "<default>"})\r | |
353 | L = list(cf.items("section"))\r | |
354 | L.sort()\r | |
355 | self.assertEqual(L, expected)\r | |
356 | \r | |
357 | \r | |
358 | class ConfigParserTestCase(TestCaseBase):\r | |
359 | config_class = ConfigParser.ConfigParser\r | |
360 | allow_no_value = True\r | |
361 | \r | |
362 | def test_interpolation(self):\r | |
363 | rawval = {\r | |
364 | ConfigParser.ConfigParser: ("something %(with11)s "\r | |
365 | "lots of interpolation (11 steps)"),\r | |
366 | ConfigParser.SafeConfigParser: "%(with1)s",\r | |
367 | }\r | |
368 | cf = self.get_interpolation_config()\r | |
369 | eq = self.assertEqual\r | |
370 | eq(cf.get("Foo", "getname"), "Foo")\r | |
371 | eq(cf.get("Foo", "bar"), "something with interpolation (1 step)")\r | |
372 | eq(cf.get("Foo", "bar9"),\r | |
373 | "something with lots of interpolation (9 steps)")\r | |
374 | eq(cf.get("Foo", "bar10"),\r | |
375 | "something with lots of interpolation (10 steps)")\r | |
376 | self.get_error(ConfigParser.InterpolationDepthError, "Foo", "bar11")\r | |
377 | \r | |
378 | def test_interpolation_missing_value(self):\r | |
379 | self.get_interpolation_config()\r | |
380 | e = self.get_error(ConfigParser.InterpolationError,\r | |
381 | "Interpolation Error", "name")\r | |
382 | self.assertEqual(e.reference, "reference")\r | |
383 | self.assertEqual(e.section, "Interpolation Error")\r | |
384 | self.assertEqual(e.option, "name")\r | |
385 | \r | |
386 | def test_items(self):\r | |
387 | self.check_items_config([('default', '<default>'),\r | |
388 | ('getdefault', '|<default>|'),\r | |
389 | ('getname', '|section|'),\r | |
390 | ('key', '|value|'),\r | |
391 | ('name', 'value')])\r | |
392 | \r | |
393 | def test_set_nonstring_types(self):\r | |
394 | cf = self.newconfig()\r | |
395 | cf.add_section('non-string')\r | |
396 | cf.set('non-string', 'int', 1)\r | |
397 | cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13, '%('])\r | |
398 | cf.set('non-string', 'dict', {'pi': 3.14159, '%(': 1,\r | |
399 | '%(list)': '%(list)'})\r | |
400 | cf.set('non-string', 'string_with_interpolation', '%(list)s')\r | |
401 | cf.set('non-string', 'no-value')\r | |
402 | self.assertEqual(cf.get('non-string', 'int', raw=True), 1)\r | |
403 | self.assertRaises(TypeError, cf.get, 'non-string', 'int')\r | |
404 | self.assertEqual(cf.get('non-string', 'list', raw=True),\r | |
405 | [0, 1, 1, 2, 3, 5, 8, 13, '%('])\r | |
406 | self.assertRaises(TypeError, cf.get, 'non-string', 'list')\r | |
407 | self.assertEqual(cf.get('non-string', 'dict', raw=True),\r | |
408 | {'pi': 3.14159, '%(': 1, '%(list)': '%(list)'})\r | |
409 | self.assertRaises(TypeError, cf.get, 'non-string', 'dict')\r | |
410 | self.assertEqual(cf.get('non-string', 'string_with_interpolation',\r | |
411 | raw=True), '%(list)s')\r | |
412 | self.assertRaises(ValueError, cf.get, 'non-string',\r | |
413 | 'string_with_interpolation', raw=False)\r | |
414 | self.assertEqual(cf.get('non-string', 'no-value'), None)\r | |
415 | \r | |
416 | class MultilineValuesTestCase(TestCaseBase):\r | |
417 | config_class = ConfigParser.ConfigParser\r | |
418 | wonderful_spam = ("I'm having spam spam spam spam "\r | |
419 | "spam spam spam beaked beans spam "\r | |
420 | "spam spam and spam!").replace(' ', '\t\n')\r | |
421 | \r | |
422 | def setUp(self):\r | |
423 | cf = self.newconfig()\r | |
424 | for i in range(100):\r | |
425 | s = 'section{}'.format(i)\r | |
426 | cf.add_section(s)\r | |
427 | for j in range(10):\r | |
428 | cf.set(s, 'lovely_spam{}'.format(j), self.wonderful_spam)\r | |
429 | with open(test_support.TESTFN, 'w') as f:\r | |
430 | cf.write(f)\r | |
431 | \r | |
432 | def tearDown(self):\r | |
433 | os.unlink(test_support.TESTFN)\r | |
434 | \r | |
435 | def test_dominating_multiline_values(self):\r | |
436 | # we're reading from file because this is where the code changed\r | |
437 | # during performance updates in Python 3.2\r | |
438 | cf_from_file = self.newconfig()\r | |
439 | with open(test_support.TESTFN) as f:\r | |
440 | cf_from_file.readfp(f)\r | |
441 | self.assertEqual(cf_from_file.get('section8', 'lovely_spam4'),\r | |
442 | self.wonderful_spam.replace('\t\n', '\n'))\r | |
443 | \r | |
444 | class RawConfigParserTestCase(TestCaseBase):\r | |
445 | config_class = ConfigParser.RawConfigParser\r | |
446 | \r | |
447 | def test_interpolation(self):\r | |
448 | cf = self.get_interpolation_config()\r | |
449 | eq = self.assertEqual\r | |
450 | eq(cf.get("Foo", "getname"), "%(__name__)s")\r | |
451 | eq(cf.get("Foo", "bar"),\r | |
452 | "something %(with1)s interpolation (1 step)")\r | |
453 | eq(cf.get("Foo", "bar9"),\r | |
454 | "something %(with9)s lots of interpolation (9 steps)")\r | |
455 | eq(cf.get("Foo", "bar10"),\r | |
456 | "something %(with10)s lots of interpolation (10 steps)")\r | |
457 | eq(cf.get("Foo", "bar11"),\r | |
458 | "something %(with11)s lots of interpolation (11 steps)")\r | |
459 | \r | |
460 | def test_items(self):\r | |
461 | self.check_items_config([('default', '<default>'),\r | |
462 | ('getdefault', '|%(default)s|'),\r | |
463 | ('getname', '|%(__name__)s|'),\r | |
464 | ('key', '|%(name)s|'),\r | |
465 | ('name', 'value')])\r | |
466 | \r | |
467 | def test_set_nonstring_types(self):\r | |
468 | cf = self.newconfig()\r | |
469 | cf.add_section('non-string')\r | |
470 | cf.set('non-string', 'int', 1)\r | |
471 | cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13])\r | |
472 | cf.set('non-string', 'dict', {'pi': 3.14159})\r | |
473 | self.assertEqual(cf.get('non-string', 'int'), 1)\r | |
474 | self.assertEqual(cf.get('non-string', 'list'),\r | |
475 | [0, 1, 1, 2, 3, 5, 8, 13])\r | |
476 | self.assertEqual(cf.get('non-string', 'dict'), {'pi': 3.14159})\r | |
477 | \r | |
478 | \r | |
479 | class SafeConfigParserTestCase(ConfigParserTestCase):\r | |
480 | config_class = ConfigParser.SafeConfigParser\r | |
481 | \r | |
482 | def test_safe_interpolation(self):\r | |
483 | # See http://www.python.org/sf/511737\r | |
484 | cf = self.fromstring("[section]\n"\r | |
485 | "option1=xxx\n"\r | |
486 | "option2=%(option1)s/xxx\n"\r | |
487 | "ok=%(option1)s/%%s\n"\r | |
488 | "not_ok=%(option2)s/%%s")\r | |
489 | self.assertEqual(cf.get("section", "ok"), "xxx/%s")\r | |
490 | self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s")\r | |
491 | \r | |
492 | def test_set_malformatted_interpolation(self):\r | |
493 | cf = self.fromstring("[sect]\n"\r | |
494 | "option1=foo\n")\r | |
495 | \r | |
496 | self.assertEqual(cf.get('sect', "option1"), "foo")\r | |
497 | \r | |
498 | self.assertRaises(ValueError, cf.set, "sect", "option1", "%foo")\r | |
499 | self.assertRaises(ValueError, cf.set, "sect", "option1", "foo%")\r | |
500 | self.assertRaises(ValueError, cf.set, "sect", "option1", "f%oo")\r | |
501 | \r | |
502 | self.assertEqual(cf.get('sect', "option1"), "foo")\r | |
503 | \r | |
504 | # bug #5741: double percents are *not* malformed\r | |
505 | cf.set("sect", "option2", "foo%%bar")\r | |
506 | self.assertEqual(cf.get("sect", "option2"), "foo%bar")\r | |
507 | \r | |
508 | def test_set_nonstring_types(self):\r | |
509 | cf = self.fromstring("[sect]\n"\r | |
510 | "option1=foo\n")\r | |
511 | # Check that we get a TypeError when setting non-string values\r | |
512 | # in an existing section:\r | |
513 | self.assertRaises(TypeError, cf.set, "sect", "option1", 1)\r | |
514 | self.assertRaises(TypeError, cf.set, "sect", "option1", 1.0)\r | |
515 | self.assertRaises(TypeError, cf.set, "sect", "option1", object())\r | |
516 | self.assertRaises(TypeError, cf.set, "sect", "option2", 1)\r | |
517 | self.assertRaises(TypeError, cf.set, "sect", "option2", 1.0)\r | |
518 | self.assertRaises(TypeError, cf.set, "sect", "option2", object())\r | |
519 | \r | |
520 | def test_add_section_default_1(self):\r | |
521 | cf = self.newconfig()\r | |
522 | self.assertRaises(ValueError, cf.add_section, "default")\r | |
523 | \r | |
524 | def test_add_section_default_2(self):\r | |
525 | cf = self.newconfig()\r | |
526 | self.assertRaises(ValueError, cf.add_section, "DEFAULT")\r | |
527 | \r | |
528 | \r | |
529 | class SafeConfigParserTestCaseNoValue(SafeConfigParserTestCase):\r | |
530 | allow_no_value = True\r | |
531 | \r | |
532 | \r | |
533 | class Issue7005TestCase(unittest.TestCase):\r | |
534 | """Test output when None is set() as a value and allow_no_value == False.\r | |
535 | \r | |
536 | http://bugs.python.org/issue7005\r | |
537 | \r | |
538 | """\r | |
539 | \r | |
540 | expected_output = "[section]\noption = None\n\n"\r | |
541 | \r | |
542 | def prepare(self, config_class):\r | |
543 | # This is the default, but that's the point.\r | |
544 | cp = config_class(allow_no_value=False)\r | |
545 | cp.add_section("section")\r | |
546 | cp.set("section", "option", None)\r | |
547 | sio = StringIO.StringIO()\r | |
548 | cp.write(sio)\r | |
549 | return sio.getvalue()\r | |
550 | \r | |
551 | def test_none_as_value_stringified(self):\r | |
552 | output = self.prepare(ConfigParser.ConfigParser)\r | |
553 | self.assertEqual(output, self.expected_output)\r | |
554 | \r | |
555 | def test_none_as_value_stringified_raw(self):\r | |
556 | output = self.prepare(ConfigParser.RawConfigParser)\r | |
557 | self.assertEqual(output, self.expected_output)\r | |
558 | \r | |
559 | \r | |
560 | class SortedTestCase(RawConfigParserTestCase):\r | |
561 | def newconfig(self, defaults=None):\r | |
562 | self.cf = self.config_class(defaults=defaults, dict_type=SortedDict)\r | |
563 | return self.cf\r | |
564 | \r | |
565 | def test_sorted(self):\r | |
566 | self.fromstring("[b]\n"\r | |
567 | "o4=1\n"\r | |
568 | "o3=2\n"\r | |
569 | "o2=3\n"\r | |
570 | "o1=4\n"\r | |
571 | "[a]\n"\r | |
572 | "k=v\n")\r | |
573 | output = StringIO.StringIO()\r | |
574 | self.cf.write(output)\r | |
575 | self.assertEqual(output.getvalue(),\r | |
576 | "[a]\n"\r | |
577 | "k = v\n\n"\r | |
578 | "[b]\n"\r | |
579 | "o1 = 4\n"\r | |
580 | "o2 = 3\n"\r | |
581 | "o3 = 2\n"\r | |
582 | "o4 = 1\n\n")\r | |
583 | \r | |
584 | \r | |
585 | def test_main():\r | |
586 | test_support.run_unittest(\r | |
587 | ConfigParserTestCase,\r | |
588 | MultilineValuesTestCase,\r | |
589 | RawConfigParserTestCase,\r | |
590 | SafeConfigParserTestCase,\r | |
591 | SafeConfigParserTestCaseNoValue,\r | |
592 | SortedTestCase,\r | |
593 | Issue7005TestCase,\r | |
594 | )\r | |
595 | \r | |
596 | \r | |
597 | if __name__ == "__main__":\r | |
598 | test_main()\r |