test_tempfile.py revision 4adfde8bc82dd39f59e0445588c3e599ada477d2
1# tempfile.py unit tests.
2import tempfile
3import errno
4import io
5import os
6import signal
7import shutil
8import sys
9import re
10import warnings
11
12import unittest
13from test import test_support as support
14
15warnings.filterwarnings("ignore",
16                        category=RuntimeWarning,
17                        message="mktemp", module=__name__)
18
19if hasattr(os, 'stat'):
20    import stat
21    has_stat = 1
22else:
23    has_stat = 0
24
25has_textmode = (tempfile._text_openflags != tempfile._bin_openflags)
26has_spawnl = hasattr(os, 'spawnl')
27
28# TEST_FILES may need to be tweaked for systems depending on the maximum
29# number of files that can be opened at one time (see ulimit -n)
30if sys.platform in ('openbsd3', 'openbsd4'):
31    TEST_FILES = 48
32else:
33    TEST_FILES = 100
34
35# This is organized as one test for each chunk of code in tempfile.py,
36# in order of their appearance in the file.  Testing which requires
37# threads is not done here.
38
39# Common functionality.
40class TC(unittest.TestCase):
41
42    str_check = re.compile(r"[a-zA-Z0-9_-]{6}$")
43
44    def failOnException(self, what, ei=None):
45        if ei is None:
46            ei = sys.exc_info()
47        self.fail("%s raised %s: %s" % (what, ei[0], ei[1]))
48
49    def nameCheck(self, name, dir, pre, suf):
50        (ndir, nbase) = os.path.split(name)
51        npre  = nbase[:len(pre)]
52        nsuf  = nbase[len(nbase)-len(suf):]
53
54        # check for equality of the absolute paths!
55        self.assertEqual(os.path.abspath(ndir), os.path.abspath(dir),
56                         "file '%s' not in directory '%s'" % (name, dir))
57        self.assertEqual(npre, pre,
58                         "file '%s' does not begin with '%s'" % (nbase, pre))
59        self.assertEqual(nsuf, suf,
60                         "file '%s' does not end with '%s'" % (nbase, suf))
61
62        nbase = nbase[len(pre):len(nbase)-len(suf)]
63        self.assertTrue(self.str_check.match(nbase),
64                     "random string '%s' does not match /^[a-zA-Z0-9_-]{6}$/"
65                     % nbase)
66
67test_classes = []
68
69class test_exports(TC):
70    def test_exports(self):
71        # There are no surprising symbols in the tempfile module
72        dict = tempfile.__dict__
73
74        expected = {
75            "NamedTemporaryFile" : 1,
76            "TemporaryFile" : 1,
77            "mkstemp" : 1,
78            "mkdtemp" : 1,
79            "mktemp" : 1,
80            "TMP_MAX" : 1,
81            "gettempprefix" : 1,
82            "gettempdir" : 1,
83            "tempdir" : 1,
84            "template" : 1,
85            "SpooledTemporaryFile" : 1
86        }
87
88        unexp = []
89        for key in dict:
90            if key[0] != '_' and key not in expected:
91                unexp.append(key)
92        self.assertTrue(len(unexp) == 0,
93                        "unexpected keys: %s" % unexp)
94
95test_classes.append(test_exports)
96
97
98class test__RandomNameSequence(TC):
99    """Test the internal iterator object _RandomNameSequence."""
100
101    def setUp(self):
102        self.r = tempfile._RandomNameSequence()
103
104    def test_get_six_char_str(self):
105        # _RandomNameSequence returns a six-character string
106        s = self.r.next()
107        self.nameCheck(s, '', '', '')
108
109    def test_many(self):
110        # _RandomNameSequence returns no duplicate strings (stochastic)
111
112        dict = {}
113        r = self.r
114        for i in xrange(TEST_FILES):
115            s = r.next()
116            self.nameCheck(s, '', '', '')
117            self.assertNotIn(s, dict)
118            dict[s] = 1
119
120    def test_supports_iter(self):
121        # _RandomNameSequence supports the iterator protocol
122
123        i = 0
124        r = self.r
125        try:
126            for s in r:
127                i += 1
128                if i == 20:
129                    break
130        except:
131            self.failOnException("iteration")
132
133    @unittest.skipUnless(hasattr(os, 'fork'),
134        "os.fork is required for this test")
135    def test_process_awareness(self):
136        # ensure that the random source differs between
137        # child and parent.
138        read_fd, write_fd = os.pipe()
139        pid = None
140        try:
141            pid = os.fork()
142            if not pid:
143                os.close(read_fd)
144                os.write(write_fd, next(self.r).encode("ascii"))
145                os.close(write_fd)
146                # bypass the normal exit handlers- leave those to
147                # the parent.
148                os._exit(0)
149            parent_value = next(self.r)
150            child_value = os.read(read_fd, len(parent_value)).decode("ascii")
151        finally:
152            if pid:
153                # best effort to ensure the process can't bleed out
154                # via any bugs above
155                try:
156                    os.kill(pid, signal.SIGKILL)
157                except EnvironmentError:
158                    pass
159            os.close(read_fd)
160            os.close(write_fd)
161        self.assertNotEqual(child_value, parent_value)
162
163
164test_classes.append(test__RandomNameSequence)
165
166
167class test__candidate_tempdir_list(TC):
168    """Test the internal function _candidate_tempdir_list."""
169
170    def test_nonempty_list(self):
171        # _candidate_tempdir_list returns a nonempty list of strings
172
173        cand = tempfile._candidate_tempdir_list()
174
175        self.assertFalse(len(cand) == 0)
176        for c in cand:
177            self.assertIsInstance(c, basestring)
178
179    def test_wanted_dirs(self):
180        # _candidate_tempdir_list contains the expected directories
181
182        # Make sure the interesting environment variables are all set.
183        with support.EnvironmentVarGuard() as env:
184            for envname in 'TMPDIR', 'TEMP', 'TMP':
185                dirname = os.getenv(envname)
186                if not dirname:
187                    env[envname] = os.path.abspath(envname)
188
189            cand = tempfile._candidate_tempdir_list()
190
191            for envname in 'TMPDIR', 'TEMP', 'TMP':
192                dirname = os.getenv(envname)
193                if not dirname: raise ValueError
194                self.assertIn(dirname, cand)
195
196            try:
197                dirname = os.getcwd()
198            except (AttributeError, os.error):
199                dirname = os.curdir
200
201            self.assertIn(dirname, cand)
202
203            # Not practical to try to verify the presence of OS-specific
204            # paths in this list.
205
206test_classes.append(test__candidate_tempdir_list)
207
208# We test _get_default_tempdir some more by testing gettempdir.
209
210class TestGetDefaultTempdir(TC):
211    """Test _get_default_tempdir()."""
212
213    def test_no_files_left_behind(self):
214        # use a private empty directory
215        our_temp_directory = tempfile.mkdtemp()
216        try:
217            # force _get_default_tempdir() to consider our empty directory
218            def our_candidate_list():
219                return [our_temp_directory]
220
221            with support.swap_attr(tempfile, "_candidate_tempdir_list",
222                                   our_candidate_list):
223                # verify our directory is empty after _get_default_tempdir()
224                tempfile._get_default_tempdir()
225                self.assertEqual(os.listdir(our_temp_directory), [])
226
227                def raise_OSError(*args, **kwargs):
228                    raise OSError(-1)
229
230                with support.swap_attr(io, "open", raise_OSError):
231                    # test again with failing io.open()
232                    with self.assertRaises(IOError) as cm:
233                        tempfile._get_default_tempdir()
234                    self.assertEqual(cm.exception.errno, errno.ENOENT)
235                    self.assertEqual(os.listdir(our_temp_directory), [])
236
237                open = io.open
238                def bad_writer(*args, **kwargs):
239                    fp = open(*args, **kwargs)
240                    fp.write = raise_OSError
241                    return fp
242
243                with support.swap_attr(io, "open", bad_writer):
244                    # test again with failing write()
245                    with self.assertRaises(IOError) as cm:
246                        tempfile._get_default_tempdir()
247                    self.assertEqual(cm.exception.errno, errno.ENOENT)
248                    self.assertEqual(os.listdir(our_temp_directory), [])
249        finally:
250            shutil.rmtree(our_temp_directory)
251
252test_classes.append(TestGetDefaultTempdir)
253
254
255class test__get_candidate_names(TC):
256    """Test the internal function _get_candidate_names."""
257
258    def test_retval(self):
259        # _get_candidate_names returns a _RandomNameSequence object
260        obj = tempfile._get_candidate_names()
261        self.assertIsInstance(obj, tempfile._RandomNameSequence)
262
263    def test_same_thing(self):
264        # _get_candidate_names always returns the same object
265        a = tempfile._get_candidate_names()
266        b = tempfile._get_candidate_names()
267
268        self.assertTrue(a is b)
269
270test_classes.append(test__get_candidate_names)
271
272
273class test__mkstemp_inner(TC):
274    """Test the internal function _mkstemp_inner."""
275
276    class mkstemped:
277        _bflags = tempfile._bin_openflags
278        _tflags = tempfile._text_openflags
279        _close = os.close
280        _unlink = os.unlink
281
282        def __init__(self, dir, pre, suf, bin):
283            if bin: flags = self._bflags
284            else:   flags = self._tflags
285
286            (self.fd, self.name) = tempfile._mkstemp_inner(dir, pre, suf, flags)
287
288        def write(self, str):
289            os.write(self.fd, str)
290
291        def __del__(self):
292            self._close(self.fd)
293            self._unlink(self.name)
294
295    def do_create(self, dir=None, pre="", suf="", bin=1):
296        if dir is None:
297            dir = tempfile.gettempdir()
298        try:
299            file = self.mkstemped(dir, pre, suf, bin)
300        except:
301            self.failOnException("_mkstemp_inner")
302
303        self.nameCheck(file.name, dir, pre, suf)
304        return file
305
306    def test_basic(self):
307        # _mkstemp_inner can create files
308        self.do_create().write("blat")
309        self.do_create(pre="a").write("blat")
310        self.do_create(suf="b").write("blat")
311        self.do_create(pre="a", suf="b").write("blat")
312        self.do_create(pre="aa", suf=".txt").write("blat")
313
314    def test_basic_many(self):
315        # _mkstemp_inner can create many files (stochastic)
316        extant = range(TEST_FILES)
317        for i in extant:
318            extant[i] = self.do_create(pre="aa")
319
320    def test_choose_directory(self):
321        # _mkstemp_inner can create files in a user-selected directory
322        dir = tempfile.mkdtemp()
323        try:
324            self.do_create(dir=dir).write("blat")
325        finally:
326            os.rmdir(dir)
327
328    def test_file_mode(self):
329        # _mkstemp_inner creates files with the proper mode
330        if not has_stat:
331            return            # ugh, can't use SkipTest.
332
333        file = self.do_create()
334        mode = stat.S_IMODE(os.stat(file.name).st_mode)
335        expected = 0600
336        if sys.platform in ('win32', 'os2emx'):
337            # There's no distinction among 'user', 'group' and 'world';
338            # replicate the 'user' bits.
339            user = expected >> 6
340            expected = user * (1 + 8 + 64)
341        self.assertEqual(mode, expected)
342
343    def test_noinherit(self):
344        # _mkstemp_inner file handles are not inherited by child processes
345        if not has_spawnl:
346            return            # ugh, can't use SkipTest.
347
348        if support.verbose:
349            v="v"
350        else:
351            v="q"
352
353        file = self.do_create()
354        fd = "%d" % file.fd
355
356        try:
357            me = __file__
358        except NameError:
359            me = sys.argv[0]
360
361        # We have to exec something, so that FD_CLOEXEC will take
362        # effect.  The core of this test is therefore in
363        # tf_inherit_check.py, which see.
364        tester = os.path.join(os.path.dirname(os.path.abspath(me)),
365                              "tf_inherit_check.py")
366
367        # On Windows a spawn* /path/ with embedded spaces shouldn't be quoted,
368        # but an arg with embedded spaces should be decorated with double
369        # quotes on each end
370        if sys.platform in ('win32',):
371            decorated = '"%s"' % sys.executable
372            tester = '"%s"' % tester
373        else:
374            decorated = sys.executable
375
376        retval = os.spawnl(os.P_WAIT, sys.executable, decorated, tester, v, fd)
377        self.assertFalse(retval < 0,
378                    "child process caught fatal signal %d" % -retval)
379        self.assertFalse(retval > 0, "child process reports failure %d"%retval)
380
381    def test_textmode(self):
382        # _mkstemp_inner can create files in text mode
383        if not has_textmode:
384            return            # ugh, can't use SkipTest.
385
386        self.do_create(bin=0).write("blat\n")
387        # XXX should test that the file really is a text file
388
389test_classes.append(test__mkstemp_inner)
390
391
392class test_gettempprefix(TC):
393    """Test gettempprefix()."""
394
395    def test_sane_template(self):
396        # gettempprefix returns a nonempty prefix string
397        p = tempfile.gettempprefix()
398
399        self.assertIsInstance(p, basestring)
400        self.assertTrue(len(p) > 0)
401
402    def test_usable_template(self):
403        # gettempprefix returns a usable prefix string
404
405        # Create a temp directory, avoiding use of the prefix.
406        # Then attempt to create a file whose name is
407        # prefix + 'xxxxxx.xxx' in that directory.
408        p = tempfile.gettempprefix() + "xxxxxx.xxx"
409        d = tempfile.mkdtemp(prefix="")
410        try:
411            p = os.path.join(d, p)
412            try:
413                fd = os.open(p, os.O_RDWR | os.O_CREAT)
414            except:
415                self.failOnException("os.open")
416            os.close(fd)
417            os.unlink(p)
418        finally:
419            os.rmdir(d)
420
421test_classes.append(test_gettempprefix)
422
423
424class test_gettempdir(TC):
425    """Test gettempdir()."""
426
427    def test_directory_exists(self):
428        # gettempdir returns a directory which exists
429
430        dir = tempfile.gettempdir()
431        self.assertTrue(os.path.isabs(dir) or dir == os.curdir,
432                     "%s is not an absolute path" % dir)
433        self.assertTrue(os.path.isdir(dir),
434                     "%s is not a directory" % dir)
435
436    def test_directory_writable(self):
437        # gettempdir returns a directory writable by the user
438
439        # sneaky: just instantiate a NamedTemporaryFile, which
440        # defaults to writing into the directory returned by
441        # gettempdir.
442        try:
443            file = tempfile.NamedTemporaryFile()
444            file.write("blat")
445            file.close()
446        except:
447            self.failOnException("create file in %s" % tempfile.gettempdir())
448
449    def test_same_thing(self):
450        # gettempdir always returns the same object
451        a = tempfile.gettempdir()
452        b = tempfile.gettempdir()
453
454        self.assertTrue(a is b)
455
456test_classes.append(test_gettempdir)
457
458
459class test_mkstemp(TC):
460    """Test mkstemp()."""
461
462    def do_create(self, dir=None, pre="", suf=""):
463        if dir is None:
464            dir = tempfile.gettempdir()
465        try:
466            (fd, name) = tempfile.mkstemp(dir=dir, prefix=pre, suffix=suf)
467            (ndir, nbase) = os.path.split(name)
468            adir = os.path.abspath(dir)
469            self.assertEqual(adir, ndir,
470                "Directory '%s' incorrectly returned as '%s'" % (adir, ndir))
471        except:
472            self.failOnException("mkstemp")
473
474        try:
475            self.nameCheck(name, dir, pre, suf)
476        finally:
477            os.close(fd)
478            os.unlink(name)
479
480    def test_basic(self):
481        # mkstemp can create files
482        self.do_create()
483        self.do_create(pre="a")
484        self.do_create(suf="b")
485        self.do_create(pre="a", suf="b")
486        self.do_create(pre="aa", suf=".txt")
487        self.do_create(dir=".")
488
489    def test_choose_directory(self):
490        # mkstemp can create directories in a user-selected directory
491        dir = tempfile.mkdtemp()
492        try:
493            self.do_create(dir=dir)
494        finally:
495            os.rmdir(dir)
496
497test_classes.append(test_mkstemp)
498
499
500class test_mkdtemp(TC):
501    """Test mkdtemp()."""
502
503    def do_create(self, dir=None, pre="", suf=""):
504        if dir is None:
505            dir = tempfile.gettempdir()
506        try:
507            name = tempfile.mkdtemp(dir=dir, prefix=pre, suffix=suf)
508        except:
509            self.failOnException("mkdtemp")
510
511        try:
512            self.nameCheck(name, dir, pre, suf)
513            return name
514        except:
515            os.rmdir(name)
516            raise
517
518    def test_basic(self):
519        # mkdtemp can create directories
520        os.rmdir(self.do_create())
521        os.rmdir(self.do_create(pre="a"))
522        os.rmdir(self.do_create(suf="b"))
523        os.rmdir(self.do_create(pre="a", suf="b"))
524        os.rmdir(self.do_create(pre="aa", suf=".txt"))
525
526    def test_basic_many(self):
527        # mkdtemp can create many directories (stochastic)
528        extant = range(TEST_FILES)
529        try:
530            for i in extant:
531                extant[i] = self.do_create(pre="aa")
532        finally:
533            for i in extant:
534                if(isinstance(i, basestring)):
535                    os.rmdir(i)
536
537    def test_choose_directory(self):
538        # mkdtemp can create directories in a user-selected directory
539        dir = tempfile.mkdtemp()
540        try:
541            os.rmdir(self.do_create(dir=dir))
542        finally:
543            os.rmdir(dir)
544
545    def test_mode(self):
546        # mkdtemp creates directories with the proper mode
547        if not has_stat:
548            return            # ugh, can't use SkipTest.
549
550        dir = self.do_create()
551        try:
552            mode = stat.S_IMODE(os.stat(dir).st_mode)
553            mode &= 0777 # Mask off sticky bits inherited from /tmp
554            expected = 0700
555            if sys.platform in ('win32', 'os2emx'):
556                # There's no distinction among 'user', 'group' and 'world';
557                # replicate the 'user' bits.
558                user = expected >> 6
559                expected = user * (1 + 8 + 64)
560            self.assertEqual(mode, expected)
561        finally:
562            os.rmdir(dir)
563
564test_classes.append(test_mkdtemp)
565
566
567class test_mktemp(TC):
568    """Test mktemp()."""
569
570    # For safety, all use of mktemp must occur in a private directory.
571    # We must also suppress the RuntimeWarning it generates.
572    def setUp(self):
573        self.dir = tempfile.mkdtemp()
574
575    def tearDown(self):
576        if self.dir:
577            os.rmdir(self.dir)
578            self.dir = None
579
580    class mktemped:
581        _unlink = os.unlink
582        _bflags = tempfile._bin_openflags
583
584        def __init__(self, dir, pre, suf):
585            self.name = tempfile.mktemp(dir=dir, prefix=pre, suffix=suf)
586            # Create the file.  This will raise an exception if it's
587            # mysteriously appeared in the meanwhile.
588            os.close(os.open(self.name, self._bflags, 0600))
589
590        def __del__(self):
591            self._unlink(self.name)
592
593    def do_create(self, pre="", suf=""):
594        try:
595            file = self.mktemped(self.dir, pre, suf)
596        except:
597            self.failOnException("mktemp")
598
599        self.nameCheck(file.name, self.dir, pre, suf)
600        return file
601
602    def test_basic(self):
603        # mktemp can choose usable file names
604        self.do_create()
605        self.do_create(pre="a")
606        self.do_create(suf="b")
607        self.do_create(pre="a", suf="b")
608        self.do_create(pre="aa", suf=".txt")
609
610    def test_many(self):
611        # mktemp can choose many usable file names (stochastic)
612        extant = range(TEST_FILES)
613        for i in extant:
614            extant[i] = self.do_create(pre="aa")
615
616##     def test_warning(self):
617##         # mktemp issues a warning when used
618##         warnings.filterwarnings("error",
619##                                 category=RuntimeWarning,
620##                                 message="mktemp")
621##         self.assertRaises(RuntimeWarning,
622##                           tempfile.mktemp, dir=self.dir)
623
624test_classes.append(test_mktemp)
625
626
627# We test _TemporaryFileWrapper by testing NamedTemporaryFile.
628
629
630class test_NamedTemporaryFile(TC):
631    """Test NamedTemporaryFile()."""
632
633    def do_create(self, dir=None, pre="", suf="", delete=True):
634        if dir is None:
635            dir = tempfile.gettempdir()
636        try:
637            file = tempfile.NamedTemporaryFile(dir=dir, prefix=pre, suffix=suf,
638                                               delete=delete)
639        except:
640            self.failOnException("NamedTemporaryFile")
641
642        self.nameCheck(file.name, dir, pre, suf)
643        return file
644
645
646    def test_basic(self):
647        # NamedTemporaryFile can create files
648        self.do_create()
649        self.do_create(pre="a")
650        self.do_create(suf="b")
651        self.do_create(pre="a", suf="b")
652        self.do_create(pre="aa", suf=".txt")
653
654    def test_creates_named(self):
655        # NamedTemporaryFile creates files with names
656        f = tempfile.NamedTemporaryFile()
657        self.assertTrue(os.path.exists(f.name),
658                        "NamedTemporaryFile %s does not exist" % f.name)
659
660    def test_del_on_close(self):
661        # A NamedTemporaryFile is deleted when closed
662        dir = tempfile.mkdtemp()
663        try:
664            f = tempfile.NamedTemporaryFile(dir=dir)
665            f.write('blat')
666            f.close()
667            self.assertFalse(os.path.exists(f.name),
668                        "NamedTemporaryFile %s exists after close" % f.name)
669        finally:
670            os.rmdir(dir)
671
672    def test_dis_del_on_close(self):
673        # Tests that delete-on-close can be disabled
674        dir = tempfile.mkdtemp()
675        tmp = None
676        try:
677            f = tempfile.NamedTemporaryFile(dir=dir, delete=False)
678            tmp = f.name
679            f.write('blat')
680            f.close()
681            self.assertTrue(os.path.exists(f.name),
682                        "NamedTemporaryFile %s missing after close" % f.name)
683        finally:
684            if tmp is not None:
685                os.unlink(tmp)
686            os.rmdir(dir)
687
688    def test_multiple_close(self):
689        # A NamedTemporaryFile can be closed many times without error
690        f = tempfile.NamedTemporaryFile()
691        f.write('abc\n')
692        f.close()
693        try:
694            f.close()
695            f.close()
696        except:
697            self.failOnException("close")
698
699    def test_context_manager(self):
700        # A NamedTemporaryFile can be used as a context manager
701        with tempfile.NamedTemporaryFile() as f:
702            self.assertTrue(os.path.exists(f.name))
703        self.assertFalse(os.path.exists(f.name))
704        def use_closed():
705            with f:
706                pass
707        self.assertRaises(ValueError, use_closed)
708
709    # How to test the mode and bufsize parameters?
710
711test_classes.append(test_NamedTemporaryFile)
712
713class test_SpooledTemporaryFile(TC):
714    """Test SpooledTemporaryFile()."""
715
716    def do_create(self, max_size=0, dir=None, pre="", suf=""):
717        if dir is None:
718            dir = tempfile.gettempdir()
719        try:
720            file = tempfile.SpooledTemporaryFile(max_size=max_size, dir=dir, prefix=pre, suffix=suf)
721        except:
722            self.failOnException("SpooledTemporaryFile")
723
724        return file
725
726
727    def test_basic(self):
728        # SpooledTemporaryFile can create files
729        f = self.do_create()
730        self.assertFalse(f._rolled)
731        f = self.do_create(max_size=100, pre="a", suf=".txt")
732        self.assertFalse(f._rolled)
733
734    def test_del_on_close(self):
735        # A SpooledTemporaryFile is deleted when closed
736        dir = tempfile.mkdtemp()
737        try:
738            f = tempfile.SpooledTemporaryFile(max_size=10, dir=dir)
739            self.assertFalse(f._rolled)
740            f.write('blat ' * 5)
741            self.assertTrue(f._rolled)
742            filename = f.name
743            f.close()
744            self.assertFalse(os.path.exists(filename),
745                        "SpooledTemporaryFile %s exists after close" % filename)
746        finally:
747            os.rmdir(dir)
748
749    def test_rewrite_small(self):
750        # A SpooledTemporaryFile can be written to multiple within the max_size
751        f = self.do_create(max_size=30)
752        self.assertFalse(f._rolled)
753        for i in range(5):
754            f.seek(0, 0)
755            f.write('x' * 20)
756        self.assertFalse(f._rolled)
757
758    def test_write_sequential(self):
759        # A SpooledTemporaryFile should hold exactly max_size bytes, and roll
760        # over afterward
761        f = self.do_create(max_size=30)
762        self.assertFalse(f._rolled)
763        f.write('x' * 20)
764        self.assertFalse(f._rolled)
765        f.write('x' * 10)
766        self.assertFalse(f._rolled)
767        f.write('x')
768        self.assertTrue(f._rolled)
769
770    def test_writelines(self):
771        # Verify writelines with a SpooledTemporaryFile
772        f = self.do_create()
773        f.writelines((b'x', b'y', b'z'))
774        f.seek(0)
775        buf = f.read()
776        self.assertEqual(buf, b'xyz')
777
778    def test_writelines_sequential(self):
779        # A SpooledTemporaryFile should hold exactly max_size bytes, and roll
780        # over afterward
781        f = self.do_create(max_size=35)
782        f.writelines((b'x' * 20, b'x' * 10, b'x' * 5))
783        self.assertFalse(f._rolled)
784        f.write(b'x')
785        self.assertTrue(f._rolled)
786
787    def test_xreadlines(self):
788        f = self.do_create(max_size=20)
789        f.write(b'abc\n' * 5)
790        f.seek(0)
791        self.assertFalse(f._rolled)
792        self.assertEqual(list(f.xreadlines()), [b'abc\n'] * 5)
793        f.write(b'x\ny')
794        self.assertTrue(f._rolled)
795        f.seek(0)
796        self.assertEqual(list(f.xreadlines()), [b'abc\n'] * 5 + [b'x\n', b'y'])
797
798    def test_sparse(self):
799        # A SpooledTemporaryFile that is written late in the file will extend
800        # when that occurs
801        f = self.do_create(max_size=30)
802        self.assertFalse(f._rolled)
803        f.seek(100, 0)
804        self.assertFalse(f._rolled)
805        f.write('x')
806        self.assertTrue(f._rolled)
807
808    def test_fileno(self):
809        # A SpooledTemporaryFile should roll over to a real file on fileno()
810        f = self.do_create(max_size=30)
811        self.assertFalse(f._rolled)
812        self.assertTrue(f.fileno() > 0)
813        self.assertTrue(f._rolled)
814
815    def test_multiple_close_before_rollover(self):
816        # A SpooledTemporaryFile can be closed many times without error
817        f = tempfile.SpooledTemporaryFile()
818        f.write('abc\n')
819        self.assertFalse(f._rolled)
820        f.close()
821        try:
822            f.close()
823            f.close()
824        except:
825            self.failOnException("close")
826
827    def test_multiple_close_after_rollover(self):
828        # A SpooledTemporaryFile can be closed many times without error
829        f = tempfile.SpooledTemporaryFile(max_size=1)
830        f.write('abc\n')
831        self.assertTrue(f._rolled)
832        f.close()
833        try:
834            f.close()
835            f.close()
836        except:
837            self.failOnException("close")
838
839    def test_bound_methods(self):
840        # It should be OK to steal a bound method from a SpooledTemporaryFile
841        # and use it independently; when the file rolls over, those bound
842        # methods should continue to function
843        f = self.do_create(max_size=30)
844        read = f.read
845        write = f.write
846        seek = f.seek
847
848        write("a" * 35)
849        write("b" * 35)
850        seek(0, 0)
851        self.assertTrue(read(70) == 'a'*35 + 'b'*35)
852
853    def test_properties(self):
854        f = tempfile.SpooledTemporaryFile(max_size=10)
855        f.write(b'x' * 10)
856        self.assertFalse(f._rolled)
857        self.assertEqual(f.mode, 'w+b')
858        self.assertIsNone(f.name)
859        with self.assertRaises(AttributeError):
860            f.newlines
861        with self.assertRaises(AttributeError):
862            f.encoding
863
864        f.write(b'x')
865        self.assertTrue(f._rolled)
866        self.assertEqual(f.mode, 'w+b')
867        self.assertIsNotNone(f.name)
868        with self.assertRaises(AttributeError):
869            f.newlines
870        with self.assertRaises(AttributeError):
871            f.encoding
872
873    def test_context_manager_before_rollover(self):
874        # A SpooledTemporaryFile can be used as a context manager
875        with tempfile.SpooledTemporaryFile(max_size=1) as f:
876            self.assertFalse(f._rolled)
877            self.assertFalse(f.closed)
878        self.assertTrue(f.closed)
879        def use_closed():
880            with f:
881                pass
882        self.assertRaises(ValueError, use_closed)
883
884    def test_context_manager_during_rollover(self):
885        # A SpooledTemporaryFile can be used as a context manager
886        with tempfile.SpooledTemporaryFile(max_size=1) as f:
887            self.assertFalse(f._rolled)
888            f.write('abc\n')
889            f.flush()
890            self.assertTrue(f._rolled)
891            self.assertFalse(f.closed)
892        self.assertTrue(f.closed)
893        def use_closed():
894            with f:
895                pass
896        self.assertRaises(ValueError, use_closed)
897
898    def test_context_manager_after_rollover(self):
899        # A SpooledTemporaryFile can be used as a context manager
900        f = tempfile.SpooledTemporaryFile(max_size=1)
901        f.write('abc\n')
902        f.flush()
903        self.assertTrue(f._rolled)
904        with f:
905            self.assertFalse(f.closed)
906        self.assertTrue(f.closed)
907        def use_closed():
908            with f:
909                pass
910        self.assertRaises(ValueError, use_closed)
911
912
913test_classes.append(test_SpooledTemporaryFile)
914
915
916class test_TemporaryFile(TC):
917    """Test TemporaryFile()."""
918
919    def test_basic(self):
920        # TemporaryFile can create files
921        # No point in testing the name params - the file has no name.
922        try:
923            tempfile.TemporaryFile()
924        except:
925            self.failOnException("TemporaryFile")
926
927    def test_has_no_name(self):
928        # TemporaryFile creates files with no names (on this system)
929        dir = tempfile.mkdtemp()
930        f = tempfile.TemporaryFile(dir=dir)
931        f.write('blat')
932
933        # Sneaky: because this file has no name, it should not prevent
934        # us from removing the directory it was created in.
935        try:
936            os.rmdir(dir)
937        except:
938            ei = sys.exc_info()
939            # cleanup
940            f.close()
941            os.rmdir(dir)
942            self.failOnException("rmdir", ei)
943
944    def test_multiple_close(self):
945        # A TemporaryFile can be closed many times without error
946        f = tempfile.TemporaryFile()
947        f.write('abc\n')
948        f.close()
949        try:
950            f.close()
951            f.close()
952        except:
953            self.failOnException("close")
954
955    # How to test the mode and bufsize parameters?
956
957
958if tempfile.NamedTemporaryFile is not tempfile.TemporaryFile:
959    test_classes.append(test_TemporaryFile)
960
961def test_main():
962    support.run_unittest(*test_classes)
963
964if __name__ == "__main__":
965    test_main()
966