~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to ivle/testfilespace.py

  • Committer: David Coles
  • Date: 2010-07-20 05:42:59 UTC
  • Revision ID: coles.david@gmail.com-20100720054259-j4xyqagognlis8wh
Added Subversion rename to Filebrowser.

Allows for versioned files to be renamed without having to delete/add them.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# IVLE - Informatics Virtual Learning Environment
 
2
# Copyright (C) 2007-2008 The University of Melbourne
 
3
#
 
4
# This program is free software; you can redistribute it and/or modify
 
5
# it under the terms of the GNU General Public License as published by
 
6
# the Free Software Foundation; either version 2 of the License, or
 
7
# (at your option) any later version.
 
8
#
 
9
# This program is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
# GNU General Public License for more details.
 
13
#
 
14
# You should have received a copy of the GNU General Public License
 
15
# along with this program; if not, write to the Free Software
 
16
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
17
 
 
18
# Module: TestFilespace
 
19
# Author: Dilshan Angampitiya
 
20
#         Steven Bird (revisions)
 
21
#         David Coles (revisions and moved to module)
 
22
# Date:   24/1/2008
 
23
 
 
24
import StringIO
 
25
 
 
26
class TestFilespace:
 
27
    """
 
28
    Our dummy file system which is accessed by code being tested.
 
29
    Implemented as a dictionary which maps filenames to strings
 
30
    """
 
31
    def __init__(self, files=None):
 
32
        "Initialise, optionally with filename-filedata pairs"
 
33
 
 
34
        if files == None:
 
35
            files = {}
 
36
 
 
37
        # dict mapping files to strings
 
38
        self._files = {}
 
39
        self._files.update(files)
 
40
        # set of file names
 
41
        self._modified_files = set([])
 
42
        # dict mapping files to stringIO objects
 
43
        self._open_files = {}
 
44
 
 
45
    def add_file(self, filename, data):
 
46
        " Add a file to the filespace "
 
47
        self._files[filename] = data
 
48
 
 
49
    def openfile(self, filename, mode='r'):
 
50
        """ Open a file from the filespace with the given mode.
 
51
        Return a StringIO subclass object with the file contents.
 
52
        """
 
53
        # currently very messy, needs to be cleaned up
 
54
        # Probably most of this should be in the initialiser to the TestStringIO
 
55
        
 
56
        import re
 
57
 
 
58
        if filename in self._open_files:
 
59
            raise IOError("File already open: %s" %filename)
 
60
 
 
61
        if not re.compile("[rwa][+b]{0,2}").match(mode):
 
62
            raise IOError("invalid mode %s" %mode)
 
63
        
 
64
        ## TODO: validate filename?
 
65
        
 
66
        mode.replace("b",'')
 
67
        
 
68
        # initialise the file properly (truncate/create if required)
 
69
        if mode[0] == 'w':
 
70
            self._files[filename] = ''
 
71
            self._modified_files.add(filename)
 
72
        elif filename not in self._files:
 
73
            if mode[0] == 'a':
 
74
                self._files[filename] = ''
 
75
                self._modified_files.add(filename)
 
76
            else:
 
77
                raise IOError(2, "Access to file denied: %s" %filename)
 
78
 
 
79
        # for append mode, remember the existing data
 
80
        if mode[0] == 'a':
 
81
            existing_data = self._files[filename]
 
82
        else:
 
83
            existing_data = ""
 
84
 
 
85
        # determine what operations are allowed
 
86
        reading_ok = (len(mode) == 2 or mode[0] == 'r')
 
87
        writing_ok = (len(mode) == 2 or mode[0] in 'wa')
 
88
 
 
89
        # for all writing modes, start off with blank file
 
90
        if mode[0] == 'w':
 
91
            initial_data = ''
 
92
        else:
 
93
            initial_data = self._files[filename]
 
94
 
 
95
        file_object = TestStringIO(initial_data, filename, self, reading_ok, writing_ok, existing_data)
 
96
        self._open_files[filename] = file_object
 
97
        
 
98
        return file_object
 
99
 
 
100
    def flush_all(self):
 
101
        """ Flush all open files
 
102
        """
 
103
        for file_object in self._open_files.values():
 
104
            file_object.flush()
 
105
 
 
106
    def updatefile(self,filename, data):
 
107
        """ Callback function used by an open file to inform when it has been updated.
 
108
        """
 
109
        if filename in self._open_files:
 
110
            self._files[filename] = data
 
111
            if self._open_files[filename].is_modified():
 
112
                self._modified_files.add(filename)
 
113
        else:
 
114
            raise IOError(2, "Access to file denied: %s" %filename)
 
115
 
 
116
    def closefile(self, filename):
 
117
        """ Callback function used by an open file to inform when it has been closed.
 
118
        """
 
119
        if filename in self._open_files:
 
120
            del self._open_files[filename]
 
121
 
 
122
    def get_modified_files(self):
 
123
        """" A subset of the filespace containing only those files which have been
 
124
        modified
 
125
        """
 
126
        modified_files = {}
 
127
        for filename in self._modified_files:
 
128
            modified_files[filename] = self._files[filename]
 
129
 
 
130
        return modified_files
 
131
 
 
132
    def get_open_files(self):
 
133
        " Return the names of all open files "
 
134
        return self._open_files.keys()
 
135
            
 
136
    def copy(self):
 
137
        """ Return a copy of the current filespace.
 
138
        Only the files are copied, not the modified or open file lists.
 
139
        """
 
140
        self.flush_all()
 
141
        return TestFilespace(self._files)
 
142
 
 
143
class TestStringIO(StringIO.StringIO):
 
144
    """
 
145
    A subclass of StringIO which acts as a file in our dummy file system
 
146
    """
 
147
    def __init__(self, string, filename, filespace, reading_ok, writing_ok, existing_data):
 
148
        """ Initialise with the filedata, file name and infomation on what ops are
 
149
        acceptable """
 
150
        StringIO.StringIO.__init__(self, string)
 
151
        self._filename = filename
 
152
        self._filespace = filespace
 
153
        self._reading_ok = reading_ok
 
154
        self._writing_ok = writing_ok
 
155
        self._existing_data = existing_data
 
156
        self._modified = False
 
157
        self._open = True
 
158
 
 
159
    # Override all standard file ops. Make sure that they are valid with the given
 
160
    # permissions and if so then call the corresponding method in StringIO
 
161
    
 
162
    def read(self, *args):
 
163
        if not self._reading_ok:
 
164
            raise IOError(9, "Bad file descriptor")
 
165
        else:
 
166
            return StringIO.StringIO.read(self, *args)
 
167
 
 
168
    def readline(self, *args):
 
169
        if not self._reading_ok:
 
170
            raise IOError(9, "Bad file descriptor")
 
171
        else:
 
172
            return StringIO.StringIO.readline(self, *args)
 
173
 
 
174
    def readlines(self, *args):
 
175
        if not self._reading_ok:
 
176
            raise IOError(9, "Bad file descriptor")
 
177
        else:
 
178
            return StringIO.StringIO.readlines(self, *args)
 
179
 
 
180
    def seek(self, *args):
 
181
        if not self._reading_ok:
 
182
            raise IOError(9, "Bad file descriptor")
 
183
        else:
 
184
            return StringIO.StringIO.seek(self, *args)
 
185
 
 
186
    def truncate(self, *args):
 
187
        self._modified = True
 
188
        if not self._writing_ok:
 
189
            raise IOError(9, "Bad file descriptor")
 
190
        else:
 
191
            return StringIO.StringIO.truncate(self, *args)
 
192
        
 
193
    def write(self, *args):
 
194
        self._modified = True
 
195
        if not self._writing_ok:
 
196
            raise IOError(9, "Bad file descriptor")
 
197
        else:
 
198
            return StringIO.StringIO.write(self, *args)
 
199
 
 
200
    def writelines(self, *args):
 
201
        self._modified = True
 
202
        if not self._writing_ok:
 
203
            raise IOError(9, "Bad file descriptor")
 
204
        else:
 
205
            return StringIO.StringIO.writelines(self, *args)
 
206
 
 
207
    def is_modified(self):
 
208
        " Return true if the file has been written to, or truncated"
 
209
        return self._modified
 
210
        
 
211
    def flush(self):
 
212
        " Update the contents of the filespace with the new data "
 
213
        self._filespace.updatefile(self._filename, self._existing_data+self.getvalue())
 
214
        return StringIO.StringIO.flush(self)
 
215
 
 
216
    def close(self):
 
217
        " Flush the file and close it "
 
218
        self.flush()
 
219
        self._filespace.closefile(self._filename)
 
220
        return StringIO.StringIO.close(self)
 
221