diff --git a/CHANGES.md b/CHANGES.md index 0472b854..455a8b42 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,6 +4,8 @@ The released versions correspond to PyPi releases. ## Version 4.2.0 (as yet unreleased) #### Fixes + * do not truncate file on failed flush + (see [#548](../../issues/548)) * suppress deprecation warnings while collecting modules (see [#542](../../issues/542)) * add support for `os.truncate` and `os.ftruncate` diff --git a/pyfakefs/fake_filesystem.py b/pyfakefs/fake_filesystem.py index 81ab908b..a2487fd1 100644 --- a/pyfakefs/fake_filesystem.py +++ b/pyfakefs/fake_filesystem.py @@ -384,11 +384,11 @@ def _set_initial_contents(self, contents): changed = self._byte_contents != contents st_size = len(contents) - if self._byte_contents: - self.size = 0 current_size = self.st_size or 0 self.filesystem.change_disk_usage( st_size - current_size, self.name, self.st_dev) + if self._byte_contents: + self.size = 0 self._byte_contents = contents self.st_size = st_size self.epoch += 1 diff --git a/pyfakefs/tests/fake_open_test.py b/pyfakefs/tests/fake_open_test.py index fc343e04..e684f07d 100644 --- a/pyfakefs/tests/fake_open_test.py +++ b/pyfakefs/tests/fake_open_test.py @@ -918,6 +918,26 @@ def test_write_devnull(self): with self.open(self.os.devnull) as f: self.assertEqual('', f.read()) + def test_failed_flush_does_not_truncate_file(self): + # regression test for #548 + self.skip_real_fs() # cannot set fs size in real fs + self.filesystem.set_disk_usage(100) + self.os.makedirs("foo") + file_path = self.os.path.join('foo', 'bar.txt') + with self.open(file_path, 'wb') as f: + f.write(b'a' * 50) + f.flush() + with self.open(file_path, "rb") as r: + x = r.read() + self.assertTrue(x.startswith(b'a' * 50)) + with self.assertRaises(OSError): + f.write(b'b' * 200) + f.flush() + with self.open(file_path, "rb") as r: + x = r.read() + self.assertTrue(x.startswith(b'a' * 50)) + f.truncate(50) + class RealFileOpenTest(FakeFileOpenTest): def use_real_fs(self):