]> git.proxmox.com Git - mirror_edk2.git/blame - AppPkg/Applications/Python/Python-2.7.2/Lib/test/test_cfgparser.py
EmbeddedPkg: Extend NvVarStoreFormattedLib LIBRARY_CLASS
[mirror_edk2.git] / AppPkg / Applications / Python / Python-2.7.2 / Lib / test / test_cfgparser.py
CommitLineData
4710c53d 1import ConfigParser\r
2import StringIO\r
3import os\r
4import unittest\r
5import UserDict\r
6\r
7from test import test_support\r
8\r
9\r
10class 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
32class 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
358class 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
416class 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
444class 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
479class 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
529class SafeConfigParserTestCaseNoValue(SafeConfigParserTestCase):\r
530 allow_no_value = True\r
531\r
532\r
533class 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
560class 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
585def 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
597if __name__ == "__main__":\r
598 test_main()\r