public async Task TokensNotFiredForHiddenAndSystemFiles()
        {
            using (var root = new DisposableFileSystem())
            {
                var hiddenFileName = Guid.NewGuid().ToString();
                var hiddenFilePath = Path.Combine(root.RootPath, hiddenFileName);
                File.Create(hiddenFilePath);
                var fileInfo = new FileInfo(hiddenFilePath);
                File.SetAttributes(hiddenFilePath, fileInfo.Attributes | FileAttributes.Hidden);

                var systemFileName = Guid.NewGuid().ToString();
                var systemFilePath = Path.Combine(root.RootPath, systemFileName);
                File.Create(systemFilePath);
                fileInfo = new FileInfo(systemFilePath);
                File.SetAttributes(systemFilePath, fileInfo.Attributes | FileAttributes.System);

                using (var fileSystemWatcher = new MockFileSystemWatcher(root.RootPath))
                {
                    using (var physicalFilesWatcher = new PhysicalFilesWatcher(root.RootPath + Path.DirectorySeparatorChar, fileSystemWatcher))
                    {
                        using (var provider = new PhysicalFileProvider(root.RootPath, physicalFilesWatcher))
                        {
                            var hiddenFiletoken = provider.Watch(Path.GetFileName(hiddenFileName));
                            var systemFiletoken = provider.Watch(Path.GetFileName(systemFileName));

                            fileSystemWatcher.CallOnChanged(new FileSystemEventArgs(WatcherChangeTypes.Changed, root.RootPath, hiddenFileName));
                            await Task.Delay(WaitTimeForTokenToFire);
                            Assert.False(hiddenFiletoken.HasChanged);

                            fileSystemWatcher.CallOnChanged(new FileSystemEventArgs(WatcherChangeTypes.Changed, root.RootPath, systemFileName));
                            await Task.Delay(WaitTimeForTokenToFire);
                            Assert.False(systemFiletoken.HasChanged);
                        }
                    }
                }
            }
        }
        public async Task TokenFiredForRegularExpressionPatternsPointingToSubDirectory()
        {
            using (var root = new DisposableFileSystem())
            {
                using (var fileSystemWatcher = new MockFileSystemWatcher(root.RootPath))
                {
                    using (var physicalFilesWatcher = new PhysicalFilesWatcher(root.RootPath + Path.DirectorySeparatorChar, fileSystemWatcher))
                    {
                        using (var provider = new PhysicalFileProvider(root.RootPath, physicalFilesWatcher))
                        {
                            var subDirectoryName = Guid.NewGuid().ToString();
                            var pattern = string.Format(Path.Combine(subDirectoryName, "**", "*.cshtml"));
                            var token = provider.Watch(pattern);

                            var subSubDirectoryName = Guid.NewGuid().ToString();
                            var fileName = Guid.NewGuid().ToString() + ".cshtml";
                            fileSystemWatcher.CallOnChanged(new FileSystemEventArgs(WatcherChangeTypes.Changed, Path.Combine(root.RootPath, subDirectoryName, subSubDirectoryName), fileName));
                            await Task.Delay(WaitTimeForTokenToFire);

                            Assert.True(token.HasChanged);
                        }
                    }
                }
            }
        }
        public async Task TokenNotFiredForFileNameStartingWithPeriod()
        {
            using (var root = new DisposableFileSystem())
            {
                using (var fileSystemWatcher = new MockFileSystemWatcher(root.RootPath))
                {
                    using (var physicalFilesWatcher = new PhysicalFilesWatcher(root.RootPath + Path.DirectorySeparatorChar, fileSystemWatcher))
                    {
                        using (var provider = new PhysicalFileProvider(root.RootPath, physicalFilesWatcher))
                        {
                            var fileName = "." + Guid.NewGuid().ToString();
                            var token = provider.Watch(Path.GetFileName(fileName));

                            fileSystemWatcher.CallOnChanged(new FileSystemEventArgs(WatcherChangeTypes.Changed, root.RootPath, fileName));
                            await Task.Delay(WaitTimeForTokenToFire);

                            Assert.False(token.HasChanged);
                        }
                    }
                }
            }
        }
        public async Task TokenFiredForFilesUnderPathEndingWithSlash()
        {
            using (var root = new DisposableFileSystem())
            {
                using (var fileSystemWatcher = new MockFileSystemWatcher(root.RootPath))
                {
                    using (var physicalFilesWatcher = new PhysicalFilesWatcher(root.RootPath + Path.DirectorySeparatorChar, fileSystemWatcher))
                    {
                        using (var provider = new PhysicalFileProvider(root.RootPath, physicalFilesWatcher))
                        {
                            var directoryName = Guid.NewGuid().ToString();
                            var token = provider.Watch(directoryName + Path.DirectorySeparatorChar);

                            fileSystemWatcher.CallOnChanged(new FileSystemEventArgs(WatcherChangeTypes.Changed, Path.Combine(root.RootPath, directoryName), Guid.NewGuid().ToString()));
                            await Task.Delay(WaitTimeForTokenToFire);

                            Assert.True(token.HasChanged);
                        }
                    }
                }
            }
        }
        public async Task TokensFiredForRegularExpressionPatterns()
        {
            using (var root = new DisposableFileSystem())
            {
                using (var fileSystemWatcher = new MockFileSystemWatcher(root.RootPath))
                {
                    using (var physicalFilesWatcher = new PhysicalFilesWatcher(root.RootPath + Path.DirectorySeparatorChar, fileSystemWatcher))
                    {
                        using (var provider = new PhysicalFileProvider(root.RootPath, physicalFilesWatcher))
                        {
                            var token1 = provider.Watch("**/*");
                            var pattern1tokenCount = 0;
                            token1.RegisterChangeCallback(_ => { pattern1tokenCount++; }, null);

                            var token2 = provider.Watch("*.cshtml");
                            var pattern2tokenCount = 0;
                            token2.RegisterChangeCallback(_ => { pattern2tokenCount++; }, null);

                            var fileName = Guid.NewGuid().ToString();

                            fileSystemWatcher.CallOnChanged(new FileSystemEventArgs(WatcherChangeTypes.Changed, root.RootPath, fileName + ".cshtml"));
                            await Task.Delay(WaitTimeForTokenToFire);

                            Assert.Equal(1, pattern1tokenCount);
                            Assert.Equal(1, pattern2tokenCount);

                            token1 = provider.Watch("**/*");
                            token1.RegisterChangeCallback(_ => { pattern1tokenCount++; }, null);
                            fileSystemWatcher.CallOnChanged(new FileSystemEventArgs(WatcherChangeTypes.Changed, root.RootPath, fileName + ".txt"));
                            await Task.Delay(WaitTimeForTokenToFire);

                            Assert.Equal(2, pattern1tokenCount);
                            Assert.Equal(1, pattern2tokenCount);
                        }
                    }
                }
            }
        }
        public async Task TokenFiredOnCreation()
        {
            using (var root = new DisposableFileSystem())
            {
                using (var fileSystemWatcher = new MockFileSystemWatcher(root.RootPath))
                {
                    using (var physicalFilesWatcher = new PhysicalFilesWatcher(root.RootPath + Path.DirectorySeparatorChar, fileSystemWatcher))
                    {
                        using (var provider = new PhysicalFileProvider(root.RootPath, physicalFilesWatcher))
                        {
                            var name = Guid.NewGuid().ToString();
                            var token = provider.Watch(name);

                            fileSystemWatcher.CallOnChanged(new FileSystemEventArgs(WatcherChangeTypes.Created, root.RootPath, name));
                            await Task.Delay(WaitTimeForTokenToFire);

                            Assert.True(token.HasChanged);
                        }
                    }
                }
            }
        }
        public async Task TokenNotAffectedByExceptions()
        {
            using (var root = new DisposableFileSystem())
            {
                using (var fileSystemWatcher = new MockFileSystemWatcher(root.RootPath))
                {
                    using (var physicalFilesWatcher = new PhysicalFilesWatcher(root.RootPath + Path.DirectorySeparatorChar, fileSystemWatcher))
                    {
                        using (var provider = new PhysicalFileProvider(root.RootPath, physicalFilesWatcher))
                        {
                            var fileName = Guid.NewGuid().ToString();
                            var token = provider.Watch(fileName);

                            token.RegisterChangeCallback(_ =>
                            {
                                throw new Exception();
                            }, null);

                            fileSystemWatcher.CallOnChanged(new FileSystemEventArgs(WatcherChangeTypes.Changed, root.RootPath, fileName));
                            await Task.Delay(WaitTimeForTokenToFire);

                            Assert.True(token.HasChanged);
                        }
                    }
                }
            }
        }
        public async Task CorrectTokensFiredForMultipleFiles()
        {
            using (var root = new DisposableFileSystem())
            {
                using (var fileSystemWatcher = new MockFileSystemWatcher(root.RootPath))
                {
                    using (var physicalFilesWatcher = new PhysicalFilesWatcher(root.RootPath + Path.DirectorySeparatorChar, fileSystemWatcher))
                    {
                        using (var provider = new PhysicalFileProvider(root.RootPath, physicalFilesWatcher))
                        {
                            var fileName1 = Guid.NewGuid().ToString();
                            var token1 = provider.Watch(fileName1);
                            var fileName2 = Guid.NewGuid().ToString();
                            var token2 = provider.Watch(fileName2);

                            fileSystemWatcher.CallOnChanged(new FileSystemEventArgs(WatcherChangeTypes.Changed, root.RootPath, fileName1));
                            await Task.Delay(WaitTimeForTokenToFire);

                            Assert.True(token1.HasChanged);
                            Assert.False(token2.HasChanged);

                            fileSystemWatcher.CallOnChanged(new FileSystemEventArgs(WatcherChangeTypes.Changed, root.RootPath, fileName2));
                            await Task.Delay(WaitTimeForTokenToFire);

                            Assert.True(token2.HasChanged);
                        }
                    }
                }
            }
        }
        public async Task FileChangeTokenNotNotifiedAfterExpiry()
        {
            using (var root = new DisposableFileSystem())
            {
                using (var fileSystemWatcher = new MockFileSystemWatcher(root.RootPath))
                {
                    using (var physicalFilesWatcher = new PhysicalFilesWatcher(root.RootPath + Path.DirectorySeparatorChar, fileSystemWatcher))
                    {
                        using (var provider = new PhysicalFileProvider(root.RootPath, physicalFilesWatcher))
                        {
                            var fileName = Guid.NewGuid().ToString();
                            var changeToken = provider.Watch(fileName);
                            var invocationCount = 0;
                            changeToken.RegisterChangeCallback(_ => { invocationCount++; }, null);

                            // Callback expected.
                            fileSystemWatcher.CallOnChanged(new FileSystemEventArgs(WatcherChangeTypes.Changed, root.RootPath, fileName));
                            await Task.Delay(WaitTimeForTokenToFire);

                            // Callback not expected.
                            fileSystemWatcher.CallOnChanged(new FileSystemEventArgs(WatcherChangeTypes.Changed, root.RootPath, fileName));
                            await Task.Delay(WaitTimeForTokenToFire);

                            Assert.Equal(1, invocationCount);
                        }
                    }
                }
            }
        }
        public async Task TokenCallbackInvokedOnFileChange()
        {
            using (var root = new DisposableFileSystem())
            {
                var fileName = Guid.NewGuid().ToString();
                var fileLocation = Path.Combine(root.RootPath, fileName);

                using (var fileSystemWatcher = new MockFileSystemWatcher(root.RootPath))
                {
                    using (var physicalFilesWatcher = new PhysicalFilesWatcher(root.RootPath + Path.DirectorySeparatorChar, fileSystemWatcher))
                    {
                        using (var provider = new PhysicalFileProvider(root.RootPath, physicalFilesWatcher))
                        {
                            var token = provider.Watch(fileName);
                            Assert.NotNull(token);
                            Assert.False(token.HasChanged);
                            Assert.True(token.ActiveChangeCallbacks);

                            bool callbackInvoked = false;
                            token.RegisterChangeCallback(state =>
                            {
                                callbackInvoked = true;
                            }, state: null);

                            fileSystemWatcher.CallOnChanged(new FileSystemEventArgs(WatcherChangeTypes.Changed, root.RootPath, fileName));
                            await Task.Delay(WaitTimeForTokenToFire);

                            Assert.True(callbackInvoked);
                        }
                    }
                }
            }
        }