Fix Mono.Posix tests on Windows
authorNiklas Therning <niklas@therning.org>
Thu, 17 Nov 2016 12:34:09 +0000 (13:34 +0100)
committerNiklas Therning <niklas@therning.org>
Thu, 17 Nov 2016 13:10:49 +0000 (14:10 +0100)
Cleaned up Mono_Posix_FromSeekFlags() in support/map.c. It didn't properly
handle the case when L_INCR, L_SET, L_XTND aren't available, like on Windows.

Added Mono_Posix_Stdlib_GetLastError() to support/errno.c and changed
Stdlib.GetlastError() use it. Without this Stdlib.GetlastError() wouldn't take
errno in the C runtime used by libMonoPosixHelper.dll into account.

On Windows the Syscall class failed to initialize due to missing functions,
e.g. Mono_Posix_Syscall_get_at_fdcwd(), in libMonoPosixHelper.dll. Those
readonly static fields which were initialized at class initialization have now
been converted to static readonly properties so that the Syscall class can be
initialized despite those functions not being defined.

Cleaned up temp file handling in StdioFileStreamTest to avoid failures due to
sharing violations on Windows.

Fixed a bug in the StdioFileStreamTest.Write() test method when reading back
the batch of bytes written in the second part of the test.

Enabled the Mono.Posix test suite to run on PR builds. This test suite should
from now on be green.

mcs/class/Mono.Posix/Mono.Unix.Native/Stdlib.cs
mcs/class/Mono.Posix/Mono.Unix.Native/Syscall.cs
mcs/class/Mono.Posix/Test/Mono.Unix/StdioFileStreamTest.cs
msvc/monoposixhelper.def
scripts/ci/run-test-default.sh
support/errno.c
support/map.c
support/map.h
support/stdio.c

index 86cdb7126fe305d62a5283fc7bed694d3ec264b2..9b95fba6f3c115923b9c1b1c1e3722326f145f43 100644 (file)
@@ -426,10 +426,20 @@ namespace Mono.Unix.Native {
 
                public static Errno GetLastError ()
                {
-                       int errno = Marshal.GetLastWin32Error ();
-                       return NativeConvert.ToErrno (errno);
+                       if (Environment.OSVersion.Platform != PlatformID.Unix) {
+                               // On Windows Marshal.GetLastWin32Error() doesn't take errno
+                               // into account so we need to call Mono_Posix_Stdlib_GetLastError()
+                               // which returns the value of errno in the C runtime
+                               // libMonoPosixHelper.dll was linked against.
+                               return (Errno) _GetLastError ();
+                       }
+                       return NativeConvert.ToErrno (Marshal.GetLastWin32Error ());
                }
 
+               [DllImport (MPH, CallingConvention=CallingConvention.Cdecl,
+                               EntryPoint="Mono_Posix_Stdlib_GetLastError")]
+               private static extern int _GetLastError ();
+
                [DllImport (MPH, CallingConvention=CallingConvention.Cdecl,
                                EntryPoint="Mono_Posix_Stdlib_SetLastError")]
                private static extern void SetLastError (int error);
index cbeb54b0ec2778f87a457f5494c2f349d5ddb223..e998a74ee4969ffdb481b54de4edcf00f01a687a 100644 (file)
@@ -3085,7 +3085,7 @@ namespace Mono.Unix.Native {
                                EntryPoint="Mono_Posix_Syscall_get_at_fdcwd")]
                private static extern int get_at_fdcwd ();
 
-               public static readonly int AT_FDCWD = get_at_fdcwd ();
+               public static int AT_FDCWD { get { return get_at_fdcwd (); } }
 
                #endregion
 
@@ -3657,12 +3657,12 @@ namespace Mono.Unix.Native {
                [DllImport (MPH, EntryPoint="Mono_Posix_Syscall_L_ctermid")]
                private static extern int _L_ctermid ();
 
-               public static readonly int L_ctermid = _L_ctermid ();
+               public static int L_ctermid { get { return _L_ctermid (); } }
 
                [DllImport (MPH, EntryPoint="Mono_Posix_Syscall_L_cuserid")]
                private static extern int _L_cuserid ();
 
-               public static readonly int L_cuserid = _L_cuserid ();
+               public static int L_cuserid { get { return _L_cuserid (); } }
 
                internal static object getlogin_lock = new object ();
 
@@ -4043,9 +4043,9 @@ namespace Mono.Unix.Native {
                                EntryPoint="Mono_Posix_Syscall_get_utime_omit")]
                private static extern long get_utime_omit ();
 
-               public static readonly long UTIME_NOW = get_utime_now ();
+               public static long UTIME_NOW { get { return get_utime_now (); } }
 
-               public static readonly long UTIME_OMIT = get_utime_omit ();
+               public static long UTIME_OMIT { get { return get_utime_omit (); } }
 
                [DllImport (MPH, SetLastError=true, 
                                EntryPoint="Mono_Posix_Syscall_futimens")]
index aaae08271ed602f6f7d2db79f171aafc98a013bb..9ae0c61b288180fe2c44e97acb3a7a855f321c6f 100644 (file)
@@ -21,25 +21,43 @@ namespace MonoTests.System.IO
        [TestFixture]
        public class StdioFileStreamTest {
 
-               string TempFolder = Path.Combine (Path.GetTempPath (), "MonoTests.Mono.Unix.Tests");
+               static string BaseTempFolder = Path.Combine (Path.GetTempPath (),
+                       "MonoTests.Mono.Unix.Tests");
+               static string TempFolder;
                static readonly char DSC = Path.DirectorySeparatorChar;
 
-               [TearDown]
-               public void TearDown()
+               [TestFixtureSetUp]
+               public void FixtureSetUp ()
                {
-                       if (Directory.Exists (TempFolder))
-                               Directory.Delete (TempFolder, true);
+                       try {
+                               // Try to cleanup from any previous NUnit run.
+                               Directory.Delete (BaseTempFolder, true);
+                       } catch (Exception) {
+                       }
                }
 
                [SetUp]
                public void SetUp ()
                {
-                       if (Directory.Exists (TempFolder))
-                               Directory.Delete (TempFolder, true);
-
+                       int i = 0;
+                       do {
+                               TempFolder = Path.Combine (BaseTempFolder, (++i).ToString());
+                       } while (Directory.Exists (TempFolder));
                        Directory.CreateDirectory (TempFolder);
                }
 
+               [TearDown]
+               public void TearDown ()
+               {
+                       try {
+                               // This might throw an exception on Windows
+                               // since the directory may contain open files.
+                               Directory.Delete (TempFolder, true);
+                       } catch (Exception e) {
+                               Console.WriteLine (e);
+                       }
+               }
+
                public void TestCtr ()
                {
                        string path = TempFolder + DSC + "testfilestream.tmp.1";
@@ -226,7 +244,7 @@ namespace MonoTests.System.IO
                {
                        StdioFileStream fs = null;
                        StdioFileStream fs2 = null;
-                       string tempPath = Path.Combine (Path.GetTempPath (), "temp");
+                       string tempPath = Path.Combine (TempFolder, "temp");
                        try {
                                if (!File.Exists (tempPath)) {
                                        TextWriter tw = File.CreateText (tempPath);
@@ -240,8 +258,6 @@ namespace MonoTests.System.IO
                                        fs.Close ();
                                if (fs2 != null)
                                        fs2.Close ();
-                               if (File.Exists (tempPath))
-                                       File.Delete (tempPath);
                        }
                }
 
@@ -273,8 +289,9 @@ namespace MonoTests.System.IO
                        stream.Write (outbytes, 7, 7);
                        stream.Write (outbytes, 14, 1);
 
-                       stream.Read (bytes, 0, 15);
                        stream.Seek (15, SeekOrigin.Begin);
+                       Array.Clear (bytes, 0, bytes.Length);
+                       stream.Read (bytes, 0, 15);
                        for (int i = 0; i < 15; ++i)
                                Assert.AreEqual (i + 1, bytes [i]);
                        stream.Close ();
index bd2ac9f5a8389707eaae5efecb3c7b31d977f2bc..b8cf7cbfe551818251d48c6737bc66a60f4478bc 100644 (file)
@@ -35,6 +35,7 @@ Mono_Posix_Stdlib_EXIT_FAILURE
 Mono_Posix_Stdlib_EXIT_SUCCESS\r
 Mono_Posix_Stdlib_FILENAME_MAX\r
 Mono_Posix_Stdlib_FOPEN_MAX\r
+Mono_Posix_Stdlib_GetLastError\r
 Mono_Posix_Stdlib_InvokeSignalHandler\r
 Mono_Posix_Stdlib_L_tmpnam\r
 Mono_Posix_Stdlib_MB_CUR_MAX\r
index 5f0767219f8ab2300666f59f05788c27919e122e..28cf98515c373e4385c41e67d8ca3d8a30259728 100755 (executable)
@@ -28,7 +28,7 @@ ${TESTCMD} --label=System.Data --timeout=5m make -w -C mcs/class/System.Data run
 if [[ ${label} == w* ]]; then ${TESTCMD} --label=Mono.Data.Sqlite --skip; else ${TESTCMD} --label=Mono.Data.Sqlite --timeout=5m make -w -C mcs/class/Mono.Data.Sqlite run-test; fi
 ${TESTCMD} --label=System.Data.OracleClient --timeout=5m make -w -C mcs/class/System.Data.OracleClient run-test;
 ${TESTCMD} --label=System.Design --timeout=5m make -w -C mcs/class/System.Design run-test;
-if [[ -n "${ghprbPullId}" ]] && [[ ${label} == w* ]]; then ${TESTCMD} --label=Mono.Posix --skip; else ${TESTCMD} --label=Mono.Posix --timeout=5m make -w -C mcs/class/Mono.Posix run-test; fi
+${TESTCMD} --label=Mono.Posix --timeout=5m make -w -C mcs/class/Mono.Posix run-test
 ${TESTCMD} --label=System.Web --timeout=30m make -w -C mcs/class/System.Web run-test
 ${TESTCMD} --label=System.Web.Services --timeout=5m make -w -C mcs/class/System.Web.Services run-test
 ${TESTCMD} --label=System.Runtime.SFS --timeout=5m make -w -C mcs/class/System.Runtime.Serialization.Formatters.Soap run-test;
index 74c2fdf5648bd0613f87d8cb93b41431e1481e2d..b066d462b167c0a3121486d462612e3e050fb171 100644 (file)
 
 G_BEGIN_DECLS
 
+int
+Mono_Posix_Stdlib_GetLastError (void)
+{
+       return errno;
+}
+
 void
 Mono_Posix_Stdlib_SetLastError (int error_number)
 {
index 92fca755371d09ab6336dd25c5c131d014c47d7d..615584889dfa5c4e7b8659d43b9dcc638481648c 100644 (file)
@@ -4716,52 +4716,36 @@ int Mono_Posix_ToPosixMadviseAdvice (int x, int *r)
 int Mono_Posix_FromSeekFlags (short x, short *r)
 {
        *r = 0;
-       if (x == Mono_Posix_SeekFlags_L_INCR)
 #ifdef L_INCR
+       if (x == Mono_Posix_SeekFlags_L_INCR)
                {*r = L_INCR; return 0;}
-#else /* def L_INCR */
-               {errno = EINVAL; return -1;}
-#endif /* ndef L_INCR */
-       if (x == Mono_Posix_SeekFlags_L_SET)
+#endif /* def L_INCR */
 #ifdef L_SET
+       if (x == Mono_Posix_SeekFlags_L_SET)
                {*r = L_SET; return 0;}
-#else /* def L_SET */
-               {errno = EINVAL; return -1;}
-#endif /* ndef L_SET */
-       if (x == Mono_Posix_SeekFlags_L_XTND)
+#endif /* def L_SET */
 #ifdef L_XTND
+       if (x == Mono_Posix_SeekFlags_L_XTND)
                {*r = L_XTND; return 0;}
-#else /* def L_XTND */
-               {errno = EINVAL; return -1;}
-#endif /* ndef L_XTND */
-       if (x == Mono_Posix_SeekFlags_SEEK_CUR)
+#endif /* def L_XTND */
 #ifdef SEEK_CUR
+       if (x == Mono_Posix_SeekFlags_SEEK_CUR)
                {*r = SEEK_CUR; return 0;}
-#else /* def SEEK_CUR */
-               {errno = EINVAL; return -1;}
-#endif /* ndef SEEK_CUR */
-       if (x == Mono_Posix_SeekFlags_SEEK_END)
+#endif /* def SEEK_CUR */
 #ifdef SEEK_END
+       if (x == Mono_Posix_SeekFlags_SEEK_END)
                {*r = SEEK_END; return 0;}
-#else /* def SEEK_END */
-               {errno = EINVAL; return -1;}
-#endif /* ndef SEEK_END */
-       if (x == Mono_Posix_SeekFlags_SEEK_SET)
+#endif /* def SEEK_END */
 #ifdef SEEK_SET
+       if (x == Mono_Posix_SeekFlags_SEEK_SET)
                {*r = SEEK_SET; return 0;}
-#else /* def SEEK_SET */
-               {errno = EINVAL; return -1;}
-#endif /* ndef SEEK_SET */
-       if (x == 0)
-               return 0;
+#endif /* def SEEK_SET */
        errno = EINVAL; return -1;
 }
 
 int Mono_Posix_ToSeekFlags (short x, short *r)
 {
        *r = 0;
-       if (x == 0)
-               return 0;
 #ifdef L_INCR
        if (x == L_INCR)
                {*r = Mono_Posix_SeekFlags_L_INCR; return 0;}
index 8c6ef5000f2fc22c8dea1fac92404d3e2284ba74..cf6213c8c56f9e1b8f31cc5f2ca735390312e88d 100644 (file)
@@ -2184,6 +2184,7 @@ void* Mono_Posix_Stdlib_realloc (void* ptr, guint64 size);
 void Mono_Posix_Stdlib_free (void* p);
 int Mono_Posix_Stdlib_rewind (void* stream);
 int Mono_Posix_Stdlib_setbuf (void* stream, void* buf);
+int Mono_Posix_Stdlib_GetLastError (void);
 void Mono_Posix_Stdlib_SetLastError (int error);
 int Mono_Posix_Stdlib_setvbuf (void* stream, void* buf, int mode, guint64 size);
 void* Mono_Posix_Stdlib_fopen (char* path, char* mode);
index b914dfdb1d098ec4d4518fd5b28f13b770200b2c..22ce6077de9999cde3fc924b61d308e93f58a7f0 100644 (file)
@@ -49,7 +49,21 @@ Mono_Posix_Stdlib_fwrite (unsigned char *ptr, mph_size_t size, mph_size_t nmemb,
        mph_return_if_size_t_overflow (size);
        mph_return_if_size_t_overflow (nmemb);
 
-       return fwrite (ptr, (size_t) size, (size_t) nmemb, (FILE*) stream);
+       size_t ret = fwrite (ptr, (size_t) size, (size_t) nmemb, (FILE*) stream);
+#ifdef HOST_WIN32
+       // Workaround for a particular weirdness on Windows triggered by the
+       // StdioFileStreamTest.Write() test method. The test writes 15 bytes to a
+       // file, then rewinds the file pointer and reads the same bytes. It then
+       // writes 15 additional bytes to the file. This second write fails on
+       // Windows with 0 returned from fwrite(). Calling fseek() followed by a retry
+       // of fwrite() like we do here fixes the issue.
+       if (ret != nmemb)
+       {
+               fseek (stream, 0, SEEK_CUR);
+               ret = fwrite (ptr + (ret * nmemb), (size_t) size, (size_t) nmemb - ret, (FILE*) stream);
+       }
+#endif
+       return ret;
 }
 
 #ifdef HAVE_VSNPRINTF