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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# IVLE - Informatics Virtual Learning Environment
# Copyright (C) 2007-2008 The University of Melbourne
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

# Module: TestFilespace
# Author: Dilshan Angampitiya
#         Steven Bird (revisions)
#         David Coles (revisions and moved to module)
# Date:   24/1/2008

import StringIO

class TestFilespace:
    """
    Our dummy file system which is accessed by code being tested.
    Implemented as a dictionary which maps filenames to strings
    """
    def __init__(self, files=None):
        "Initialise, optionally with filename-filedata pairs"

        if files == None:
            files = {}

        # dict mapping files to strings
        self._files = {}
        self._files.update(files)
        # set of file names
        self._modified_files = set([])
        # dict mapping files to stringIO objects
        self._open_files = {}

    def add_file(self, filename, data):
        " Add a file to the filespace "
        self._files[filename] = data

    def openfile(self, filename, mode='r'):
        """ Open a file from the filespace with the given mode.
        Return a StringIO subclass object with the file contents.
        """
        # currently very messy, needs to be cleaned up
        # Probably most of this should be in the initialiser to the TestStringIO
        
        import re

        if filename in self._open_files:
            raise IOError("File already open: %s" %filename)

        if not re.compile("[rwa][+b]{0,2}").match(mode):
            raise IOError("invalid mode %s" %mode)
        
        ## TODO: validate filename?
        
        mode.replace("b",'')
        
        # initialise the file properly (truncate/create if required)
        if mode[0] == 'w':
            self._files[filename] = ''
            self._modified_files.add(filename)
        elif filename not in self._files:
            if mode[0] == 'a':
                self._files[filename] = ''
                self._modified_files.add(filename)
            else:
                raise IOError(2, "Access to file denied: %s" %filename)

        # for append mode, remember the existing data
        if mode[0] == 'a':
            existing_data = self._files[filename]
        else:
            existing_data = ""

        # determine what operations are allowed
        reading_ok = (len(mode) == 2 or mode[0] == 'r')
        writing_ok = (len(mode) == 2 or mode[0] in 'wa')

        # for all writing modes, start off with blank file
        if mode[0] == 'w':
            initial_data = ''
        else:
            initial_data = self._files[filename]

        file_object = TestStringIO(initial_data, filename, self, reading_ok, writing_ok, existing_data)
        self._open_files[filename] = file_object
        
        return file_object

    def flush_all(self):
        """ Flush all open files
        """
        for file_object in self._open_files.values():
            file_object.flush()

    def updatefile(self,filename, data):
        """ Callback function used by an open file to inform when it has been updated.
        """
        if filename in self._open_files:
            self._files[filename] = data
            if self._open_files[filename].is_modified():
                self._modified_files.add(filename)
        else:
            raise IOError(2, "Access to file denied: %s" %filename)

    def closefile(self, filename):
        """ Callback function used by an open file to inform when it has been closed.
        """
        if filename in self._open_files:
            del self._open_files[filename]

    def get_modified_files(self):
        """" A subset of the filespace containing only those files which have been
        modified
        """
        modified_files = {}
        for filename in self._modified_files:
            modified_files[filename] = self._files[filename]

        return modified_files

    def get_open_files(self):
        " Return the names of all open files "
        return self._open_files.keys()
            
    def copy(self):
        """ Return a copy of the current filespace.
        Only the files are copied, not the modified or open file lists.
        """
        self.flush_all()
        return TestFilespace(self._files)

class TestStringIO(StringIO.StringIO):
    """
    A subclass of StringIO which acts as a file in our dummy file system
    """
    def __init__(self, string, filename, filespace, reading_ok, writing_ok, existing_data):
        """ Initialise with the filedata, file name and infomation on what ops are
        acceptable """
        StringIO.StringIO.__init__(self, string)
        self._filename = filename
        self._filespace = filespace
        self._reading_ok = reading_ok
        self._writing_ok = writing_ok
        self._existing_data = existing_data
        self._modified = False
        self._open = True

    # Override all standard file ops. Make sure that they are valid with the given
    # permissions and if so then call the corresponding method in StringIO
    
    def read(self, *args):
        if not self._reading_ok:
            raise IOError(9, "Bad file descriptor")
        else:
            return StringIO.StringIO.read(self, *args)

    def readline(self, *args):
        if not self._reading_ok:
            raise IOError(9, "Bad file descriptor")
        else:
            return StringIO.StringIO.readline(self, *args)

    def readlines(self, *args):
        if not self._reading_ok:
            raise IOError(9, "Bad file descriptor")
        else:
            return StringIO.StringIO.readlines(self, *args)

    def seek(self, *args):
        if not self._reading_ok:
            raise IOError(9, "Bad file descriptor")
        else:
            return StringIO.StringIO.seek(self, *args)

    def truncate(self, *args):
        self._modified = True
        if not self._writing_ok:
            raise IOError(9, "Bad file descriptor")
        else:
            return StringIO.StringIO.truncate(self, *args)
        
    def write(self, *args):
        self._modified = True
        if not self._writing_ok:
            raise IOError(9, "Bad file descriptor")
        else:
            return StringIO.StringIO.write(self, *args)

    def writelines(self, *args):
        self._modified = True
        if not self._writing_ok:
            raise IOError(9, "Bad file descriptor")
        else:
            return StringIO.StringIO.writelines(self, *args)

    def is_modified(self):
        " Return true if the file has been written to, or truncated"
        return self._modified
        
    def flush(self):
        " Update the contents of the filespace with the new data "
        self._filespace.updatefile(self._filename, self._existing_data+self.getvalue())
        return StringIO.StringIO.flush(self)

    def close(self):
        " Flush the file and close it "
        self.flush()
        self._filespace.closefile(self._filename)
        return StringIO.StringIO.close(self)