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