~ubuntu-branches/ubuntu/karmic/pypy/karmic

« back to all changes in this revision

Viewing changes to lib-python/2.4.1/test/test_mmap.py

  • Committer: Bazaar Package Importer
  • Author(s): Alexandre Fayolle
  • Date: 2007-04-13 09:33:09 UTC
  • Revision ID: james.westby@ubuntu.com-20070413093309-yoojh4jcoocu2krz
Tags: upstream-1.0.0
ImportĀ upstreamĀ versionĀ 1.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
from test.test_support import verify, vereq, TESTFN
 
2
import mmap
 
3
import os, re
 
4
 
 
5
PAGESIZE = mmap.PAGESIZE
 
6
 
 
7
def test_both():
 
8
    "Test mmap module on Unix systems and Windows"
 
9
 
 
10
    # Create a file to be mmap'ed.
 
11
    if os.path.exists(TESTFN):
 
12
        os.unlink(TESTFN)
 
13
    f = open(TESTFN, 'w+')
 
14
 
 
15
    try:    # unlink TESTFN no matter what
 
16
        # Write 2 pages worth of data to the file
 
17
        f.write('\0'* PAGESIZE)
 
18
        f.write('foo')
 
19
        f.write('\0'* (PAGESIZE-3) )
 
20
        f.flush()
 
21
        m = mmap.mmap(f.fileno(), 2 * PAGESIZE)
 
22
        f.close()
 
23
 
 
24
        # Simple sanity checks
 
25
 
 
26
        print type(m)  # SF bug 128713:  segfaulted on Linux
 
27
        print '  Position of foo:', m.find('foo') / float(PAGESIZE), 'pages'
 
28
        vereq(m.find('foo'), PAGESIZE)
 
29
 
 
30
        print '  Length of file:', len(m) / float(PAGESIZE), 'pages'
 
31
        vereq(len(m), 2*PAGESIZE)
 
32
 
 
33
        print '  Contents of byte 0:', repr(m[0])
 
34
        vereq(m[0], '\0')
 
35
        print '  Contents of first 3 bytes:', repr(m[0:3])
 
36
        vereq(m[0:3], '\0\0\0')
 
37
 
 
38
        # Modify the file's content
 
39
        print "\n  Modifying file's content..."
 
40
        m[0] = '3'
 
41
        m[PAGESIZE +3: PAGESIZE +3+3] = 'bar'
 
42
 
 
43
        # Check that the modification worked
 
44
        print '  Contents of byte 0:', repr(m[0])
 
45
        vereq(m[0], '3')
 
46
        print '  Contents of first 3 bytes:', repr(m[0:3])
 
47
        vereq(m[0:3], '3\0\0')
 
48
        print '  Contents of second page:',  repr(m[PAGESIZE-1 : PAGESIZE + 7])
 
49
        vereq(m[PAGESIZE-1 : PAGESIZE + 7], '\0foobar\0')
 
50
 
 
51
        m.flush()
 
52
 
 
53
        # Test doing a regular expression match in an mmap'ed file
 
54
        match = re.search('[A-Za-z]+', m)
 
55
        if match is None:
 
56
            print '  ERROR: regex match on mmap failed!'
 
57
        else:
 
58
            start, end = match.span(0)
 
59
            length = end - start
 
60
 
 
61
            print '  Regex match on mmap (page start, length of match):',
 
62
            print start / float(PAGESIZE), length
 
63
 
 
64
            vereq(start, PAGESIZE)
 
65
            vereq(end, PAGESIZE + 6)
 
66
 
 
67
        # test seeking around (try to overflow the seek implementation)
 
68
        m.seek(0,0)
 
69
        print '  Seek to zeroth byte'
 
70
        vereq(m.tell(), 0)
 
71
        m.seek(42,1)
 
72
        print '  Seek to 42nd byte'
 
73
        vereq(m.tell(), 42)
 
74
        m.seek(0,2)
 
75
        print '  Seek to last byte'
 
76
        vereq(m.tell(), len(m))
 
77
 
 
78
        print '  Try to seek to negative position...'
 
79
        try:
 
80
            m.seek(-1)
 
81
        except ValueError:
 
82
            pass
 
83
        else:
 
84
            verify(0, 'expected a ValueError but did not get it')
 
85
 
 
86
        print '  Try to seek beyond end of mmap...'
 
87
        try:
 
88
            m.seek(1,2)
 
89
        except ValueError:
 
90
            pass
 
91
        else:
 
92
            verify(0, 'expected a ValueError but did not get it')
 
93
 
 
94
        print '  Try to seek to negative position...'
 
95
        try:
 
96
            m.seek(-len(m)-1,2)
 
97
        except ValueError:
 
98
            pass
 
99
        else:
 
100
            verify(0, 'expected a ValueError but did not get it')
 
101
 
 
102
        # Try resizing map
 
103
        print '  Attempting resize()'
 
104
        try:
 
105
            m.resize(512)
 
106
        except SystemError:
 
107
            # resize() not supported
 
108
            # No messages are printed, since the output of this test suite
 
109
            # would then be different across platforms.
 
110
            pass
 
111
        else:
 
112
            # resize() is supported
 
113
            verify(len(m) == 512,
 
114
                    "len(m) is %d, but expecting 512" % (len(m),) )
 
115
            # Check that we can no longer seek beyond the new size.
 
116
            try:
 
117
                m.seek(513,0)
 
118
            except ValueError:
 
119
                pass
 
120
            else:
 
121
                verify(0, 'Could seek beyond the new size')
 
122
 
 
123
        m.close()
 
124
 
 
125
    finally:
 
126
        try:
 
127
            f.close()
 
128
        except OSError:
 
129
            pass
 
130
        try:
 
131
            os.unlink(TESTFN)
 
132
        except OSError:
 
133
            pass
 
134
 
 
135
    # Test for "access" keyword parameter
 
136
    try:
 
137
        mapsize = 10
 
138
        print "  Creating", mapsize, "byte test data file."
 
139
        open(TESTFN, "wb").write("a"*mapsize)
 
140
        print "  Opening mmap with access=ACCESS_READ"
 
141
        f = open(TESTFN, "rb")
 
142
        m = mmap.mmap(f.fileno(), mapsize, access=mmap.ACCESS_READ)
 
143
        verify(m[:] == 'a'*mapsize, "Readonly memory map data incorrect.")
 
144
 
 
145
        print "  Ensuring that readonly mmap can't be slice assigned."
 
146
        try:
 
147
            m[:] = 'b'*mapsize
 
148
        except TypeError:
 
149
            pass
 
150
        else:
 
151
            verify(0, "Able to write to readonly memory map")
 
152
 
 
153
        print "  Ensuring that readonly mmap can't be item assigned."
 
154
        try:
 
155
            m[0] = 'b'
 
156
        except TypeError:
 
157
            pass
 
158
        else:
 
159
            verify(0, "Able to write to readonly memory map")
 
160
 
 
161
        print "  Ensuring that readonly mmap can't be write() to."
 
162
        try:
 
163
            m.seek(0,0)
 
164
            m.write('abc')
 
165
        except TypeError:
 
166
            pass
 
167
        else:
 
168
            verify(0, "Able to write to readonly memory map")
 
169
 
 
170
        print "  Ensuring that readonly mmap can't be write_byte() to."
 
171
        try:
 
172
            m.seek(0,0)
 
173
            m.write_byte('d')
 
174
        except TypeError:
 
175
            pass
 
176
        else:
 
177
            verify(0, "Able to write to readonly memory map")
 
178
 
 
179
        print "  Ensuring that readonly mmap can't be resized."
 
180
        try:
 
181
            m.resize(2*mapsize)
 
182
        except SystemError:   # resize is not universally supported
 
183
            pass
 
184
        except TypeError:
 
185
            pass
 
186
        else:
 
187
            verify(0, "Able to resize readonly memory map")
 
188
        del m, f
 
189
        verify(open(TESTFN, "rb").read() == 'a'*mapsize,
 
190
               "Readonly memory map data file was modified")
 
191
 
 
192
        print "  Opening mmap with size too big"
 
193
        import sys
 
194
        f = open(TESTFN, "r+b")
 
195
        try:
 
196
            m = mmap.mmap(f.fileno(), mapsize+1)
 
197
        except ValueError:
 
198
            # we do not expect a ValueError on Windows
 
199
            # CAUTION:  This also changes the size of the file on disk, and
 
200
            # later tests assume that the length hasn't changed.  We need to
 
201
            # repair that.
 
202
            if sys.platform.startswith('win'):
 
203
                verify(0, "Opening mmap with size+1 should work on Windows.")
 
204
        else:
 
205
            # we expect a ValueError on Unix, but not on Windows
 
206
            if not sys.platform.startswith('win'):
 
207
                verify(0, "Opening mmap with size+1 should raise ValueError.")
 
208
            m.close()
 
209
        f.close()
 
210
        if sys.platform.startswith('win'):
 
211
            # Repair damage from the resizing test.
 
212
            f = open(TESTFN, 'r+b')
 
213
            f.truncate(mapsize)
 
214
            f.close()
 
215
 
 
216
        print "  Opening mmap with access=ACCESS_WRITE"
 
217
        f = open(TESTFN, "r+b")
 
218
        m = mmap.mmap(f.fileno(), mapsize, access=mmap.ACCESS_WRITE)
 
219
        print "  Modifying write-through memory map."
 
220
        m[:] = 'c'*mapsize
 
221
        verify(m[:] == 'c'*mapsize,
 
222
               "Write-through memory map memory not updated properly.")
 
223
        m.flush()
 
224
        m.close()
 
225
        f.close()
 
226
        f = open(TESTFN, 'rb')
 
227
        stuff = f.read()
 
228
        f.close()
 
229
        verify(stuff == 'c'*mapsize,
 
230
               "Write-through memory map data file not updated properly.")
 
231
 
 
232
        print "  Opening mmap with access=ACCESS_COPY"
 
233
        f = open(TESTFN, "r+b")
 
234
        m = mmap.mmap(f.fileno(), mapsize, access=mmap.ACCESS_COPY)
 
235
        print "  Modifying copy-on-write memory map."
 
236
        m[:] = 'd'*mapsize
 
237
        verify(m[:] == 'd' * mapsize,
 
238
               "Copy-on-write memory map data not written correctly.")
 
239
        m.flush()
 
240
        verify(open(TESTFN, "rb").read() == 'c'*mapsize,
 
241
               "Copy-on-write test data file should not be modified.")
 
242
        try:
 
243
            print "  Ensuring copy-on-write maps cannot be resized."
 
244
            m.resize(2*mapsize)
 
245
        except TypeError:
 
246
            pass
 
247
        else:
 
248
            verify(0, "Copy-on-write mmap resize did not raise exception.")
 
249
        del m, f
 
250
        try:
 
251
            print "  Ensuring invalid access parameter raises exception."
 
252
            f = open(TESTFN, "r+b")
 
253
            m = mmap.mmap(f.fileno(), mapsize, access=4)
 
254
        except ValueError:
 
255
            pass
 
256
        else:
 
257
            verify(0, "Invalid access code should have raised exception.")
 
258
 
 
259
        if os.name == "posix":
 
260
            # Try incompatible flags, prot and access parameters.
 
261
            f = open(TESTFN, "r+b")
 
262
            try:
 
263
                m = mmap.mmap(f.fileno(), mapsize, flags=mmap.MAP_PRIVATE,
 
264
                              prot=mmap.PROT_READ, access=mmap.ACCESS_WRITE)
 
265
            except ValueError:
 
266
                pass
 
267
            else:
 
268
                verify(0, "Incompatible parameters should raise ValueError.")
 
269
            f.close()
 
270
    finally:
 
271
        try:
 
272
            os.unlink(TESTFN)
 
273
        except OSError:
 
274
            pass
 
275
 
 
276
    # Do a tougher .find() test.  SF bug 515943 pointed out that, in 2.2,
 
277
    # searching for data with embedded \0 bytes didn't work.
 
278
    f = open(TESTFN, 'w+')
 
279
 
 
280
    try:    # unlink TESTFN no matter what
 
281
        data = 'aabaac\x00deef\x00\x00aa\x00'
 
282
        n = len(data)
 
283
        f.write(data)
 
284
        f.flush()
 
285
        m = mmap.mmap(f.fileno(), n)
 
286
        f.close()
 
287
 
 
288
        for start in range(n+1):
 
289
            for finish in range(start, n+1):
 
290
                slice = data[start : finish]
 
291
                vereq(m.find(slice), data.find(slice))
 
292
                vereq(m.find(slice + 'x'), -1)
 
293
        m.close()
 
294
 
 
295
    finally:
 
296
        os.unlink(TESTFN)
 
297
 
 
298
    # make sure a double close doesn't crash on Solaris (Bug# 665913)
 
299
    f = open(TESTFN, 'w+')
 
300
 
 
301
    try:    # unlink TESTFN no matter what
 
302
        f.write(2**16 * 'a') # Arbitrary character
 
303
        f.close()
 
304
 
 
305
        f = open(TESTFN)
 
306
        mf = mmap.mmap(f.fileno(), 2**16, access=mmap.ACCESS_READ)
 
307
        mf.close()
 
308
        mf.close()
 
309
        f.close()
 
310
 
 
311
    finally:
 
312
        os.unlink(TESTFN)
 
313
 
 
314
 
 
315
    print ' Test passed'
 
316
 
 
317
test_both()