• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# -*- coding: utf-8 -*-
2#
3# Copyright 2009 Google Inc. All Rights Reserved.
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17"""Unit tests for fake_filesystem.FakeOsModule."""
18
19import errno
20import io
21import locale
22import os
23import stat
24import sys
25import time
26import unittest
27
28from pyfakefs import fake_filesystem
29from pyfakefs.fake_filesystem import is_root, PERM_READ, FakeIoModule
30from pyfakefs.fake_filesystem_unittest import PatchMode
31from pyfakefs.tests.test_utils import RealFsTestCase
32
33
34class FakeFileOpenTestBase(RealFsTestCase):
35    def setUp(self):
36        super(FakeFileOpenTestBase, self).setUp()
37        if self.use_real_fs():
38            self.open = io.open
39        else:
40            self.fake_io_module = FakeIoModule(self.filesystem)
41            self.open = self.fake_io_module.open
42
43    def path_separator(self):
44        return '!'
45
46
47class FakeFileOpenTest(FakeFileOpenTestBase):
48    def setUp(self):
49        super(FakeFileOpenTest, self).setUp()
50        self.orig_time = time.time
51
52    def tearDown(self):
53        super(FakeFileOpenTest, self).tearDown()
54        time.time = self.orig_time
55
56    def test_open_no_parent_dir(self):
57        """Expect raise when opening a file in a missing directory."""
58        file_path = self.make_path('foo', 'bar.txt')
59        self.assert_raises_os_error(errno.ENOENT, self.open, file_path, 'w')
60
61    def test_delete_on_close(self):
62        self.skip_real_fs()
63        file_dir = 'boo'
64        file_path = 'boo!far'
65        self.os.mkdir(file_dir)
66        self.open = fake_filesystem.FakeFileOpen(self.filesystem,
67                                                 delete_on_close=True)
68        with self.open(file_path, 'w'):
69            self.assertTrue(self.filesystem.exists(file_path))
70        self.assertFalse(self.filesystem.exists(file_path))
71
72    def test_no_delete_on_close_by_default(self):
73        file_path = self.make_path('czar')
74        with self.open(file_path, 'w'):
75            self.assertTrue(self.os.path.exists(file_path))
76        self.assertTrue(self.os.path.exists(file_path))
77
78    def test_compatibility_of_with_statement(self):
79        self.skip_real_fs()
80        self.open = fake_filesystem.FakeFileOpen(self.filesystem,
81                                                 delete_on_close=True)
82        file_path = 'foo'
83        self.assertFalse(self.os.path.exists(file_path))
84        with self.open(file_path, 'w'):
85            self.assertTrue(self.os.path.exists(file_path))
86        # After the 'with' statement, the close() method should have been
87        # called.
88        self.assertFalse(self.os.path.exists(file_path))
89
90    def test_unicode_contents(self):
91        file_path = self.make_path('foo')
92        # note that this will work only if the string can be represented
93        # by the locale preferred encoding - which under Windows is
94        # usually not UTF-8, but something like Latin1, depending on the locale
95        text_fractions = 'Ümläüts'
96        try:
97            with self.open(file_path, 'w') as f:
98                f.write(text_fractions)
99        except UnicodeEncodeError:
100            # see https://github.com/jmcgeheeiv/pyfakefs/issues/623
101            self.skipTest("This test does not work with an ASCII locale")
102
103        with self.open(file_path) as f:
104            contents = f.read()
105        self.assertEqual(contents, text_fractions)
106
107    def test_byte_contents(self):
108        file_path = self.make_path('foo')
109        byte_fractions = b'\xe2\x85\x93 \xe2\x85\x94 \xe2\x85\x95 \xe2\x85\x96'
110        with self.open(file_path, 'wb') as f:
111            f.write(byte_fractions)
112        # the encoding has to be specified, otherwise the locale default
113        # is used which can be different on different systems
114        with self.open(file_path, encoding='utf-8') as f:
115            contents = f.read()
116        self.assertEqual(contents, byte_fractions.decode('utf-8'))
117
118    def test_write_str_read_bytes(self):
119        file_path = self.make_path('foo')
120        str_contents = 'Äsgül'
121        try:
122            with self.open(file_path, 'w') as f:
123                f.write(str_contents)
124        except UnicodeEncodeError:
125            # see https://github.com/jmcgeheeiv/pyfakefs/issues/623
126            self.skipTest("This test does not work with an ASCII locale")
127        with self.open(file_path, 'rb') as f:
128            contents = f.read()
129        self.assertEqual(str_contents, contents.decode(
130            locale.getpreferredencoding(False)))
131
132    def test_open_valid_file(self):
133        contents = [
134            'I am he as\n',
135            'you are he as\n',
136            'you are me and\n',
137            'we are all together\n'
138        ]
139        file_path = self.make_path('bar.txt')
140        self.create_file(file_path, contents=''.join(contents))
141        with self.open(file_path) as fake_file:
142            self.assertEqual(contents, fake_file.readlines())
143
144    def test_open_valid_args(self):
145        contents = [
146            "Bang bang Maxwell's silver hammer\n",
147            'Came down on her head',
148        ]
149        file_path = self.make_path('abbey_road', 'maxwell')
150        self.create_file(file_path, contents=''.join(contents))
151
152        with self.open(file_path, buffering=1) as f:
153            self.assertEqual(contents, f.readlines())
154        with self.open(file_path, buffering=1,
155                       errors='strict', newline='\n', opener=None) as f:
156            expected_contents = [contents[0][:-1] + self.os.linesep,
157                                 contents[1]]
158            self.assertEqual(expected_contents, f.readlines())
159
160    def test_open_valid_file_with_cwd(self):
161        contents = [
162            'I am he as\n',
163            'you are he as\n',
164            'you are me and\n',
165            'we are all together\n'
166        ]
167        file_path = self.make_path('bar.txt')
168        self.create_file(file_path, contents=''.join(contents))
169        self.os.chdir(self.base_path)
170        with self.open(file_path) as f:
171            self.assertEqual(contents, f.readlines())
172
173    def test_iterate_over_file(self):
174        contents = [
175            "Bang bang Maxwell's silver hammer",
176            'Came down on her head',
177        ]
178        file_path = self.make_path('abbey_road', 'maxwell')
179        self.create_file(file_path, contents='\n'.join(contents))
180        with self.open(file_path) as fake_file:
181            result = [line.rstrip() for line in fake_file]
182        self.assertEqual(contents, result)
183
184    def test_next_over_file(self):
185        contents = [
186            'Live long\n',
187            'and prosper\n'
188        ]
189        result = []
190        file_path = self.make_path('foo.txt')
191        self.create_file(file_path, contents=''.join(contents))
192        with self.open(file_path) as fake_file:
193            result.append(next(fake_file))
194            result.append(next(fake_file))
195        self.assertEqual(contents, result)
196
197    def test_open_directory_error(self):
198        directory_path = self.make_path('foo')
199        self.os.mkdir(directory_path)
200        if self.is_windows:
201            self.assert_raises_os_error(errno.EACCES, self.open.__call__,
202                                        directory_path)
203        else:
204            self.assert_raises_os_error(errno.EISDIR, self.open.__call__,
205                                        directory_path)
206
207    def test_create_file_with_write(self):
208        contents = [
209            "Here comes the sun, little darlin'",
210            'Here comes the sun, and I say,',
211            "It's alright",
212        ]
213        file_dir = self.make_path('abbey_road')
214        file_path = self.os.path.join(file_dir, 'here_comes_the_sun')
215        self.os.mkdir(file_dir)
216        with self.open(file_path, 'w') as fake_file:
217            for line in contents:
218                fake_file.write(line + '\n')
219        with self.open(file_path) as fake_file:
220            result = [line.rstrip() for line in fake_file]
221        self.assertEqual(contents, result)
222
223    def test_create_file_with_append(self):
224        contents = [
225            "Here comes the sun, little darlin'",
226            'Here comes the sun, and I say,',
227            "It's alright",
228        ]
229        file_dir = self.make_path('abbey_road')
230        file_path = self.os.path.join(file_dir, 'here_comes_the_sun')
231        self.os.mkdir(file_dir)
232        with self.open(file_path, 'a') as fake_file:
233            for line in contents:
234                fake_file.write(line + '\n')
235        with self.open(file_path) as fake_file:
236            result = [line.rstrip() for line in fake_file]
237        self.assertEqual(contents, result)
238
239    def test_exclusive_create_file_failure(self):
240        self.skip_if_symlink_not_supported()
241        file_path = self.make_path('bar')
242        self.create_file(file_path)
243        self.assert_raises_os_error(errno.EEXIST, self.open, file_path, 'x')
244        self.assert_raises_os_error(errno.EEXIST, self.open, file_path, 'xb')
245
246    def test_exclusive_create_file(self):
247        file_dir = self.make_path('foo')
248        file_path = self.os.path.join(file_dir, 'bar')
249        self.os.mkdir(file_dir)
250        contents = 'String contents'
251        with self.open(file_path, 'x') as fake_file:
252            fake_file.write(contents)
253        with self.open(file_path) as fake_file:
254            self.assertEqual(contents, fake_file.read())
255
256    def test_exclusive_create_binary_file(self):
257        file_dir = self.make_path('foo')
258        file_path = self.os.path.join(file_dir, 'bar')
259        self.os.mkdir(file_dir)
260        contents = b'Binary contents'
261        with self.open(file_path, 'xb') as fake_file:
262            fake_file.write(contents)
263        with self.open(file_path, 'rb') as fake_file:
264            self.assertEqual(contents, fake_file.read())
265
266    def test_overwrite_existing_file(self):
267        file_path = self.make_path('overwite')
268        self.create_file(file_path, contents='To disappear')
269        new_contents = [
270            'Only these lines',
271            'should be in the file.',
272        ]
273        with self.open(file_path, 'w') as fake_file:
274            for line in new_contents:
275                fake_file.write(line + '\n')
276        with self.open(file_path) as fake_file:
277            result = [line.rstrip() for line in fake_file]
278        self.assertEqual(new_contents, result)
279
280    def test_append_existing_file(self):
281        file_path = self.make_path('appendfile')
282        contents = [
283            'Contents of original file'
284            'Appended contents',
285        ]
286
287        self.create_file(file_path, contents=contents[0])
288        with self.open(file_path, 'a') as fake_file:
289            for line in contents[1:]:
290                fake_file.write(line + '\n')
291        with self.open(file_path) as fake_file:
292            result = [line.rstrip() for line in fake_file]
293        self.assertEqual(contents, result)
294
295    def test_open_with_wplus(self):
296        # set up
297        file_path = self.make_path('wplus_file')
298        self.create_file(file_path, contents='old contents')
299        self.assertTrue(self.os.path.exists(file_path))
300        with self.open(file_path, 'r') as fake_file:
301            self.assertEqual('old contents', fake_file.read())
302        # actual tests
303        with self.open(file_path, 'w+') as fake_file:
304            fake_file.write('new contents')
305            fake_file.seek(0)
306            self.assertTrue('new contents', fake_file.read())
307
308    def test_open_with_wplus_truncation(self):
309        # set up
310        file_path = self.make_path('wplus_file')
311        self.create_file(file_path, contents='old contents')
312        self.assertTrue(self.os.path.exists(file_path))
313        with self.open(file_path, 'r') as fake_file:
314            self.assertEqual('old contents', fake_file.read())
315        # actual tests
316        with self.open(file_path, 'w+') as fake_file:
317            fake_file.seek(0)
318            self.assertEqual('', fake_file.read())
319
320    def test_open_with_append_flag(self):
321        contents = [
322            'I am he as\n',
323            'you are he as\n',
324            'you are me and\n',
325            'we are all together\n'
326        ]
327        additional_contents = [
328            'These new lines\n',
329            'like you a lot.\n'
330        ]
331        file_path = self.make_path('appendfile')
332        self.create_file(file_path, contents=''.join(contents))
333        with self.open(file_path, 'a') as fake_file:
334            with self.assertRaises(io.UnsupportedOperation):
335                fake_file.read(0)
336            with self.assertRaises(io.UnsupportedOperation):
337                fake_file.readline()
338            expected_len = len(''.join(contents))
339            expected_len += len(contents) * (len(self.os.linesep) - 1)
340            self.assertEqual(expected_len, fake_file.tell())
341            fake_file.seek(0)
342            self.assertEqual(0, fake_file.tell())
343            fake_file.writelines(additional_contents)
344        with self.open(file_path) as fake_file:
345            self.assertEqual(
346                contents + additional_contents, fake_file.readlines())
347
348    def check_append_with_aplus(self):
349        file_path = self.make_path('aplus_file')
350        self.create_file(file_path, contents='old contents')
351        self.assertTrue(self.os.path.exists(file_path))
352        with self.open(file_path, 'r') as fake_file:
353            self.assertEqual('old contents', fake_file.read())
354
355        if self.filesystem:
356            # need to recreate FakeFileOpen for OS specific initialization
357            self.open = fake_filesystem.FakeFileOpen(self.filesystem,
358                                                     delete_on_close=True)
359        with self.open(file_path, 'a+') as fake_file:
360            self.assertEqual(12, fake_file.tell())
361            fake_file.write('new contents')
362            self.assertEqual(24, fake_file.tell())
363            fake_file.seek(0)
364            self.assertEqual('old contentsnew contents', fake_file.read())
365
366    def test_append_with_aplus_mac_os(self):
367        self.check_macos_only()
368        self.check_append_with_aplus()
369
370    def test_append_with_aplus_linux_windows(self):
371        self.check_linux_and_windows()
372        self.check_append_with_aplus()
373
374    def test_append_with_aplus_read_with_loop(self):
375        # set up
376        file_path = self.make_path('aplus_file')
377        self.create_file(file_path, contents='old contents')
378        self.assertTrue(self.os.path.exists(file_path))
379        with self.open(file_path, 'r') as fake_file:
380            self.assertEqual('old contents', fake_file.read())
381        # actual tests
382        with self.open(file_path, 'a+') as fake_file:
383            fake_file.seek(0)
384            fake_file.write('new contents')
385            fake_file.seek(0)
386            for line in fake_file:
387                self.assertEqual('old contentsnew contents', line)
388
389    def test_read_empty_file_with_aplus(self):
390        file_path = self.make_path('aplus_file')
391        with self.open(file_path, 'a+') as fake_file:
392            self.assertEqual('', fake_file.read())
393
394    def test_read_with_rplus(self):
395        # set up
396        file_path = self.make_path('rplus_file')
397        self.create_file(file_path, contents='old contents here')
398        self.assertTrue(self.os.path.exists(file_path))
399        with self.open(file_path, 'r') as fake_file:
400            self.assertEqual('old contents here', fake_file.read())
401        # actual tests
402        with self.open(file_path, 'r+') as fake_file:
403            self.assertEqual('old contents here', fake_file.read())
404            fake_file.seek(0)
405            fake_file.write('new contents')
406            fake_file.seek(0)
407            self.assertEqual('new contents here', fake_file.read())
408
409    def create_with_permission(self, file_path, perm_bits):
410        self.create_file(file_path)
411        self.os.chmod(file_path, perm_bits)
412        if perm_bits & PERM_READ:
413            st = self.os.stat(file_path)
414            self.assert_mode_equal(perm_bits, st.st_mode)
415            self.assertTrue(st.st_mode & stat.S_IFREG)
416            self.assertFalse(st.st_mode & stat.S_IFDIR)
417
418    def test_open_flags700(self):
419        # set up
420        self.check_posix_only()
421        file_path = self.make_path('target_file')
422        self.create_with_permission(file_path, 0o700)
423        # actual tests
424        self.open(file_path, 'r').close()
425        self.open(file_path, 'w').close()
426        self.open(file_path, 'w+').close()
427        with self.assertRaises(ValueError):
428            self.open(file_path, 'INV')
429
430    def test_open_flags400(self):
431        # set up
432        self.check_posix_only()
433        file_path = self.make_path('target_file')
434        self.create_with_permission(file_path, 0o400)
435        # actual tests
436        self.open(file_path, 'r').close()
437        if not is_root():
438            self.assert_raises_os_error(
439                errno.EACCES, self.open, file_path, 'w')
440            self.assert_raises_os_error(
441                errno.EACCES, self.open, file_path, 'w+')
442        else:
443            self.open(file_path, 'w').close()
444            self.open(file_path, 'w+').close()
445
446    def test_open_flags200(self):
447        # set up
448        self.check_posix_only()
449        file_path = self.make_path('target_file')
450        self.create_with_permission(file_path, 0o200)
451        # actual tests
452        self.open(file_path, 'w').close()
453        if not is_root():
454            with self.assertRaises(OSError):
455                self.open(file_path, 'r')
456            with self.assertRaises(OSError):
457                self.open(file_path, 'w+')
458        else:
459            self.open(file_path, 'r').close()
460            self.open(file_path, 'w+').close()
461
462    def test_open_flags100(self):
463        # set up
464        self.check_posix_only()
465        file_path = self.make_path('target_file')
466        self.create_with_permission(file_path, 0o100)
467        # actual tests
468        if not is_root():
469            with self.assertRaises(OSError):
470                self.open(file_path, 'r')
471            with self.assertRaises(OSError):
472                self.open(file_path, 'w')
473            with self.assertRaises(OSError):
474                self.open(file_path, 'w+')
475        else:
476            self.open(file_path, 'r').close()
477            self.open(file_path, 'w').close()
478            self.open(file_path, 'w+').close()
479
480    def test_follow_link_read(self):
481        self.skip_if_symlink_not_supported()
482        link_path = self.make_path('foo', 'bar', 'baz')
483        target = self.make_path('tarJAY')
484        target_contents = 'real baz contents'
485        self.create_file(target, contents=target_contents)
486        self.create_symlink(link_path, target)
487        self.assert_equal_paths(target, self.os.readlink(link_path))
488        fh = self.open(link_path, 'r')
489        got_contents = fh.read()
490        fh.close()
491        self.assertEqual(target_contents, got_contents)
492
493    def test_follow_link_write(self):
494        self.skip_if_symlink_not_supported()
495        link_path = self.make_path('foo', 'bar', 'TBD')
496        target = self.make_path('tarJAY')
497        target_contents = 'real baz contents'
498        self.create_symlink(link_path, target)
499        self.assertFalse(self.os.path.exists(target))
500
501        with self.open(link_path, 'w') as fh:
502            fh.write(target_contents)
503        with self.open(target, 'r') as fh:
504            got_contents = fh.read()
505        self.assertEqual(target_contents, got_contents)
506
507    def test_follow_intra_path_link_write(self):
508        # Test a link in the middle of of a file path.
509        self.skip_if_symlink_not_supported()
510        link_path = self.os.path.join(
511            self.base_path, 'foo', 'build', 'local_machine', 'output', '1')
512        target = self.make_path('tmp', 'output', '1')
513        self.create_dir(self.make_path('tmp', 'output'))
514        self.create_symlink(self.os.path.join(
515            self.base_path, 'foo', 'build', 'local_machine'),
516            self.make_path('tmp'))
517
518        self.assertFalse(self.os.path.exists(link_path))
519        self.assertFalse(self.os.path.exists(target))
520
521        target_contents = 'real baz contents'
522        with self.open(link_path, 'w') as fh:
523            fh.write(target_contents)
524        with self.open(target, 'r') as fh:
525            got_contents = fh.read()
526        self.assertEqual(target_contents, got_contents)
527
528    def test_open_raises_on_symlink_loop(self):
529        # Regression test for #274
530        self.check_posix_only()
531        file_dir = self.make_path('foo')
532        self.os.mkdir(file_dir)
533        file_path = self.os.path.join(file_dir, 'baz')
534        self.os.symlink(file_path, file_path)
535        self.assert_raises_os_error(errno.ELOOP, self.open, file_path)
536
537    def test_file_descriptors_for_different_files(self):
538        first_path = self.make_path('some_file1')
539        self.create_file(first_path, contents='contents here1')
540        second_path = self.make_path('some_file2')
541        self.create_file(second_path, contents='contents here2')
542        third_path = self.make_path('some_file3')
543        self.create_file(third_path, contents='contents here3')
544
545        with self.open(first_path) as fake_file1:
546            with self.open(second_path) as fake_file2:
547                with self.open(third_path) as fake_file3:
548                    fileno2 = fake_file2.fileno()
549                    self.assertGreater(fileno2, fake_file1.fileno())
550                    self.assertGreater(fake_file3.fileno(), fileno2)
551
552    def test_file_descriptors_for_the_same_file_are_different(self):
553        first_path = self.make_path('some_file1')
554        self.create_file(first_path, contents='contents here1')
555        second_path = self.make_path('some_file2')
556        self.create_file(second_path, contents='contents here2')
557        with self.open(first_path) as fake_file1:
558            with self.open(second_path) as fake_file2:
559                with self.open(first_path) as fake_file1a:
560                    fileno2 = fake_file2.fileno()
561                    self.assertGreater(fileno2, fake_file1.fileno())
562                    self.assertGreater(fake_file1a.fileno(), fileno2)
563
564    def test_reused_file_descriptors_do_not_affect_others(self):
565        first_path = self.make_path('some_file1')
566        self.create_file(first_path, contents='contents here1')
567        second_path = self.make_path('some_file2')
568        self.create_file(second_path, contents='contents here2')
569        third_path = self.make_path('some_file3')
570        self.create_file(third_path, contents='contents here3')
571
572        with self.open(first_path, 'r') as fake_file1:
573            with self.open(second_path, 'r') as fake_file2:
574                fake_file3 = self.open(third_path, 'r')
575                fake_file1a = self.open(first_path, 'r')
576                fileno1 = fake_file1.fileno()
577                fileno2 = fake_file2.fileno()
578                fileno3 = fake_file3.fileno()
579                fileno4 = fake_file1a.fileno()
580
581        with self.open(second_path, 'r') as fake_file2:
582            with self.open(first_path, 'r') as fake_file1b:
583                self.assertEqual(fileno1, fake_file2.fileno())
584                self.assertEqual(fileno2, fake_file1b.fileno())
585                self.assertEqual(fileno3, fake_file3.fileno())
586                self.assertEqual(fileno4, fake_file1a.fileno())
587        fake_file3.close()
588        fake_file1a.close()
589
590    def test_intertwined_read_write(self):
591        file_path = self.make_path('some_file')
592        self.create_file(file_path)
593
594        with self.open(file_path, 'a') as writer:
595            with self.open(file_path, 'r') as reader:
596                writes = ['hello', 'world\n', 'somewhere\nover', 'the\n',
597                          'rainbow']
598                reads = []
599                # when writes are flushes, they are piped to the reader
600                for write in writes:
601                    writer.write(write)
602                    writer.flush()
603                    reads.append(reader.read())
604                    reader.flush()
605                self.assertEqual(writes, reads)
606                writes = ['nothing', 'to\nsee', 'here']
607                reads = []
608                # when writes are not flushed, the reader doesn't read
609                # anything new
610                for write in writes:
611                    writer.write(write)
612                    reads.append(reader.read())
613                self.assertEqual(['' for _ in writes], reads)
614
615    def test_intertwined_read_write_python3_str(self):
616        file_path = self.make_path('some_file')
617        self.create_file(file_path)
618
619        with self.open(file_path, 'a', encoding='utf-8') as writer:
620            with self.open(file_path, 'r', encoding='utf-8') as reader:
621                writes = ['привет', 'мир\n', 'где-то\nза', 'радугой']
622                reads = []
623                # when writes are flushes, they are piped to the reader
624                for write in writes:
625                    writer.write(write)
626                    writer.flush()
627                    reads.append(reader.read())
628                    reader.flush()
629                self.assertEqual(writes, reads)
630                writes = ['ничего', 'не\nвидно']
631                reads = []
632                # when writes are not flushed, the reader doesn't
633                # read anything new
634                for write in writes:
635                    writer.write(write)
636                    reads.append(reader.read())
637                self.assertEqual(['' for _ in writes], reads)
638
639    def test_open_io_errors(self):
640        file_path = self.make_path('some_file')
641        self.create_file(file_path)
642
643        with self.open(file_path, 'a') as fh:
644            with self.assertRaises(OSError):
645                fh.read()
646            with self.assertRaises(OSError):
647                fh.readlines()
648        with self.open(file_path, 'w') as fh:
649            with self.assertRaises(OSError):
650                fh.read()
651            with self.assertRaises(OSError):
652                fh.readlines()
653        with self.open(file_path, 'r') as fh:
654            with self.assertRaises(OSError):
655                fh.truncate()
656            with self.assertRaises(OSError):
657                fh.write('contents')
658            with self.assertRaises(OSError):
659                fh.writelines(['con', 'tents'])
660
661        def _iterator_open(mode):
662            with self.open(file_path, mode) as f:
663                for _ in f:
664                    pass
665
666        with self.assertRaises(OSError):
667            _iterator_open('w')
668        with self.assertRaises(OSError):
669            _iterator_open('a')
670
671    def test_open_raises_io_error_if_parent_is_file_posix(self):
672        self.check_posix_only()
673        file_path = self.make_path('bar')
674        self.create_file(file_path)
675        file_path = self.os.path.join(file_path, 'baz')
676        self.assert_raises_os_error(errno.ENOTDIR, self.open, file_path, 'w')
677
678    def test_open_raises_io_error_if_parent_is_file_windows(self):
679        self.check_windows_only()
680        file_path = self.make_path('bar')
681        self.create_file(file_path)
682        file_path = self.os.path.join(file_path, 'baz')
683        self.assert_raises_os_error(errno.ENOENT, self.open, file_path, 'w')
684
685    def check_open_with_trailing_sep(self, error_nr):
686        # regression test for #362
687        path = self.make_path('foo') + self.os.path.sep
688        self.assert_raises_os_error(error_nr, self.open, path, 'w')
689
690    def test_open_with_trailing_sep_linux(self):
691        self.check_linux_only()
692        self.check_open_with_trailing_sep(errno.EISDIR)
693
694    def test_open_with_trailing_sep_macos(self):
695        self.check_macos_only()
696        self.check_open_with_trailing_sep(errno.ENOENT)
697
698    def test_open_with_trailing_sep_windows(self):
699        self.check_windows_only()
700        self.check_open_with_trailing_sep(errno.EINVAL)
701
702    def test_can_read_from_block_device(self):
703        self.skip_real_fs()
704        device_path = 'device'
705        self.filesystem.create_file(device_path, stat.S_IFBLK
706                                    | fake_filesystem.PERM_ALL)
707        with self.open(device_path, 'r') as fh:
708            self.assertEqual('', fh.read())
709
710    def test_truncate_flushes_contents(self):
711        # Regression test for #285
712        file_path = self.make_path('baz')
713        self.create_file(file_path)
714        with self.open(file_path, 'w') as f0:
715            f0.write('test')
716            f0.truncate()
717            self.assertEqual(4, self.os.path.getsize(file_path))
718
719    def test_update_other_instances_of_same_file_on_flush(self):
720        # Regression test for #302
721        file_path = self.make_path('baz')
722        with self.open(file_path, 'w') as f0:
723            with self.open(file_path, 'w') as f1:
724                f0.write('test')
725                f0.truncate()
726                f1.flush()
727                self.assertEqual(4, self.os.path.getsize(file_path))
728
729    def test_getsize_after_truncate(self):
730        # Regression test for #412
731        file_path = self.make_path('foo')
732        with self.open(file_path, 'a') as f:
733            f.write('a')
734            f.seek(0)
735            f.truncate()
736            f.write('b')
737            f.truncate()
738            self.assertEqual(1, self.os.path.getsize(file_path))
739            self.assertEqual(1, self.os.stat(file_path).st_size)
740
741    def test_st_size_after_truncate(self):
742        # Regression test for #412
743        file_path = self.make_path('foo')
744        with self.open(file_path, 'a') as f:
745            f.write('a')
746            f.truncate()
747            f.write('b')
748            f.truncate()
749            self.assertEqual(2, self.os.stat(file_path).st_size)
750
751    def test_that_read_over_end_does_not_reset_position(self):
752        # Regression test for #286
753        file_path = self.make_path('baz')
754        self.create_file(file_path)
755        with self.open(file_path) as f0:
756            f0.seek(2)
757            f0.read()
758            self.assertEqual(2, f0.tell())
759
760    def test_accessing_closed_file_raises(self):
761        # Regression test for #275, #280
762        if self.is_pypy:
763            raise unittest.SkipTest('Different exceptions with PyPy')
764        file_path = self.make_path('foo')
765        self.create_file(file_path, contents=b'test')
766        fake_file = self.open(file_path, 'r')
767        fake_file.close()
768        with self.assertRaises(ValueError):
769            fake_file.read(1)
770        with self.assertRaises(ValueError):
771            fake_file.write('a')
772        with self.assertRaises(ValueError):
773            fake_file.readline()
774        with self.assertRaises(ValueError):
775            fake_file.truncate()
776        with self.assertRaises(ValueError):
777            fake_file.tell()
778        with self.assertRaises(ValueError):
779            fake_file.seek(1)
780        with self.assertRaises(ValueError):
781            fake_file.flush()
782
783    def test_accessing_open_file_with_another_handle_raises(self):
784        # Regression test for #282
785        if self.is_pypy:
786            raise unittest.SkipTest('Different exceptions with PyPy')
787        file_path = self.make_path('foo')
788        f0 = self.os.open(file_path, os.O_CREAT | os.O_WRONLY | os.O_TRUNC)
789        fake_file = self.open(file_path, 'r')
790        fake_file.close()
791        with self.assertRaises(ValueError):
792            fake_file.read(1)
793        with self.assertRaises(ValueError):
794            fake_file.write('a')
795        self.os.close(f0)
796
797    def test_tell_flushes_under_mac_os(self):
798        # Regression test for #288
799        self.check_macos_only()
800        file_path = self.make_path('foo')
801        with self.open(file_path, 'w') as f0:
802            f0.write('test')
803            self.assertEqual(4, f0.tell())
804            self.assertEqual(4, self.os.path.getsize(file_path))
805
806    def test_tell_flushes_in_python3(self):
807        # Regression test for #288
808        self.check_linux_and_windows()
809        file_path = self.make_path('foo')
810        with self.open(file_path, 'w') as f0:
811            f0.write('test')
812            self.assertEqual(4, f0.tell())
813            self.assertEqual(4, self.os.path.getsize(file_path))
814
815    def test_read_flushes_under_posix(self):
816        # Regression test for #278
817        self.check_posix_only()
818        file_path = self.make_path('foo')
819        with self.open(file_path, 'a+') as f0:
820            f0.write('test')
821            self.assertEqual('', f0.read())
822            self.assertEqual(4, self.os.path.getsize(file_path))
823
824    def test_read_flushes_under_windows_in_python3(self):
825        # Regression test for #278
826        self.check_windows_only()
827        file_path = self.make_path('foo')
828        with self.open(file_path, 'w+') as f0:
829            f0.write('test')
830            f0.read()
831            self.assertEqual(4, self.os.path.getsize(file_path))
832
833    def test_seek_flushes(self):
834        # Regression test for #290
835        file_path = self.make_path('foo')
836        with self.open(file_path, 'w') as f0:
837            f0.write('test')
838            self.assertEqual(0, self.os.path.getsize(file_path))
839            f0.seek(3)
840            self.assertEqual(4, self.os.path.getsize(file_path))
841
842    def test_truncate_flushes(self):
843        # Regression test for #291
844        file_path = self.make_path('foo')
845        with self.open(file_path, 'a') as f0:
846            f0.write('test')
847            self.assertEqual(0, self.os.path.getsize(file_path))
848            f0.truncate()
849            self.assertEqual(4, self.os.path.getsize(file_path))
850
851    def check_seek_outside_and_truncate_sets_size(self, mode):
852        # Regression test for #294 and #296
853        file_path = self.make_path('baz')
854        with self.open(file_path, mode) as f0:
855            f0.seek(1)
856            f0.truncate()
857            self.assertEqual(1, f0.tell())
858            self.assertEqual(1, self.os.path.getsize(file_path))
859            f0.seek(1)
860            self.assertEqual(1, self.os.path.getsize(file_path))
861        self.assertEqual(1, self.os.path.getsize(file_path))
862
863    def test_seek_outside_and_truncate_sets_size_in_write_mode(self):
864        # Regression test for #294
865        self.check_seek_outside_and_truncate_sets_size('w')
866
867    def test_seek_outside_and_truncate_sets_size_in_append_mode(self):
868        # Regression test for #295
869        self.check_seek_outside_and_truncate_sets_size('a')
870
871    def test_closed(self):
872        file_path = self.make_path('foo')
873        f = self.open(file_path, 'w')
874        self.assertFalse(f.closed)
875        f.close()
876        self.assertTrue(f.closed)
877        f = self.open(file_path)
878        self.assertFalse(f.closed)
879        f.close()
880        self.assertTrue(f.closed)
881
882    def test_closing_closed_file_does_nothing(self):
883        # Regression test for #299
884        file_path = self.make_path('baz')
885        f0 = self.open(file_path, 'w')
886        f0.close()
887        with self.open(file_path) as f1:
888            # would close f1 if not handled
889            f0.close()
890            self.assertEqual('', f1.read())
891
892    def test_closing_file_with_different_close_mode(self):
893        self.skip_real_fs()
894        filename = self.make_path('test.txt')
895        fd = self.os.open(filename, os.O_CREAT | os.O_RDWR)
896        file_obj = self.filesystem.get_object(filename)
897        with self.open(fd, 'wb', closefd=False) as fp:
898            fp.write(b'test')
899        self.assertTrue(self.filesystem.has_open_file(file_obj))
900        self.os.close(fd)
901        self.assertFalse(self.filesystem.has_open_file(file_obj))
902
903    def test_truncate_flushes_zeros(self):
904        # Regression test for #301
905        file_path = self.make_path('baz')
906        with self.open(file_path, 'w') as f0:
907            with self.open(file_path) as f1:
908                f0.seek(1)
909                f0.truncate()
910                self.assertEqual('\0', f1.read())
911
912    def test_byte_filename(self):
913        file_path = self.make_path(b'test')
914        with self.open(file_path, 'wb') as f:
915            f.write(b'test')
916        with self.open(file_path, 'rb') as f:
917            self.assertEqual(b'test', f.read())
918
919    def test_unicode_filename(self):
920        file_path = self.make_path('тест')
921        with self.open(file_path, 'wb') as f:
922            f.write(b'test')
923        with self.open(file_path, 'rb') as f:
924            self.assertEqual(b'test', f.read())
925
926    def test_write_devnull(self):
927        for mode in ('r+', 'w', 'w+', 'a', 'a+'):
928            with self.open(self.os.devnull, mode) as f:
929                f.write('test')
930            with self.open(self.os.devnull) as f:
931                self.assertEqual('', f.read())
932
933    def test_utf16_text(self):
934        # regression test for #574
935        file_path = self.make_path('foo')
936        with self.open(file_path, "w", encoding='utf-16') as f:
937            assert f.write("1") == 1
938
939        with self.open(file_path, "a", encoding='utf-16') as f:
940            assert f.write("2") == 1
941
942        with self.open(file_path, "r", encoding='utf-16') as f:
943            text = f.read()
944            assert text == "12"
945
946
947class RealFileOpenTest(FakeFileOpenTest):
948    def use_real_fs(self):
949        return True
950
951
952@unittest.skipIf(sys.version_info < (3, 8),
953                 'open_code only present since Python 3.8')
954class FakeFilePatchedOpenCodeTest(FakeFileOpenTestBase):
955
956    def setUp(self):
957        super(FakeFilePatchedOpenCodeTest, self).setUp()
958        if self.use_real_fs():
959            self.open_code = io.open_code
960        else:
961            self.filesystem.patch_open_code = PatchMode.ON
962            self.open_code = self.fake_io_module.open_code
963
964    def tearDown(self):
965        if not self.use_real_fs():
966            self.filesystem.patch_open_code = False
967        super(FakeFilePatchedOpenCodeTest, self).tearDown()
968
969    def test_invalid_path(self):
970        with self.assertRaises(TypeError):
971            self.open_code(4)
972
973    def test_byte_contents_open_code(self):
974        byte_fractions = b'\xe2\x85\x93 \xe2\x85\x94 \xe2\x85\x95 \xe2\x85\x96'
975        file_path = self.make_path('foo')
976        self.create_file(file_path, contents=byte_fractions)
977        with self.open_code(file_path) as f:
978            contents = f.read()
979        self.assertEqual(contents, byte_fractions)
980
981    def test_open_code_in_real_fs(self):
982        self.skip_real_fs()
983        file_path = __file__
984        with self.assertRaises(OSError):
985            self.open_code(file_path)
986
987
988class RealPatchedFileOpenCodeTest(FakeFilePatchedOpenCodeTest):
989    def use_real_fs(self):
990        return True
991
992
993@unittest.skipIf(sys.version_info < (3, 8),
994                 'open_code only present since Python 3.8')
995class FakeFileUnpatchedOpenCodeTest(FakeFileOpenTestBase):
996
997    def setUp(self):
998        super(FakeFileUnpatchedOpenCodeTest, self).setUp()
999        if self.use_real_fs():
1000            self.open_code = io.open_code
1001        else:
1002            self.open_code = self.fake_io_module.open_code
1003
1004    def test_invalid_path(self):
1005        with self.assertRaises(TypeError):
1006            self.open_code(4)
1007
1008    def test_open_code_in_real_fs(self):
1009        file_path = __file__
1010
1011        with self.open_code(file_path) as f:
1012            contents = f.read()
1013        self.assertTrue(len(contents) > 100)
1014
1015
1016class RealUnpatchedFileOpenCodeTest(FakeFileUnpatchedOpenCodeTest):
1017    def use_real_fs(self):
1018        return True
1019
1020    def test_byte_contents_open_code(self):
1021        byte_fractions = b'\xe2\x85\x93 \xe2\x85\x94 \xe2\x85\x95 \xe2\x85\x96'
1022        file_path = self.make_path('foo')
1023        self.create_file(file_path, contents=byte_fractions)
1024        with self.open_code(file_path) as f:
1025            contents = f.read()
1026        self.assertEqual(contents, byte_fractions)
1027
1028
1029class BufferingModeTest(FakeFileOpenTestBase):
1030    def test_no_buffering(self):
1031        file_path = self.make_path("buffertest.bin")
1032        with self.open(file_path, 'wb', buffering=0) as f:
1033            f.write(b'a' * 128)
1034            with self.open(file_path, "rb") as r:
1035                x = r.read()
1036                self.assertEqual(b'a' * 128, x)
1037
1038    def test_no_buffering_not_allowed_in_textmode(self):
1039        file_path = self.make_path("buffertest.txt")
1040        with self.assertRaises(ValueError):
1041            self.open(file_path, 'w', buffering=0)
1042
1043    def test_default_buffering_no_flush(self):
1044        file_path = self.make_path("buffertest.bin")
1045        with self.open(file_path, 'wb') as f:
1046            f.write(b'a' * 2048)
1047            with self.open(file_path, "rb") as r:
1048                x = r.read()
1049                self.assertEqual(b'', x)
1050        with self.open(file_path, "rb") as r:
1051            x = r.read()
1052            self.assertEqual(b'a' * 2048, x)
1053
1054    def test_default_buffering_flush(self):
1055        file_path = self.make_path("buffertest.bin")
1056        with self.open(file_path, 'wb') as f:
1057            f.write(b'a' * 2048)
1058            f.flush()
1059            with self.open(file_path, "rb") as r:
1060                x = r.read()
1061                self.assertEqual(b'a' * 2048, x)
1062
1063    def test_writing_with_specific_buffer(self):
1064        file_path = self.make_path("buffertest.bin")
1065        with self.open(file_path, 'wb', buffering=512) as f:
1066            f.write(b'a' * 500)
1067            with self.open(file_path, "rb") as r:
1068                x = r.read()
1069                # buffer not filled - not written
1070                self.assertEqual(0, len(x))
1071            f.write(b'a' * 400)
1072            with self.open(file_path, "rb") as r:
1073                x = r.read()
1074                # buffer exceeded, but new buffer (400) not - previous written
1075                self.assertEqual(500, len(x))
1076            f.write(b'a' * 100)
1077            with self.open(file_path, "rb") as r:
1078                x = r.read()
1079                # buffer not full (500) not written
1080                self.assertEqual(500, len(x))
1081            f.write(b'a' * 100)
1082            with self.open(file_path, "rb") as r:
1083                x = r.read()
1084                # buffer exceeded (600) -> write previous
1085                # new buffer not full (100) - not written
1086                self.assertEqual(1000, len(x))
1087            f.write(b'a' * 600)
1088            with self.open(file_path, "rb") as r:
1089                x = r.read()
1090                # new buffer exceeded (600) -> all written
1091                self.assertEqual(1700, len(x))
1092
1093    def test_writing_text_with_line_buffer(self):
1094        file_path = self.make_path("buffertest.bin")
1095        with self.open(file_path, 'w', buffering=1) as f:
1096            f.write('test' * 100)
1097            with self.open(file_path, "r") as r:
1098                x = r.read()
1099                # no new line - not written
1100                self.assertEqual(0, len(x))
1101            f.write('\ntest')
1102            with self.open(file_path, "r") as r:
1103                x = r.read()
1104                # new line - buffer written
1105                self.assertEqual(405, len(x))
1106            f.write('test' * 10)
1107            with self.open(file_path, "r") as r:
1108                x = r.read()
1109                # buffer not filled - not written
1110                self.assertEqual(405, len(x))
1111            f.write('\ntest')
1112            with self.open(file_path, "r") as r:
1113                x = r.read()
1114                # new line - buffer written
1115                self.assertEqual(450, len(x))
1116
1117    def test_writing_large_text_with_line_buffer(self):
1118        file_path = self.make_path("buffertest.bin")
1119        with self.open(file_path, 'w', buffering=1) as f:
1120            f.write('test' * 4000)
1121            with self.open(file_path, "r") as r:
1122                x = r.read()
1123                # buffer larger than default - written
1124                self.assertEqual(16000, len(x))
1125            f.write('test')
1126            with self.open(file_path, "r") as r:
1127                x = r.read()
1128                # buffer not filled - not written
1129                self.assertEqual(16000, len(x))
1130            f.write('\ntest')
1131            with self.open(file_path, "r") as r:
1132                x = r.read()
1133                # new line - buffer written
1134                self.assertEqual(16009, len(x))
1135            f.write('\ntest')
1136            with self.open(file_path, "r") as r:
1137                x = r.read()
1138                # another new line - buffer written
1139                self.assertEqual(16014, len(x))
1140
1141    def test_writing_text_with_default_buffer(self):
1142        file_path = self.make_path("buffertest.txt")
1143        with self.open(file_path, 'w') as f:
1144            f.write('test' * 5)
1145            with self.open(file_path, "r") as r:
1146                x = r.read()
1147                # buffer not filled - not written
1148                self.assertEqual(0, len(x))
1149            f.write('\ntest')
1150            with self.open(file_path, "r") as r:
1151                x = r.read()
1152                # buffer exceeded, but new buffer (400) not - previous written
1153                self.assertEqual(0, len(x))
1154            f.write('test' * 10)
1155            with self.open(file_path, "r") as r:
1156                x = r.read()
1157                # buffer not filled - not written
1158                self.assertEqual(0, len(x))
1159            f.write('\ntest')
1160            with self.open(file_path, "r") as r:
1161                x = r.read()
1162                self.assertEqual(0, len(x))
1163
1164    def test_writing_text_with_specific_buffer(self):
1165        file_path = self.make_path("buffertest.txt")
1166        with self.open(file_path, 'w', buffering=2) as f:
1167            f.write('a' * 8000)
1168            with self.open(file_path, "r") as r:
1169                x = r.read()
1170                # buffer not filled - not written
1171                self.assertEqual(0, len(x))
1172            f.write('test')
1173            with self.open(file_path, "r") as r:
1174                x = r.read()
1175                # buffer exceeded, but new buffer (400) not - previous written
1176                self.assertEqual(0, len(x))
1177            f.write('test')
1178            with self.open(file_path, "r") as r:
1179                x = r.read()
1180                # buffer not filled - not written
1181                self.assertEqual(0, len(x))
1182            f.write('test')
1183            with self.open(file_path, "r") as r:
1184                x = r.read()
1185                self.assertEqual(0, len(x))
1186        # with self.open(file_path, "r") as r:
1187        #     x = r.read()
1188        #     self.assertEqual(35, len(x))
1189
1190    def test_append_with_specific_buffer(self):
1191        file_path = self.make_path("buffertest.bin")
1192        with self.open(file_path, 'wb', buffering=512) as f:
1193            f.write(b'a' * 500)
1194        with self.open(file_path, 'ab', buffering=512) as f:
1195            f.write(b'a' * 500)
1196            with self.open(file_path, "rb") as r:
1197                x = r.read()
1198                # buffer not filled - not written
1199                self.assertEqual(500, len(x))
1200            f.write(b'a' * 400)
1201            with self.open(file_path, "rb") as r:
1202                x = r.read()
1203                # buffer exceeded, but new buffer (400) not - previous written
1204                self.assertEqual(1000, len(x))
1205            f.write(b'a' * 100)
1206            with self.open(file_path, "rb") as r:
1207                x = r.read()
1208                # buffer not full (500) not written
1209                self.assertEqual(1000, len(x))
1210            f.write(b'a' * 100)
1211            with self.open(file_path, "rb") as r:
1212                x = r.read()
1213                # buffer exceeded (600) -> write previous
1214                # new buffer not full (100) - not written
1215                self.assertEqual(1500, len(x))
1216            f.write(b'a' * 600)
1217            with self.open(file_path, "rb") as r:
1218                x = r.read()
1219                # new buffer exceeded (600) -> all written
1220                self.assertEqual(2200, len(x))
1221
1222    def test_failed_flush_does_not_truncate_file(self):
1223        # regression test for #548
1224        self.skip_real_fs()  # cannot set fs size in real fs
1225        self.filesystem.set_disk_usage(100)
1226        self.os.makedirs("foo")
1227        file_path = self.os.path.join('foo', 'bar.txt')
1228        with self.open(file_path, 'wb') as f:
1229            f.write(b'a' * 50)
1230            f.flush()
1231            with self.open(file_path, "rb") as r:
1232                x = r.read()
1233                self.assertTrue(x.startswith(b'a' * 50))
1234            with self.assertRaises(OSError):
1235                f.write(b'b' * 200)
1236                f.flush()
1237            with self.open(file_path, "rb") as r:
1238                x = r.read()
1239                self.assertTrue(x.startswith(b'a' * 50))
1240            f.truncate(50)
1241
1242    def test_failed_write_does_not_truncate_file(self):
1243        # test the same with no buffering and no flush
1244        self.skip_real_fs()  # cannot set fs size in real fs
1245        self.filesystem.set_disk_usage(100)
1246        self.os.makedirs("foo")
1247        file_path = self.os.path.join('foo', 'bar.txt')
1248        with self.open(file_path, 'wb', buffering=0) as f:
1249            f.write(b'a' * 50)
1250            with self.open(file_path, "rb") as r:
1251                x = r.read()
1252                self.assertEqual(b'a' * 50, x)
1253            with self.assertRaises(OSError):
1254                f.write(b'b' * 200)
1255            with self.open(file_path, "rb") as r:
1256                x = r.read()
1257                self.assertEqual(b'a' * 50, x)
1258
1259
1260class RealBufferingTest(BufferingModeTest):
1261    def use_real_fs(self):
1262        return True
1263
1264
1265class OpenFileWithEncodingTest(FakeFileOpenTestBase):
1266    """Tests that are similar to some open file tests above but using
1267    an explicit text encoding."""
1268
1269    def setUp(self):
1270        super(OpenFileWithEncodingTest, self).setUp()
1271        self.file_path = self.make_path('foo')
1272
1273    def test_write_str_read_bytes(self):
1274        str_contents = u'علي بابا'
1275        with self.open(self.file_path, 'w', encoding='arabic') as f:
1276            f.write(str_contents)
1277        with self.open(self.file_path, 'rb') as f:
1278            contents = f.read()
1279        self.assertEqual(str_contents, contents.decode('arabic'))
1280
1281    def test_write_str_error_modes(self):
1282        str_contents = u'علي بابا'
1283        with self.open(self.file_path, 'w', encoding='cyrillic') as f:
1284            with self.assertRaises(UnicodeEncodeError):
1285                f.write(str_contents)
1286
1287        with self.open(self.file_path, 'w', encoding='ascii',
1288                       errors='xmlcharrefreplace') as f:
1289            f.write(str_contents)
1290        with self.open(self.file_path, 'r', encoding='ascii') as f:
1291            contents = f.read()
1292        self.assertEqual('&#1593;&#1604;&#1610; &#1576;&#1575;&#1576;&#1575;',
1293                         contents)
1294
1295        with self.open(self.file_path, 'w', encoding='ascii',
1296                       errors='namereplace') as f:
1297            f.write(str_contents)
1298        with self.open(self.file_path, 'r', encoding='ascii') as f:
1299            contents = f.read()
1300        self.assertEqual(
1301            r'\N{ARABIC LETTER AIN}\N{ARABIC LETTER LAM}\N'
1302            r'{ARABIC LETTER YEH} \N{ARABIC LETTER BEH}\N'
1303            r'{ARABIC LETTER ALEF}\N{ARABIC LETTER BEH}'
1304            r'\N{ARABIC LETTER ALEF}', contents)
1305
1306    def test_read_str_error_modes(self):
1307        str_contents = u'علي بابا'
1308        with self.open(self.file_path, 'w', encoding='arabic') as f:
1309            f.write(str_contents)
1310
1311        # default strict encoding
1312        with self.open(self.file_path, encoding='ascii') as f:
1313            with self.assertRaises(UnicodeDecodeError):
1314                f.read()
1315        with self.open(self.file_path, encoding='ascii',
1316                       errors='replace') as f:
1317            contents = f.read()
1318        self.assertNotEqual(str_contents, contents)
1319
1320        with self.open(self.file_path, encoding='ascii',
1321                       errors='backslashreplace') as f:
1322            contents = f.read()
1323        self.assertEqual(r'\xd9\xe4\xea \xc8\xc7\xc8\xc7', contents)
1324
1325    def test_write_and_read_str(self):
1326        str_contents = u'علي بابا'
1327        with self.open(self.file_path, 'w', encoding='arabic') as f:
1328            f.write(str_contents)
1329        with self.open(self.file_path, 'r', encoding='arabic') as f:
1330            contents = f.read()
1331        self.assertEqual(str_contents, contents)
1332
1333    def test_create_file_with_append(self):
1334        contents = [
1335            u'Allons enfants de la Patrie,'
1336            u'Le jour de gloire est arrivé!',
1337            u'Contre nous de la tyrannie,',
1338            u'L’étendard sanglant est levé.',
1339        ]
1340        with self.open(self.file_path, 'a', encoding='utf-8') as fake_file:
1341            for line in contents:
1342                fake_file.write(line + '\n')
1343        with self.open(self.file_path, encoding='utf-8') as fake_file:
1344            result = [line.rstrip() for line in fake_file]
1345        self.assertEqual(contents, result)
1346
1347    def test_append_existing_file(self):
1348        contents = [
1349            u'Оригинальное содержание'
1350            u'Дополнительное содержание',
1351        ]
1352        self.create_file(self.file_path, contents=contents[0],
1353                         encoding='cyrillic')
1354        with self.open(self.file_path, 'a', encoding='cyrillic') as fake_file:
1355            for line in contents[1:]:
1356                fake_file.write(line + '\n')
1357        with self.open(self.file_path, encoding='cyrillic') as fake_file:
1358            result = [line.rstrip() for line in fake_file]
1359        self.assertEqual(contents, result)
1360
1361    def test_open_with_wplus(self):
1362        self.create_file(self.file_path,
1363                         contents=u'старое содержание',
1364                         encoding='cyrillic')
1365        with self.open(self.file_path, 'r', encoding='cyrillic') as fake_file:
1366            self.assertEqual(u'старое содержание', fake_file.read())
1367
1368        with self.open(self.file_path, 'w+', encoding='cyrillic') as fake_file:
1369            fake_file.write(u'новое содержание')
1370            fake_file.seek(0)
1371            self.assertTrue(u'новое содержание', fake_file.read())
1372
1373    def test_open_with_append_flag(self):
1374        contents = [
1375            u'Калинка,\n',
1376            u'калинка,\n',
1377            u'калинка моя,\n'
1378        ]
1379        additional_contents = [
1380            u'В саду ягода-малинка,\n',
1381            u'малинка моя.\n'
1382        ]
1383        self.create_file(self.file_path, contents=''.join(contents),
1384                         encoding='cyrillic')
1385        with self.open(self.file_path, 'a', encoding='cyrillic') as fake_file:
1386            with self.assertRaises(io.UnsupportedOperation):
1387                fake_file.read(0)
1388            with self.assertRaises(io.UnsupportedOperation):
1389                fake_file.readline()
1390            self.assertEqual(len(''.join(contents)), fake_file.tell())
1391            fake_file.seek(0)
1392            self.assertEqual(0, fake_file.tell())
1393            fake_file.writelines(additional_contents)
1394        with self.open(self.file_path, encoding='cyrillic') as fake_file:
1395            self.assertEqual(contents + additional_contents,
1396                             fake_file.readlines())
1397
1398    def test_append_with_aplus(self):
1399        self.create_file(self.file_path,
1400                         contents=u'старое содержание',
1401                         encoding='cyrillic')
1402        fake_file = self.open(self.file_path, 'r', encoding='cyrillic')
1403        fake_file.close()
1404
1405        with self.open(self.file_path, 'a+', encoding='cyrillic') as fake_file:
1406            self.assertEqual(17, fake_file.tell())
1407            fake_file.write(u'новое содержание')
1408            self.assertEqual(33, fake_file.tell())
1409            fake_file.seek(0)
1410            self.assertEqual(u'старое содержаниеновое содержание',
1411                             fake_file.read())
1412
1413    def test_read_with_rplus(self):
1414        self.create_file(self.file_path,
1415                         contents=u'старое содержание здесь',
1416                         encoding='cyrillic')
1417        fake_file = self.open(self.file_path, 'r', encoding='cyrillic')
1418        fake_file.close()
1419
1420        with self.open(self.file_path, 'r+', encoding='cyrillic') as fake_file:
1421            self.assertEqual(u'старое содержание здесь', fake_file.read())
1422            fake_file.seek(0)
1423            fake_file.write(u'новое  содержание')
1424            fake_file.seek(0)
1425            self.assertEqual(u'новое  содержание здесь', fake_file.read())
1426
1427
1428class OpenRealFileWithEncodingTest(OpenFileWithEncodingTest):
1429    def use_real_fs(self):
1430        return True
1431
1432
1433class FakeFileOpenLineEndingTest(FakeFileOpenTestBase):
1434    def setUp(self):
1435        super(FakeFileOpenLineEndingTest, self).setUp()
1436
1437    def test_read_default_newline_mode(self):
1438        file_path = self.make_path('some_file')
1439        for contents in (b'1\n2', b'1\r\n2', b'1\r2'):
1440            self.create_file(file_path, contents=contents)
1441            with self.open(file_path, mode='r') as f:
1442                self.assertEqual(['1\n', '2'], f.readlines())
1443            with self.open(file_path, mode='r') as f:
1444                self.assertEqual('1\n2', f.read())
1445            with self.open(file_path, mode='rb') as f:
1446                self.assertEqual(contents, f.read())
1447
1448    def test_write_universal_newline_mode(self):
1449        file_path = self.make_path('some_file')
1450        with self.open(file_path, 'w') as f:
1451            f.write('1\n2')
1452        with self.open(file_path, mode='rb') as f:
1453            self.assertEqual(b'1' + self.os.linesep.encode() + b'2',
1454                             f.read())
1455
1456        with self.open(file_path, 'w') as f:
1457            f.write('1\r\n2')
1458        with self.open(file_path, mode='rb') as f:
1459            self.assertEqual(b'1\r' + self.os.linesep.encode() + b'2',
1460                             f.read())
1461
1462    def test_read_with_newline_arg(self):
1463        file_path = self.make_path('some_file')
1464        file_contents = b'1\r\n2\n3\r4'
1465        self.create_file(file_path, contents=file_contents)
1466        with self.open(file_path, mode='r', newline='') as f:
1467            self.assertEqual('1\r\n2\n3\r4', f.read())
1468        with self.open(file_path, mode='r', newline='\r') as f:
1469            self.assertEqual('1\r\n2\n3\r4', f.read())
1470        with self.open(file_path, mode='r', newline='\n') as f:
1471            self.assertEqual('1\r\n2\n3\r4', f.read())
1472        with self.open(file_path, mode='r', newline='\r\n') as f:
1473            self.assertEqual('1\r\n2\n3\r4', f.read())
1474
1475    def test_readlines_with_newline_arg(self):
1476        file_path = self.make_path('some_file')
1477        file_contents = b'1\r\n2\n3\r4'
1478        self.create_file(file_path, contents=file_contents)
1479        with self.open(file_path, mode='r', newline='') as f:
1480            self.assertEqual(['1\r\n', '2\n', '3\r', '4'],
1481                             f.readlines())
1482        with self.open(file_path, mode='r', newline='\r') as f:
1483            self.assertEqual(['1\r', '\n2\n3\r', '4'], f.readlines())
1484        with self.open(file_path, mode='r', newline='\n') as f:
1485            self.assertEqual(['1\r\n', '2\n', '3\r4'], f.readlines())
1486        with self.open(file_path, mode='r', newline='\r\n') as f:
1487            self.assertEqual(['1\r\n', '2\n3\r4'], f.readlines())
1488
1489    def test_read_with_ignored_universal_newlines_flag(self):
1490        file_path = self.make_path('some_file')
1491        file_contents = b'1\r\n2\n3\r4'
1492        self.create_file(file_path, contents=file_contents)
1493        with self.open(file_path, mode='r', newline='\r') as f:
1494            self.assertEqual('1\r\n2\n3\r4', f.read())
1495        with self.open(file_path, mode='r', newline='\r') as f:
1496            self.assertEqual('1\r\n2\n3\r4', f.read())
1497        with self.open(file_path, mode='U', newline='\r') as f:
1498            self.assertEqual('1\r\n2\n3\r4', f.read())
1499
1500    def test_write_with_newline_arg(self):
1501        file_path = self.make_path('some_file')
1502        with self.open(file_path, 'w', newline='') as f:
1503            f.write('1\r\n2\n3\r4')
1504        with self.open(file_path, mode='rb') as f:
1505            self.assertEqual(b'1\r\n2\n3\r4', f.read())
1506
1507        with self.open(file_path, 'w', newline='\n') as f:
1508            f.write('1\r\n2\n3\r4')
1509        with self.open(file_path, mode='rb') as f:
1510            self.assertEqual(b'1\r\n2\n3\r4', f.read())
1511
1512        with self.open(file_path, 'w', newline='\r\n') as f:
1513            f.write('1\r\n2\n3\r4')
1514        with self.open(file_path, mode='rb') as f:
1515            self.assertEqual(b'1\r\r\n2\r\n3\r4', f.read())
1516
1517        with self.open(file_path, 'w', newline='\r') as f:
1518            f.write('1\r\n2\n3\r4')
1519        with self.open(file_path, mode='rb') as f:
1520            self.assertEqual(b'1\r\r2\r3\r4', f.read())
1521
1522    def test_binary_readline(self):
1523        file_path = self.make_path('some_file')
1524        file_contents = b'\x80\n\x80\r\x80\r\n\x80'
1525
1526        def chunk_line():
1527            px = 0
1528            while px < len(file_contents):
1529                ix = file_contents.find(b'\n', px)
1530                if ix == -1:
1531                    yield file_contents[px:]
1532                    return
1533                yield file_contents[px:ix + 1]
1534                px = ix + 1
1535
1536        chunked_contents = list(chunk_line())
1537        self.create_file(file_path, contents=file_contents)
1538        with self.open(file_path, mode='rb') as f:
1539            self.assertEqual(chunked_contents, list(f))
1540
1541
1542class RealFileOpenLineEndingTest(FakeFileOpenLineEndingTest):
1543    def use_real_fs(self):
1544        return True
1545
1546
1547class FakeFileOpenLineEndingWithEncodingTest(FakeFileOpenTestBase):
1548    def setUp(self):
1549        super(FakeFileOpenLineEndingWithEncodingTest, self).setUp()
1550
1551    def test_read_standard_newline_mode(self):
1552        file_path = self.make_path('some_file')
1553        for contents in (u'раз\nдва', u'раз\r\nдва', u'раз\rдва'):
1554            self.create_file(file_path, contents=contents, encoding='cyrillic')
1555            with self.open(file_path, mode='r',
1556                           encoding='cyrillic') as fake_file:
1557                self.assertEqual([u'раз\n', u'два'], fake_file.readlines())
1558            with self.open(file_path, mode='r',
1559                           encoding='cyrillic') as fake_file:
1560                self.assertEqual(u'раз\nдва', fake_file.read())
1561
1562    def test_write_universal_newline_mode(self):
1563        file_path = self.make_path('some_file')
1564        with self.open(file_path, 'w', encoding='cyrillic') as f:
1565            f.write(u'раз\nдва')
1566        with self.open(file_path, mode='rb') as f:
1567            self.assertEqual(u'раз'.encode('cyrillic') +
1568                             self.os.linesep.encode()
1569                             + u'два'.encode('cyrillic'), f.read())
1570
1571        with self.open(file_path, 'w', encoding='cyrillic') as f:
1572            f.write(u'раз\r\nдва')
1573        with self.open(file_path, mode='rb') as f:
1574            self.assertEqual(u'раз\r'.encode('cyrillic') +
1575                             self.os.linesep.encode() +
1576                             u'два'.encode('cyrillic'), f.read())
1577
1578    def test_read_with_newline_arg(self):
1579        file_path = self.make_path('some_file')
1580        file_contents = u'раз\r\nдва\nтри\rчетыре'
1581        self.create_file(file_path, contents=file_contents,
1582                         encoding='cyrillic')
1583        with self.open(file_path, mode='r', newline='',
1584                       encoding='cyrillic') as f:
1585            self.assertEqual(u'раз\r\nдва\nтри\rчетыре', f.read())
1586        with self.open(file_path, mode='r', newline='\r',
1587                       encoding='cyrillic') as f:
1588            self.assertEqual(u'раз\r\nдва\nтри\rчетыре', f.read())
1589        with self.open(file_path, mode='r', newline='\n',
1590                       encoding='cyrillic') as f:
1591            self.assertEqual(u'раз\r\nдва\nтри\rчетыре', f.read())
1592        with self.open(file_path, mode='r', newline='\r\n',
1593                       encoding='cyrillic') as f:
1594            self.assertEqual(u'раз\r\nдва\nтри\rчетыре', f.read())
1595
1596    def test_readlines_with_newline_arg(self):
1597        file_path = self.make_path('some_file')
1598        file_contents = u'раз\r\nдва\nтри\rчетыре'
1599        self.create_file(file_path, contents=file_contents,
1600                         encoding='cyrillic')
1601        with self.open(file_path, mode='r', newline='',
1602                       encoding='cyrillic') as f:
1603            self.assertEqual([u'раз\r\n', u'два\n', u'три\r', u'четыре'],
1604                             f.readlines())
1605        with self.open(file_path, mode='r', newline='\r',
1606                       encoding='cyrillic') as f:
1607            self.assertEqual([u'раз\r', u'\nдва\nтри\r', u'четыре'],
1608                             f.readlines())
1609        with self.open(file_path, mode='r', newline='\n',
1610                       encoding='cyrillic') as f:
1611            self.assertEqual([u'раз\r\n', u'два\n', u'три\rчетыре'],
1612                             f.readlines())
1613        with self.open(file_path, mode='r', newline='\r\n',
1614                       encoding='cyrillic') as f:
1615            self.assertEqual([u'раз\r\n', u'два\nтри\rчетыре'],
1616                             f.readlines())
1617
1618    def test_write_with_newline_arg(self):
1619        file_path = self.make_path('some_file')
1620        with self.open(file_path, 'w', newline='',
1621                       encoding='cyrillic') as f:
1622            f.write(u'раз\r\nдва\nтри\rчетыре')
1623        with self.open(file_path, mode='rb') as f:
1624            self.assertEqual(u'раз\r\nдва\nтри\rчетыре'.encode('cyrillic'),
1625                             f.read())
1626
1627        with self.open(file_path, 'w', newline='\n',
1628                       encoding='cyrillic') as f:
1629            f.write('раз\r\nдва\nтри\rчетыре')
1630        with self.open(file_path, mode='rb') as f:
1631            self.assertEqual(u'раз\r\nдва\nтри\rчетыре'.encode('cyrillic'),
1632                             f.read())
1633
1634        with self.open(file_path, 'w', newline='\r\n',
1635                       encoding='cyrillic') as f:
1636            f.write('раз\r\nдва\nтри\rчетыре')
1637        with self.open(file_path, mode='rb') as f:
1638            self.assertEqual(u'раз\r\r\nдва\r\nтри\rчетыре'.encode('cyrillic'),
1639                             f.read())
1640
1641        with self.open(file_path, 'w', newline='\r',
1642                       encoding='cyrillic') as f:
1643            f.write('раз\r\nдва\nтри\rчетыре')
1644        with self.open(file_path, mode='rb') as f:
1645            self.assertEqual(u'раз\r\rдва\rтри\rчетыре'.encode('cyrillic'),
1646                             f.read())
1647
1648
1649class RealFileOpenLineEndingWithEncodingTest(
1650        FakeFileOpenLineEndingWithEncodingTest):
1651    def use_real_fs(self):
1652        return True
1653
1654
1655class OpenWithFileDescriptorTest(FakeFileOpenTestBase):
1656    def test_open_with_file_descriptor(self):
1657        file_path = self.make_path('this', 'file')
1658        self.create_file(file_path)
1659        fd = self.os.open(file_path, os.O_CREAT)
1660        self.assertEqual(fd, self.open(fd, 'r').fileno())
1661
1662    def test_closefd_with_file_descriptor(self):
1663        file_path = self.make_path('this', 'file')
1664        self.create_file(file_path)
1665        fd = self.os.open(file_path, os.O_CREAT)
1666        fh = self.open(fd, 'r', closefd=False)
1667        fh.close()
1668        self.assertIsNotNone(self.filesystem.open_files[fd])
1669        fh = self.open(fd, 'r', closefd=True)
1670        fh.close()
1671        self.assertIsNone(self.filesystem.open_files[fd])
1672
1673
1674class OpenWithRealFileDescriptorTest(FakeFileOpenTestBase):
1675    def use_real_fs(self):
1676        return True
1677
1678
1679class OpenWithFlagsTestBase(FakeFileOpenTestBase):
1680    def setUp(self):
1681        super(OpenWithFlagsTestBase, self).setUp()
1682        self.file_path = self.make_path('some_file')
1683        self.file_contents = None
1684
1685    def open_file(self, mode):
1686        return self.open(self.file_path, mode=mode)
1687
1688    def open_file_and_seek(self, mode):
1689        fake_file = self.open(self.file_path, mode=mode)
1690        fake_file.seek(0, 2)
1691        return fake_file
1692
1693    def write_and_reopen_file(self, fake_file, mode='r', encoding=None):
1694        fake_file.write(self.file_contents)
1695        fake_file.close()
1696        args = {'mode': mode}
1697        if encoding:
1698            args['encoding'] = encoding
1699        return self.open(self.file_path, **args)
1700
1701
1702class OpenWithBinaryFlagsTest(OpenWithFlagsTestBase):
1703    def setUp(self):
1704        super(OpenWithBinaryFlagsTest, self).setUp()
1705        self.file_contents = b'real binary contents: \x1f\x8b'
1706        self.create_file(self.file_path, contents=self.file_contents)
1707
1708    def test_read_binary(self):
1709        with self.open_file('rb') as fake_file:
1710            self.assertEqual(self.file_contents, fake_file.read())
1711
1712    def test_write_binary(self):
1713        with self.open_file_and_seek('wb') as f:
1714            self.assertEqual(0, f.tell())
1715            with self.write_and_reopen_file(f, mode='rb') as f1:
1716                self.assertEqual(self.file_contents, f1.read())
1717                # Attempt to reopen the file in text mode
1718                with self.open_file('wb') as f2:
1719                    with self.write_and_reopen_file(f2, mode='r',
1720                                                    encoding='ascii') as f3:
1721                        with self.assertRaises(UnicodeDecodeError):
1722                            f3.read()
1723
1724    def test_write_and_read_binary(self):
1725        with self.open_file_and_seek('w+b') as f:
1726            self.assertEqual(0, f.tell())
1727            with self.write_and_reopen_file(f, mode='rb') as f1:
1728                self.assertEqual(self.file_contents, f1.read())
1729
1730
1731class RealOpenWithBinaryFlagsTest(OpenWithBinaryFlagsTest):
1732    def use_real_fs(self):
1733        return True
1734
1735
1736class OpenWithTextModeFlagsTest(OpenWithFlagsTestBase):
1737    def setUp(self):
1738        super(OpenWithTextModeFlagsTest, self).setUp()
1739        self.setUpFileSystem()
1740
1741    def setUpFileSystem(self):
1742        self.file_path = self.make_path('some_file')
1743        self.file_contents = b'two\r\nlines'
1744        self.original_contents = 'two\r\nlines'
1745        self.converted_contents = 'two\nlines'
1746        self.create_file(self.file_path, contents=self.file_contents)
1747
1748    def test_read_text(self):
1749        """Test that text mode flag is ignored"""
1750        self.check_windows_only()
1751        with self.open_file('r') as f:
1752            self.assertEqual(self.converted_contents, f.read())
1753        with self.open_file('rt') as f:
1754            self.assertEqual(self.converted_contents, f.read())
1755
1756    def test_mixed_text_and_binary_flags(self):
1757        with self.assertRaises(ValueError):
1758            self.open_file_and_seek('w+bt')
1759
1760
1761class RealOpenWithTextModeFlagsTest(OpenWithTextModeFlagsTest):
1762    def use_real_fs(self):
1763        return True
1764
1765
1766class OpenWithInvalidFlagsTest(FakeFileOpenTestBase):
1767    def test_capital_r(self):
1768        with self.assertRaises(ValueError):
1769            self.open('some_file', 'R')
1770
1771    def test_capital_w(self):
1772        with self.assertRaises(ValueError):
1773            self.open('some_file', 'W')
1774
1775    def test_capital_a(self):
1776        with self.assertRaises(ValueError):
1777            self.open('some_file', 'A')
1778
1779    def test_lower_u(self):
1780        with self.assertRaises(ValueError):
1781            self.open('some_file', 'u')
1782
1783    def test_lower_rw(self):
1784        with self.assertRaises(ValueError):
1785            self.open('some_file', 'rw')
1786
1787
1788class OpenWithInvalidFlagsRealFsTest(OpenWithInvalidFlagsTest):
1789    def use_real_fs(self):
1790        return True
1791
1792
1793class ResolvePathTest(FakeFileOpenTestBase):
1794    def write_to_file(self, file_name):
1795        with self.open(file_name, 'w') as fh:
1796            fh.write('x')
1797
1798    def test_none_filepath_raises_type_error(self):
1799        with self.assertRaises(TypeError):
1800            self.open(None, 'w')
1801
1802    def test_empty_filepath_raises_io_error(self):
1803        with self.assertRaises(OSError):
1804            self.open('', 'w')
1805
1806    def test_normal_path(self):
1807        file_path = self.make_path('foo')
1808        self.write_to_file(file_path)
1809        self.assertTrue(self.os.path.exists(file_path))
1810
1811    def test_link_within_same_directory(self):
1812        self.skip_if_symlink_not_supported()
1813        final_target = self.make_path('foo', 'baz')
1814        link_path = self.make_path('foo', 'bar')
1815        self.create_symlink(link_path, 'baz')
1816        self.write_to_file(link_path)
1817        self.assertTrue(self.os.path.exists(final_target))
1818        self.assertEqual(1, self.os.stat(final_target)[stat.ST_SIZE])
1819
1820    def test_link_to_sub_directory(self):
1821        self.skip_if_symlink_not_supported()
1822        final_target = self.make_path('foo', 'baz', 'bip')
1823        dir_path = self.make_path('foo', 'baz')
1824        self.create_dir(dir_path)
1825        link_path = self.make_path('foo', 'bar')
1826        target_path = self.os.path.join('baz', 'bip')
1827        self.create_symlink(link_path, target_path)
1828        self.write_to_file(link_path)
1829        self.assertTrue(self.os.path.exists(final_target))
1830        self.assertEqual(1, self.os.stat(final_target)[stat.ST_SIZE])
1831        self.assertTrue(self.os.path.exists(dir_path))
1832        # Make sure that intermediate directory got created.
1833        self.assertTrue(self.os.stat(dir_path)[stat.ST_MODE] & stat.S_IFDIR)
1834
1835    def test_link_to_parent_directory(self):
1836        self.skip_if_symlink_not_supported()
1837        final_target = self.make_path('baz', 'bip')
1838        self.create_dir(self.make_path('foo'))
1839        self.create_dir(self.make_path('baz'))
1840        link_path = self.make_path('foo', 'bar')
1841        self.create_symlink(link_path, self.os.path.join('..', 'baz'))
1842        self.write_to_file(self.make_path('foo', 'bar', 'bip'))
1843        self.assertTrue(self.os.path.exists(final_target))
1844        self.assertEqual(1, self.os.stat(final_target)[stat.ST_SIZE])
1845        self.assertTrue(self.os.path.exists(link_path))
1846
1847    def test_link_to_absolute_path(self):
1848        self.skip_if_symlink_not_supported()
1849        final_target = self.make_path('foo', 'baz', 'bip')
1850        self.create_dir(self.make_path('foo', 'baz'))
1851        link_path = self.make_path('foo', 'bar')
1852        self.create_symlink(link_path, final_target)
1853        self.write_to_file(link_path)
1854        self.assertTrue(self.os.path.exists(final_target))
1855
1856    def test_relative_links_work_after_chdir(self):
1857        self.skip_if_symlink_not_supported()
1858        final_target = self.make_path('foo', 'baz', 'bip')
1859        self.create_dir(self.make_path('foo', 'baz'))
1860        link_path = self.make_path('foo', 'bar')
1861        self.create_symlink(link_path, self.os.path.join('.', 'baz', 'bip'))
1862        if not self.is_windows:
1863            self.assert_equal_paths(
1864                final_target, self.os.path.realpath(link_path))
1865
1866        self.assertTrue(self.os.path.islink(link_path))
1867        self.os.chdir(self.make_path('foo'))
1868        self.assert_equal_paths(self.make_path('foo'), self.os.getcwd())
1869        self.assertTrue(self.os.path.islink('bar'))
1870        if not self.is_windows:
1871            self.assert_equal_paths(final_target, self.os.path.realpath('bar'))
1872
1873        self.write_to_file(link_path)
1874        self.assertTrue(self.os.path.exists(final_target))
1875
1876    def test_absolute_links_work_after_chdir(self):
1877        self.skip_if_symlink_not_supported()
1878        final_target = self.make_path('foo', 'baz', 'bip')
1879        self.create_dir(self.make_path('foo', 'baz'))
1880        link_path = self.make_path('foo', 'bar')
1881        self.create_symlink(link_path, final_target)
1882        if not self.is_windows:
1883            self.assert_equal_paths(
1884                final_target, self.os.path.realpath(link_path))
1885
1886        self.assertTrue(self.os.path.islink(link_path))
1887        self.os.chdir(self.make_path('foo'))
1888        self.assert_equal_paths(self.make_path('foo'), self.os.getcwd())
1889        self.assertTrue(self.os.path.islink('bar'))
1890        if not self.is_windows:
1891            self.assert_equal_paths(final_target, self.os.path.realpath('bar'))
1892
1893        self.write_to_file(link_path)
1894        self.assertTrue(self.os.path.exists(final_target))
1895
1896    def test_chdir_through_relative_link(self):
1897        self.check_posix_only()
1898        dir1_path = self.make_path('x', 'foo')
1899        dir2_path = self.make_path('x', 'bar')
1900        self.create_dir(dir1_path)
1901        self.create_dir(dir2_path)
1902        link_path = self.make_path('x', 'foo', 'bar')
1903        self.create_symlink(link_path,
1904                            self.os.path.join('..', 'bar'))
1905        self.assert_equal_paths(dir2_path, self.os.path.realpath(link_path))
1906
1907        self.os.chdir(dir1_path)
1908        self.assert_equal_paths(dir1_path, self.os.getcwd())
1909        self.assert_equal_paths(dir2_path, self.os.path.realpath('bar'))
1910
1911        self.os.chdir('bar')
1912        self.assert_equal_paths(dir2_path, self.os.getcwd())
1913
1914    def test_chdir_uses_open_fd_as_path(self):
1915        self.check_posix_only()
1916        if self.is_pypy:
1917            # unclear behavior with PyPi
1918            self.skip_real_fs()
1919        self.assert_raises_os_error(
1920            [errno.ENOTDIR, errno.EBADF], self.os.chdir, 500)
1921        dir_path = self.make_path('foo', 'bar')
1922        self.create_dir(dir_path)
1923
1924        path_des = self.os.open(dir_path, os.O_RDONLY)
1925        self.os.chdir(path_des)
1926        self.os.close(path_des)
1927        self.assert_equal_paths(dir_path, self.os.getcwd())
1928
1929    def test_read_link_to_link(self):
1930        # Write into the final link target and read back from a file which will
1931        # point to that.
1932        self.skip_if_symlink_not_supported()
1933        link_path = self.make_path('foo', 'bar')
1934        self.create_symlink(link_path, 'link')
1935        self.create_symlink(self.make_path('foo', 'link'), 'baz')
1936        self.write_to_file(self.make_path('foo', 'baz'))
1937        fh = self.open(link_path, 'r')
1938        self.assertEqual('x', fh.read())
1939
1940    def test_write_link_to_link(self):
1941        self.skip_if_symlink_not_supported()
1942        final_target = self.make_path('foo', 'baz')
1943        link_path = self.make_path('foo', 'bar')
1944        self.create_symlink(link_path, 'link')
1945        self.create_symlink(self.make_path('foo', 'link'), 'baz')
1946        self.write_to_file(link_path)
1947        self.assertTrue(self.os.path.exists(final_target))
1948
1949    def test_multiple_links(self):
1950        self.skip_if_symlink_not_supported()
1951        self.os.makedirs(self.make_path('a', 'link1', 'c', 'link2'))
1952
1953        self.create_symlink(self.make_path('a', 'b'), 'link1')
1954
1955        if not self.is_windows:
1956            self.assert_equal_paths(self.make_path('a', 'link1'),
1957                                    self.os.path.realpath(
1958                                        self.make_path('a', 'b')))
1959            self.assert_equal_paths(self.make_path('a', 'link1', 'c'),
1960                                    self.os.path.realpath(
1961                                        self.make_path('a', 'b', 'c')))
1962
1963        link_path = self.make_path('a', 'link1', 'c', 'd')
1964        self.create_symlink(link_path, 'link2')
1965        self.assertTrue(self.os.path.exists(link_path))
1966        self.assertTrue(self.os.path.exists(
1967            self.make_path('a', 'b', 'c', 'd')))
1968
1969        final_target = self.make_path('a', 'link1', 'c', 'link2', 'e')
1970        self.assertFalse(self.os.path.exists(final_target))
1971        self.write_to_file(self.make_path('a', 'b', 'c', 'd', 'e'))
1972        self.assertTrue(self.os.path.exists(final_target))
1973
1974    def test_utime_link(self):
1975        """os.utime() and os.stat() via symbolic link (issue #49)"""
1976        self.skip_if_symlink_not_supported()
1977        self.create_dir(self.make_path('foo', 'baz'))
1978        target_path = self.make_path('foo', 'baz', 'bip')
1979        self.write_to_file(target_path)
1980        link_name = self.make_path('foo', 'bar')
1981        self.create_symlink(link_name, target_path)
1982
1983        self.os.utime(link_name, (1, 2))
1984        st = self.os.stat(link_name)
1985        self.assertEqual(1, st.st_atime)
1986        self.assertEqual(2, st.st_mtime)
1987        self.os.utime(link_name, (3, 4))
1988        st = self.os.stat(link_name)
1989        self.assertEqual(3, st.st_atime)
1990        self.assertEqual(4, st.st_mtime)
1991
1992    def test_too_many_links(self):
1993        self.check_posix_only()
1994        link_path = self.make_path('a', 'loop')
1995        self.create_symlink(link_path, 'loop')
1996        self.assertFalse(self.os.path.exists(link_path))
1997
1998    def test_that_drive_letters_are_preserved(self):
1999        self.check_windows_only()
2000        self.skip_real_fs()
2001        self.assertEqual('C:!foo!bar',
2002                         self.filesystem.resolve_path('C:!foo!!bar'))
2003
2004    def test_that_unc_paths_are_preserved(self):
2005        self.check_windows_only()
2006        self.skip_real_fs()
2007        self.assertEqual('!!foo!bar!baz',
2008                         self.filesystem.resolve_path('!!foo!bar!baz!!'))
2009
2010
2011class RealResolvePathTest(ResolvePathTest):
2012    def use_real_fs(self):
2013        return True
2014
2015
2016if __name__ == '__main__':
2017    unittest.main()
2018