Summary

Class:WireMock.Util.EnhancedFileSystemWatcher
Assembly:WireMock.Net
File(s):C:\Users\azureuser\Documents\Github\WireMock.Net\src\WireMock.Net\Util\EnhancedFileSystemWatcher.cs
Covered lines:0
Uncovered lines:90
Coverable lines:90
Total lines:265
Line coverage:0%
Branch coverage:0%

Metrics

MethodCyclomatic complexity  NPath complexity  Sequence coverage  Branch coverage  
.ctor(...)2000
.ctor(...)2000
.ctor(...)2000
OnChanged(...)2200
OnCreated(...)2200
OnDeleted(...)2200
OnRenamed(...)2200
InitializeMembers(...)1000
HasAnotherFileEventOccuredRecently(...)3400
OnChanged(...)2200
OnCreated(...)2200
OnDeleted(...)2200
OnRenamed(...)2200
Dispose()1000

File(s)

C:\Users\azureuser\Documents\Github\WireMock.Net\src\WireMock.Net\Util\EnhancedFileSystemWatcher.cs

#LineLine coverage
 1using System;
 2using System.Collections.Concurrent;
 3using System.IO;
 4using JetBrains.Annotations;
 5using WireMock.Validation;
 6
 7namespace WireMock.Util
 8{
 9    /// <summary>
 10    /// An EnhancedFileSystemWatcher, which can be used to suppress duplicate events that fire on a single change to the
 11    /// </summary>
 12    /// <seealso cref="System.IO.FileSystemWatcher" />
 13    /// <seealso cref="System.IDisposable" />
 14    public class EnhancedFileSystemWatcher : FileSystemWatcher, IDisposable
 15    {
 16        #region Private Members
 17        // Default Watch Interval in Milliseconds
 18        private const int DefaultWatchInterval = 100;
 19
 20        // This Dictionary keeps the track of when an event occured last for a particular file
 21        private ConcurrentDictionary<string, DateTime> _lastFileEvent;
 22
 23        // Watch Interval in Milliseconds
 24        private int _interval;
 25
 26        // Timespan created when interval is set
 27        private TimeSpan _recentTimeSpan;
 28        #endregion
 29
 30        #region Public Properties
 31        /// <summary>
 32        /// Interval, in milliseconds, within which events are considered "recent".
 33        /// </summary>
 34        [PublicAPI]
 35        public int Interval
 36        {
 037            get => _interval;
 38            set
 039            {
 040                _interval = value;
 41
 42                // Set timespan based on the value passed
 043                _recentTimeSpan = new TimeSpan(0, 0, 0, 0, value);
 044            }
 45        }
 46
 47        /// <summary>
 48        /// Allows user to set whether to filter recent events.
 49        /// If this is set a false, this class behaves like System.IO.FileSystemWatcher class.
 50        /// </summary>
 51        [PublicAPI]
 052        public bool FilterRecentEvents { get; set; }
 53        #endregion
 54
 55        #region Constructors
 56        /// <summary>
 57        /// Initializes a new instance of the <see cref="EnhancedFileSystemWatcher"/> class.
 58        /// </summary>
 59        /// <param name="interval">The interval.</param>
 060        public EnhancedFileSystemWatcher(int interval = DefaultWatchInterval)
 061        {
 062            Check.Condition(interval, i => i >= 0, nameof(interval));
 63
 064            InitializeMembers(interval);
 065        }
 66
 67        /// <summary>
 68        /// Initializes a new instance of the <see cref="EnhancedFileSystemWatcher"/> class.
 69        /// </summary>
 70        /// <param name="path">The directory to monitor, in standard or Universal Naming Convention (UNC) notation.</par
 71        /// <param name="interval">The interval.</param>
 072        public EnhancedFileSystemWatcher([NotNull] string path, int interval = DefaultWatchInterval) : base(path)
 073        {
 074            Check.NotNullOrEmpty(path, nameof(path));
 075            Check.Condition(interval, i => i >= 0, nameof(interval));
 76
 077            InitializeMembers(interval);
 078        }
 79
 80        /// <summary>
 81        /// Initializes a new instance of the <see cref="EnhancedFileSystemWatcher"/> class.
 82        /// </summary>
 83        /// <param name="path">The directory to monitor, in standard or Universal Naming Convention (UNC) notation.</par
 84        /// <param name="filter">The type of files to watch. For example, "*.txt" watches for changes to all text files.
 85        /// <param name="interval">The interval.</param>
 086        public EnhancedFileSystemWatcher([NotNull] string path, [NotNull] string filter, int interval = DefaultWatchInte
 087        {
 088            Check.NotNullOrEmpty(path, nameof(path));
 089            Check.NotNullOrEmpty(filter, nameof(filter));
 090            Check.Condition(interval, i => i >= 0, nameof(interval));
 91
 092            InitializeMembers(interval);
 093        }
 94        #endregion
 95
 96        #region Events
 97        // These events hide the events from the base class.
 98        // We want to raise these events appropriately and we do not want the
 99        // users of this class subscribing to these events of the base class accidentally
 100
 101        /// <summary>
 102        /// Occurs when a file or directory in the specified <see cref="P:System.IO.FileSystemWatcher.Path" /> is change
 103        /// </summary>
 104        public new event FileSystemEventHandler Changed;
 105
 106        /// <summary>
 107        /// Occurs when a file or directory in the specified <see cref="P:System.IO.FileSystemWatcher.Path" /> is create
 108        /// </summary>
 109        public new event FileSystemEventHandler Created;
 110
 111        /// <summary>
 112        /// Occurs when a file or directory in the specified <see cref="P:System.IO.FileSystemWatcher.Path" /> is delete
 113        /// </summary>
 114        public new event FileSystemEventHandler Deleted;
 115
 116        /// <summary>
 117        /// Occurs when a file or directory in the specified <see cref="P:System.IO.FileSystemWatcher.Path" /> is rename
 118        /// </summary>
 119        public new event RenamedEventHandler Renamed;
 120        #endregion
 121
 122        #region Protected Methods to raise the Events for this class
 123        /// <summary>
 124        /// Raises the <see cref="E:System.IO.FileSystemWatcher.Changed" /> event.
 125        /// </summary>
 126        /// <param name="e">A <see cref="T:System.IO.FileSystemEventArgs" /> that contains the event data.</param>
 127        protected new virtual void OnChanged(FileSystemEventArgs e)
 0128        {
 0129             Changed?.Invoke(this, e);
 0130        }
 131
 132        /// <summary>
 133        /// Raises the <see cref="E:System.IO.FileSystemWatcher.Created" /> event.
 134        /// </summary>
 135        /// <param name="e">A <see cref="T:System.IO.FileSystemEventArgs" /> that contains the event data.</param>
 136        protected new virtual void OnCreated(FileSystemEventArgs e)
 0137        {
 0138             Created?.Invoke(this, e);
 0139        }
 140
 141        /// <summary>
 142        /// Raises the <see cref="E:System.IO.FileSystemWatcher.Deleted" /> event.
 143        /// </summary>
 144        /// <param name="e">A <see cref="T:System.IO.FileSystemEventArgs" /> that contains the event data.</param>
 145        protected new virtual void OnDeleted(FileSystemEventArgs e)
 0146        {
 0147             Deleted?.Invoke(this, e);
 0148        }
 149
 150        /// <summary>
 151        /// Raises the <see cref="E:System.IO.FileSystemWatcher.Renamed" /> event.
 152        /// </summary>
 153        /// <param name="e">A <see cref="T:System.IO.RenamedEventArgs" /> that contains the event data.</param>
 154        protected new virtual void OnRenamed(RenamedEventArgs e)
 0155        {
 0156             Renamed?.Invoke(this, e);
 0157        }
 158        #endregion
 159
 160        #region Private Methods
 161        /// <summary>
 162        /// This Method Initializes the private members.
 163        /// Interval is set to its default value of 100 millisecond.
 164        /// FilterRecentEvents is set to true, _lastFileEvent dictionary is initialized.
 165        /// We subscribe to the base class events.
 166        /// </summary>
 167        private void InitializeMembers(int interval = 100)
 0168        {
 0169            Interval = interval;
 0170            FilterRecentEvents = true;
 0171            _lastFileEvent = new ConcurrentDictionary<string, DateTime>();
 172
 0173            base.Created += OnCreated;
 0174            base.Changed += OnChanged;
 0175            base.Deleted += OnDeleted;
 0176            base.Renamed += OnRenamed;
 0177        }
 178
 179        /// <summary>
 180        /// This method searches the dictionary to find out when the last event occured
 181        /// for a particular file. If that event occured within the specified timespan
 182        /// it returns true, else false
 183        /// </summary>
 184        /// <param name="fileName">The filename to be checked</param>
 185        /// <returns>True if an event has occured within the specified interval, False otherwise</returns>
 186        private bool HasAnotherFileEventOccuredRecently(string fileName)
 0187        {
 188            // Check dictionary only if user wants to filter recent events otherwise return value stays false.
 0189             if (!FilterRecentEvents)
 0190            {
 0191                return false;
 192            }
 193
 0194            bool retVal = false;
 0195             if (_lastFileEvent.ContainsKey(fileName))
 0196            {
 197                // If dictionary contains the filename, check how much time has elapsed
 198                // since the last event occured. If the timespan is less that the
 199                // specified interval, set return value to true
 200                // and store current datetime in dictionary for this file
 0201                DateTime lastEventTime = _lastFileEvent[fileName];
 0202                DateTime currentTime = DateTime.Now;
 0203                TimeSpan timeSinceLastEvent = currentTime - lastEventTime;
 0204                retVal = timeSinceLastEvent < _recentTimeSpan;
 0205                _lastFileEvent[fileName] = currentTime;
 0206            }
 207            else
 0208            {
 209                // If dictionary does not contain the filename,
 210                // no event has occured in past for this file, so set return value to false
 211                // and append filename along with current datetime to the dictionary
 0212                _lastFileEvent.TryAdd(fileName, DateTime.Now);
 0213            }
 214
 0215            return retVal;
 0216        }
 217
 218        #region FileSystemWatcher EventHandlers
 219        // Base class Event Handlers. Check if an event has occured recently and call method
 220        // to raise appropriate event only if no recent event is detected
 221        private void OnChanged(object sender, FileSystemEventArgs e)
 0222        {
 0223             if (!HasAnotherFileEventOccuredRecently(e.FullPath))
 0224            {
 0225                OnChanged(e);
 0226            }
 0227        }
 228
 229        private void OnCreated(object sender, FileSystemEventArgs e)
 0230        {
 0231             if (!HasAnotherFileEventOccuredRecently(e.FullPath))
 0232            {
 0233                OnCreated(e);
 0234            }
 0235        }
 236
 237        private void OnDeleted(object sender, FileSystemEventArgs e)
 0238        {
 0239             if (!HasAnotherFileEventOccuredRecently(e.FullPath))
 0240            {
 0241                OnDeleted(e);
 0242            }
 0243        }
 244
 245        private void OnRenamed(object sender, RenamedEventArgs e)
 0246        {
 0247             if (!HasAnotherFileEventOccuredRecently(e.OldFullPath))
 0248            {
 0249                OnRenamed(e);
 0250            }
 0251        }
 252        #endregion
 253        #endregion
 254
 255        #region IDisposable Members
 256        /// <summary>
 257        /// Releases all resources used by the <see cref="T:System.ComponentModel.Component" />.
 258        /// </summary>
 259        public new void Dispose()
 0260        {
 0261            base.Dispose();
 0262        }
 263        #endregion
 264    }
 265}