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.
33 using System.IO.MemoryMappedFiles;
36 using NUnit.Framework;
38 namespace MonoTests.System.IO.MemoryMappedFiles {
41 public class MemoryMappedFileTest {
43 void AssertThrows<ExType> (Action del) where ExType : Exception {
51 Assert.IsTrue (thrown);
54 static int named_index;
55 static String MkNamedMapping ()
57 return "test-" + named_index++;
61 static string tempDir = Path.Combine (Path.GetTempPath (), typeof (MemoryMappedFileTest).FullName);
66 protected void SetUp () {
67 if (Directory.Exists (tempDir))
68 Directory.Delete (tempDir, true);
70 Directory.CreateDirectory (tempDir);
72 fname = Path.Combine (tempDir, "basic.txt");
74 using (StreamWriter sw = new StreamWriter (fname)) {
75 sw.WriteLine ("Hello!");
76 sw.WriteLine ("World!");
81 protected void TearDown () {
82 if (Directory.Exists (tempDir))
83 Directory.Delete (tempDir, true);
87 public void Basic () {
88 var file = MemoryMappedFile.CreateFromFile (fname, FileMode.Open);
90 using (var stream = file.CreateViewStream ()) {
91 TextReader r = new StreamReader (stream);
96 Assert.AreEqual ("Hello!", s);
98 Assert.AreEqual ("World!", s);
103 public void CreateNew ()
106 MemoryMappedFile.CreateNew (Path.Combine (tempDir, "createNew.test"), 8192);
110 [ExpectedException (typeof (IOException))]
111 public void CreateNew_OnExistingFile ()
114 MemoryMappedFile.CreateNew (Path.Combine (tempDir, "createNew.test"), 8192);
116 // This should fail, the file exists
117 MemoryMappedFile.CreateNew (Path.Combine (tempDir, "createNew.test"), 8192);
120 // Call this twice, it should always work
122 public void CreateOrOpen_Multiple ()
124 MemoryMappedFile.CreateOrOpen (Path.Combine (tempDir, "createOrOpen.test"), 8192);
125 MemoryMappedFile.CreateOrOpen (Path.Combine (tempDir, "createOrOpen.test"), 8192);
129 [ExpectedException(typeof(ArgumentOutOfRangeException))]
130 public void CreateFromFileWithSmallerCapacityThanFile ()
132 var f = Path.Combine (tempDir, "8192-file");
133 File.WriteAllBytes (f, new byte [8192]);
135 // We are requesting fewer bytes to map.
136 MemoryMappedFile.CreateFromFile (f, FileMode.Open, "myMap", 4192);
140 public void CreateFromFile_Null () {
141 AssertThrows<ArgumentNullException> (delegate () {
142 MemoryMappedFile.CreateFromFile (null);
147 public void CreateViewStream_Offsets () {
148 var file = MemoryMappedFile.CreateFromFile (fname, FileMode.Open);
150 using (var stream = file.CreateViewStream (2, 3)) {
151 byte[] arr = new byte [128];
153 int len = stream.Read (arr, 0, 128);
155 Assert.AreEqual (3, len);
157 Assert.AreEqual ('l', (char)arr [0]);
158 Assert.AreEqual ('l', (char)arr [1]);
159 Assert.AreEqual ('o', (char)arr [2]);
164 public void CreateViewStream_Rights () {
165 var file = MemoryMappedFile.CreateFromFile (fname, FileMode.Open);
167 using (var stream = file.CreateViewStream (0, 0, MemoryMappedFileAccess.Read)) {
168 AssertThrows<NotSupportedException> (delegate () {
169 stream.WriteByte (0);
173 using (var stream = file.CreateViewStream (0, 0, MemoryMappedFileAccess.Write)) {
174 AssertThrows<NotSupportedException> (delegate () {
181 public unsafe void CreateViewBasic () {
182 var file = MemoryMappedFile.CreateFromFile (fname, FileMode.Open);
184 using (var v = file.CreateViewAccessor ()) {
188 var handle = v.SafeMemoryMappedViewHandle;
192 handle.AcquirePointer (ref b);
194 for (int i = 0; i < 5; ++i)
197 handle.ReleasePointer ();
200 Assert.AreEqual ("Hello", s);
205 public unsafe void ViewReadArray () {
206 var file = MemoryMappedFile.CreateFromFile (fname, FileMode.Open);
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);
219 public void NamedMappingToInvalidFile ()
221 var fileName = Path.Combine (tempDir, "temp_file_123");
222 if (File.Exists (fileName))
223 File.Delete (fileName);
224 var memoryMappedFile90 = MemoryMappedFile.CreateNew (fileName, 4194304, MemoryMappedFileAccess.ReadWrite);
225 memoryMappedFile90.CreateViewStream (4186112, 3222, MemoryMappedFileAccess.Write);
229 public void CreateTheSameAreaTwiceShouldFail ()
231 var name = MkNamedMapping ();
232 using (var m0 = MemoryMappedFile.CreateNew(name, 4096, MemoryMappedFileAccess.ReadWrite)) {
234 using (var m1 = MemoryMappedFile.CreateNew (name, 4096, MemoryMappedFileAccess.ReadWrite)) {
235 Assert.Fail ("Must fail");
237 } catch (IOException) {}
242 public void MapAFileToAMemoryAreaShouldFail ()
244 var name = MkNamedMapping ();
245 using (var m0 = MemoryMappedFile.CreateNew(name, 4096, MemoryMappedFileAccess.ReadWrite)) {
247 using (var m1 = MemoryMappedFile.CreateFromFile (fname, FileMode.OpenOrCreate, name)) {
248 Assert.Fail ("Must fail");
250 } catch (IOException) {}
255 public void NamedMappingsShareMemoryArea ()
257 var name = MkNamedMapping ();
258 using (var m0 = MemoryMappedFile.CreateNew(name, 4096, MemoryMappedFileAccess.ReadWrite)) {
259 using (var m1 = MemoryMappedFile.CreateOrOpen (name, 4096, MemoryMappedFileAccess.ReadWrite)) {
260 using (MemoryMappedViewAccessor v0 = m0.CreateViewAccessor (), v1 = m1.CreateViewAccessor ()) {
261 v0.Write (10, 0x12345);
262 Assert.AreEqual (0x12345, v1.ReadInt32 (10));
269 public void NamedFileCanBeOpen ()
271 var name = MkNamedMapping ();
272 using (var sw = new FileStream (fname, FileMode.Open)) {
273 byte[] b = new byte[20];
274 for (int i = 0; i < 20; ++i)
279 using (var m0 = MemoryMappedFile.CreateFromFile (fname, FileMode.Open, name)) {
280 using (var m1 = MemoryMappedFile.CreateOrOpen (name, 4096)) {
281 using (MemoryMappedViewAccessor v0 = m0.CreateViewAccessor (), v1 = m1.CreateViewAccessor ()) {
282 v0.Write (10, 0x11223344);
283 Assert.AreEqual (0x11223344, v1.ReadInt32 (10));
290 public void MapAtEdgeOfPage ()
292 using (var f = new FileStream (fname, FileMode.Open)) {
293 var b = new byte [4096];
294 for (int i = 0; i < 4096; ++i)
296 for (int i = 0; i < 2; ++i)
297 f.Write (b, 0, 4096);
299 var m0 = MemoryMappedFile.CreateFromFile (fname, FileMode.Open);
300 var v0 = m0.CreateViewAccessor (500, 4096);
301 var v1 = m0.CreateViewAccessor (0, 4096 * 2);
302 for (int i = 0; i < 4096; ++i) {
303 Assert.AreEqual (0xAA, v1.ReadByte (i + 500));
304 v0.Write (i, (byte)0xFF);
305 Assert.AreEqual (0xFF, v1.ReadByte (i + 500));
310 public void DoubleAccountingInOffsetCalculation ()
312 var memoryMappedFile90 = MemoryMappedFile.CreateNew (MkNamedMapping (), 4194304, MemoryMappedFileAccess.ReadWrite);
313 var stream = memoryMappedFile90.CreateViewStream (4186112, 3222, MemoryMappedFileAccess.Write);
314 using (var tw = new StreamWriter(stream))
316 tw.WriteLine ("Hello World!");
321 [ExpectedException(typeof(IOException))]
322 public void CreateViewStreamWithOffsetPastFileEnd ()
324 string f = Path.Combine (tempDir, "8192-file");
325 File.WriteAllBytes (f, new byte [8192]);
327 MemoryMappedFile mappedFile = MemoryMappedFile.CreateFromFile (f, FileMode.Open, "myMap", 8192);
329 /* Should throw exception when trying to map past end of file */
330 MemoryMappedViewStream stream = mappedFile.CreateViewStream (8200, 10, MemoryMappedFileAccess.ReadWrite);
334 [ExpectedException(typeof(IOException))]
335 public void CreateViewStreamWithOffsetPastFileEnd2 ()
337 string f = Path.Combine (tempDir, "8192-file");
338 File.WriteAllBytes (f, new byte [8192]);
340 MemoryMappedFile mappedFile = MemoryMappedFile.CreateFromFile (f, FileMode.Open);
342 MemoryMappedViewStream stream = mappedFile.CreateViewStream (8191, 8191, MemoryMappedFileAccess.ReadWrite);
346 public void CreateViewStreamAlignToPageSize ()
348 int pageSize = Environment.SystemPageSize;
349 string f = Path.Combine (tempDir, "p-file");
350 File.WriteAllBytes (f, new byte [pageSize * 2 + 1]);
352 MemoryMappedFile mappedFile = MemoryMappedFile.CreateFromFile (f, FileMode.Open);
354 MemoryMappedViewStream stream = mappedFile.CreateViewStream (pageSize * 2, 0, MemoryMappedFileAccess.ReadWrite);
356 Assert.AreEqual (stream.Capacity, Environment.SystemPageSize);
358 stream.Write (new byte [pageSize], 0, pageSize);