[System.Core] Updated MemoryMappedFileTest
[mono.git] / mcs / class / System.Core / Test / System.IO.MemoryMappedFiles / MemoryMappedFileTest.cs
1 //
2 // MemoryMappedFileTest.cs
3 //
4 // Author:
5 //   Zoltan Varga (vargaz@gmail.com)
6 //
7 // (C) 2009 Novell, Inc. (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 #if NET_4_0
30
31 using System;
32 using System.IO;
33 using System.IO.MemoryMappedFiles;
34 using System.Linq;
35
36 using NUnit.Framework;
37
38 namespace MonoTests.System.IO.MemoryMappedFiles {
39
40         [TestFixture]
41         public class MemoryMappedFileTest {
42
43                 void AssertThrows<ExType> (Action del) where ExType : Exception {
44                         bool thrown = false;
45
46                         try {
47                                 del ();
48                         } catch (ExType) {
49                                 thrown = true;
50                         }
51                         Assert.IsTrue (thrown);
52                 }
53
54                 static int named_index;
55                 static String MkNamedMapping ()
56                 {
57                         return "test-" + named_index++;
58                 }
59
60
61                 static string tempDir = Path.Combine (Path.GetTempPath (), typeof (MemoryMappedFileTest).FullName);
62
63                 string fname;
64
65                 [SetUp]
66                 protected void SetUp () {
67                         if (Directory.Exists (tempDir))
68                                 Directory.Delete (tempDir, true);
69
70                         Directory.CreateDirectory (tempDir);
71
72                         fname = Path.Combine (tempDir, "basic.txt");
73
74                         using (StreamWriter sw = new StreamWriter (fname)) {
75                                 sw.WriteLine ("Hello!");
76                                 sw.WriteLine ("World!");
77                         }
78                 }
79
80                 [TearDown]
81                 protected void TearDown () {
82                         if (Directory.Exists (tempDir))
83                                 Directory.Delete (tempDir, true);
84                 }
85
86                 [Test]
87                 public void Basic () {
88                         var file = MemoryMappedFile.CreateFromFile (fname, FileMode.Open);
89
90                         using (var stream = file.CreateViewStream ()) {
91                                 TextReader r = new StreamReader (stream);
92
93                                 string s;
94
95                                 s = r.ReadLine ();
96                                 Assert.AreEqual ("Hello!", s);
97                                 s = r.ReadLine ();
98                                 Assert.AreEqual ("World!", s);
99                         }
100                 }
101
102                 [Test]
103                 public void CreateNew ()
104                 {
105                         // This must succeed
106                         MemoryMappedFile.CreateNew (Path.Combine (tempDir, "createNew.test"), 8192);
107                 }
108
109                 [Test]
110                 [ExpectedException (typeof (IOException))]
111                 public void CreateNew_OnExistingFile ()
112                 {
113                         // This must succeed
114                         MemoryMappedFile.CreateNew (Path.Combine (tempDir, "createNew.test"), 8192);
115                         
116                         // This should fail, the file exists
117                         MemoryMappedFile.CreateNew (Path.Combine (tempDir, "createNew.test"), 8192);
118                 }
119
120                 // Call this twice, it should always work
121                 [Test]
122                 public void CreateOrOpen_Multiple ()
123                 {
124                         MemoryMappedFile.CreateOrOpen (Path.Combine (tempDir, "createOrOpen.test"), 8192);
125                         MemoryMappedFile.CreateOrOpen (Path.Combine (tempDir, "createOrOpen.test"), 8192);
126                 }
127
128                 [Test]
129                 [ExpectedException(typeof(ArgumentOutOfRangeException))]
130                 public void CreateFromFileWithSmallerCapacityThanFile ()
131                 {
132                         var f = Path.Combine (tempDir, "8192-file");
133                         File.WriteAllBytes (f, new byte [8192]);
134
135                         // We are requesting fewer bytes to map.
136                         MemoryMappedFile.CreateFromFile (f, FileMode.Open, "myMap", 4192);
137                 }
138         
139                 [Test]
140                 public void CreateFromFile_Null () {
141                         AssertThrows<ArgumentNullException> (delegate () {
142                                         MemoryMappedFile.CreateFromFile (null);
143                                 });
144                 }
145
146                 [Test]
147                 public void CreateViewStream_Offsets () {
148                         var file = MemoryMappedFile.CreateFromFile (fname, FileMode.Open);
149
150                         using (var stream = file.CreateViewStream (2, 3)) {
151                                 byte[] arr = new byte [128];
152
153                                 int len = stream.Read (arr, 0, 128);
154
155                                 Assert.AreEqual (3, len);
156
157                                 Assert.AreEqual ('l', (char)arr [0]);
158                                 Assert.AreEqual ('l', (char)arr [1]);
159                                 Assert.AreEqual ('o', (char)arr [2]);
160                         }
161                 }
162
163                 [Test]
164                 public void CreateViewStream_Rights () {
165                         var file = MemoryMappedFile.CreateFromFile (fname, FileMode.Open);
166
167                         using (var stream = file.CreateViewStream (0, 0, MemoryMappedFileAccess.Read)) {
168                                 AssertThrows<NotSupportedException> (delegate () {
169                                                 stream.WriteByte (0);
170                                         });
171                         }
172
173                         using (var stream = file.CreateViewStream (0, 0, MemoryMappedFileAccess.Write)) {
174                                 AssertThrows<NotSupportedException> (delegate () {
175                                                 stream.ReadByte ();
176                                         });
177                         }
178                 }
179
180                 [Test]
181                 public unsafe void CreateViewBasic () {
182                         var file = MemoryMappedFile.CreateFromFile (fname, FileMode.Open);
183
184                         using (var v = file.CreateViewAccessor ()) {
185                                 string s = "";
186
187                                 // FIXME: Use using
188                                 var handle = v.SafeMemoryMappedViewHandle;
189                                 byte *b = null;
190
191                                 try {
192                                         handle.AcquirePointer (ref b);
193
194                                         for (int i = 0; i < 5; ++i)
195                                                 s += (char)b [i];
196                                 } finally {
197                                         handle.ReleasePointer ();
198                                 }
199
200                                 Assert.AreEqual ("Hello", s);
201                         }
202                 }
203
204                 [Test]
205                 public unsafe void ViewReadArray () {
206                         var file = MemoryMappedFile.CreateFromFile (fname, FileMode.Open);
207
208                         using (var v = file.CreateViewAccessor ()) {
209                                 var a = new byte [5];
210                                 var n = v.ReadArray (0, a, 0, 5);
211                                 Assert.AreEqual (5, n);
212                                 var s = new string (Array.ConvertAll (a, b => (char)b));
213                                 Assert.AreEqual ("Hello", s);
214                         }
215                 }
216
217                 [Test]
218                 public unsafe void ViewAccessorReadArrayWithOffset () {
219                         var file = MemoryMappedFile.CreateFromFile (fname, FileMode.Open);
220                         var offset = 3;
221                         var expected = "lo!";
222
223                         using (var v = file.CreateViewAccessor (offset, expected.Length)) {
224                                 // PointerOffset Mono implementation is always 0.
225                                 // Assert.AreEqual (offset, v.PointerOffset);
226
227                                 var a = new byte [expected.Length];
228                                 var n = v.ReadArray (0, a, 0, expected.Length);
229                                 Assert.AreEqual (expected.Length, n);
230                                 var s = new string (Array.ConvertAll (a, b => (char)b));
231                                 Assert.AreEqual (expected, s);
232                         }
233                 }
234
235                 [Test]
236                 public unsafe void ViewStreamReadWithOffset () {
237                         var file = MemoryMappedFile.CreateFromFile (fname, FileMode.Open);
238                         var offset = 3;
239                         var expected = "lo!";
240
241                         using (var v = file.CreateViewStream (offset, expected.Length)) {
242                                 // PointerOffset Mono implementation is always 0.
243                                 // Assert.AreEqual (offset, v.PointerOffset);
244
245                                 var a = new byte [expected.Length];
246                                 var n = v.Read (a, 0, expected.Length);
247                                 Assert.AreEqual (expected.Length, n);
248                                 var s = new string (Array.ConvertAll (a, b => (char)b));
249                                 Assert.AreEqual (expected, s);
250                         }
251                 }
252
253                 [Test]
254                 public void NamedMappingToInvalidFile ()
255                 {
256                         var fileName = Path.Combine (tempDir, "temp_file_123");
257                 if (File.Exists (fileName))
258                     File.Delete (fileName);
259                 var memoryMappedFile90 = MemoryMappedFile.CreateNew (fileName, 4194304, MemoryMappedFileAccess.ReadWrite);
260                 memoryMappedFile90.CreateViewStream (4186112, 3222, MemoryMappedFileAccess.Write);
261                 }
262
263                 [Test]
264                 public void CreateTheSameAreaTwiceShouldFail ()
265                 {
266                         var name = MkNamedMapping ();
267                         using (var m0 = MemoryMappedFile.CreateNew(name, 4096, MemoryMappedFileAccess.ReadWrite)) {
268                                 try {
269                                         using (var m1 = MemoryMappedFile.CreateNew (name, 4096, MemoryMappedFileAccess.ReadWrite)) {
270                                                 Assert.Fail ("Must fail");
271                                         }
272                                 } catch (IOException) {}
273                         }
274                 }
275
276                 [Test]
277                 public void MapAFileToAMemoryAreaShouldFail ()
278                 {
279                         var name = MkNamedMapping ();
280                         using (var m0 = MemoryMappedFile.CreateNew(name, 4096, MemoryMappedFileAccess.ReadWrite)) {
281                                 try {
282                                         using (var m1 = MemoryMappedFile.CreateFromFile (fname, FileMode.OpenOrCreate, name)) {
283                                                 Assert.Fail ("Must fail");
284                                         }
285                                 } catch (IOException) {}
286                         }
287                 }
288
289                 [Test]
290                 public void NamedMappingsShareMemoryArea ()
291                 {
292                         var name = MkNamedMapping ();
293                         using (var m0 = MemoryMappedFile.CreateNew(name, 4096, MemoryMappedFileAccess.ReadWrite)) {
294                                 using (var m1 = MemoryMappedFile.CreateOrOpen (name, 4096, MemoryMappedFileAccess.ReadWrite)) {
295                                         using (MemoryMappedViewAccessor v0 = m0.CreateViewAccessor (), v1 = m1.CreateViewAccessor ()) {
296                                                 v0.Write (10, 0x12345);
297                                                 Assert.AreEqual (0x12345, v1.ReadInt32 (10));
298                                         }
299                                 }
300                         }
301                 }
302
303                 [Test]
304                 public void NamedFileCanBeOpen ()
305                 {
306                         var name = MkNamedMapping ();
307                         using (var sw = new FileStream (fname, FileMode.Open)) {
308                                 byte[] b = new byte[20];
309                                 for (int i = 0; i < 20; ++i)
310                                         b[i] = 0xFF;
311                                 sw.Write (b, 0, 20);
312                         }
313
314                         using (var m0 = MemoryMappedFile.CreateFromFile (fname, FileMode.Open, name)) {
315                                 using (var m1 = MemoryMappedFile.CreateOrOpen (name, 4096)) {
316                                         using (MemoryMappedViewAccessor v0 = m0.CreateViewAccessor (), v1 = m1.CreateViewAccessor ()) {
317                                                 v0.Write (10, 0x11223344);
318                                                 Assert.AreEqual (0x11223344, v1.ReadInt32 (10));
319                                         }
320                                 }
321                         }
322                 }
323
324                 [Test]
325                 public void MapAtEdgeOfPage ()
326                 {
327                         using (var f = new FileStream (fname, FileMode.Open)) {
328                                 var b = new byte [4096];
329                                 for (int i = 0; i < 4096; ++i)
330                                         b[i] = 0xAA;
331                                 for (int i = 0; i < 2; ++i)
332                                         f.Write (b, 0, 4096);
333                         }
334                         var m0 = MemoryMappedFile.CreateFromFile (fname, FileMode.Open);
335                         var v0 = m0.CreateViewAccessor (500, 4096);
336                         var v1 = m0.CreateViewAccessor (0, 4096 * 2);
337                         for (int i = 0; i < 4096; ++i) {
338                                 Assert.AreEqual (0xAA, v1.ReadByte (i + 500));
339                                 v0.Write (i, (byte)0xFF);
340                                 Assert.AreEqual (0xFF, v1.ReadByte (i + 500));
341                         }
342                 }
343
344                 [Test]
345                 public void DoubleAccountingInOffsetCalculation ()
346                 {
347                         var memoryMappedFile90 = MemoryMappedFile.CreateNew (MkNamedMapping (), 4194304, MemoryMappedFileAccess.ReadWrite);
348                         var stream = memoryMappedFile90.CreateViewStream (4186112, 3222, MemoryMappedFileAccess.Write);
349                         using (var tw = new StreamWriter(stream))
350                         {
351                                 tw.WriteLine ("Hello World!");
352                         }
353                 }
354
355                 [Test]
356                 [ExpectedException(typeof(IOException))]
357                 public void CreateViewStreamWithOffsetPastFileEnd ()
358                 {
359                         string f = Path.Combine (tempDir, "8192-file");
360                         File.WriteAllBytes (f, new byte [8192]);
361
362                         MemoryMappedFile mappedFile = MemoryMappedFile.CreateFromFile (f, FileMode.Open, "myMap", 8192);
363
364                         /* Should throw exception when trying to map past end of file */
365                         MemoryMappedViewStream stream = mappedFile.CreateViewStream (8200, 10, MemoryMappedFileAccess.ReadWrite);
366                 }
367
368                 [Test]
369                 [ExpectedException(typeof(IOException))]
370                 public void CreateViewStreamWithOffsetPastFileEnd2 ()
371                 {
372                         string f = Path.Combine (tempDir, "8192-file");
373                         File.WriteAllBytes (f, new byte [8192]);
374
375                         MemoryMappedFile mappedFile = MemoryMappedFile.CreateFromFile (f, FileMode.Open);
376
377                         MemoryMappedViewStream stream = mappedFile.CreateViewStream (8191, 8191, MemoryMappedFileAccess.ReadWrite);
378                 }
379
380                 [Test]
381                 public void CreateViewStreamAlignToPageSize ()
382                 {
383 #if MONOTOUCH
384                         // iOS bugs on ARM64 - bnc #27667 - apple #
385                         int pageSize = (IntPtr.Size == 4) ? Environment.SystemPageSize : 4096;
386 #else
387                         int pageSize = Environment.SystemPageSize;
388 #endif
389                         string f = Path.Combine (tempDir, "p-file");
390                         File.WriteAllBytes (f, new byte [pageSize * 2 + 1]);
391
392                         MemoryMappedFile mappedFile = MemoryMappedFile.CreateFromFile (f, FileMode.Open);
393
394                         MemoryMappedViewStream stream = mappedFile.CreateViewStream (pageSize * 2, 0, MemoryMappedFileAccess.ReadWrite);
395 #if !MONOTOUCH
396                         Assert.AreEqual (stream.Capacity, Environment.SystemPageSize);
397 #endif
398                         stream.Write (new byte [pageSize], 0, pageSize);
399                 }
400         }
401 }
402
403 #endif
404