1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System; 6 using System.Collections.Generic; 7 using System.ComponentModel; 8 using System.IO; 9 using System.Linq; 10 using System.Runtime.InteropServices; 11 using System.Threading; 12 using Xunit; 13 14 namespace System.IO.Tests 15 { 16 public class FileSystemWatcherTests_netstandard17 : FileSystemWatcherTest 17 { 18 public class TestSite : ISite 19 { 20 public bool designMode; 21 public bool DesignMode => designMode; 22 public IComponent Component => null; 23 public IContainer Container => null; 24 public string Name { get; set; } 25 public object GetService(Type serviceType) => null; 26 } 27 28 [Fact] Site_GetSetRoundtrips()29 public void Site_GetSetRoundtrips() 30 { 31 using (var testDirectory = new TempDirectory(GetTestFilePath())) 32 using (var watcher = new TestFileSystemWatcher(testDirectory.Path, "*")) 33 { 34 TestSite site = new TestSite(); 35 Assert.Null(watcher.Site); 36 watcher.Site = site; 37 Assert.Equal(site, watcher.Site); 38 watcher.Site = null; 39 Assert.Null(watcher.Site); 40 Assert.False(watcher.EnableRaisingEvents); 41 } 42 } 43 44 /// <summary> 45 /// When the FSW Site is set to a nonnull Site with DesignMode enabled, Event raising will be set to true 46 /// </summary> 47 [Fact] Site_NonNullSetEnablesRaisingEvents()48 public void Site_NonNullSetEnablesRaisingEvents() 49 { 50 using (var testDirectory = new TempDirectory(GetTestFilePath())) 51 using (var watcher = new TestFileSystemWatcher(testDirectory.Path, "*")) 52 { 53 TestSite site = new TestSite() { designMode = true }; 54 watcher.Site = site; 55 Assert.True(watcher.EnableRaisingEvents); 56 } 57 } 58 59 internal class TestISynchronizeInvoke : ISynchronizeInvoke 60 { 61 public bool BeginInvoke_Called; 62 public Delegate ExpectedDelegate; 63 BeginInvoke(Delegate method, object[] args)64 public IAsyncResult BeginInvoke(Delegate method, object[] args) 65 { 66 Assert.Equal(ExpectedDelegate, method); 67 BeginInvoke_Called = true; 68 return null; 69 } 70 71 public bool InvokeRequired => true; 72 public object EndInvoke(IAsyncResult result) => null; Invoke(Delegate method, object[] args)73 public object Invoke(Delegate method, object[] args) => null; 74 } 75 76 [Fact] SynchronizingObject_GetSetRoundtrips()77 public void SynchronizingObject_GetSetRoundtrips() 78 { 79 TestISynchronizeInvoke invoker = new TestISynchronizeInvoke() { }; 80 using (var testDirectory = new TempDirectory(GetTestFilePath())) 81 using (var watcher = new TestFileSystemWatcher(testDirectory.Path, "*")) 82 { 83 Assert.Null(watcher.SynchronizingObject); 84 watcher.SynchronizingObject = invoker; 85 Assert.Equal(invoker, watcher.SynchronizingObject); 86 watcher.SynchronizingObject = null; 87 Assert.Null(watcher.SynchronizingObject); 88 } 89 } 90 91 /// <summary> 92 /// Ensure that the SynchronizeObject is invoked when an event occurs 93 /// </summary> 94 [Theory] 95 [InlineData(WatcherChangeTypes.Changed)] 96 [InlineData(WatcherChangeTypes.Deleted)] 97 [InlineData(WatcherChangeTypes.Created)] SynchronizingObject_CalledOnEvent(WatcherChangeTypes expectedChangeType)98 public void SynchronizingObject_CalledOnEvent(WatcherChangeTypes expectedChangeType) 99 { 100 FileSystemEventHandler dele = (sender, e) => { Assert.Equal(expectedChangeType, e.ChangeType); }; 101 TestISynchronizeInvoke invoker = new TestISynchronizeInvoke() { ExpectedDelegate = dele }; 102 using (var testDirectory = new TempDirectory(GetTestFilePath())) 103 using (var watcher = new TestFileSystemWatcher(testDirectory.Path, "*")) 104 { 105 watcher.SynchronizingObject = invoker; 106 if (expectedChangeType == WatcherChangeTypes.Created) 107 { 108 watcher.Created += dele; 109 watcher.CallOnCreated(new FileSystemEventArgs(WatcherChangeTypes.Created, "test", "name")); 110 } 111 else if (expectedChangeType == WatcherChangeTypes.Deleted) 112 { 113 watcher.Deleted += dele; 114 watcher.CallOnDeleted(new FileSystemEventArgs(WatcherChangeTypes.Deleted, "test", "name")); 115 } 116 else if (expectedChangeType == WatcherChangeTypes.Changed) 117 { 118 watcher.Changed += dele; 119 watcher.CallOnChanged(new FileSystemEventArgs(WatcherChangeTypes.Changed, "test", "name")); 120 } 121 Assert.True(invoker.BeginInvoke_Called); 122 } 123 } 124 125 /// <summary> 126 /// Ensure that the SynchronizeObject is invoked when an Renamed event occurs 127 /// </summary> 128 [Fact] SynchronizingObject_CalledOnRenamed()129 public void SynchronizingObject_CalledOnRenamed() 130 { 131 RenamedEventHandler dele = (sender, e) => { Assert.Equal(WatcherChangeTypes.Renamed, e.ChangeType); }; 132 TestISynchronizeInvoke invoker = new TestISynchronizeInvoke() { ExpectedDelegate = dele }; 133 using (var testDirectory = new TempDirectory(GetTestFilePath())) 134 using (var watcher = new TestFileSystemWatcher(testDirectory.Path, "*")) 135 { 136 watcher.SynchronizingObject = invoker; 137 watcher.Renamed += dele; 138 watcher.CallOnRenamed(new RenamedEventArgs(WatcherChangeTypes.Changed, "test", "name", "oldname")); 139 Assert.True(invoker.BeginInvoke_Called); 140 } 141 } 142 143 /// <summary> 144 /// Ensure that the SynchronizeObject is invoked when an Error event occurs 145 /// </summary> 146 [Fact] SynchronizingObject_CalledOnError()147 public void SynchronizingObject_CalledOnError() 148 { 149 ErrorEventHandler dele = (sender, e) => { Assert.IsType<FileNotFoundException>(e.GetException()); }; 150 TestISynchronizeInvoke invoker = new TestISynchronizeInvoke() { ExpectedDelegate = dele }; 151 using (var testDirectory = new TempDirectory(GetTestFilePath())) 152 using (var watcher = new TestFileSystemWatcher(testDirectory.Path, "*")) 153 { 154 watcher.SynchronizingObject = invoker; 155 watcher.Error += dele; 156 watcher.CallOnError(new ErrorEventArgs(new FileNotFoundException())); 157 Assert.True(invoker.BeginInvoke_Called); 158 } 159 } 160 161 /// <summary> 162 /// Calling BeginInit and EndInit in a loop is fine. If events are enabled, they will start and stop in the loop as well. 163 /// </summary> 164 [Fact] BeginEndInit_Repeated()165 public void BeginEndInit_Repeated() 166 { 167 using (var testDirectory = new TempDirectory(GetTestFilePath())) 168 using (var watcher = new TestFileSystemWatcher(testDirectory.Path, "*")) 169 { 170 watcher.BeginInit(); 171 watcher.EndInit(); 172 watcher.BeginInit(); 173 watcher.EndInit(); 174 Assert.False(watcher.EnableRaisingEvents); 175 } 176 } 177 178 /// <summary> 179 /// BeginInit followed by a EnableRaisingEvents=true does not cause the watcher to begin. 180 /// </summary> 181 [Fact] BeginInit_PausesEnableRaisingEvents()182 public void BeginInit_PausesEnableRaisingEvents() 183 { 184 using (var testDirectory = new TempDirectory(GetTestFilePath())) 185 using (var watcher = new TestFileSystemWatcher(testDirectory.Path, "*")) 186 { 187 watcher.Created += (obj, e) => { Assert.False(true, "Created event should not occur"); }; 188 watcher.Deleted += (obj, e) => { Assert.False(true, "Deleted event should not occur"); }; 189 watcher.BeginInit(); 190 watcher.EnableRaisingEvents = true; 191 new TempFile(Path.Combine(testDirectory.Path, GetTestFileName())).Dispose(); 192 Thread.Sleep(WaitForExpectedEventTimeout); 193 } 194 } 195 196 /// <summary> 197 /// EndInit will begin EnableRaisingEvents if we previously set EnableRaisingEvents=true 198 /// </summary> 199 [Fact] EndInit_ResumesPausedEnableRaisingEvents()200 public void EndInit_ResumesPausedEnableRaisingEvents() 201 { 202 using (var testDirectory = new TempDirectory(GetTestFilePath())) 203 using (var watcher = new TestFileSystemWatcher(testDirectory.Path, "*")) 204 { 205 watcher.BeginInit(); 206 watcher.EnableRaisingEvents = true; 207 watcher.EndInit(); 208 ExpectEvent(watcher, WatcherChangeTypes.Created | WatcherChangeTypes.Deleted, () => new TempFile(Path.Combine(testDirectory.Path, GetTestFileName())).Dispose(), null); 209 } 210 } 211 212 /// <summary> 213 /// EndInit will begin EnableRaisingEvents if we previously set EnableRaisingEvents=true 214 /// </summary> 215 [Theory] 216 [InlineData(true)] 217 [InlineData(false)] EndInit_ResumesPausedEnableRaisingEvents(bool setBeforeBeginInit)218 public void EndInit_ResumesPausedEnableRaisingEvents(bool setBeforeBeginInit) 219 { 220 using (var testDirectory = new TempDirectory(GetTestFilePath())) 221 using (var watcher = new TestFileSystemWatcher(testDirectory.Path, "*")) 222 { 223 if (setBeforeBeginInit) 224 watcher.EnableRaisingEvents = true; 225 watcher.BeginInit(); 226 if (!setBeforeBeginInit) 227 watcher.EnableRaisingEvents = true; 228 watcher.EndInit(); 229 ExpectEvent(watcher, WatcherChangeTypes.Created | WatcherChangeTypes.Deleted, () => new TempFile(Path.Combine(testDirectory.Path, GetTestFileName())).Dispose(), null); 230 } 231 } 232 233 /// <summary> 234 /// Stopping events during the initialization period will prevent the watcher from restarting after EndInit() 235 /// </summary> 236 [Fact] EndRaisingEventsDuringPause()237 public void EndRaisingEventsDuringPause() 238 { 239 using (var testDirectory = new TempDirectory(GetTestFilePath())) 240 using (var watcher = new TestFileSystemWatcher(testDirectory.Path, "*")) 241 { 242 watcher.EnableRaisingEvents = true; 243 watcher.BeginInit(); 244 watcher.EnableRaisingEvents = false; 245 watcher.EndInit(); 246 new TempFile(Path.Combine(testDirectory.Path, GetTestFileName())).Dispose(); 247 Thread.Sleep(WaitForExpectedEventTimeout); 248 } 249 } 250 251 /// <summary> 252 /// EndInit will not start event raising unless EnableRaisingEvents was set to true. 253 /// </summary> 254 [Fact] EndInit_DoesNotEnableEventRaisedEvents()255 public void EndInit_DoesNotEnableEventRaisedEvents() 256 { 257 using (var testDirectory = new TempDirectory(GetTestFilePath())) 258 using (var watcher = new TestFileSystemWatcher(testDirectory.Path, "*")) 259 { 260 watcher.Created += (obj, e) => { Assert.False(true, "Created event should not occur"); }; 261 watcher.Deleted += (obj, e) => { Assert.False(true, "Deleted event should not occur"); }; 262 watcher.BeginInit(); 263 watcher.EndInit(); 264 new TempFile(Path.Combine(testDirectory.Path, GetTestFileName())).Dispose(); 265 Thread.Sleep(WaitForExpectedEventTimeout); 266 } 267 } 268 } 269 } 270