public void DeserializeCache_WithExistingCacheAndChanges_CacheIsCorrect()
        {
            //Arrange
            List<FileSystemItem> cacheItems = new List<FileSystemItem>
                                             {
                                                 new FileSystemItem("name1", "folder1"),
                                                 new FileSystemItem("name1", "folder2"),
                                                 new FileSystemItem("C:\\")
                                             };
            FileSystemCache cache = new FileSystemCache(cacheItems, DateTime.Now.AddDays(-2));
            _serializer.SerializeCache(cache);

            List<FileSystemChangeEventArgs> changeItems = new List<FileSystemChangeEventArgs>
                                                              {
                                                                  new FileSystemChangeEventArgs("folder1", null),
                                                                  new FileSystemChangeEventArgs(null, "folder3"),
                                                                  new FileSystemChangeEventArgs("folder2", "folder4")
                                                              };

            DateTime dateTime = DateTime.Now;
            FileSystemChanges changes = new FileSystemChanges { Changes = changeItems, LastFullScanTime = dateTime };
            _serializer.SerializeCacheChanges(changes);

            //Act
            FileSystemCache actualCache = _serializer.DeserializeCache();

            //Assert
            //Serialization does not preserve milliseconds, so we use epsilon check.
            Assert.That(dateTime - actualCache.LastFullScanTime, Is.LessThan(new TimeSpan(0, 0, 1)));
            Assert.That(actualCache.Items.Count, Is.EqualTo(3));

            Assert.That(actualCache.Items[0].FullPath, Is.EqualTo(Path.GetFullPath("C:\\")));
            Assert.That(actualCache.Items[0].Name, Is.EqualTo(""));

            Assert.That(actualCache.Items[1].FullPath, Is.EqualTo(Path.GetFullPath("folder3")));
            Assert.That(actualCache.Items[1].Name, Is.EqualTo("folder3"));

            Assert.That(actualCache.Items[2].FullPath, Is.EqualTo(Path.GetFullPath("folder4")));
            Assert.That(actualCache.Items[2].Name, Is.EqualTo("folder4"));
        }
        private void SerializeChanges()
        {
            //Serialize changes even if the cache is not up to date to preserve as actual version as possible.
            _fileSystemChanges.LastFullScanTime = _cacheUpToDate ? DateTime.Now : _lastFullScanTime;

            _cacheSerializer.SerializeCacheChanges(_fileSystemChanges);
            _fileSystemChanges = new FileSystemChanges();
        }
        private void Initialize(bool appRunOnStartup)
        {
            bool cacheFolderCreated;
            _filteredCacheItems = ReadCache(appRunOnStartup, out _cacheUpToDate, out cacheFolderCreated, out _lastFullScanTime);
            _fileSystemChanges = new FileSystemChanges();
            if (cacheFolderCreated)
            {
                string cacheFolder = GetCacheFolder();
                try
                {
                    FileSystemChangeEventArgs e = new FileSystemChangeEventArgs(null, cacheFolder);
                    HandleFolderSystemChanged(this, e);
                }
                catch (PathTooLongException)
                {

                }
            }

            //Listen to the changes in the whole system to update the fullCache.
            //This handler should be bound just after reading the full cache to ensure that _fullCache is initialized.
            _fileSystemListener.FolderSystemChanged += HandleFolderSystemChanged;
            _fileSystemListener.StartListening(null);

            //Parse file system fully (asynchronously).
            if (!_cacheUpToDate)
            {
                StartFileSystemParsing();
            }
        }
        private void HandleParsingFinished(object sender, ItemEventArgs<FileSystemCache> e)
        {
            lock (_cacheSync)
            {
                FileSystemCache fullCache = e.Item;
                fullCache.LastFullScanTime = DateTime.Now;
                _cacheSerializer.SerializeCache(fullCache);

                _lastFullScanTime = fullCache.LastFullScanTime;
                _filteredCacheItems = FilterCache(fullCache);
                _fileSystemChanges = new FileSystemChanges();
                fullCache = null;
                GC.Collect();

                _asyncFileSystemParser.ParsingFinished -= HandleParsingFinished;
            }
        }
        private FileSystemChanges ReadChanges()
        {
            string[] lines = File.ReadAllLines(_cacheChangesFilePath);

            List<FileSystemChangeEventArgs> items = lines.Skip(1).Select(ParseChangeItem).Where(i => i != null).ToList();
            DateTime lastFullScanTime = DateTime.Parse(lines[0], CultureInfo.InvariantCulture);
            FileSystemChanges changes = new FileSystemChanges {Changes = items, LastFullScanTime = lastFullScanTime};

            return changes;
        }
        public void SerializeCacheChanges(FileSystemChanges changes)
        {
            if (changes == null || changes.Changes == null)
            {
                throw new ArgumentNullException("changes");
            }

            lock (CacheSync)
            {
                DirectoryUtility.EnsureFolder(Path.GetDirectoryName(_cacheFilePath));
                string dateTime = changes.LastFullScanTime.ToString(CultureInfo.InvariantCulture);

                List<string> lines;
                if (File.Exists(_cacheChangesFilePath))
                {
                    lines = File.ReadAllLines(_cacheChangesFilePath).ToList();
                    lines[0] = dateTime;
                }
                else
                {
                    lines = new List<string> { dateTime };
                }

                List<string> linesToAdd = changes.Changes.Select(GetChangeItemLine).ToList();
                lines.AddRange(linesToAdd);

                File.WriteAllLines(_cacheChangesFilePath, lines.ToArray());
            }

            GC.Collect();
        }
        public void DeserializeCache_WithExistingChangesAndAbsentCache_CacheIsNull()
        {
            //Arrange
            List<FileSystemChangeEventArgs> changeItems = new List<FileSystemChangeEventArgs>
                                                              {
                                                                  new FileSystemChangeEventArgs("folder1", null),
                                                                  new FileSystemChangeEventArgs(null, "folder3"),
                                                                  new FileSystemChangeEventArgs("folder2", "folder4")
                                                              };
            DateTime dateTime = DateTime.Now;
            FileSystemChanges changes = new FileSystemChanges { Changes = changeItems, LastFullScanTime = DateTime.Now };
            _serializer.SerializeCacheChanges(changes);

            //Act
            FileSystemCache actualCache = _serializer.DeserializeCache();

            //Assert
            Assert.That(actualCache, Is.Null);
        }