1#! /usr/bin/env python
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"""Test that FakeFilesystem calls work identically to a real filesystem."""
18
19#pylint: disable-all
20
21import os #@UnusedImport
22import os.path
23import shutil
24import sys
25import tempfile
26import time
27import sys
28if sys.version_info < (2, 7):
29    import unittest2 as unittest
30else:
31    import unittest
32
33import fake_filesystem
34
35
36def Sep(path):
37    """Converts slashes in the path to the architecture's path seperator."""
38    if isinstance(path, str):
39        return path.replace('/', os.sep)
40    return path
41
42
43class TestCase(unittest.TestCase):
44    is_windows = sys.platform.startswith('win')
45    is_cygwin = sys.platform == 'cygwin'
46    _FAKE_FS_BASE = Sep('/fakefs')
47
48
49class FakeFilesystemVsRealTest(TestCase):
50
51    def _Paths(self, path):
52        """For a given path, return paths in the real and fake filesystems."""
53        if not path:
54            return (None, None)
55        return (os.path.join(self.real_base, path),
56                        os.path.join(self.fake_base, path))
57
58    def _CreateTestFile(self, file_type, path, contents=None):
59        """Create a dir, file, or link in both the real fs and the fake."""
60        path = Sep(path)
61        self._created_files.append([file_type, path, contents])
62        real_path, fake_path = self._Paths(path)
63        if file_type == 'd':
64            os.mkdir(real_path)
65            self.fake_os.mkdir(fake_path)
66        if file_type == 'f':
67            fh = open(real_path, 'w')
68            fh.write(contents or '')
69            fh.close()
70            fh = self.fake_open(fake_path, 'w')
71            fh.write(contents or '')
72            fh.close()
73        # b for binary file
74        if file_type == 'b':
75            fh = open(real_path, 'wb')
76            fh.write(contents or '')
77            fh.close()
78            fh = self.fake_open(fake_path, 'wb')
79            fh.write(contents or '')
80            fh.close()
81        # l for symlink, h for hard link
82        if file_type in ('l', 'h'):
83            real_target, fake_target = (contents, contents)
84            # If it begins with '/', make it relative to the base.    You can't go
85            # creating files in / for the real file system.
86            if contents.startswith(os.sep):
87                real_target, fake_target = self._Paths(contents[1:])
88            if file_type == 'l':
89                os.symlink(real_target, real_path)
90                self.fake_os.symlink(fake_target, fake_path)
91            elif file_type == 'h':
92                os.link(real_target, real_path)
93                self.fake_os.link(fake_target, fake_path)
94
95    def setUp(self):
96        # Base paths in the real and test file systems.     We keep them different
97        # so that missing features in the fake don't fall through to the base
98        # operations and magically succeed.
99        tsname = 'fakefs.%s' % time.time()
100        # Fully expand the base_path - required on OS X.
101        self.real_base = os.path.realpath(
102                os.path.join(tempfile.gettempdir(), tsname))
103        os.chdir(tempfile.gettempdir())
104        if os.path.isdir(self.real_base):
105            shutil.rmtree(self.real_base)
106        os.mkdir(self.real_base)
107        self.fake_base = self._FAKE_FS_BASE
108
109        # Make sure we can write to the physical testing temp directory.
110        self.assertTrue(os.access(self.real_base, os.W_OK))
111
112        self.fake_filesystem = fake_filesystem.FakeFilesystem()
113        self.fake_filesystem.CreateDirectory(self.fake_base)
114        self.fake_os = fake_filesystem.FakeOsModule(self.fake_filesystem)
115        self.fake_open = fake_filesystem.FakeFileOpen(self.fake_filesystem)
116        self._created_files = []
117
118        os.chdir(self.real_base)
119        self.fake_os.chdir(self.fake_base)
120
121    def tearDown(self):
122        # We have to remove all the files from the real FS. Doing the same for the
123        # fake FS is optional, but doing it is an extra sanity check.
124        os.chdir(tempfile.gettempdir())
125        try:
126            rev_files = self._created_files[:]
127            rev_files.reverse()
128            for info in rev_files:
129                real_path, fake_path = self._Paths(info[1])
130                if info[0] == 'd':
131                    try:
132                        os.rmdir(real_path)
133                    except OSError as e:
134                        if 'Directory not empty' in e:
135                            self.fail('Real path %s not empty: %s : %s' % (
136                                    real_path, e, os.listdir(real_path)))
137                        else:
138                            raise
139                    self.fake_os.rmdir(fake_path)
140                if info[0] == 'f' or info[0] == 'l':
141                    os.remove(real_path)
142                    self.fake_os.remove(fake_path)
143        finally:
144            shutil.rmtree(self.real_base)
145
146    def _GetErrno(self, raised_error):
147        try:
148            return (raised_error and raised_error.errno) or None
149        except AttributeError:
150            return None
151
152    def _CompareBehaviors(self, method_name, path, real, fake,
153                                                method_returns_path=False):
154        """Invoke an os method in both real and fake contexts and compare results.
155
156        Invoke a real filesystem method with a path to a real file and invoke a fake
157        filesystem method with a path to a fake file and compare the results.    We
158        expect some calls to throw Exceptions, so we catch those and compare them.
159
160        Args:
161            method_name: Name of method being tested, for use in error messages.
162            path: potential path to a file in the real and fake file systems, passing
163                an empty tuple indicates that no arguments to pass to method.
164            real: built-in system library or method from the built-in system library
165                which takes a path as an arg and returns some value.
166            fake: fake_filsystem object or method from a fake_filesystem class
167                which takes a path as an arg and returns some value.
168            method_returns_path: True if the method returns a path, and thus we must
169                compensate for expected difference between real and fake.
170
171        Returns:
172            A description of the difference in behavior, or None.
173        """
174        # pylint: disable=C6403
175
176        def _ErrorClass(e):
177            return (e and e.__class__.__name__) or 'None'
178
179        real_value = None
180        fake_value = None
181        real_err = None
182        fake_err = None
183        method_call = '%s' % method_name
184        method_call += '()' if path == () else '(%s)' % path
185        # Catching Exception below gives a lint warning, but it's what we need.
186        try:
187            args = [] if path == () else [path]
188            real_method = real
189            if not callable(real):
190                real_method = getattr(real, method_name)
191            real_value = str(real_method(*args))
192        except Exception as e:    # pylint: disable-msg=W0703
193            real_err = e
194        try:
195            fake_method = fake
196            if not callable(fake):
197                fake_method = getattr(fake, method_name)
198            args = [] if path == () else [path]
199            fake_value = str(fake_method(*args))
200        except Exception as e:    # pylint: disable-msg=W0703
201            fake_err = e
202        # We only compare on the error class because the acutal error contents
203        # is almost always different because of the file paths.
204        if _ErrorClass(real_err) != _ErrorClass(fake_err):
205            if real_err is None:
206                return '%s: real version returned %s, fake raised %s' % (
207                        method_call, real_value, _ErrorClass(fake_err))
208            if fake_err is None:
209                return '%s: real version raised %s, fake returned %s' % (
210                        method_call, _ErrorClass(real_err), fake_value)
211            return '%s: real version raised %s, fake raised %s' % (
212                    method_call, _ErrorClass(real_err), _ErrorClass(fake_err))
213        real_errno = self._GetErrno(real_err)
214        fake_errno = self._GetErrno(fake_err)
215        if real_errno != fake_errno:
216            return '%s(%s): both raised %s, real errno %s, fake errno %s' % (
217                    method_name, path, _ErrorClass(real_err), real_errno, fake_errno)
218        # If the method is supposed to return a full path AND both values
219        # begin with the expected full path, then trim it off.
220        if method_returns_path:
221            if (real_value and fake_value
222                    and real_value.startswith(self.real_base)
223                    and fake_value.startswith(self.fake_base)):
224                real_value = real_value[len(self.real_base):]
225                fake_value = fake_value[len(self.fake_base):]
226        if real_value != fake_value:
227            return '%s: real return %s, fake returned %s' % (
228                    method_call, real_value, fake_value)
229        return None
230
231    def assertOsMethodBehaviorMatches(self, method_name, path,
232                                                                        method_returns_path=False):
233        """Invoke an os method in both real and fake contexts and compare.
234
235        For a given method name (from the os module) and a path, compare the
236        behavior of the system provided module against the fake_filesytem module.
237        We expect results and/or Exceptions raised to be identical.
238
239        Args:
240            method_name: Name of method being tested.
241            path: potential path to a file in the real and fake file systems.
242            method_returns_path: True if the method returns a path, and thus we must
243                compensate for expected difference between real and fake.
244
245        Returns:
246            A description of the difference in behavior, or None.
247        """
248        path = Sep(path)
249        return self._CompareBehaviors(method_name, path, os, self.fake_os,
250                                                                    method_returns_path)
251
252    def DiffOpenMethodBehavior(self, method_name, path, mode, data,
253                                                         method_returns_data=True):
254        """Invoke an open method in both real and fkae contexts and compare.
255
256        Args:
257            method_name: Name of method being tested.
258            path: potential path to a file in the real and fake file systems.
259            mode: how to open the file.
260            data: any data to pass to the method.
261            method_returns_data: True if a method returns some sort of data.
262
263        For a given method name (from builtin open) and a path, compare the
264        behavior of the system provided module against the fake_filesytem module.
265        We expect results and/or Exceptions raised to be identical.
266
267        Returns:
268            A description of the difference in behavior, or None.
269        """
270        with open(path, mode) as real_fh:
271            with self.fake_open(path, mode) as fake_fh:
272                return self._CompareBehaviors(method_name, data, real_fh, fake_fh,
273                                                                            method_returns_data)
274
275    def DiffOsPathMethodBehavior(self, method_name, path,
276                                                             method_returns_path=False):
277        """Invoke an os.path method in both real and fake contexts and compare.
278
279        For a given method name (from the os.path module) and a path, compare the
280        behavior of the system provided module against the fake_filesytem module.
281        We expect results and/or Exceptions raised to be identical.
282
283        Args:
284            method_name: Name of method being tested.
285            path: potential path to a file in the real and fake file systems.
286            method_returns_path: True if the method returns a path, and thus we must
287                compensate for expected difference between real and fake.
288
289        Returns:
290            A description of the difference in behavior, or None.
291        """
292        return self._CompareBehaviors(method_name, path, os.path, self.fake_os.path,
293                                                                    method_returns_path)
294
295    def assertOsPathMethodBehaviorMatches(self, method_name, path,
296                                                                                method_returns_path=False):
297        """Assert that an os.path behaves the same in both real and fake contexts.
298
299        Wraps DiffOsPathMethodBehavior, raising AssertionError if any differences
300        are reported.
301
302        Args:
303            method_name: Name of method being tested.
304            path: potential path to a file in the real and fake file systems.
305            method_returns_path: True if the method returns a path, and thus we must
306                compensate for expected difference between real and fake.
307
308        Raises:
309            AssertionError if there is any difference in behavior.
310        """
311        path = Sep(path)
312        diff = self.DiffOsPathMethodBehavior(method_name, path, method_returns_path)
313        if diff:
314            self.fail(diff)
315
316    def assertAllOsBehaviorsMatch(self, path):
317        path = Sep(path)
318        os_method_names = [] if self.is_windows else ['readlink']
319        os_method_names_no_args = ['getcwd']
320        if sys.version_info < (3, 0):
321            os_method_names_no_args.append('getcwdu')
322        os_path_method_names = ['isabs',
323                                                        'isdir',
324                                                        'isfile',
325                                                        'exists'
326                                                     ]
327        if not self.is_windows:
328            os_path_method_names.append('islink')
329            os_path_method_names.append('lexists')
330        wrapped_methods = [['access', self._AccessReal, self._AccessFake],
331                                             ['stat.size', self._StatSizeReal, self._StatSizeFake],
332                                             ['lstat.size', self._LstatSizeReal, self._LstatSizeFake]
333                                            ]
334
335        differences = []
336        for method_name in os_method_names:
337            diff = self.assertOsMethodBehaviorMatches(method_name, path)
338            if diff:
339                differences.append(diff)
340        for method_name in os_method_names_no_args:
341            diff = self.assertOsMethodBehaviorMatches(method_name, (),
342                                                                                                method_returns_path=True)
343            if diff:
344                differences.append(diff)
345        for method_name in os_path_method_names:
346            diff = self.DiffOsPathMethodBehavior(method_name, path)
347            if diff:
348                differences.append(diff)
349        for m in wrapped_methods:
350            diff = self._CompareBehaviors(m[0], path, m[1], m[2])
351            if diff:
352                differences.append(diff)
353        if differences:
354            self.fail('Behaviors do not match for %s:\n    %s' %
355                                (path, '\n    '.join(differences)))
356
357    def assertFileHandleBehaviorsMatch(self, path, mode, data):
358        path = Sep(path)
359        write_method_names = ['write', 'writelines']
360        read_method_names = ['read', 'readlines']
361        other_method_names = ['truncate', 'flush', 'close']
362        differences = []
363        for method_name in write_method_names:
364            diff = self.DiffOpenMethodBehavior(method_name, path, mode, data)
365            if diff:
366                differences.append(diff)
367        for method_name in read_method_names + other_method_names:
368            diff = self.DiffOpenMethodBehavior(method_name, path, mode, ())
369            if diff:
370                differences.append(diff)
371        if differences:
372            self.fail('Behaviors do not match for %s:\n    %s' %
373                                (path, '\n    '.join(differences)))
374
375    # Helpers for checks which are not straight method calls.
376
377    def _AccessReal(self, path):
378        return os.access(path, os.R_OK)
379
380    def _AccessFake(self, path):
381        return self.fake_os.access(path, os.R_OK)
382
383    def _StatSizeReal(self, path):
384        real_path, unused_fake_path = self._Paths(path)
385        # fake_filesystem.py does not implement stat().st_size for directories
386        if os.path.isdir(real_path):
387            return None
388        return os.stat(real_path).st_size
389
390    def _StatSizeFake(self, path):
391        unused_real_path, fake_path = self._Paths(path)
392        # fake_filesystem.py does not implement stat().st_size for directories
393        if self.fake_os.path.isdir(fake_path):
394            return None
395        return self.fake_os.stat(fake_path).st_size
396
397    def _LstatSizeReal(self, path):
398        real_path, unused_fake_path = self._Paths(path)
399        if os.path.isdir(real_path):
400            return None
401        size = os.lstat(real_path).st_size
402        # Account for the difference in the lengths of the absolute paths.
403        if os.path.islink(real_path):
404            if os.readlink(real_path).startswith(os.sep):
405                size -= len(self.real_base)
406        return size
407
408    def _LstatSizeFake(self, path):
409        unused_real_path, fake_path = self._Paths(path)
410        #size = 0
411        if self.fake_os.path.isdir(fake_path):
412            return None
413        size = self.fake_os.lstat(fake_path).st_size
414        # Account for the difference in the lengths of the absolute paths.
415        if self.fake_os.path.islink(fake_path):
416            if self.fake_os.readlink(fake_path).startswith(os.sep):
417                size -= len(self.fake_base)
418        return size
419
420    def testIsabs(self):
421        # We do not have to create any files for isabs.
422        self.assertOsPathMethodBehaviorMatches('isabs', None)
423        self.assertOsPathMethodBehaviorMatches('isabs', '')
424        self.assertOsPathMethodBehaviorMatches('isabs', '/')
425        self.assertOsPathMethodBehaviorMatches('isabs', '/a')
426        self.assertOsPathMethodBehaviorMatches('isabs', 'a')
427
428    def testNonePath(self):
429        self.assertAllOsBehaviorsMatch(None)
430
431    def testEmptyPath(self):
432        self.assertAllOsBehaviorsMatch('')
433
434    def testRootPath(self):
435        self.assertAllOsBehaviorsMatch('/')
436
437    def testNonExistantFile(self):
438        self.assertAllOsBehaviorsMatch('foo')
439
440    def testEmptyFile(self):
441        self._CreateTestFile('f', 'aFile')
442        self.assertAllOsBehaviorsMatch('aFile')
443
444    def testFileWithContents(self):
445        self._CreateTestFile('f', 'aFile', 'some contents')
446        self.assertAllOsBehaviorsMatch('aFile')
447
448    def testFileWithBinaryContents(self):
449        self._CreateTestFile('b', 'aFile', b'some contents')
450        self.assertAllOsBehaviorsMatch('aFile')
451
452    @unittest.skipIf(TestCase.is_windows, 'no symlink in Windows')
453    def testSymLinkToEmptyFile(self):
454        self._CreateTestFile('f', 'aFile')
455        self._CreateTestFile('l', 'link_to_empty', 'aFile')
456        self.assertAllOsBehaviorsMatch('link_to_empty')
457
458    @unittest.skipIf(TestCase.is_windows, 'no symlink in Windows')
459    def TBD_testHardLinkToEmptyFile(self):
460        self._CreateTestFile('f', 'aFile')
461        self._CreateTestFile('h', 'link_to_empty', 'aFile')
462        self.assertAllOsBehaviorsMatch('link_to_empty')
463
464    @unittest.skipIf(TestCase.is_windows, 'no symlink in Windows')
465    def testSymLinkToRealFile(self):
466        self._CreateTestFile('f', 'aFile', 'some contents')
467        self._CreateTestFile('l', 'link_to_file', 'aFile')
468        self.assertAllOsBehaviorsMatch('link_to_file')
469
470    @unittest.skipIf(TestCase.is_windows, 'no symlink in Windows')
471    def TBD_testHardLinkToRealFile(self):
472        self._CreateTestFile('f', 'aFile', 'some contents')
473        self._CreateTestFile('h', 'link_to_file', 'aFile')
474        self.assertAllOsBehaviorsMatch('link_to_file')
475
476    @unittest.skipIf(TestCase.is_windows, 'no symlink in Windows')
477    def testBrokenSymLink(self):
478        self._CreateTestFile('l', 'broken_link', 'broken')
479        self._CreateTestFile('l', 'loop', '/a/loop')
480        self.assertAllOsBehaviorsMatch('broken_link')
481
482    def testFileInAFolder(self):
483        self._CreateTestFile('d', 'a')
484        self._CreateTestFile('d', 'a/b')
485        self._CreateTestFile('f', 'a/b/file', 'contents')
486        self.assertAllOsBehaviorsMatch('a/b/file')
487
488    @unittest.skipIf(TestCase.is_windows, 'no symlink in Windows')
489    def testAbsoluteSymLinkToFolder(self):
490        self._CreateTestFile('d', 'a')
491        self._CreateTestFile('d', 'a/b')
492        self._CreateTestFile('f', 'a/b/file', 'contents')
493        self._CreateTestFile('l', 'a/link', '/a/b')
494        self.assertAllOsBehaviorsMatch('a/link/file')
495
496    @unittest.skipIf(TestCase.is_windows, 'no symlink in Windows')
497    def testLinkToFolderAfterChdir(self):
498        self._CreateTestFile('d', 'a')
499        self._CreateTestFile('d', 'a/b')
500        self._CreateTestFile('f', 'a/b/file', 'contents')
501        self._CreateTestFile('l', 'a/link', '/a/b')
502
503        real_dir, fake_dir = self._Paths('a/b')
504        os.chdir(real_dir)
505        self.fake_os.chdir(fake_dir)
506        self.assertAllOsBehaviorsMatch('file')
507
508    @unittest.skipIf(TestCase.is_windows, 'no symlink in Windows')
509    def testRelativeSymLinkToFolder(self):
510        self._CreateTestFile('d', 'a')
511        self._CreateTestFile('d', 'a/b')
512        self._CreateTestFile('f', 'a/b/file', 'contents')
513        self._CreateTestFile('l', 'a/link', 'b')
514        self.assertAllOsBehaviorsMatch('a/link/file')
515
516    @unittest.skipIf(TestCase.is_windows, 'no symlink in Windows')
517    def testSymLinkToParent(self):
518        # Soft links on HFS+ / OS X behave differently.
519        if os.uname()[0] != 'Darwin':
520            self._CreateTestFile('d', 'a')
521            self._CreateTestFile('d', 'a/b')
522            self._CreateTestFile('l', 'a/b/c', '..')
523            self.assertAllOsBehaviorsMatch('a/b/c')
524
525    @unittest.skipIf(TestCase.is_windows, 'no symlink in Windows')
526    def testPathThroughSymLinkToParent(self):
527        self._CreateTestFile('d', 'a')
528        self._CreateTestFile('f', 'a/target', 'contents')
529        self._CreateTestFile('d', 'a/b')
530        self._CreateTestFile('l', 'a/b/c', '..')
531        self.assertAllOsBehaviorsMatch('a/b/c/target')
532
533    @unittest.skipIf(TestCase.is_windows, 'no symlink in Windows')
534    def testSymLinkToSiblingDirectory(self):
535        self._CreateTestFile('d', 'a')
536        self._CreateTestFile('d', 'a/b')
537        self._CreateTestFile('d', 'a/sibling_of_b')
538        self._CreateTestFile('f', 'a/sibling_of_b/target', 'contents')
539        self._CreateTestFile('l', 'a/b/c', '../sibling_of_b')
540        self.assertAllOsBehaviorsMatch('a/b/c/target')
541
542    @unittest.skipIf(TestCase.is_windows, 'no symlink in Windows')
543    def testSymLinkToSiblingDirectoryNonExistantFile(self):
544        self._CreateTestFile('d', 'a')
545        self._CreateTestFile('d', 'a/b')
546        self._CreateTestFile('d', 'a/sibling_of_b')
547        self._CreateTestFile('f', 'a/sibling_of_b/target', 'contents')
548        self._CreateTestFile('l', 'a/b/c', '../sibling_of_b')
549        self.assertAllOsBehaviorsMatch('a/b/c/file_does_not_exist')
550
551    @unittest.skipIf(TestCase.is_windows, 'no symlink in Windows')
552    def testBrokenSymLinkToSiblingDirectory(self):
553        self._CreateTestFile('d', 'a')
554        self._CreateTestFile('d', 'a/b')
555        self._CreateTestFile('d', 'a/sibling_of_b')
556        self._CreateTestFile('f', 'a/sibling_of_b/target', 'contents')
557        self._CreateTestFile('l', 'a/b/c', '../broken_sibling_of_b')
558        self.assertAllOsBehaviorsMatch('a/b/c/target')
559
560    def testRelativePath(self):
561        self._CreateTestFile('d', 'a')
562        self._CreateTestFile('d', 'a/b')
563        self._CreateTestFile('d', 'a/sibling_of_b')
564        self._CreateTestFile('f', 'a/sibling_of_b/target', 'contents')
565        self.assertAllOsBehaviorsMatch('a/b/../sibling_of_b/target')
566
567    def testBrokenRelativePath(self):
568        self._CreateTestFile('d', 'a')
569        self._CreateTestFile('d', 'a/b')
570        self._CreateTestFile('d', 'a/sibling_of_b')
571        self._CreateTestFile('f', 'a/sibling_of_b/target', 'contents')
572        self.assertAllOsBehaviorsMatch('a/b/../broken/target')
573
574    def testBadRelativePath(self):
575        self._CreateTestFile('d', 'a')
576        self._CreateTestFile('f', 'a/target', 'contents')
577        self._CreateTestFile('d', 'a/b')
578        self._CreateTestFile('d', 'a/sibling_of_b')
579        self._CreateTestFile('f', 'a/sibling_of_b/target', 'contents')
580        self.assertAllOsBehaviorsMatch('a/b/../broken/../target')
581
582    def testGetmtimeNonexistantPath(self):
583        self.assertOsPathMethodBehaviorMatches('getmtime', 'no/such/path')
584
585    def testBuiltinOpenModes(self):
586        self._CreateTestFile('f', 'read', 'some contents')
587        self._CreateTestFile('f', 'write', 'some contents')
588        self._CreateTestFile('f', 'append', 'some contents')
589        self.assertFileHandleBehaviorsMatch('read', 'r', 'other contents')
590        self.assertFileHandleBehaviorsMatch('write', 'w', 'other contents')
591        self.assertFileHandleBehaviorsMatch('append', 'a', 'other contents')
592        self._CreateTestFile('f', 'readplus', 'some contents')
593        self._CreateTestFile('f', 'writeplus', 'some contents')
594        self.assertFileHandleBehaviorsMatch('readplus', 'r+', 'other contents')
595        self.assertFileHandleBehaviorsMatch('writeplus', 'w+', 'other contents')
596        self._CreateTestFile('b', 'binaryread', b'some contents')
597        self._CreateTestFile('b', 'binarywrite', b'some contents')
598        self._CreateTestFile('b', 'binaryappend', b'some contents')
599        self.assertFileHandleBehaviorsMatch('binaryread', 'rb', b'other contents')
600        self.assertFileHandleBehaviorsMatch('binarywrite', 'wb', b'other contents')
601        self.assertFileHandleBehaviorsMatch('binaryappend', 'ab', b'other contents')
602        self.assertFileHandleBehaviorsMatch('read', 'rb', 'other contents')
603        self.assertFileHandleBehaviorsMatch('write', 'wb', 'other contents')
604        self.assertFileHandleBehaviorsMatch('append', 'ab', 'other contents')
605
606
607def main(unused_argv):
608    unittest.main()
609
610
611if __name__ == '__main__':
612    unittest.main()
613