Summary

Class:WireMock.Util.EnhancedFileSystemWatcher
Assembly:WireMock.Net
File(s):C:\Users\StefHeyenrath\Documents\GitHub\WireMock.Net\src\WireMock.Net\Util\EnhancedFileSystemWatcher.cs
Covered lines:0
Uncovered lines:87
Coverable lines:87
Total lines:254
Line coverage:0%
Branch coverage:0%

Metrics

MethodCyclomatic complexity NPath complexity Sequence coverage Branch coverage
OnChanged(...)0000
OnCreated(...)0000
OnDeleted(...)0000
OnRenamed(...)0000
InitializeMembers(...)0000
HasAnotherFileEventOccuredRecently(...)0000
OnChanged(...)0000
OnCreated(...)0000
OnDeleted(...)0000
OnRenamed(...)0000
.ctor(...)0000
.ctor(...)0000
.ctor(...)0000

File(s)

C:\Users\StefHeyenrath\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="FileSystemWatcher" />
 13    public class EnhancedFileSystemWatcher : FileSystemWatcher
 14    {
 15        #region Private Members
 16        // Default Watch Interval in Milliseconds
 17        private const int DefaultWatchInterval = 100;
 18
 19        // This Dictionary keeps the track of when an event occured last for a particular file
 20        private ConcurrentDictionary<string, DateTime> _lastFileEvent;
 21
 22        // Watch Interval in Milliseconds
 23        private int _interval;
 24
 25        // Timespan created when interval is set
 26        private TimeSpan _recentTimeSpan;
 27        #endregion
 28
 29        #region Public Properties
 30        /// <summary>
 31        /// Interval, in milliseconds, within which events are considered "recent".
 32        /// </summary>
 33        [PublicAPI]
 34        public int Interval
 35        {
 036            get => _interval;
 37            set
 038            {
 039                _interval = value;
 40
 41                // Set timespan based on the value passed
 042                _recentTimeSpan = new TimeSpan(0, 0, 0, 0, value);
 043            }
 44        }
 45
 46        /// <summary>
 47        /// Allows user to set whether to filter recent events.
 48        /// If this is set a false, this class behaves like System.IO.FileSystemWatcher class.
 49        /// </summary>
 50        [PublicAPI]
 051        public bool FilterRecentEvents { get; set; }
 52        #endregion
 53
 54        #region Constructors
 55        /// <summary>
 56        /// Initializes a new instance of the <see cref="EnhancedFileSystemWatcher"/> class.
 57        /// </summary>
 58        /// <param name="interval">The interval.</param>
 059        public EnhancedFileSystemWatcher(int interval = DefaultWatchInterval)
 060        {
 061            Check.Condition(interval, i => i >= 0, nameof(interval));
 62
 063            InitializeMembers(interval);
 064        }
 65
 66        /// <summary>
 67        /// Initializes a new instance of the <see cref="EnhancedFileSystemWatcher"/> class.
 68        /// </summary>
 69        /// <param name="path">The directory to monitor, in standard or Universal Naming Convention (UNC) notation.</par
 70        /// <param name="interval">The interval.</param>
 071        public EnhancedFileSystemWatcher([NotNull] string path, int interval = DefaultWatchInterval) : base(path)
 072        {
 073            Check.NotNullOrEmpty(path, nameof(path));
 074            Check.Condition(interval, i => i >= 0, nameof(interval));
 75
 076            InitializeMembers(interval);
 077        }
 78
 79        /// <summary>
 80        /// Initializes a new instance of the <see cref="EnhancedFileSystemWatcher"/> class.
 81        /// </summary>
 82        /// <param name="path">The directory to monitor, in standard or Universal Naming Convention (UNC) notation.</par
 83        /// <param name="filter">The type of files to watch. For example, "*.txt" watches for changes to all text files.
 84        /// <param name="interval">The interval.</param>
 085        public EnhancedFileSystemWatcher([NotNull] string path, [NotNull] string filter, int interval = DefaultWatchInte
 086        {
 087            Check.NotNullOrEmpty(path, nameof(path));
 088            Check.NotNullOrEmpty(filter, nameof(filter));
 089            Check.Condition(interval, i => i >= 0, nameof(interval));
 90
 091            InitializeMembers(interval);
 092        }
 93        #endregion
 94
 95        #region Events
 96        // These events hide the events from the base class.
 97        // We want to raise these events appropriately and we do not want the
 98        // users of this class subscribing to these events of the base class accidentally
 99
 100        /// <summary>
 101        /// Occurs when a file or directory in the specified <see cref="P:System.IO.FileSystemWatcher.Path" /> is change
 102        /// </summary>
 103        public new event FileSystemEventHandler Changed;
 104
 105        /// <summary>
 106        /// Occurs when a file or directory in the specified <see cref="P:System.IO.FileSystemWatcher.Path" /> is create
 107        /// </summary>
 108        public new event FileSystemEventHandler Created;
 109
 110        /// <summary>
 111        /// Occurs when a file or directory in the specified <see cref="P:System.IO.FileSystemWatcher.Path" /> is delete
 112        /// </summary>
 113        public new event FileSystemEventHandler Deleted;
 114
 115        /// <summary>
 116        /// Occurs when a file or directory in the specified <see cref="P:System.IO.FileSystemWatcher.Path" /> is rename
 117        /// </summary>
 118        public new event RenamedEventHandler Renamed;
 119        #endregion
 120
 121        #region Protected Methods to raise the Events for this class
 122        /// <summary>
 123        /// Raises the <see cref="E:System.IO.FileSystemWatcher.Changed" /> event.
 124        /// </summary>
 125        /// <param name="e">A <see cref="T:System.IO.FileSystemEventArgs" /> that contains the event data.</param>
 126        protected new virtual void OnChanged(FileSystemEventArgs e)
 0127        {
 0128            Changed?.Invoke(this, e);
 0129        }
 130
 131        /// <summary>
 132        /// Raises the <see cref="E:System.IO.FileSystemWatcher.Created" /> event.
 133        /// </summary>
 134        /// <param name="e">A <see cref="T:System.IO.FileSystemEventArgs" /> that contains the event data.</param>
 135        protected new virtual void OnCreated(FileSystemEventArgs e)
 0136        {
 0137            Created?.Invoke(this, e);
 0138        }
 139
 140        /// <summary>
 141        /// Raises the <see cref="E:System.IO.FileSystemWatcher.Deleted" /> event.
 142        /// </summary>
 143        /// <param name="e">A <see cref="T:System.IO.FileSystemEventArgs" /> that contains the event data.</param>
 144        protected new virtual void OnDeleted(FileSystemEventArgs e)
 0145        {
 0146            Deleted?.Invoke(this, e);
 0147        }
 148
 149        /// <summary>
 150        /// Raises the <see cref="E:System.IO.FileSystemWatcher.Renamed" /> event.
 151        /// </summary>
 152        /// <param name="e">A <see cref="T:System.IO.RenamedEventArgs" /> that contains the event data.</param>
 153        protected new virtual void OnRenamed(RenamedEventArgs e)
 0154        {
 0155            Renamed?.Invoke(this, e);
 0156        }
 157        #endregion
 158
 159        #region Private Methods
 160        /// <summary>
 161        /// This Method Initializes the private members.
 162        /// Interval is set to its default value of 100 millisecond.
 163        /// FilterRecentEvents is set to true, _lastFileEvent dictionary is initialized.
 164        /// We subscribe to the base class events.
 165        /// </summary>
 166        private void InitializeMembers(int interval = 100)
 0167        {
 0168            Interval = interval;
 0169            FilterRecentEvents = true;
 0170            _lastFileEvent = new ConcurrentDictionary<string, DateTime>();
 171
 0172            base.Created += OnCreated;
 0173            base.Changed += OnChanged;
 0174            base.Deleted += OnDeleted;
 0175            base.Renamed += OnRenamed;
 0176        }
 177
 178        /// <summary>
 179        /// This method searches the dictionary to find out when the last event occured
 180        /// for a particular file. If that event occured within the specified timespan
 181        /// it returns true, else false
 182        /// </summary>
 183        /// <param name="fileName">The filename to be checked</param>
 184        /// <returns>True if an event has occured within the specified interval, False otherwise</returns>
 185        private bool HasAnotherFileEventOccuredRecently(string fileName)
 0186        {
 187            // Check dictionary only if user wants to filter recent events otherwise return value stays false.
 0188            if (!FilterRecentEvents)
 0189            {
 0190                return false;
 191            }
 192
 0193            bool retVal = false;
 0194            if (_lastFileEvent.ContainsKey(fileName))
 0195            {
 196                // If dictionary contains the filename, check how much time has elapsed
 197                // since the last event occured. If the timespan is less that the
 198                // specified interval, set return value to true
 199                // and store current datetime in dictionary for this file
 0200                DateTime lastEventTime = _lastFileEvent[fileName];
 0201                DateTime currentTime = DateTime.Now;
 0202                TimeSpan timeSinceLastEvent = currentTime - lastEventTime;
 0203                retVal = timeSinceLastEvent < _recentTimeSpan;
 0204                _lastFileEvent[fileName] = currentTime;
 0205            }
 206            else
 0207            {
 208                // If dictionary does not contain the filename,
 209                // no event has occured in past for this file, so set return value to false
 210                // and append filename along with current datetime to the dictionary
 0211                _lastFileEvent.TryAdd(fileName, DateTime.Now);
 0212            }
 213
 0214            return retVal;
 0215        }
 216
 217        #region FileSystemWatcher EventHandlers
 218        // Base class Event Handlers. Check if an event has occured recently and call method
 219        // to raise appropriate event only if no recent event is detected
 220        private void OnChanged(object sender, FileSystemEventArgs e)
 0221        {
 0222            if (!HasAnotherFileEventOccuredRecently(e.FullPath))
 0223            {
 0224                OnChanged(e);
 0225            }
 0226        }
 227
 228        private void OnCreated(object sender, FileSystemEventArgs e)
 0229        {
 0230            if (!HasAnotherFileEventOccuredRecently(e.FullPath))
 0231            {
 0232                OnCreated(e);
 0233            }
 0234        }
 235
 236        private void OnDeleted(object sender, FileSystemEventArgs e)
 0237        {
 0238            if (!HasAnotherFileEventOccuredRecently(e.FullPath))
 0239            {
 0240                OnDeleted(e);
 0241            }
 0242        }
 243
 244        private void OnRenamed(object sender, RenamedEventArgs e)
 0245        {
 0246            if (!HasAnotherFileEventOccuredRecently(e.OldFullPath))
 0247            {
 0248                OnRenamed(e);
 0249            }
 0250        }
 251        #endregion
 252        #endregion
 253    }
 254}