diff options
-rw-r--r-- | mcs/class/System/System.IO/FileSystemWatcher.cs | 2 | ||||
-rw-r--r-- | mcs/class/System/Test/System.IO/FileSystemWatcherTest.cs | 78 |
2 files changed, 78 insertions, 2 deletions
diff --git a/mcs/class/System/System.IO/FileSystemWatcher.cs b/mcs/class/System/System.IO/FileSystemWatcher.cs index 9c003a80e5a..cbf71e7a9a6 100644 --- a/mcs/class/System/System.IO/FileSystemWatcher.cs +++ b/mcs/class/System/System.IO/FileSystemWatcher.cs @@ -61,7 +61,7 @@ namespace System.IO { SearchPattern2 pattern; bool disposed; string mangledFilter; - static IFileWatcher watcher; + IFileWatcher watcher; object watcher_handle; static object lockobj = new object (); diff --git a/mcs/class/System/Test/System.IO/FileSystemWatcherTest.cs b/mcs/class/System/Test/System.IO/FileSystemWatcherTest.cs index 358a43eb1cd..5e1a2b7303a 100644 --- a/mcs/class/System/Test/System.IO/FileSystemWatcherTest.cs +++ b/mcs/class/System/Test/System.IO/FileSystemWatcherTest.cs @@ -11,6 +11,7 @@ using NUnit.Framework; using System; using System.IO; +using System.Reflection; using MonoTests.Helpers; @@ -109,7 +110,82 @@ namespace MonoTests.System.IO } } } + + [Test] + public void CreateTwoAndDispose () + { + // Create two FSW instances and dispose them. Verify + // that the backend IFileWatcher's Dispose + // (watcher_handle) method got called. + + // FIXME: This only works for the + // CoreFXFileSystemWatcherProxy not the other backends. + + using (var tmp = new TempDirectory ()) { + // have to use reflection to poke at the private fields of FileSystemWatcher. + var watcherField = typeof (FileSystemWatcher).GetField ("watcher", BindingFlags.Instance | BindingFlags.NonPublic); + Assert.IsNotNull (watcherField); + var watcherHandleField = typeof (FileSystemWatcher).GetField ("watcher_handle", BindingFlags.Instance | BindingFlags.NonPublic); + Assert.IsNotNull (watcherHandleField); + var proxyType = typeof (FileSystemWatcher).Assembly.GetType ("System.IO.CoreFXFileSystemWatcherProxy"); + Assert.IsNotNull (proxyType); + // the "internal_map" maps watcher handles to backend CoreFX FSW instances + var proxyTypeInternalMapField = proxyType.GetField ("internal_map", BindingFlags.Static | BindingFlags.NonPublic); + Assert.IsNotNull (proxyTypeInternalMapField); + + var fsw1 = new FileSystemWatcher (tmp.Path, "*"); + var fsw2 = new FileSystemWatcher (tmp.Path, "*"); + // at this point watcher and watcher_handle should be set + + global::System.Collections.Generic.IDictionary<object, global::System.IO.CoreFX.FileSystemWatcher> internal_map = null; + object handle1 = null; + object handle2 = null; + + // using "using" to ensure that Dispose gets called even if we throw an exception + using (var fsw11 = fsw1) + using (var fsw22 = fsw2) { + + // Once at least one FSW is initialized, watcher should be set. But if the + // wrong backend is getting used, ignore this test because the other checks + // (internal_map in particular) won't be valid. + var watcher = watcherField.GetValue (fsw1); + Assert.IsNotNull (watcher); + if (!proxyType.IsAssignableFrom (watcher.GetType ())) + Assert.Ignore ("Testing only CoreFXFileSystemWatcherProxy FSW backend"); + + handle1 = watcherHandleField.GetValue (fsw1); + handle2 = watcherHandleField.GetValue (fsw2); + + Assert.IsNotNull (handle1); + Assert.IsNotNull (handle2); + + // Can't check for internal_map earlier - it is lazily created when the first + // FSW instance is created + internal_map = proxyTypeInternalMapField.GetValue (null) + as global::System.Collections.Generic.IDictionary<object, global::System.IO.CoreFX.FileSystemWatcher>; + Assert.IsNotNull (internal_map); + + // Both of handles should be in the internal map while the file system watchers + // are not disposed. + Assert.IsTrue (internal_map.ContainsKey (handle1)); + Assert.IsTrue (internal_map.ContainsKey (handle2)); + + } + + // Dispose was called, now watcher_handle should be null + + Assert.IsNull (watcherHandleField.GetValue (fsw1)); + Assert.IsNull (watcherHandleField.GetValue (fsw2)); + + // This pair are the critical checks: after we call Dispose on fsw1 and fsw2, the + // backend's internal map shouldn't have anything keyed on handle1 and handle2. + // Therefore System.IO.CoreFX.FileSystemWatcher instances will be disposed of, too. + Assert.IsFalse (internal_map.ContainsKey (handle1)); + Assert.IsFalse (internal_map.ContainsKey (handle2)); + } + } + } } -#endif
\ No newline at end of file +#endif |