private PatternTestResult MatchPatternContexts <TFileInfoBase>(TFileInfoBase fileinfo, Func <IPatternContext, TFileInfoBase, PatternTestResult> test)
        {
            PatternTestResult result = PatternTestResult.Failed;

            // If the given file/directory matches any including pattern, continues to next step.
            foreach (IPatternContext context in _includePatternContexts)
            {
                PatternTestResult localResult = test(context, fileinfo);
                if (localResult.IsSuccessful)
                {
                    result = localResult;
                    break;
                }
            }

            // If the given file/directory doesn't match any of the including pattern, returns false.
            if (!result.IsSuccessful)
            {
                return(PatternTestResult.Failed);
            }

            // If the given file/directory matches any excluding pattern, returns false.
            foreach (IPatternContext context in _excludePatternContexts)
            {
                if (test(context, fileinfo).IsSuccessful)
                {
                    return(PatternTestResult.Failed);
                }
            }

            return(result);
        }
 // Used to adapt Test(DirectoryInfoBase) for the below overload
 private bool MatchPatternContexts <TFileInfoBase>(TFileInfoBase fileinfo, Func <IPatternContext, TFileInfoBase, bool> test)
 {
     return(MatchPatternContexts(
                fileinfo,
                (ctx, file) =>
     {
         if (test(ctx, file))
         {
             return PatternTestResult.Success(stem: string.Empty);
         }
         else
         {
             return PatternTestResult.Failed;
         }
     }).IsSuccessful);
 }
        private void Match(DirectoryInfoBase directory, string parentRelativePath)
        {
            // Request all the including and excluding patterns to push current directory onto their status stack.
            PushDirectory(directory);
            Declare();

            var entities = new List <FileSystemInfoBase>();

            if (_declaredWildcardPathSegment || _declaredLiteralFileSegments.Any())
            {
                entities.AddRange(directory.EnumerateFileSystemInfos());
            }
            else
            {
                IEnumerable <DirectoryInfoBase> candidates = directory.EnumerateFileSystemInfos().OfType <DirectoryInfoBase>();
                foreach (DirectoryInfoBase candidate in candidates)
                {
                    if (_declaredLiteralFolderSegmentInString.Contains(candidate.Name))
                    {
                        entities.Add(candidate);
                    }
                }
            }

            if (_declaredParentPathSegment)
            {
                entities.Add(directory.GetDirectory(".."));
            }

            // collect files and sub directories
            var subDirectories = new List <DirectoryInfoBase>();

            foreach (FileSystemInfoBase entity in entities)
            {
                var fileInfo = entity as FileInfoBase;
                if (fileInfo != null)
                {
                    PatternTestResult result = MatchPatternContexts(fileInfo, (pattern, file) => pattern.Test(file));
                    if (result.IsSuccessful)
                    {
                        _files.Add(new FilePatternMatch(
                                       path: CombinePath(parentRelativePath, fileInfo.Name),
                                       stem: result.Stem));
                    }

                    continue;
                }

                var directoryInfo = entity as DirectoryInfoBase;
                if (directoryInfo != null)
                {
                    if (MatchPatternContexts(directoryInfo, (pattern, dir) => pattern.Test(dir)))
                    {
                        subDirectories.Add(directoryInfo);
                    }

                    continue;
                }
            }

            // Matches the sub directories recursively
            foreach (DirectoryInfoBase subDir in subDirectories)
            {
                string relativePath = CombinePath(parentRelativePath, subDir.Name);

                Match(subDir, relativePath);
            }

            // Request all the including and excluding patterns to pop their status stack.
            PopDirectory();
        }