Do not truncate file on failed flush
- fixes #548
diff --git a/CHANGES.md b/CHANGES.md
index 0472b85..455a8b4 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -4,6 +4,8 @@
## 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 81ab908..a2487fd 100644
--- a/pyfakefs/fake_filesystem.py
+++ b/pyfakefs/fake_filesystem.py
@@ -384,11 +384,11 @@
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 fc343e0..e684f07 100644
--- a/pyfakefs/tests/fake_open_test.py
+++ b/pyfakefs/tests/fake_open_test.py
@@ -918,6 +918,26 @@
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):