From 6ebe50450d5c21772ad5afd72e1f5959c0a0c1d8 Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Mon, 28 Mar 2005 17:28:54 +0000 Subject: * Mono.Posix_test.dll.sources: Added Test/Mono.Unix/StdioFileStreamTest.cs. * Mono.Unix/UnixConvert.cs: Add ToFopenMode() methods, which convert FileMode/FileAccess into an fopen(3) mode string. ToOpenFlags() should throw ArgumentOutOfRangeException for argument violations. * Mono.Unix/StdioFileStream.cs: Add constructor overloads accepting filename and FileMode/FileAccess overloads; Compatibility fixes with regression tests; remove IDisposable implementation since System.IO.Stream already implements it (which calls Close() for us). * Test/Mono.Unix/StdioFileStreamTest.cs: Added; based on MonoTests.System.IO.FileStreamTest. svn path=/trunk/mcs/; revision=42310 --- mcs/class/Mono.Posix/ChangeLog | 4 + mcs/class/Mono.Posix/Mono.Posix_test.dll.sources | 1 + mcs/class/Mono.Posix/Mono.Unix/ChangeLog | 10 + mcs/class/Mono.Posix/Mono.Unix/StdioFileStream.cs | 173 ++++- mcs/class/Mono.Posix/Mono.Unix/UnixConvert.cs | 61 +- mcs/class/Mono.Posix/Test/Mono.Unix/ChangeLog | 4 + .../Test/Mono.Unix/StdioFileStreamTest.cs | 813 +++++++++++++++++++++ 7 files changed, 1037 insertions(+), 29 deletions(-) create mode 100644 mcs/class/Mono.Posix/Test/Mono.Unix/StdioFileStreamTest.cs (limited to 'mcs/class/Mono.Posix') diff --git a/mcs/class/Mono.Posix/ChangeLog b/mcs/class/Mono.Posix/ChangeLog index 21db9c78276..18f53b333f4 100644 --- a/mcs/class/Mono.Posix/ChangeLog +++ b/mcs/class/Mono.Posix/ChangeLog @@ -1,3 +1,7 @@ +2005-02-28 Jonathan Pryor + + * Mono.Posix_test.dll.sources: Added Test/Mono.Unix/StdioFileStreamTest.cs. + 2005-01-13 Jonathan Pryor * Mono.Posix_test.dll.sources: Added Test/Mono.Unix/StdlibTest.cs. diff --git a/mcs/class/Mono.Posix/Mono.Posix_test.dll.sources b/mcs/class/Mono.Posix/Mono.Posix_test.dll.sources index 1ceffcada9b..657a14fa2b8 100644 --- a/mcs/class/Mono.Posix/Mono.Posix_test.dll.sources +++ b/mcs/class/Mono.Posix/Mono.Posix_test.dll.sources @@ -1,3 +1,4 @@ +Mono.Unix/StdioFileStreamTest.cs Mono.Unix/StdlibTest.cs Mono.Unix/UnixUserTest.cs Mono.Unix/UnixGroupTest.cs diff --git a/mcs/class/Mono.Posix/Mono.Unix/ChangeLog b/mcs/class/Mono.Posix/Mono.Unix/ChangeLog index 263560bf970..17b1d3ec40b 100644 --- a/mcs/class/Mono.Posix/Mono.Unix/ChangeLog +++ b/mcs/class/Mono.Posix/Mono.Unix/ChangeLog @@ -1,3 +1,13 @@ +2005-03-28 Jonathan Pryor + + * UnixConvert.cs: Add ToFopenMode() methods, which convert FileMode/FileAccess + into an fopen(3) mode string. ToOpenFlags() should throw + ArgumentOutOfRangeException for argument violations. + * StdioFileStream.cs: Add constructor overloads accepting filename and + FileMode/FileAccess overloads; Compatibility fixes with regression tests; + remove IDisposable implementation since System.IO.Stream already + implements it (which calls Close() for us). + 2005-03-17 Jonathan Pryor * Stdlib.cs: Move Errno-related functionality into Stdlib from Syscall, diff --git a/mcs/class/Mono.Posix/Mono.Unix/StdioFileStream.cs b/mcs/class/Mono.Posix/Mono.Unix/StdioFileStream.cs index 0831552077d..10e90724069 100644 --- a/mcs/class/Mono.Posix/Mono.Unix/StdioFileStream.cs +++ b/mcs/class/Mono.Posix/Mono.Unix/StdioFileStream.cs @@ -34,7 +34,7 @@ using Mono.Unix; namespace Mono.Unix { - public class StdioFileStream : Stream, IDisposable + public class StdioFileStream : Stream { public static readonly IntPtr InvalidFileStream = IntPtr.Zero; public static readonly IntPtr StandardInput = Stdlib.stdin; @@ -45,6 +45,62 @@ namespace Mono.Unix { : this (fileStream, true) {} public StdioFileStream (IntPtr fileStream, bool ownsHandle) + { + InitStream (fileStream, ownsHandle); + } + + public StdioFileStream (IntPtr fileStream, FileAccess access) + : this (fileStream, access, true) {} + + public StdioFileStream (IntPtr fileStream, FileAccess access, bool ownsHandle) + { + InitStream (fileStream, ownsHandle); + InitCanReadWrite (access); + } + + public StdioFileStream (string path) + { + InitStream (Fopen (path, "r"), true); + } + + public StdioFileStream (string path, string mode) + { + InitStream (Fopen (path, mode), true); + } + + public StdioFileStream (string path, FileMode mode) + { + InitStream (Fopen (path, ToFopenMode (path, mode)), true); + } + + public StdioFileStream (string path, FileAccess access) + { + InitStream (Fopen (path, ToFopenMode (path, access)), true); + InitCanReadWrite (access); + } + + public StdioFileStream (string path, FileMode mode, FileAccess access) + { + InitStream (Fopen (path, ToFopenMode (path, mode, access)), true); + InitCanReadWrite (access); + } + + private static IntPtr Fopen (string path, string mode) + { + if (path == null) + throw new ArgumentNullException ("path"); + if (path.Length == 0) + throw new ArgumentException ("path"); + if (mode == null) + throw new ArgumentNullException ("path"); + IntPtr f = Stdlib.fopen (path, mode); + if (f == IntPtr.Zero) + throw new DirectoryNotFoundException ("path", + UnixMarshal.CreateExceptionForLastError ()); + return f; + } + + private void InitStream (IntPtr fileStream, bool ownsHandle) { if (InvalidFileStream == fileStream) throw new ArgumentException (Locale.GetText ("Invalid file stream"), "fileStream"); @@ -52,16 +108,73 @@ namespace Mono.Unix { this.file = fileStream; this.owner = ownsHandle; - long offset = Stdlib.fseek (file, 0, SeekFlags.SEEK_CUR); - if (offset != -1) - canSeek = true; - Stdlib.fread (IntPtr.Zero, 0, 0, file); - if (Stdlib.ferror (file) == 0) - canRead = true; - Stdlib.fwrite (IntPtr.Zero, 0, 0, file); - if (Stdlib.ferror (file) == 0) - canWrite = true; - Stdlib.clearerr (file); + try { + long offset = Stdlib.fseek (file, 0, SeekFlags.SEEK_CUR); + if (offset != -1) + canSeek = true; + Stdlib.fread (IntPtr.Zero, 0, 0, file); + if (Stdlib.ferror (file) == 0) + canRead = true; + Stdlib.fwrite (IntPtr.Zero, 0, 0, file); + if (Stdlib.ferror (file) == 0) + canWrite = true; + Stdlib.clearerr (file); + } + catch (Exception e) { + throw new ArgumentException (Locale.GetText ("Invalid file stream"), "fileStream"); + } + } + + private void InitCanReadWrite (FileAccess access) + { + canRead = canRead && + (access == FileAccess.Read || access == FileAccess.ReadWrite); + canWrite = canWrite && + (access == FileAccess.Write || access == FileAccess.ReadWrite); + } + + private static string ToFopenMode (string file, FileMode mode) + { + string cmode = UnixConvert.ToFopenMode (mode); + AssertFileMode (file, mode); + return cmode; + } + + private static string ToFopenMode (string file, FileAccess access) + { + return UnixConvert.ToFopenMode (access); + } + + private static string ToFopenMode (string file, FileMode mode, FileAccess access) + { + string cmode = UnixConvert.ToFopenMode (mode, access); + bool exists = AssertFileMode (file, mode); + // HACK: for open-or-create & read, mode is "rb", which doesn't create + // files. If the file doesn't exist, we need to use "w+b" to ensure + // file creation. + if (mode == FileMode.OpenOrCreate && access == FileAccess.Read && !exists) + cmode = "w+b"; + return cmode; + } + + private static bool AssertFileMode (string file, FileMode mode) + { + bool exists = FileExists (file); + if (mode == FileMode.CreateNew && exists) + throw new IOException ("File exists and FileMode.CreateNew specified"); + if ((mode == FileMode.Open || mode == FileMode.Truncate) && !exists) + throw new FileNotFoundException ("File doesn't exist and FileMode.Open specified", file); + return exists; + } + + private static bool FileExists (string file) + { + bool found = false; + IntPtr f = Stdlib.fopen (file, "r"); + found = f != IntPtr.Zero; + if (f != IntPtr.Zero) + Stdlib.fclose (f); + return found; } private void AssertNotDisposed () @@ -71,7 +184,7 @@ namespace Mono.Unix { } public IntPtr Handle { - get {return file;} + get {AssertNotDisposed (); return file;} } public override bool CanRead { @@ -119,18 +232,21 @@ namespace Mono.Unix { return (long) pos; } set { + AssertNotDisposed (); Seek (value, SeekOrigin.Begin); } } public FilePosition FilePosition { get { + AssertNotDisposed (); FilePosition pos = new FilePosition (); int r = Stdlib.fgetpos (file, pos); UnixMarshal.ThrowExceptionForLastErrorIf (r); return pos; } set { + AssertNotDisposed (); if (value == null) throw new ArgumentNullException ("value"); int r = Stdlib.fsetpos (file, value); @@ -140,6 +256,7 @@ namespace Mono.Unix { public override void Flush () { + AssertNotDisposed (); int r = Stdlib.fflush (file); if (r != 0) UnixMarshal.ThrowExceptionForLastError (); @@ -157,8 +274,6 @@ namespace Mono.Unix { r = Stdlib.fread (buf, 1, (ulong) count, file); } if (r != (ulong) count) { - if (Stdlib.feof (file) != 0) - throw new EndOfStreamException (); if (Stdlib.ferror (file) != 0) throw new IOException (); } @@ -181,6 +296,7 @@ namespace Mono.Unix { public void Rewind () { + AssertNotDisposed (); Stdlib.rewind (file); } @@ -195,15 +311,18 @@ namespace Mono.Unix { case SeekOrigin.Begin: sf = SeekFlags.SEEK_SET; break; case SeekOrigin.Current: sf = SeekFlags.SEEK_CUR; break; case SeekOrigin.End: sf = SeekFlags.SEEK_END; break; + default: throw new ArgumentException ("origin"); } int r = Stdlib.fseek (file, offset, sf); if (r != 0) - UnixMarshal.ThrowExceptionForLastError (); + throw new IOException ("Unable to seek", + UnixMarshal.CreateExceptionForLastError ()); long pos = Stdlib.ftell (file); if (pos == -1) - UnixMarshal.ThrowExceptionForLastError (); + throw new IOException ("Unable to get current file position", + UnixMarshal.CreateExceptionForLastError ()); return pos; } @@ -237,23 +356,21 @@ namespace Mono.Unix { { if (file == InvalidFileStream) return; + + GC.SuppressFinalize (this); Flush (); - int r = Stdlib.fclose (file); - if (r != 0) - UnixMarshal.ThrowExceptionForLastError (); - file = InvalidFileStream; - } - - void IDisposable.Dispose () - { - AssertNotDisposed (); - GC.SuppressFinalize (this); if (owner) { - Close (); + int r = Stdlib.fclose (file); + if (r != 0) + UnixMarshal.ThrowExceptionForLastError (); } + file = InvalidFileStream; + canRead = false; + canSeek = false; + canWrite = false; } - + private bool canSeek = false; private bool canRead = false; private bool canWrite = false; diff --git a/mcs/class/Mono.Posix/Mono.Unix/UnixConvert.cs b/mcs/class/Mono.Posix/Mono.Unix/UnixConvert.cs index f5dbde18d66..b2d56024d24 100644 --- a/mcs/class/Mono.Posix/Mono.Unix/UnixConvert.cs +++ b/mcs/class/Mono.Posix/Mono.Unix/UnixConvert.cs @@ -745,11 +745,70 @@ namespace Mono.Unix { flags |= OpenFlags.O_RDWR; break; default: - throw new ArgumentException (Locale.GetText ("Unsupported access value"), "access"); + throw new ArgumentOutOfRangeException (Locale.GetText ("Unsupported access value"), "access"); } return flags; } + + public static string ToFopenMode (FileAccess access) + { + switch (access) { + case FileAccess.Read: return "rb"; + case FileAccess.Write: return "wb"; + case FileAccess.ReadWrite: return "r+b"; + default: throw new ArgumentOutOfRangeException ("access"); + } + } + + public static string ToFopenMode (FileMode mode) + { + switch (mode) { + case FileMode.CreateNew: case FileMode.Create: return "w+b"; + case FileMode.Open: case FileMode.OpenOrCreate: return "r+b"; + case FileMode.Truncate: return "w+b"; + case FileMode.Append: return "a+b"; + default: throw new ArgumentOutOfRangeException ("mode"); + } + } + + private static readonly string[][] fopen_modes = new string[][]{ + // Read Write ReadWrite + /* FileMode.CreateNew: */ new string[]{"Can't Read+Create", "wb", "w+b"}, + /* FileMode.Create: */ new string[]{"Can't Read+Create", "wb", "w+b"}, + /* FileMode.Open: */ new string[]{"rb", "wb", "r+b"}, + /* FileMode.OpenOrCreate: */ new string[]{"rb", "wb", "r+b"}, + /* FileMode.Truncate: */ new string[]{"Cannot Truncate and Read","wb", "w+b"}, + /* FileMode.Append: */ new string[]{"Cannot Append and Read", "ab", "a+b"}, + }; + + public static string ToFopenMode (FileMode mode, FileAccess access) + { + int fm = -1, fa = -1; + switch (mode) { + case FileMode.CreateNew: fm = 0; break; + case FileMode.Create: fm = 1; break; + case FileMode.Open: fm = 2; break; + case FileMode.OpenOrCreate: fm = 3; break; + case FileMode.Truncate: fm = 4; break; + case FileMode.Append: fm = 5; break; + } + switch (access) { + case FileAccess.Read: fa = 0; break; + case FileAccess.Write: fa = 1; break; + case FileAccess.ReadWrite: fa = 2; break; + } + + if (fm == -1) + throw new ArgumentOutOfRangeException ("mode"); + if (fa == -1) + throw new ArgumentOutOfRangeException ("access"); + + string fopen_mode = fopen_modes [fm][fa]; + if (fopen_mode [0] != 'r' && fopen_mode [0] != 'w' && fopen_mode [0] != 'a') + throw new ArgumentException (fopen_mode); + return fopen_mode; + } } } diff --git a/mcs/class/Mono.Posix/Test/Mono.Unix/ChangeLog b/mcs/class/Mono.Posix/Test/Mono.Unix/ChangeLog index 3d41eef82e8..4153d583a62 100644 --- a/mcs/class/Mono.Posix/Test/Mono.Unix/ChangeLog +++ b/mcs/class/Mono.Posix/Test/Mono.Unix/ChangeLog @@ -1,3 +1,7 @@ +2005-03-28 Jonathan Pryor + + * StdioFileStreamTest.cs: Added; based on MonoTests.System.IO.FileStreamTest. + 2005-02-09 Jonathan Pryor * StdlibTest.cs: Signal is currently ignored, but add Category(NotDotNet) so diff --git a/mcs/class/Mono.Posix/Test/Mono.Unix/StdioFileStreamTest.cs b/mcs/class/Mono.Posix/Test/Mono.Unix/StdioFileStreamTest.cs new file mode 100644 index 00000000000..a4e1e7fdad4 --- /dev/null +++ b/mcs/class/Mono.Posix/Test/Mono.Unix/StdioFileStreamTest.cs @@ -0,0 +1,813 @@ +// StdioFileStreamTest.cs - NUnit2 Test Cases for Mono.Unix.StdioFileStream class +// +// Authors: +// Ville Palo (vi64pa@koti.soon.fi) +// Gert Driesen (gert.driesen@ardatis.com) +// Gonzalo Paniagua Javier (gonzalo@ximian.com) +// +// (C) Ville Palo +// (c) 2003 Ximian, Inc. (http://www.ximian.com) +// + + +using NUnit.Framework; +using System; +using System.IO; +using System.Text; +using Mono.Unix; + +namespace MonoTests.System.IO +{ + [TestFixture] + public class StdioFileStreamTest { + + string TempFolder = Path.Combine (Path.GetTempPath (), "MonoTests.Mono.Unix.Tests"); + static readonly char DSC = Path.DirectorySeparatorChar; + + [TearDown] + public void TearDown() + { + if (Directory.Exists (TempFolder)) + Directory.Delete (TempFolder, true); + } + + [SetUp] + public void SetUp () + { + if (Directory.Exists (TempFolder)) + Directory.Delete (TempFolder, true); + + Directory.CreateDirectory (TempFolder); + } + + public void TestCtr () + { + string path = TempFolder + DSC + "testfilestream.tmp.1"; + DeleteFile (path); + StdioFileStream stream = null; + try { + stream = new StdioFileStream (path, FileMode.Create); + } finally { + + if (stream != null) + stream.Close (); + DeleteFile (path); + } + } + + [Test] + [ExpectedException (typeof (ArgumentException))] + public void CtorArgumentException1 () + { + StdioFileStream stream; + stream = new StdioFileStream ("", FileMode.Create); + stream.Close (); + } + + [Test] + [ExpectedException (typeof (ArgumentNullException))] + public void CtorArgumentNullException () + { + StdioFileStream stream = new StdioFileStream (null, FileMode.Create); + stream.Close (); + } + + [Test] + [ExpectedException (typeof (FileNotFoundException))] + public void CtorFileNotFoundException1 () + { + string path = TempFolder + DSC + "thisfileshouldnotexists.test"; + DeleteFile (path); + StdioFileStream stream = null; + try { + stream = new StdioFileStream (path, FileMode.Open); + } finally { + if (stream != null) + stream.Close (); + DeleteFile (path); + } + } + + [Test] + [ExpectedException (typeof (FileNotFoundException))] + public void CtorFileNotFoundException2 () + { + string path = TempFolder + DSC + "thisfileshouldNOTexists.test"; + DeleteFile (path); + StdioFileStream stream = null; + + try { + stream = new StdioFileStream (path, FileMode.Truncate); + } finally { + if (stream != null) + stream.Close (); + + DeleteFile (path); + } + } + + [Test] + [ExpectedException (typeof (IOException))] + public void CtorIOException1 () + { + string path = TempFolder + DSC + "thisfileshouldexists.test"; + StdioFileStream stream = null; + DeleteFile (path); + try { + stream = new StdioFileStream (path, FileMode.CreateNew); + stream.Close (); + stream = null; + stream = new StdioFileStream (path, FileMode.CreateNew); + } finally { + + if (stream != null) + stream.Close (); + DeleteFile (path); + } + } + + [Test] + [ExpectedException (typeof (ArgumentOutOfRangeException))] + public void CtorArgumentOutOfRangeException1 () + { + StdioFileStream stream = null; + string path = TempFolder + Path.DirectorySeparatorChar + "temp"; + DeleteFile (path); + try { + stream = new StdioFileStream (path, FileMode.Append | FileMode.CreateNew); + } finally { + if (stream != null) + stream.Close (); + DeleteFile (path); + } + } + + [Test] + [ExpectedException (typeof (ArgumentOutOfRangeException))] + public void CtorArgumentOutOfRangeException2 () + { + StdioFileStream stream = null; + string path = TempFolder + Path.DirectorySeparatorChar + "temp"; + DeleteFile (path); + try { + stream = new StdioFileStream ("test.test.test", FileMode.Append | FileMode.Open); + } finally { + if (stream != null) + stream.Close (); + DeleteFile (path); + } + } + + [Test] + [ExpectedException (typeof (DirectoryNotFoundException))] + public void CtorDirectoryNotFoundException () + { + string path = TempFolder + DSC + "thisDirectoryShouldNotExists"; + if (Directory.Exists (path)) + Directory.Delete (path, true); + + StdioFileStream stream = null; + try { + stream = new StdioFileStream (path + DSC + "eitherthisfile.test", FileMode.CreateNew); + } finally { + + if (stream != null) + stream.Close (); + + if (Directory.Exists (path)) + Directory.Delete (path, true); + } + } + + [Test] + [ExpectedException (typeof (ArgumentException))] + public void CtorArgumentException3 () + { + string path = TempFolder + Path.DirectorySeparatorChar + "temp"; + StdioFileStream stream = null; + + DeleteFile (path); + + try { + stream = new StdioFileStream (".test.test.test.2", FileMode.Truncate, FileAccess.Read); + } finally { + if (stream != null) + stream.Close (); + + DeleteFile (path); + } + } + + // StdioFileStream doesn't mimic the "no writing by another object" rule + [/* Test, */ ExpectedException(typeof(IOException))] + public void CtorIOException () + { + string path = TempFolder + DSC + "CTorIOException.Test"; + StdioFileStream stream = null; + StdioFileStream stream2 = null; + DeleteFile (path); + + try { + stream = new StdioFileStream (path, FileMode.CreateNew); + + // used by an another process + stream2 = new StdioFileStream (path, FileMode.OpenOrCreate); + } finally { + if (stream != null) + stream.Close (); + if (stream2 != null) + stream2.Close (); + DeleteFile (path); + } + } + + [Test] + public void CtorAccess1Read2Read () + { + StdioFileStream fs = null; + StdioFileStream fs2 = null; + try { + if (!File.Exists ("temp")) { + TextWriter tw = File.CreateText ("temp"); + tw.Write ("FOO"); + tw.Close (); + } + fs = new StdioFileStream ("temp", FileMode.Open, FileAccess.Read); + fs2 = new StdioFileStream ("temp", FileMode.Open, FileAccess.Read); + } finally { + if (fs != null) + fs.Close (); + if (fs2 != null) + fs2.Close (); + if (File.Exists ("temp")) + File.Delete ("temp"); + } + } + + [Test] + public void Write () + { + string path = TempFolder + DSC + "StdioFileStreamTest.Write"; + + DeleteFile (path); + + StdioFileStream stream = new StdioFileStream (path, FileMode.CreateNew, FileAccess.ReadWrite); + + byte[] outbytes = new byte [] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + byte[] bytes = new byte [15]; + + // Check that the data is flushed when we overflow the buffer + // with a large amount of data + stream.Write (outbytes, 0, 5); + stream.Write (outbytes, 5, 10); + stream.Seek (0, SeekOrigin.Begin); + + stream.Read (bytes, 0, 15); + for (int i = 0; i < 15; ++i) + Assert.AreEqual (i + 1, bytes [i]); + + // Check that the data is flushed when we overflow the buffer + // with a small amount of data + stream.Write (outbytes, 0, 7); + stream.Write (outbytes, 7, 7); + stream.Write (outbytes, 14, 1); + + stream.Read (bytes, 0, 15); + stream.Seek (15, SeekOrigin.Begin); + for (int i = 0; i < 15; ++i) + Assert.AreEqual (i + 1, bytes [i]); + stream.Close (); + } + + [Test] + public void Length () + { + // Test that the Length property takes into account the data + // in the buffer + string path = TempFolder + DSC + "StdioFileStreamTest.Length"; + + DeleteFile (path); + + StdioFileStream stream = new StdioFileStream (path, FileMode.CreateNew); + + byte[] outbytes = new byte [] {1, 2, 3, 4}; + + stream.Write (outbytes, 0, 4); + Assert.AreEqual (stream.Length, 4); + stream.Close (); + } + + [Test] + public void Flush () + { + string path = TempFolder + DSC + "StdioFileStreamTest.Flush"; + StdioFileStream stream = null; + StdioFileStream stream2 = null; + + DeleteFile (path); + + try { + stream = new StdioFileStream (path, FileMode.CreateNew, FileAccess.ReadWrite); + stream2 = new StdioFileStream (path, FileMode.Open, FileAccess.ReadWrite); + + stream.Write (new byte [] {1, 2, 3, 4, 5}, 0, 5); + + byte [] bytes = new byte [5]; + stream2.Read (bytes, 0, 5); + + Assert.AreEqual (0, bytes [0], "test#01"); + Assert.AreEqual (0, bytes [1], "test#02"); + Assert.AreEqual (0, bytes [2], "test#03"); + Assert.AreEqual (0, bytes [3], "test#04"); + + stream.Flush (); + stream2.Read (bytes, 0, 5); + Assert.AreEqual (1, bytes [0], "test#05"); + Assert.AreEqual (2, bytes [1], "test#06"); + Assert.AreEqual (3, bytes [2], "test#07"); + Assert.AreEqual (4, bytes [3], "test#08"); + } finally { + if (stream != null) + stream.Close (); + if (stream2 != null) + stream2.Close (); + + DeleteFile (path); + } + } + + [Test] + public void TestDefaultProperties () + { + string path = TempFolder + Path.DirectorySeparatorChar + "testStdioFileStream.tmp.2"; + DeleteFile (path); + + StdioFileStream stream = new StdioFileStream (path, FileMode.Create); + + Assert.AreEqual (true, stream.CanRead, "test#01"); + Assert.AreEqual (true, stream.CanSeek, "test#02"); + Assert.AreEqual (true, stream.CanWrite, "test#03"); + Assert.AreEqual (0, stream.Position, "test#06"); + Assert.AreEqual ("Mono.Unix.StdioFileStream", stream.ToString(), "test#07"); + stream.Close (); + DeleteFile (path); + + stream = new StdioFileStream (path, FileMode.OpenOrCreate, FileAccess.Read); + Assert.AreEqual (true, stream.CanRead, "test#08"); + Assert.AreEqual (true, stream.CanSeek, "test#09"); + Assert.AreEqual (false, stream.CanWrite, "test#10"); + Assert.AreEqual (0, stream.Position, "test#13"); + Assert.AreEqual ("Mono.Unix.StdioFileStream", stream.ToString(), "test#14"); + stream.Close (); + + stream = new StdioFileStream (path, FileMode.Truncate, FileAccess.Write); + Assert.AreEqual (false, stream.CanRead, "test#15"); + Assert.AreEqual (true, stream.CanSeek, "test#16"); + Assert.AreEqual (true, stream.CanWrite, "test#17"); + Assert.AreEqual (0, stream.Position, "test#20"); + Assert.AreEqual ("Mono.Unix.StdioFileStream", stream.ToString(), "test#21"); + stream.Close (); + DeleteFile (path); + } + + [Test] + public void Seek () + { + string path = TempFolder + DSC + "FST.Seek.Test"; + DeleteFile (path); + + StdioFileStream stream = new StdioFileStream (path, FileMode.CreateNew, FileAccess.ReadWrite); + StdioFileStream stream2 = new StdioFileStream (path, FileMode.Open, FileAccess.ReadWrite); + + stream.Write (new byte [] {1, 2, 3, 4, 5, 6, 7, 8, 10}, 0, 9); + Assert.AreEqual (5, stream2.Seek (5, SeekOrigin.Begin), "test#01"); + Assert.AreEqual (-1, stream2.ReadByte (), "test#02"); + + Assert.AreEqual (2, stream2.Seek (-3, SeekOrigin.Current), "test#03"); + Assert.AreEqual (-1, stream2.ReadByte (), "test#04"); + + Assert.AreEqual (12, stream.Seek (3, SeekOrigin.Current), "test#05"); + Assert.AreEqual (-1, stream.ReadByte (), "test#06"); + + Assert.AreEqual (5, stream.Seek (-7, SeekOrigin.Current), "test#07"); + Assert.AreEqual (6, stream.ReadByte (), "test#08"); + + Assert.AreEqual (5, stream2.Seek (5, SeekOrigin.Begin), "test#09"); + Assert.AreEqual (6, stream2.ReadByte (), "test#10"); + + stream.Close (); + stream2.Close (); + + DeleteFile (path); + } + + [Test] + public void TestSeek () + { + string path = TempFolder + Path.DirectorySeparatorChar + "TestSeek"; + DeleteFile (path); + + StdioFileStream stream = new StdioFileStream (path, FileMode.CreateNew, FileAccess.ReadWrite); + stream.Write (new byte[] {1, 2, 3, 4, 5, 6, 7, 8 , 9, 10}, 0, 10); + + stream.Seek (5, SeekOrigin.End); + Assert.AreEqual (-1, stream.ReadByte (), "test#01"); + + stream.Seek (-5, SeekOrigin.End); + Assert.AreEqual (6, stream.ReadByte (), "test#02"); + + try { + stream.Seek (-11, SeekOrigin.End); + Assert.Fail (); + } catch (Exception e) { + Assert.AreEqual (typeof (IOException), e.GetType (), "test#03"); + } + + stream.Seek (19, SeekOrigin.Begin); + Assert.AreEqual (-1, stream.ReadByte (), "test#04"); + + stream.Seek (1, SeekOrigin.Begin); + Assert.AreEqual (2, stream.ReadByte (), "test#05"); + + stream.Seek (3, SeekOrigin.Current); + Assert.AreEqual (6, stream.ReadByte (), "test#06"); + + stream.Seek (-2, SeekOrigin.Current); + Assert.AreEqual (5, stream.ReadByte (), "test#07"); + + stream.Flush (); + + // Test that seeks work correctly when seeking inside the buffer + stream.Seek (0, SeekOrigin.Begin); + stream.WriteByte (0); + stream.WriteByte (1); + stream.Seek (0, SeekOrigin.Begin); + byte[] buf = new byte [1]; + buf [0] = 2; + stream.Write (buf, 0, 1); + stream.Write (buf, 0, 1); + stream.Flush (); + stream.Seek (0, SeekOrigin.Begin); + Assert.AreEqual (2, stream.ReadByte (), "test#08"); + Assert.AreEqual (2, stream.ReadByte (), "test#09"); + + stream.Close (); + + DeleteFile (path); + } + + [Test] + public void TestClose () + { + string path = TempFolder + Path.DirectorySeparatorChar + "TestClose"; + DeleteFile (path); + + StdioFileStream stream = new StdioFileStream (path, FileMode.CreateNew, FileAccess.ReadWrite); + + stream.Write (new byte [] {1, 2, 3, 4}, 0, 4); + stream.ReadByte (); + stream.Close (); + + try { + stream.ReadByte (); + Assert.Fail (); + } catch (Exception e) { + Assert.AreEqual (typeof (ObjectDisposedException), e.GetType (), "test#01"); + } + + try { + stream.WriteByte (64); + Assert.Fail (); + } catch (Exception e) { + Assert.AreEqual (typeof (ObjectDisposedException), e.GetType (), "test#02"); + } + + try { + stream.Flush (); + Assert.Fail (); + } catch (Exception e) { + Assert.AreEqual (typeof (ObjectDisposedException), e.GetType (), "test#03"); + } + + try { + long l = stream.Length; + l = l; + Assert.Fail (); + } catch (Exception e) { + Assert.AreEqual (typeof (ObjectDisposedException), e.GetType (), "test#04"); + } + + try { + long l = stream.Position; + l = l; + Assert.Fail (); + } catch (Exception e) { + Assert.AreEqual (typeof (ObjectDisposedException), e.GetType (), "test#05"); + } + + Assert.AreEqual (false, stream.CanRead, "test#06"); + Assert.AreEqual (false, stream.CanSeek, "test#07"); + Assert.AreEqual (false, stream.CanWrite, "test#08"); + + DeleteFile (path); + } + + + /// + /// Checks whether the throws a + /// when the stream is opened with access mode and the + /// method is called. + /// + [Test] + [ExpectedException (typeof(NotSupportedException))] + public void TestWriteVerifyAccessMode () + { + string path = TempFolder + Path.DirectorySeparatorChar + "temp"; + DeleteFile (path); + + StdioFileStream stream = null; + byte[] buffer; + + try { + buffer = Encoding.ASCII.GetBytes ("test"); + stream = new StdioFileStream (path, FileMode.OpenOrCreate, FileAccess.Read); + stream.Write (buffer, 0, buffer.Length); + } finally { + if (stream != null) + stream.Close(); + DeleteFile (path); + } + } + + /// + /// Checks whether the throws a + /// when the stream is opened with access mode and the + /// method is called. + /// + [Test] + [ExpectedException (typeof (NotSupportedException))] + public void TestWriteByteVerifyAccessMode () + { + string path = TempFolder + Path.DirectorySeparatorChar + "temp"; + DeleteFile (path); + + StdioFileStream stream = null; + + try { + stream = new StdioFileStream (path, FileMode.OpenOrCreate, FileAccess.Read); + stream.WriteByte (Byte.MinValue); + } finally { + if (stream != null) + stream.Close (); + DeleteFile (path); + } + } + + /// + /// Checks whether the throws a + /// when the stream is opened with access mode and the + /// method is called. + /// + [Test] + [ExpectedException (typeof (NotSupportedException))] + public void TestReadVerifyAccessMode () + { + string path = TempFolder + Path.DirectorySeparatorChar + "temp"; + DeleteFile (path); + + StdioFileStream stream = null; + byte[] buffer = new byte [100]; + + try { + stream = new StdioFileStream (path, FileMode.OpenOrCreate, FileAccess.Write); + stream.Read (buffer, 0, buffer.Length); + } finally { + if (stream != null) + stream.Close (); + } + } + + /// + /// Checks whether the throws a + /// when the stream is opened with access mode and the + /// method is called. + /// + [Test] + [ExpectedException (typeof (NotSupportedException))] + public void TestReadByteVerifyAccessMode () + { + string path = TempFolder + Path.DirectorySeparatorChar + "temp"; + DeleteFile (path); + + StdioFileStream stream = null; + + try { + stream = new StdioFileStream (path, FileMode.OpenOrCreate, FileAccess.Write); + int readByte = stream.ReadByte (); + readByte = readByte; + } finally { + if (stream != null) + stream.Close(); + DeleteFile (path); + } + } + + // Check that the stream is flushed even when it doesn't own the + // handle + [Test] + public void TestFlushNotOwningHandle () + { + string path = Path.Combine (TempFolder, "TestFlushNotOwningHandle"); + DeleteFile (path); + + StdioFileStream s = new StdioFileStream (path, FileMode.Create); + using (StdioFileStream s2 = new StdioFileStream (s.Handle, FileAccess.Write, false)) { + byte[] buf = new byte [2]; + buf [0] = (int)'1'; + s2.Write (buf, 0, 1); + } + + s.Position = 0; + Assert.AreEqual (s.ReadByte (), (int)'1'); + s.Close (); + } + + private void DeleteFile (string path) + { + if (File.Exists (path)) + File.Delete (path); + } + + [Test] + [ExpectedException (typeof (ArgumentOutOfRangeException))] + public void Read_OffsetNegative () + { + string path = TempFolder + Path.DirectorySeparatorChar + "temp"; + DeleteFile (path); + + using (StdioFileStream stream = new StdioFileStream (path, FileMode.OpenOrCreate, FileAccess.Read)) { + stream.Read (new byte[0], -1, 1); + } + } + + [Test] + [ExpectedException (typeof (ArgumentException))] + public void Read_OffsetOverflow () + { + string path = TempFolder + Path.DirectorySeparatorChar + "temp"; + DeleteFile (path); + + using (StdioFileStream stream = new StdioFileStream (path, FileMode.OpenOrCreate, FileAccess.Read)) { + stream.Read (new byte[0], Int32.MaxValue, 1); + } + } + + [Test] + [ExpectedException (typeof (ArgumentOutOfRangeException))] + public void Read_CountNegative () + { + string path = TempFolder + Path.DirectorySeparatorChar + "temp"; + DeleteFile (path); + + using (StdioFileStream stream = new StdioFileStream (path, FileMode.OpenOrCreate, FileAccess.Read)) { + stream.Read (new byte[0], 1, -1); + } + } + + [Test] + [ExpectedException (typeof (ArgumentException))] + public void Read_CountOverflow () + { + string path = TempFolder + Path.DirectorySeparatorChar + "temp"; + DeleteFile (path); + + using (StdioFileStream stream = new StdioFileStream (path, FileMode.OpenOrCreate, FileAccess.Read)) { + stream.Read (new byte[0], 1, Int32.MaxValue); + } + } + + [Test] + [ExpectedException (typeof (ArgumentOutOfRangeException))] + public void Write_OffsetNegative () + { + string path = TempFolder + Path.DirectorySeparatorChar + "temp"; + DeleteFile (path); + + using (StdioFileStream stream = new StdioFileStream (path, FileMode.OpenOrCreate, FileAccess.Write)) { + stream.Write (new byte[0], -1, 1); + } + } + + [Test] + [ExpectedException (typeof (ArgumentException))] + public void Write_OffsetOverflow () + { + string path = TempFolder + Path.DirectorySeparatorChar + "temp"; + DeleteFile (path); + + using (StdioFileStream stream = new StdioFileStream (path, FileMode.OpenOrCreate, FileAccess.Write)) { + stream.Write (new byte[0], Int32.MaxValue, 1); + } + } + + [Test] + [ExpectedException (typeof (ArgumentOutOfRangeException))] + public void Write_CountNegative () + { + string path = TempFolder + Path.DirectorySeparatorChar + "temp"; + DeleteFile (path); + + using (StdioFileStream stream = new StdioFileStream (path, FileMode.OpenOrCreate, FileAccess.Write)) { + stream.Write (new byte[0], 1, -1); + } + } + + [Test] + [ExpectedException (typeof (ArgumentException))] + public void Write_CountOverflow () + { + string path = TempFolder + Path.DirectorySeparatorChar + "temp"; + DeleteFile (path); + + using (StdioFileStream stream = new StdioFileStream (path, FileMode.OpenOrCreate, FileAccess.Write)) { + stream.Write (new byte[0], 1, Int32.MaxValue); + } + } + + [Test] + [ExpectedException (typeof (ArgumentException))] + public void Seek_InvalidSeekOrigin () + { + string path = TempFolder + Path.DirectorySeparatorChar + "temp"; + DeleteFile (path); + + using (StdioFileStream stream = new StdioFileStream (path, FileMode.OpenOrCreate, FileAccess.Read)) { + stream.Seek (0, (SeekOrigin) (-1)); + } + } + + [Test] + [ExpectedException (typeof (ArgumentException))] + public void Constructor_InvalidFileHandle () + { + new StdioFileStream ((IntPtr)(-1), FileAccess.Read); + } + + [Test] + [ExpectedException (typeof (ObjectDisposedException))] + public void Position_Disposed () + { + string path = TempFolder + Path.DirectorySeparatorChar + "temp"; + DeleteFile (path); + StdioFileStream stream = new StdioFileStream (path, FileMode.OpenOrCreate, FileAccess.Read); + stream.Close (); + stream.Position = 0; + } + + [Test] + [ExpectedException (typeof (ObjectDisposedException))] + public void Flush_Disposed () + { + string path = TempFolder + Path.DirectorySeparatorChar + "temp"; + DeleteFile (path); + StdioFileStream stream = new StdioFileStream (path, FileMode.OpenOrCreate, FileAccess.Write); + stream.Close (); + stream.Flush (); + } + + [Test] + [ExpectedException (typeof (ObjectDisposedException))] + public void Seek_Disposed () + { + string path = TempFolder + Path.DirectorySeparatorChar + "temp"; + DeleteFile (path); + StdioFileStream stream = new StdioFileStream (path, FileMode.OpenOrCreate, FileAccess.Write); + stream.Close (); + stream.Seek (0, SeekOrigin.Begin); + } + + [Test] + public void ReadBytePastEndOfStream () + { + string path = TempFolder + Path.DirectorySeparatorChar + "temp"; + DeleteFile (path); + using (StdioFileStream stream = new StdioFileStream (path, FileMode.OpenOrCreate, FileAccess.Read)) { + stream.Seek (0, SeekOrigin.End); + Assert.AreEqual (-1, stream.ReadByte (), "ReadByte"); + stream.Close (); + } + } + + [Test] + [ExpectedException (typeof (NotSupportedException))] + public void SetLengthWithClosedBaseStream () + { + StdioFileStream fs = new StdioFileStream ("temp", FileMode.Create); + BufferedStream bs = new BufferedStream (fs); + fs.Close (); + + bs.SetLength (1000); + } + } +} + -- cgit v1.2.3