1# Copyright 2013 Christoph Reiter
2#
3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; either version 2 of the License, or
6# (at your option) any later version.
7
8import os
9import stat
10import shutil
11
12from tests import TestCase, mkdtemp
13
14from quodlibet.util.atomic import atomic_save
15
16
17class Tatomic_save(TestCase):
18
19    def setUp(self):
20        self.dir = mkdtemp()
21
22    def tearDown(self):
23        shutil.rmtree(self.dir)
24
25    def test_basic(self):
26        filename = os.path.join(self.dir, "foo.txt")
27
28        with open(filename, "wb") as fobj:
29            fobj.write(b"nope")
30
31        with atomic_save(filename, "wb") as fobj:
32            fobj.write(b"foo")
33            temp_name = fobj.name
34
35        with open(filename, "rb") as fobj:
36            self.assertEqual(fobj.read(), b"foo")
37
38        self.assertFalse(os.path.exists(temp_name))
39        self.assertEqual(os.listdir(self.dir), [os.path.basename(filename)])
40
41    def test_non_exist(self):
42        filename = os.path.join(self.dir, "foo.txt")
43
44        with atomic_save(filename, "wb") as fobj:
45            fobj.write(b"foo")
46            temp_name = fobj.name
47
48        with open(filename, "rb") as fobj:
49            self.assertEqual(fobj.read(), b"foo")
50
51        self.assertFalse(os.path.exists(temp_name))
52        self.assertEqual(os.listdir(self.dir), [os.path.basename(filename)])
53
54    def test_readonly(self):
55        filename = os.path.join(self.dir, "foo.txt")
56
57        with open(filename, "wb") as fobj:
58            fobj.write(b"nope")
59
60        dir_mode = os.stat(self.dir).st_mode
61        file_mode = os.stat(filename).st_mode
62        # setting directory permissions doesn't work under Windows, so make
63        # the file read only, so the rename fails. On the other hand marking
64        # the file read only doesn't make rename fail on unix, so make the
65        # directory read only as well.
66        os.chmod(filename, stat.S_IREAD)
67        os.chmod(self.dir, stat.S_IREAD)
68        try:
69            with self.assertRaises(OSError):
70                with atomic_save(filename, "wb") as fobj:
71                    fobj.write(b"foo")
72        finally:
73            # restore permissions
74            os.chmod(self.dir, dir_mode)
75            os.chmod(filename, file_mode)
76
77        with open(filename, "rb") as fobj:
78            self.assertEqual(fobj.read(), b"nope")
79
80        self.assertEqual(os.listdir(self.dir), [os.path.basename(filename)])
81