2 // MemoryMappedFileTest.cs
5 // Zoltan Varga (vargaz@gmail.com)
7 // (C) 2009 Novell, Inc. (http://www.novell.com)
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
32 using System.IO.MemoryMappedFiles;
35 using NUnit.Framework;
37 namespace MonoTests.System.IO.MemoryMappedFiles {
40 public class MemoryMappedFileTest {
42 void AssertThrows<ExType> (Action del) where ExType : Exception {
50 Assert.IsTrue (thrown);
53 static int named_index;
54 static String MkNamedMapping ()
56 return "test-" + named_index++;
59 static string baseTempDir = Path.Combine (Path.GetTempPath (), typeof (MemoryMappedFileTest).FullName);
60 static string tempDir = Path.Combine (Path.GetTempPath (), typeof (MemoryMappedFileTest).FullName);
65 public void FixtureSetUp ()
68 // Try to cleanup from any previous NUnit run.
69 Directory.Delete (baseTempDir, true);
79 tempDir = Path.Combine (baseTempDir, (++i).ToString());
80 } while (Directory.Exists (tempDir));
81 Directory.CreateDirectory (tempDir);
83 fname = Path.Combine (tempDir, "basic.txt");
85 using (StreamWriter sw = new StreamWriter (fname)) {
86 sw.WriteLine ("Hello!");
87 sw.WriteLine ("World!");
92 public void TearDown ()
95 // This throws an exception under MS.NET and Mono on Windows,
96 // since the directory contains open files.
97 Directory.Delete (tempDir, true);
103 public void Basic () {
104 var file = MemoryMappedFile.CreateFromFile (fname, FileMode.Open);
106 using (var stream = file.CreateViewStream ()) {
107 TextReader r = new StreamReader (stream);
112 Assert.AreEqual ("Hello!", s);
114 Assert.AreEqual ("World!", s);
119 public void CreateNew ()
122 MemoryMappedFile.CreateNew (MkNamedMapping (), 8192);
125 // Call this twice, it should always work
127 public void CreateOrOpen_Multiple ()
129 var name = MkNamedMapping ();
130 MemoryMappedFile.CreateOrOpen (name, 8192);
131 MemoryMappedFile.CreateOrOpen (name, 8192);
135 [ExpectedException(typeof(ArgumentOutOfRangeException))]
136 public void CreateFromFileWithSmallerCapacityThanFile ()
138 var f = Path.Combine (tempDir, "8192-file");
139 File.WriteAllBytes (f, new byte [8192]);
141 // We are requesting fewer bytes to map.
142 MemoryMappedFile.CreateFromFile (f, FileMode.Open, "myMap", 4192);
146 public void CreateFromFile_Null () {
147 AssertThrows<ArgumentNullException> (delegate () {
148 MemoryMappedFile.CreateFromFile (null);
153 public void CreateViewStream_Offsets () {
154 var file = MemoryMappedFile.CreateFromFile (fname, FileMode.Open);
156 using (var stream = file.CreateViewStream (2, 3)) {
157 byte[] arr = new byte [128];
159 int len = stream.Read (arr, 0, 128);
161 Assert.AreEqual (3, len);
163 Assert.AreEqual ('l', (char)arr [0]);
164 Assert.AreEqual ('l', (char)arr [1]);
165 Assert.AreEqual ('o', (char)arr [2]);
170 public void CreateViewStream_Rights () {
171 var file = MemoryMappedFile.CreateFromFile (fname, FileMode.Open);
173 using (var stream = file.CreateViewStream (0, 0, MemoryMappedFileAccess.Read)) {
174 AssertThrows<NotSupportedException> (delegate () {
175 stream.WriteByte (0);
179 using (var stream = file.CreateViewStream (0, 0, MemoryMappedFileAccess.Write)) {
180 AssertThrows<NotSupportedException> (delegate () {
187 public unsafe void CreateViewBasic () {
188 var file = MemoryMappedFile.CreateFromFile (fname, FileMode.Open);
190 using (var v = file.CreateViewAccessor ()) {
194 var handle = v.SafeMemoryMappedViewHandle;
198 handle.AcquirePointer (ref b);
200 for (int i = 0; i < 5; ++i)
203 handle.ReleasePointer ();
206 Assert.AreEqual ("Hello", s);
211 public unsafe void ViewReadArray () {
212 var file = MemoryMappedFile.CreateFromFile (fname, FileMode.Open);
214 using (var v = file.CreateViewAccessor ()) {
215 var a = new byte [5];
216 var n = v.ReadArray (0, a, 0, 5);
217 Assert.AreEqual (5, n);
218 var s = new string (Array.ConvertAll (a, b => (char)b));
219 Assert.AreEqual ("Hello", s);
224 public unsafe void ViewAccessorReadArrayWithOffset () {
225 var file = MemoryMappedFile.CreateFromFile (fname, FileMode.Open);
227 var expected = "lo!";
229 using (var v = file.CreateViewAccessor (offset, expected.Length)) {
230 // PointerOffset Mono implementation is always 0.
231 // Assert.AreEqual (offset, v.PointerOffset);
233 var a = new byte [expected.Length];
234 var n = v.ReadArray (0, a, 0, expected.Length);
235 Assert.AreEqual (expected.Length, n);
236 var s = new string (Array.ConvertAll (a, b => (char)b));
237 Assert.AreEqual (expected, s);
242 public unsafe void ViewStreamReadWithOffset () {
243 var file = MemoryMappedFile.CreateFromFile (fname, FileMode.Open);
245 var expected = "lo!";
247 using (var v = file.CreateViewStream (offset, expected.Length)) {
248 // PointerOffset Mono implementation is always 0.
249 // Assert.AreEqual (offset, v.PointerOffset);
251 var a = new byte [expected.Length];
252 var n = v.Read (a, 0, expected.Length);
253 Assert.AreEqual (expected.Length, n);
254 var s = new string (Array.ConvertAll (a, b => (char)b));
255 Assert.AreEqual (expected, s);
260 public void NamedMappingToInvalidFile ()
262 if (Environment.OSVersion.Platform != PlatformID.Unix) {
263 Assert.Ignore ("Backslashes in mapping names are disallowed on .NET and Mono on Windows");
265 var fileName = Path.Combine (tempDir, "temp_file_123");
266 if (File.Exists (fileName))
267 File.Delete (fileName);
268 var memoryMappedFile90 = MemoryMappedFile.CreateNew (fileName, 4194304, MemoryMappedFileAccess.ReadWrite);
269 memoryMappedFile90.CreateViewStream (4186112, 3222, MemoryMappedFileAccess.Write);
273 public void CreateTheSameAreaTwiceShouldFail ()
275 var name = MkNamedMapping ();
276 using (var m0 = MemoryMappedFile.CreateNew(name, 4096, MemoryMappedFileAccess.ReadWrite)) {
278 using (var m1 = MemoryMappedFile.CreateNew (name, 4096, MemoryMappedFileAccess.ReadWrite)) {
279 Assert.Fail ("Must fail");
281 } catch (IOException) {}
286 public void MapAFileToAMemoryAreaShouldFail ()
288 var name = MkNamedMapping ();
289 using (var m0 = MemoryMappedFile.CreateNew(name, 4096, MemoryMappedFileAccess.ReadWrite)) {
291 using (var m1 = MemoryMappedFile.CreateFromFile (fname, FileMode.OpenOrCreate, name)) {
292 Assert.Fail ("Must fail");
294 } catch (IOException) {}
299 public void NamedMappingsShareMemoryArea ()
301 var name = MkNamedMapping ();
302 using (var m0 = MemoryMappedFile.CreateNew(name, 4096, MemoryMappedFileAccess.ReadWrite)) {
303 using (var m1 = MemoryMappedFile.CreateOrOpen (name, 4096, MemoryMappedFileAccess.ReadWrite)) {
304 using (MemoryMappedViewAccessor v0 = m0.CreateViewAccessor (), v1 = m1.CreateViewAccessor ()) {
305 v0.Write (10, 0x12345);
306 Assert.AreEqual (0x12345, v1.ReadInt32 (10));
313 public void NamedFileCanBeOpen ()
315 var name = MkNamedMapping ();
316 using (var sw = new FileStream (fname, FileMode.Open)) {
317 byte[] b = new byte[20];
318 for (int i = 0; i < 20; ++i)
323 using (var m0 = MemoryMappedFile.CreateFromFile (fname, FileMode.Open, name)) {
324 using (var m1 = MemoryMappedFile.CreateOrOpen (name, 4096)) {
325 using (MemoryMappedViewAccessor v0 = m0.CreateViewAccessor (), v1 = m1.CreateViewAccessor ()) {
326 v0.Write (10, 0x11223344);
327 Assert.AreEqual (0x11223344, v1.ReadInt32 (10));
334 public void MapAtEdgeOfPage ()
336 using (var f = new FileStream (fname, FileMode.Open)) {
337 var b = new byte [4096];
338 for (int i = 0; i < 4096; ++i)
340 for (int i = 0; i < 2; ++i)
341 f.Write (b, 0, 4096);
343 var m0 = MemoryMappedFile.CreateFromFile (fname, FileMode.Open);
344 var v0 = m0.CreateViewAccessor (500, 4096);
345 var v1 = m0.CreateViewAccessor (0, 4096 * 2);
346 for (int i = 0; i < 4096; ++i) {
347 Assert.AreEqual (0xAA, v1.ReadByte (i + 500));
348 v0.Write (i, (byte)0xFF);
349 Assert.AreEqual (0xFF, v1.ReadByte (i + 500));
354 public void DoubleAccountingInOffsetCalculation ()
356 var memoryMappedFile90 = MemoryMappedFile.CreateNew (MkNamedMapping (), 4194304, MemoryMappedFileAccess.ReadWrite);
357 var stream = memoryMappedFile90.CreateViewStream (4186112, 3222, MemoryMappedFileAccess.Write);
358 using (var tw = new StreamWriter(stream))
360 tw.WriteLine ("Hello World!");
365 [ExpectedException(typeof(UnauthorizedAccessException))]
366 public void CreateViewStreamWithOffsetPastFileEnd ()
368 string f = Path.Combine (tempDir, "8192-file");
369 File.WriteAllBytes (f, new byte [8192]);
371 MemoryMappedFile mappedFile = MemoryMappedFile.CreateFromFile (f, FileMode.Open, "myMap", 8192);
373 /* Should throw exception when trying to map past end of file */
374 MemoryMappedViewStream stream = mappedFile.CreateViewStream (8200, 10, MemoryMappedFileAccess.ReadWrite);
378 [ExpectedException(typeof(UnauthorizedAccessException))]
379 public void CreateViewStreamWithOffsetPastFileEnd2 ()
381 string f = Path.Combine (tempDir, "8192-file");
382 File.WriteAllBytes (f, new byte [8192]);
384 MemoryMappedFile mappedFile = MemoryMappedFile.CreateFromFile (f, FileMode.Open);
386 MemoryMappedViewStream stream = mappedFile.CreateViewStream (8191, 8191, MemoryMappedFileAccess.ReadWrite);
390 public void CreateViewStreamAlignToPageSize ()
395 // iOS bugs on ARM64 - bnc #27667 - apple #
396 int pageSize = (IntPtr.Size == 4) ? Environment.SystemPageSize : 4096;
398 int pageSize = Environment.SystemPageSize;
400 string f = Path.Combine (tempDir, "p-file");
401 File.WriteAllBytes (f, new byte [pageSize * 2 + 1]);
403 MemoryMappedFile mappedFile = MemoryMappedFile.CreateFromFile (f, FileMode.Open);
405 MemoryMappedViewStream stream = mappedFile.CreateViewStream (pageSize * 2, 0, MemoryMappedFileAccess.ReadWrite);
407 Assert.AreEqual (Environment.SystemPageSize, stream.Capacity);
409 stream.Write (new byte [pageSize], 0, pageSize);
412 [Test] // #30741 #30825
413 public void CreateFromFileNullMapName ()
416 string f = Path.Combine (tempDir, "null-map-name-file");
417 File.WriteAllBytes (f, new byte [size]);
419 FileStream file = File.OpenRead (f);
420 MemoryMappedFile.CreateFromFile (file, null, size, MemoryMappedFileAccess.Read, null, 0, false);
424 [ExpectedException(typeof(ArgumentOutOfRangeException))]
425 public void CreateNewLargerThanLogicalAddressSpace ()
427 if (IntPtr.Size != 4) {
428 Assert.Ignore ("Only applies to 32-bit systems");
430 MemoryMappedFile.CreateNew (MkNamedMapping (), (long) uint.MaxValue + 1);
434 [ExpectedException(typeof(ArgumentOutOfRangeException))]
435 public void CreateOrOpenLargerThanLogicalAddressSpace ()
437 if (IntPtr.Size != 4) {
438 Assert.Ignore ("Only applies to 32-bit systems");
440 MemoryMappedFile.CreateOrOpen (MkNamedMapping (), (long) uint.MaxValue + 1);
444 public void NamedMappingWithDelayAllocatePages ()
446 var name = MkNamedMapping ();
447 using (var m0 = MemoryMappedFile.CreateNew(name, 4096, MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.DelayAllocatePages, HandleInheritability.None)) {
448 using (MemoryMappedViewAccessor v0 = m0.CreateViewAccessor ()) {
449 Assert.AreEqual (0, v0.ReadInt32 (0));