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
288    def test_set_unicode(self):
289        try:
290            unicode
291        except NameError:
292            self.skipTest('no unicode support')
293
294        cf = self.fromstring("[sect]\n"
295                             "option1=foo\n")
296        cf.set("sect", "option1", unicode("splat"))
297        cf.set("sect", "option2", unicode("splat"))
298
299    def test_read_returns_file_list(self):
300        file1 = test_support.findfile("cfgparser.1")
301        # check when we pass a mix of readable and non-readable files:
302        cf = self.newconfig()
303        parsed_files = cf.read([file1, "nonexistent-file"])
304        self.assertEqual(parsed_files, [file1])
305        self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
306        # check when we pass only a filename:
307        cf = self.newconfig()
308        parsed_files = cf.read(file1)
309        self.assertEqual(parsed_files, [file1])
310        self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
311        # check when we pass only missing files:
312        cf = self.newconfig()
313        parsed_files = cf.read(["nonexistent-file"])
314        self.assertEqual(parsed_files, [])
315        # check when we pass no files:
316        cf = self.newconfig()
317        parsed_files = cf.read([])
318        self.assertEqual(parsed_files, [])
319
320    # shared by subclasses
321    def get_interpolation_config(self):
322        return self.fromstring(
323            "[Foo]\n"
324            "bar=something %(with1)s interpolation (1 step)\n"
325            "bar9=something %(with9)s lots of interpolation (9 steps)\n"
326            "bar10=something %(with10)s lots of interpolation (10 steps)\n"
327            "bar11=something %(with11)s lots of interpolation (11 steps)\n"
328            "with11=%(with10)s\n"
329            "with10=%(with9)s\n"
330            "with9=%(with8)s\n"
331            "with8=%(With7)s\n"
332            "with7=%(WITH6)s\n"
333            "with6=%(with5)s\n"
334            "With5=%(with4)s\n"
335            "WITH4=%(with3)s\n"
336            "with3=%(with2)s\n"
337            "with2=%(with1)s\n"
338            "with1=with\n"
339            "\n"
340            "[Mutual Recursion]\n"
341            "foo=%(bar)s\n"
342            "bar=%(foo)s\n"
343            "\n"
344            "[Interpolation Error]\n"
345            "name=%(reference)s\n",
346            # no definition for 'reference'
347            defaults={"getname": "%(__name__)s"})
348
349    def check_items_config(self, expected):
350        cf = self.fromstring(
351            "[section]\n"
352            "name = value\n"
353            "key: |%(name)s| \n"
354            "getdefault: |%(default)s|\n"
355            "getname: |%(__name__)s|",
356            defaults={"default": "<default>"})
357        L = list(cf.items("section"))
358        L.sort()
359        self.assertEqual(L, expected)
360
361
362class ConfigParserTestCase(TestCaseBase):
363    config_class = ConfigParser.ConfigParser
364    allow_no_value = True
365
366    def test_interpolation(self):
367        rawval = {
368            ConfigParser.ConfigParser: ("something %(with11)s "
369                                        "lots of interpolation (11 steps)"),
370            ConfigParser.SafeConfigParser: "%(with1)s",
371        }
372        cf = self.get_interpolation_config()
373        eq = self.assertEqual
374        eq(cf.get("Foo", "getname"), "Foo")
375        eq(cf.get("Foo", "bar"), "something with interpolation (1 step)")
376        eq(cf.get("Foo", "bar9"),
377           "something with lots of interpolation (9 steps)")
378        eq(cf.get("Foo", "bar10"),
379           "something with lots of interpolation (10 steps)")
380        self.get_error(ConfigParser.InterpolationDepthError, "Foo", "bar11")
381
382    def test_interpolation_missing_value(self):
383        self.get_interpolation_config()
384        e = self.get_error(ConfigParser.InterpolationError,
385                           "Interpolation Error", "name")
386        self.assertEqual(e.reference, "reference")
387        self.assertEqual(e.section, "Interpolation Error")
388        self.assertEqual(e.option, "name")
389
390    def test_items(self):
391        self.check_items_config([('default', '<default>'),
392                                 ('getdefault', '|<default>|'),
393                                 ('getname', '|section|'),
394                                 ('key', '|value|'),
395                                 ('name', 'value')])
396
397    def test_set_nonstring_types(self):
398        cf = self.newconfig()
399        cf.add_section('non-string')
400        cf.set('non-string', 'int', 1)
401        cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13, '%('])
402        cf.set('non-string', 'dict', {'pi': 3.14159, '%(': 1,
403                                      '%(list)': '%(list)'})
404        cf.set('non-string', 'string_with_interpolation', '%(list)s')
405        cf.set('non-string', 'no-value')
406        self.assertEqual(cf.get('non-string', 'int', raw=True), 1)
407        self.assertRaises(TypeError, cf.get, 'non-string', 'int')
408        self.assertEqual(cf.get('non-string', 'list', raw=True),
409                         [0, 1, 1, 2, 3, 5, 8, 13, '%('])
410        self.assertRaises(TypeError, cf.get, 'non-string', 'list')
411        self.assertEqual(cf.get('non-string', 'dict', raw=True),
412                         {'pi': 3.14159, '%(': 1, '%(list)': '%(list)'})
413        self.assertRaises(TypeError, cf.get, 'non-string', 'dict')
414        self.assertEqual(cf.get('non-string', 'string_with_interpolation',
415                                raw=True), '%(list)s')
416        self.assertRaises(ValueError, cf.get, 'non-string',
417                          'string_with_interpolation', raw=False)
418        self.assertEqual(cf.get('non-string', 'no-value'), None)
419
420class MultilineValuesTestCase(TestCaseBase):
421    config_class = ConfigParser.ConfigParser
422    wonderful_spam = ("I'm having spam spam spam spam "
423                      "spam spam spam beaked beans spam "
424                      "spam spam and spam!").replace(' ', '\t\n')
425
426    def setUp(self):
427        cf = self.newconfig()
428        for i in range(100):
429            s = 'section{}'.format(i)
430            cf.add_section(s)
431            for j in range(10):
432                cf.set(s, 'lovely_spam{}'.format(j), self.wonderful_spam)
433        with open(test_support.TESTFN, 'w') as f:
434            cf.write(f)
435
436    def tearDown(self):
437        os.unlink(test_support.TESTFN)
438
439    def test_dominating_multiline_values(self):
440        # we're reading from file because this is where the code changed
441        # during performance updates in Python 3.2
442        cf_from_file = self.newconfig()
443        with open(test_support.TESTFN) as f:
444            cf_from_file.readfp(f)
445        self.assertEqual(cf_from_file.get('section8', 'lovely_spam4'),
446                         self.wonderful_spam.replace('\t\n', '\n'))
447
448class RawConfigParserTestCase(TestCaseBase):
449    config_class = ConfigParser.RawConfigParser
450
451    def test_interpolation(self):
452        cf = self.get_interpolation_config()
453        eq = self.assertEqual
454        eq(cf.get("Foo", "getname"), "%(__name__)s")
455        eq(cf.get("Foo", "bar"),
456           "something %(with1)s interpolation (1 step)")
457        eq(cf.get("Foo", "bar9"),
458           "something %(with9)s lots of interpolation (9 steps)")
459        eq(cf.get("Foo", "bar10"),
460           "something %(with10)s lots of interpolation (10 steps)")
461        eq(cf.get("Foo", "bar11"),
462           "something %(with11)s lots of interpolation (11 steps)")
463
464    def test_items(self):
465        self.check_items_config([('default', '<default>'),
466                                 ('getdefault', '|%(default)s|'),
467                                 ('getname', '|%(__name__)s|'),
468                                 ('key', '|%(name)s|'),
469                                 ('name', 'value')])
470
471    def test_set_nonstring_types(self):
472        cf = self.newconfig()
473        cf.add_section('non-string')
474        cf.set('non-string', 'int', 1)
475        cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13])
476        cf.set('non-string', 'dict', {'pi': 3.14159})
477        self.assertEqual(cf.get('non-string', 'int'), 1)
478        self.assertEqual(cf.get('non-string', 'list'),
479                         [0, 1, 1, 2, 3, 5, 8, 13])
480        self.assertEqual(cf.get('non-string', 'dict'), {'pi': 3.14159})
481
482
483class SafeConfigParserTestCase(ConfigParserTestCase):
484    config_class = ConfigParser.SafeConfigParser
485
486    def test_safe_interpolation(self):
487        # See http://www.python.org/sf/511737
488        cf = self.fromstring("[section]\n"
489                             "option1=xxx\n"
490                             "option2=%(option1)s/xxx\n"
491                             "ok=%(option1)s/%%s\n"
492                             "not_ok=%(option2)s/%%s")
493        self.assertEqual(cf.get("section", "ok"), "xxx/%s")
494        self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s")
495
496    def test_set_malformatted_interpolation(self):
497        cf = self.fromstring("[sect]\n"
498                             "option1=foo\n")
499
500        self.assertEqual(cf.get('sect', "option1"), "foo")
501
502        self.assertRaises(ValueError, cf.set, "sect", "option1", "%foo")
503        self.assertRaises(ValueError, cf.set, "sect", "option1", "foo%")
504        self.assertRaises(ValueError, cf.set, "sect", "option1", "f%oo")
505
506        self.assertEqual(cf.get('sect', "option1"), "foo")
507
508        # bug #5741: double percents are *not* malformed
509        cf.set("sect", "option2", "foo%%bar")
510        self.assertEqual(cf.get("sect", "option2"), "foo%bar")
511
512    def test_set_nonstring_types(self):
513        cf = self.fromstring("[sect]\n"
514                             "option1=foo\n")
515        # Check that we get a TypeError when setting non-string values
516        # in an existing section:
517        self.assertRaises(TypeError, cf.set, "sect", "option1", 1)
518        self.assertRaises(TypeError, cf.set, "sect", "option1", 1.0)
519        self.assertRaises(TypeError, cf.set, "sect", "option1", object())
520        self.assertRaises(TypeError, cf.set, "sect", "option2", 1)
521        self.assertRaises(TypeError, cf.set, "sect", "option2", 1.0)
522        self.assertRaises(TypeError, cf.set, "sect", "option2", object())
523
524    def test_add_section_default_1(self):
525        cf = self.newconfig()
526        self.assertRaises(ValueError, cf.add_section, "default")
527
528    def test_add_section_default_2(self):
529        cf = self.newconfig()
530        self.assertRaises(ValueError, cf.add_section, "DEFAULT")
531
532
533class SafeConfigParserTestCaseNoValue(SafeConfigParserTestCase):
534    allow_no_value = True
535
536class TestChainMap(unittest.TestCase):
537    def test_issue_12717(self):
538        d1 = dict(red=1, green=2)
539        d2 = dict(green=3, blue=4)
540        dcomb = d2.copy()
541        dcomb.update(d1)
542        cm = ConfigParser._Chainmap(d1, d2)
543        self.assertIsInstance(cm.keys(), list)
544        self.assertEqual(set(cm.keys()), set(dcomb.keys()))      # keys()
545        self.assertEqual(set(cm.values()), set(dcomb.values()))  # values()
546        self.assertEqual(set(cm.items()), set(dcomb.items()))    # items()
547        self.assertEqual(set(cm), set(dcomb))                    # __iter__ ()
548        self.assertEqual(cm, dcomb)                              # __eq__()
549        self.assertEqual([cm[k] for k in dcomb], dcomb.values()) # __getitem__()
550        klist = 'red green blue black brown'.split()
551        self.assertEqual([cm.get(k, 10) for k in klist],
552                         [dcomb.get(k, 10) for k in klist])      # get()
553        self.assertEqual([k in cm for k in klist],
554                         [k in dcomb for k in klist])            # __contains__()
555        with test_support.check_py3k_warnings():
556            self.assertEqual([cm.has_key(k) for k in klist],
557                             [dcomb.has_key(k) for k in klist])  # has_key()
558
559class Issue7005TestCase(unittest.TestCase):
560    """Test output when None is set() as a value and allow_no_value == False.
561
562    http://bugs.python.org/issue7005
563
564    """
565
566    expected_output = "[section]\noption = None\n\n"
567
568    def prepare(self, config_class):
569        # This is the default, but that's the point.
570        cp = config_class(allow_no_value=False)
571        cp.add_section("section")
572        cp.set("section", "option", None)
573        sio = StringIO.StringIO()
574        cp.write(sio)
575        return sio.getvalue()
576
577    def test_none_as_value_stringified(self):
578        output = self.prepare(ConfigParser.ConfigParser)
579        self.assertEqual(output, self.expected_output)
580
581    def test_none_as_value_stringified_raw(self):
582        output = self.prepare(ConfigParser.RawConfigParser)
583        self.assertEqual(output, self.expected_output)
584
585
586class SortedTestCase(RawConfigParserTestCase):
587    def newconfig(self, defaults=None):
588        self.cf = self.config_class(defaults=defaults, dict_type=SortedDict)
589        return self.cf
590
591    def test_sorted(self):
592        self.fromstring("[b]\n"
593                        "o4=1\n"
594                        "o3=2\n"
595                        "o2=3\n"
596                        "o1=4\n"
597                        "[a]\n"
598                        "k=v\n")
599        output = StringIO.StringIO()
600        self.cf.write(output)
601        self.assertEqual(output.getvalue(),
602                         "[a]\n"
603                         "k = v\n\n"
604                         "[b]\n"
605                         "o1 = 4\n"
606                         "o2 = 3\n"
607                         "o3 = 2\n"
608                         "o4 = 1\n\n")
609
610
611class ExceptionPicklingTestCase(unittest.TestCase):
612    """Tests for issue #13760: ConfigParser exceptions are not picklable."""
613
614    def test_error(self):
615        import pickle
616        e1 = ConfigParser.Error('value')
617        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
618            pickled = pickle.dumps(e1, proto)
619            e2 = pickle.loads(pickled)
620            self.assertEqual(e1.message, e2.message)
621            self.assertEqual(repr(e1), repr(e2))
622
623    def test_nosectionerror(self):
624        import pickle
625        e1 = ConfigParser.NoSectionError('section')
626        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
627            pickled = pickle.dumps(e1, proto)
628            e2 = pickle.loads(pickled)
629            self.assertEqual(e1.message, e2.message)
630            self.assertEqual(e1.args, e2.args)
631            self.assertEqual(e1.section, e2.section)
632            self.assertEqual(repr(e1), repr(e2))
633
634    def test_nooptionerror(self):
635        import pickle
636        e1 = ConfigParser.NoOptionError('option', 'section')
637        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
638            pickled = pickle.dumps(e1, proto)
639            e2 = pickle.loads(pickled)
640            self.assertEqual(e1.message, e2.message)
641            self.assertEqual(e1.args, e2.args)
642            self.assertEqual(e1.section, e2.section)
643            self.assertEqual(e1.option, e2.option)
644            self.assertEqual(repr(e1), repr(e2))
645
646    def test_duplicatesectionerror(self):
647        import pickle
648        e1 = ConfigParser.DuplicateSectionError('section')
649        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
650            pickled = pickle.dumps(e1, proto)
651            e2 = pickle.loads(pickled)
652            self.assertEqual(e1.message, e2.message)
653            self.assertEqual(e1.args, e2.args)
654            self.assertEqual(e1.section, e2.section)
655            self.assertEqual(repr(e1), repr(e2))
656
657    def test_interpolationerror(self):
658        import pickle
659        e1 = ConfigParser.InterpolationError('option', 'section', 'msg')
660        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
661            pickled = pickle.dumps(e1, proto)
662            e2 = pickle.loads(pickled)
663            self.assertEqual(e1.message, e2.message)
664            self.assertEqual(e1.args, e2.args)
665            self.assertEqual(e1.section, e2.section)
666            self.assertEqual(e1.option, e2.option)
667            self.assertEqual(repr(e1), repr(e2))
668
669    def test_interpolationmissingoptionerror(self):
670        import pickle
671        e1 = ConfigParser.InterpolationMissingOptionError('option', 'section',
672            'rawval', 'reference')
673        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
674            pickled = pickle.dumps(e1, proto)
675            e2 = pickle.loads(pickled)
676            self.assertEqual(e1.message, e2.message)
677            self.assertEqual(e1.args, e2.args)
678            self.assertEqual(e1.section, e2.section)
679            self.assertEqual(e1.option, e2.option)
680            self.assertEqual(e1.reference, e2.reference)
681            self.assertEqual(repr(e1), repr(e2))
682
683    def test_interpolationsyntaxerror(self):
684        import pickle
685        e1 = ConfigParser.InterpolationSyntaxError('option', 'section', 'msg')
686        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
687            pickled = pickle.dumps(e1, proto)
688            e2 = pickle.loads(pickled)
689            self.assertEqual(e1.message, e2.message)
690            self.assertEqual(e1.args, e2.args)
691            self.assertEqual(e1.section, e2.section)
692            self.assertEqual(e1.option, e2.option)
693            self.assertEqual(repr(e1), repr(e2))
694
695    def test_interpolationdeptherror(self):
696        import pickle
697        e1 = ConfigParser.InterpolationDepthError('option', 'section',
698            'rawval')
699        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
700            pickled = pickle.dumps(e1, proto)
701            e2 = pickle.loads(pickled)
702            self.assertEqual(e1.message, e2.message)
703            self.assertEqual(e1.args, e2.args)
704            self.assertEqual(e1.section, e2.section)
705            self.assertEqual(e1.option, e2.option)
706            self.assertEqual(repr(e1), repr(e2))
707
708    def test_parsingerror(self):
709        import pickle
710        e1 = ConfigParser.ParsingError('source')
711        e1.append(1, 'line1')
712        e1.append(2, 'line2')
713        e1.append(3, 'line3')
714        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
715            pickled = pickle.dumps(e1, proto)
716            e2 = pickle.loads(pickled)
717            self.assertEqual(e1.message, e2.message)
718            self.assertEqual(e1.args, e2.args)
719            self.assertEqual(e1.filename, e2.filename)
720            self.assertEqual(e1.errors, e2.errors)
721            self.assertEqual(repr(e1), repr(e2))
722
723    def test_missingsectionheadererror(self):
724        import pickle
725        e1 = ConfigParser.MissingSectionHeaderError('filename', 123, 'line')
726        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
727            pickled = pickle.dumps(e1, proto)
728            e2 = pickle.loads(pickled)
729            self.assertEqual(e1.message, e2.message)
730            self.assertEqual(e1.args, e2.args)
731            self.assertEqual(e1.line, e2.line)
732            self.assertEqual(e1.filename, e2.filename)
733            self.assertEqual(e1.lineno, e2.lineno)
734            self.assertEqual(repr(e1), repr(e2))
735
736
737def test_main():
738    test_support.run_unittest(
739        ConfigParserTestCase,
740        MultilineValuesTestCase,
741        RawConfigParserTestCase,
742        SafeConfigParserTestCase,
743        SafeConfigParserTestCaseNoValue,
744        SortedTestCase,
745        Issue7005TestCase,
746        TestChainMap,
747        ExceptionPicklingTestCase,
748        )
749
750
751if __name__ == "__main__":
752    test_main()
753