Copy FileSystemGlobbing and HashCodeCombiner sources
This commit is contained in:
parent
f8631fa4b7
commit
734c9fc43b
75 changed files with 3999 additions and 43 deletions
|
@ -1,5 +1,5 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Microsoft.DotNet.InternalAbstractions
|
||||
{
|
||||
public struct HashCodeCombiner
|
||||
{
|
||||
private long _combinedHash64;
|
||||
|
||||
public int CombinedHash
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get { return _combinedHash64.GetHashCode(); }
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private HashCodeCombiner(long seed)
|
||||
{
|
||||
_combinedHash64 = seed;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Add(int i)
|
||||
{
|
||||
_combinedHash64 = ((_combinedHash64 << 5) + _combinedHash64) ^ i;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Add(string s)
|
||||
{
|
||||
var hashCode = (s != null) ? s.GetHashCode() : 0;
|
||||
Add(hashCode);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Add(object o)
|
||||
{
|
||||
var hashCode = (o != null) ? o.GetHashCode() : 0;
|
||||
Add(hashCode);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Add<TValue>(TValue value, IEqualityComparer<TValue> comparer)
|
||||
{
|
||||
var hashCode = value != null ? comparer.GetHashCode(value) : 0;
|
||||
Add(hashCode);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static HashCodeCombiner Start()
|
||||
{
|
||||
return new HashCodeCombiner(0x1505L);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,8 +5,8 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.DotNet.InternalAbstractions;
|
||||
using Microsoft.DotNet.ProjectModel.Utilities;
|
||||
using Microsoft.Extensions.Internal;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.Compilation
|
||||
{
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Abstractions
|
||||
{
|
||||
public abstract class DirectoryInfoBase : FileSystemInfoBase
|
||||
{
|
||||
public abstract IEnumerable<FileSystemInfoBase> EnumerateFileSystemInfos();
|
||||
|
||||
public abstract DirectoryInfoBase GetDirectory(string path);
|
||||
|
||||
public abstract FileInfoBase GetFile(string path);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Abstractions
|
||||
{
|
||||
public class DirectoryInfoWrapper : DirectoryInfoBase
|
||||
{
|
||||
private readonly DirectoryInfo _directoryInfo;
|
||||
private readonly bool _isParentPath;
|
||||
|
||||
public DirectoryInfoWrapper(DirectoryInfo directoryInfo, bool isParentPath = false)
|
||||
{
|
||||
_directoryInfo = directoryInfo;
|
||||
_isParentPath = isParentPath;
|
||||
}
|
||||
|
||||
public override IEnumerable<FileSystemInfoBase> EnumerateFileSystemInfos()
|
||||
{
|
||||
if (_directoryInfo.Exists)
|
||||
{
|
||||
foreach (var fileSystemInfo in _directoryInfo.EnumerateFileSystemInfos("*", SearchOption.TopDirectoryOnly))
|
||||
{
|
||||
var directoryInfo = fileSystemInfo as DirectoryInfo;
|
||||
if (directoryInfo != null)
|
||||
{
|
||||
yield return new DirectoryInfoWrapper(directoryInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return new FileInfoWrapper((FileInfo)fileSystemInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override DirectoryInfoBase GetDirectory(string name)
|
||||
{
|
||||
var isParentPath = string.Equals(name, "..", StringComparison.Ordinal);
|
||||
|
||||
if (isParentPath)
|
||||
{
|
||||
return new DirectoryInfoWrapper(new DirectoryInfo(Path.Combine(_directoryInfo.FullName, name)), isParentPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
var dirs = _directoryInfo.GetDirectories(name);
|
||||
|
||||
if (dirs.Length == 1)
|
||||
{
|
||||
return new DirectoryInfoWrapper(dirs[0], isParentPath);
|
||||
}
|
||||
else if (dirs.Length == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This shouldn't happen. The parameter name isn't supposed to contain wild card.
|
||||
throw new InvalidOperationException(
|
||||
string.Format("More than one sub directories are found under {0} with name {1}.", _directoryInfo.FullName, name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override FileInfoBase GetFile(string name)
|
||||
{
|
||||
return new FileInfoWrapper(new FileInfo(Path.Combine(_directoryInfo.FullName, name)));
|
||||
}
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get { return _isParentPath ? ".." : _directoryInfo.Name; }
|
||||
}
|
||||
|
||||
public override string FullName
|
||||
{
|
||||
get { return _directoryInfo.FullName; }
|
||||
}
|
||||
|
||||
public override DirectoryInfoBase ParentDirectory
|
||||
{
|
||||
get { return new DirectoryInfoWrapper(_directoryInfo.Parent); }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Abstractions
|
||||
{
|
||||
public abstract class FileInfoBase : FileSystemInfoBase
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.IO;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Abstractions
|
||||
{
|
||||
public class FileInfoWrapper : FileInfoBase
|
||||
{
|
||||
private FileInfo _fileInfo;
|
||||
|
||||
public FileInfoWrapper(FileInfo fileInfo)
|
||||
{
|
||||
_fileInfo = fileInfo;
|
||||
}
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get { return _fileInfo.Name; }
|
||||
}
|
||||
|
||||
public override string FullName
|
||||
{
|
||||
get { return _fileInfo.FullName; }
|
||||
}
|
||||
|
||||
public override DirectoryInfoBase ParentDirectory
|
||||
{
|
||||
get { return new DirectoryInfoWrapper(_fileInfo.Directory); }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Abstractions
|
||||
{
|
||||
public abstract class FileSystemInfoBase
|
||||
{
|
||||
public abstract string Name { get; }
|
||||
|
||||
public abstract string FullName { get; }
|
||||
|
||||
public abstract DirectoryInfoBase ParentDirectory { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.DotNet.InternalAbstractions;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing
|
||||
{
|
||||
public struct FilePatternMatch : IEquatable<FilePatternMatch>
|
||||
{
|
||||
public string Path { get; }
|
||||
public string Stem { get; }
|
||||
|
||||
public FilePatternMatch(string path, string stem)
|
||||
{
|
||||
Path = path;
|
||||
Stem = stem;
|
||||
}
|
||||
|
||||
public bool Equals(FilePatternMatch other)
|
||||
{
|
||||
return string.Equals(other.Path, Path, StringComparison.OrdinalIgnoreCase) &&
|
||||
string.Equals(other.Stem, Stem, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return Equals((FilePatternMatch)obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
var hashCodeCombiner = HashCodeCombiner.Start();
|
||||
hashCodeCombiner.Add(Path, StringComparer.OrdinalIgnoreCase);
|
||||
hashCodeCombiner.Add(Stem, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
return hashCodeCombiner.CombinedHash;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal
|
||||
{
|
||||
public interface ILinearPattern : IPattern
|
||||
{
|
||||
IList<IPathSegment> Segments { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal
|
||||
{
|
||||
public interface IPathSegment
|
||||
{
|
||||
bool CanProduceStem { get; }
|
||||
|
||||
bool Match(string value);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal
|
||||
{
|
||||
public interface IPattern
|
||||
{
|
||||
IPatternContext CreatePatternContextForInclude();
|
||||
|
||||
IPatternContext CreatePatternContextForExclude();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Abstractions;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal
|
||||
{
|
||||
public interface IPatternContext
|
||||
{
|
||||
void Declare(Action<IPathSegment, bool> onDeclare);
|
||||
|
||||
bool Test(DirectoryInfoBase directory);
|
||||
|
||||
PatternTestResult Test(FileInfoBase file);
|
||||
|
||||
void PushDirectory(DirectoryInfoBase directory);
|
||||
|
||||
void PopDirectory();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal
|
||||
{
|
||||
public interface IRaggedPattern : IPattern
|
||||
{
|
||||
IList<IPathSegment> Segments { get; }
|
||||
|
||||
IList<IPathSegment> StartsWith { get; }
|
||||
|
||||
IList<IList<IPathSegment>> Contains { get; }
|
||||
|
||||
IList<IPathSegment> EndsWith { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,250 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Abstractions;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal.PathSegments;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Util;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal
|
||||
{
|
||||
public class MatcherContext
|
||||
{
|
||||
private readonly DirectoryInfoBase _root;
|
||||
private readonly IList<IPatternContext> _includePatternContexts;
|
||||
private readonly IList<IPatternContext> _excludePatternContexts;
|
||||
private readonly IList<FilePatternMatch> _files;
|
||||
|
||||
private readonly HashSet<string> _declaredLiteralFolderSegmentInString;
|
||||
private readonly HashSet<LiteralPathSegment> _declaredLiteralFolderSegments = new HashSet<LiteralPathSegment>();
|
||||
private readonly HashSet<LiteralPathSegment> _declaredLiteralFileSegments = new HashSet<LiteralPathSegment>();
|
||||
|
||||
private bool _declaredParentPathSegment;
|
||||
private bool _declaredWildcardPathSegment;
|
||||
|
||||
private readonly StringComparison _comparisonType;
|
||||
|
||||
public MatcherContext(IEnumerable<IPattern> includePatterns,
|
||||
IEnumerable<IPattern> excludePatterns,
|
||||
DirectoryInfoBase directoryInfo,
|
||||
StringComparison comparison)
|
||||
{
|
||||
_root = directoryInfo;
|
||||
_files = new List<FilePatternMatch>();
|
||||
_comparisonType = comparison;
|
||||
|
||||
_includePatternContexts = includePatterns.Select(pattern => pattern.CreatePatternContextForInclude()).ToList();
|
||||
_excludePatternContexts = excludePatterns.Select(pattern => pattern.CreatePatternContextForExclude()).ToList();
|
||||
|
||||
_declaredLiteralFolderSegmentInString = new HashSet<string>(StringComparisonHelper.GetStringComparer(comparison));
|
||||
}
|
||||
|
||||
public PatternMatchingResult Execute()
|
||||
{
|
||||
_files.Clear();
|
||||
|
||||
Match(_root, parentRelativePath: null);
|
||||
|
||||
return new PatternMatchingResult(_files);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
var candidates = directory.EnumerateFileSystemInfos().OfType<DirectoryInfoBase>();
|
||||
foreach (var 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 (var entity in entities)
|
||||
{
|
||||
var fileInfo = entity as FileInfoBase;
|
||||
if (fileInfo != null)
|
||||
{
|
||||
var 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 (var subDir in subDirectories)
|
||||
{
|
||||
var relativePath = CombinePath(parentRelativePath, subDir.Name);
|
||||
|
||||
Match(subDir, relativePath);
|
||||
}
|
||||
|
||||
// Request all the including and excluding patterns to pop their status stack.
|
||||
PopDirectory();
|
||||
}
|
||||
|
||||
private void Declare()
|
||||
{
|
||||
_declaredLiteralFileSegments.Clear();
|
||||
_declaredLiteralFolderSegments.Clear();
|
||||
_declaredParentPathSegment = false;
|
||||
_declaredWildcardPathSegment = false;
|
||||
|
||||
foreach (var include in _includePatternContexts)
|
||||
{
|
||||
include.Declare(DeclareInclude);
|
||||
}
|
||||
}
|
||||
|
||||
private void DeclareInclude(IPathSegment patternSegment, bool isLastSegment)
|
||||
{
|
||||
var literalSegment = patternSegment as LiteralPathSegment;
|
||||
if (literalSegment != null)
|
||||
{
|
||||
if (isLastSegment)
|
||||
{
|
||||
_declaredLiteralFileSegments.Add(literalSegment);
|
||||
}
|
||||
else
|
||||
{
|
||||
_declaredLiteralFolderSegments.Add(literalSegment);
|
||||
_declaredLiteralFolderSegmentInString.Add(literalSegment.Value);
|
||||
}
|
||||
}
|
||||
else if (patternSegment is ParentPathSegment)
|
||||
{
|
||||
_declaredParentPathSegment = true;
|
||||
}
|
||||
else if (patternSegment is WildcardPathSegment)
|
||||
{
|
||||
_declaredWildcardPathSegment = true;
|
||||
}
|
||||
}
|
||||
|
||||
internal static string CombinePath(string left, string right)
|
||||
{
|
||||
if (string.IsNullOrEmpty(left))
|
||||
{
|
||||
return right;
|
||||
}
|
||||
else
|
||||
{
|
||||
return string.Format("{0}/{1}", left, right);
|
||||
}
|
||||
}
|
||||
|
||||
// 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 PatternTestResult MatchPatternContexts<TFileInfoBase>(TFileInfoBase fileinfo, Func<IPatternContext, TFileInfoBase, PatternTestResult> test)
|
||||
{
|
||||
var result = PatternTestResult.Failed;
|
||||
|
||||
// If the given file/directory matches any including pattern, continues to next step.
|
||||
foreach (var context in _includePatternContexts)
|
||||
{
|
||||
var 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 (var context in _excludePatternContexts)
|
||||
{
|
||||
if (test(context, fileinfo).IsSuccessful)
|
||||
{
|
||||
return PatternTestResult.Failed;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void PopDirectory()
|
||||
{
|
||||
foreach (var context in _excludePatternContexts)
|
||||
{
|
||||
context.PopDirectory();
|
||||
}
|
||||
|
||||
foreach (var context in _includePatternContexts)
|
||||
{
|
||||
context.PopDirectory();
|
||||
}
|
||||
}
|
||||
|
||||
private void PushDirectory(DirectoryInfoBase directory)
|
||||
{
|
||||
foreach (var context in _includePatternContexts)
|
||||
{
|
||||
context.PushDirectory(directory);
|
||||
}
|
||||
|
||||
foreach (var context in _excludePatternContexts)
|
||||
{
|
||||
context.PushDirectory(directory);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal.PathSegments
|
||||
{
|
||||
public class CurrentPathSegment : IPathSegment
|
||||
{
|
||||
public bool CanProduceStem { get { return false; } }
|
||||
|
||||
public bool Match(string value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Util;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal.PathSegments
|
||||
{
|
||||
public class LiteralPathSegment : IPathSegment
|
||||
{
|
||||
private readonly StringComparison _comparisonType;
|
||||
|
||||
public bool CanProduceStem { get { return false; } }
|
||||
|
||||
public LiteralPathSegment(string value, StringComparison comparisonType)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
Value = value;
|
||||
|
||||
_comparisonType = comparisonType;
|
||||
}
|
||||
|
||||
public string Value { get; }
|
||||
|
||||
public bool Match(string value)
|
||||
{
|
||||
return string.Equals(Value, value, _comparisonType);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
var other = obj as LiteralPathSegment;
|
||||
|
||||
return other != null &&
|
||||
_comparisonType == other._comparisonType &&
|
||||
string.Equals(other.Value, Value, _comparisonType);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return StringComparisonHelper.GetStringComparer(_comparisonType).GetHashCode(Value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal.PathSegments
|
||||
{
|
||||
public class ParentPathSegment : IPathSegment
|
||||
{
|
||||
private static readonly string LiteralParent = "..";
|
||||
|
||||
public bool CanProduceStem { get { return false; } }
|
||||
|
||||
public bool Match(string value)
|
||||
{
|
||||
return string.Equals(LiteralParent, value, StringComparison.Ordinal);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal.PathSegments
|
||||
{
|
||||
public class RecursiveWildcardSegment : IPathSegment
|
||||
{
|
||||
public bool CanProduceStem { get { return true; } }
|
||||
|
||||
public bool Match(string value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal.PathSegments
|
||||
{
|
||||
public class WildcardPathSegment : IPathSegment
|
||||
{
|
||||
// It doesn't matter which StringComparison type is used in this MatchAll segment because
|
||||
// all comparing are skipped since there is no content in the segment.
|
||||
public static readonly WildcardPathSegment MatchAll = new WildcardPathSegment(
|
||||
string.Empty, new List<string>(), string.Empty, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
private readonly StringComparison _comparisonType;
|
||||
|
||||
public WildcardPathSegment(string beginsWith, List<string> contains, string endsWith, StringComparison comparisonType)
|
||||
{
|
||||
BeginsWith = beginsWith;
|
||||
Contains = contains;
|
||||
EndsWith = endsWith;
|
||||
_comparisonType = comparisonType;
|
||||
}
|
||||
|
||||
public bool CanProduceStem { get { return true; } }
|
||||
|
||||
public string BeginsWith { get; }
|
||||
|
||||
public List<string> Contains { get; }
|
||||
|
||||
public string EndsWith { get; }
|
||||
|
||||
public bool Match(string value)
|
||||
{
|
||||
var wildcard = this;
|
||||
|
||||
if (value.Length < wildcard.BeginsWith.Length + wildcard.EndsWith.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!value.StartsWith(wildcard.BeginsWith, _comparisonType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!value.EndsWith(wildcard.EndsWith, _comparisonType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var beginRemaining = wildcard.BeginsWith.Length;
|
||||
var endRemaining = value.Length - wildcard.EndsWith.Length;
|
||||
for (var containsIndex = 0; containsIndex != wildcard.Contains.Count; ++containsIndex)
|
||||
{
|
||||
var containsValue = wildcard.Contains[containsIndex];
|
||||
var indexOf = value.IndexOf(
|
||||
value: containsValue,
|
||||
startIndex: beginRemaining,
|
||||
count: endRemaining - beginRemaining,
|
||||
comparisonType: _comparisonType);
|
||||
if (indexOf == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
beginRemaining = indexOf + containsValue.Length;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Abstractions;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal.PatternContexts
|
||||
{
|
||||
public abstract class PatternContext<TFrame> : IPatternContext
|
||||
{
|
||||
private Stack<TFrame> _stack = new Stack<TFrame>();
|
||||
protected TFrame Frame;
|
||||
|
||||
public virtual void Declare(Action<IPathSegment, bool> declare) { }
|
||||
|
||||
public abstract PatternTestResult Test(FileInfoBase file);
|
||||
|
||||
public abstract bool Test(DirectoryInfoBase directory);
|
||||
|
||||
public abstract void PushDirectory(DirectoryInfoBase directory);
|
||||
|
||||
public virtual void PopDirectory()
|
||||
{
|
||||
Frame = _stack.Pop();
|
||||
}
|
||||
|
||||
protected void PushDataFrame(TFrame frame)
|
||||
{
|
||||
_stack.Push(Frame);
|
||||
Frame = frame;
|
||||
}
|
||||
|
||||
protected bool IsStackEmpty()
|
||||
{
|
||||
return _stack.Count == 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Abstractions;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal.PatternContexts
|
||||
{
|
||||
public abstract class PatternContextLinear
|
||||
: PatternContext<PatternContextLinear.FrameData>
|
||||
{
|
||||
public PatternContextLinear(ILinearPattern pattern)
|
||||
{
|
||||
Pattern = pattern;
|
||||
}
|
||||
|
||||
public override PatternTestResult Test(FileInfoBase file)
|
||||
{
|
||||
if (IsStackEmpty())
|
||||
{
|
||||
throw new InvalidOperationException("Can't test file before entering a directory.");
|
||||
}
|
||||
|
||||
if(!Frame.IsNotApplicable && IsLastSegment() && TestMatchingSegment(file.Name))
|
||||
{
|
||||
return PatternTestResult.Success(CalculateStem(file));
|
||||
}
|
||||
|
||||
return PatternTestResult.Failed;
|
||||
}
|
||||
|
||||
public override void PushDirectory(DirectoryInfoBase directory)
|
||||
{
|
||||
// copy the current frame
|
||||
var frame = Frame;
|
||||
|
||||
if (IsStackEmpty() || Frame.IsNotApplicable)
|
||||
{
|
||||
// when the stack is being initialized
|
||||
// or no change is required.
|
||||
}
|
||||
else if (!TestMatchingSegment(directory.Name))
|
||||
{
|
||||
// nothing down this path is affected by this pattern
|
||||
frame.IsNotApplicable = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Determine this frame's contribution to the stem (if any)
|
||||
var segment = Pattern.Segments[Frame.SegmentIndex];
|
||||
if (frame.InStem || segment.CanProduceStem)
|
||||
{
|
||||
frame.InStem = true;
|
||||
frame.StemItems.Add(directory.Name);
|
||||
}
|
||||
|
||||
// directory matches segment, advance position in pattern
|
||||
frame.SegmentIndex = frame.SegmentIndex + 1;
|
||||
}
|
||||
|
||||
PushDataFrame(frame);
|
||||
}
|
||||
|
||||
public struct FrameData
|
||||
{
|
||||
public bool IsNotApplicable;
|
||||
public int SegmentIndex;
|
||||
public bool InStem;
|
||||
private IList<string> _stemItems;
|
||||
|
||||
public IList<string> StemItems
|
||||
{
|
||||
get { return _stemItems ?? (_stemItems = new List<string>()); }
|
||||
}
|
||||
|
||||
public string Stem
|
||||
{
|
||||
get { return _stemItems == null ? null : string.Join("/", _stemItems); }
|
||||
}
|
||||
}
|
||||
|
||||
protected ILinearPattern Pattern { get; }
|
||||
|
||||
protected bool IsLastSegment()
|
||||
{
|
||||
return Frame.SegmentIndex == Pattern.Segments.Count - 1;
|
||||
}
|
||||
|
||||
protected bool TestMatchingSegment(string value)
|
||||
{
|
||||
if (Frame.SegmentIndex >= Pattern.Segments.Count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Pattern.Segments[Frame.SegmentIndex].Match(value);
|
||||
}
|
||||
|
||||
protected string CalculateStem(FileInfoBase matchedFile)
|
||||
{
|
||||
return MatcherContext.CombinePath(Frame.Stem, matchedFile.Name);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Abstractions;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal.PatternContexts
|
||||
{
|
||||
public class PatternContextLinearExclude : PatternContextLinear
|
||||
{
|
||||
public PatternContextLinearExclude(ILinearPattern pattern)
|
||||
: base(pattern)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Test(DirectoryInfoBase directory)
|
||||
{
|
||||
if (IsStackEmpty())
|
||||
{
|
||||
throw new InvalidOperationException("Can't test directory before entering a directory.");
|
||||
}
|
||||
|
||||
if (Frame.IsNotApplicable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return IsLastSegment() && TestMatchingSegment(directory.Name);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Abstractions;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal.PatternContexts
|
||||
{
|
||||
public class PatternContextLinearInclude : PatternContextLinear
|
||||
{
|
||||
public PatternContextLinearInclude(ILinearPattern pattern)
|
||||
: base(pattern)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Declare(Action<IPathSegment, bool> onDeclare)
|
||||
{
|
||||
if (IsStackEmpty())
|
||||
{
|
||||
throw new InvalidOperationException("Can't declare path segment before entering a directory.");
|
||||
}
|
||||
|
||||
if (Frame.IsNotApplicable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Frame.SegmentIndex < Pattern.Segments.Count)
|
||||
{
|
||||
onDeclare(Pattern.Segments[Frame.SegmentIndex], IsLastSegment());
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Test(DirectoryInfoBase directory)
|
||||
{
|
||||
if (IsStackEmpty())
|
||||
{
|
||||
throw new InvalidOperationException("Can't test directory before entering a directory.");
|
||||
}
|
||||
|
||||
if (Frame.IsNotApplicable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return !IsLastSegment() && TestMatchingSegment(directory.Name);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Abstractions;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal.PatternContexts
|
||||
{
|
||||
public abstract class PatternContextRagged : PatternContext<PatternContextRagged.FrameData>
|
||||
{
|
||||
public PatternContextRagged(IRaggedPattern pattern)
|
||||
{
|
||||
Pattern = pattern;
|
||||
}
|
||||
|
||||
public override PatternTestResult Test(FileInfoBase file)
|
||||
{
|
||||
if (IsStackEmpty())
|
||||
{
|
||||
throw new InvalidOperationException("Can't test file before entering a directory.");
|
||||
}
|
||||
|
||||
if(!Frame.IsNotApplicable && IsEndingGroup() && TestMatchingGroup(file))
|
||||
{
|
||||
return PatternTestResult.Success(CalculateStem(file));
|
||||
}
|
||||
return PatternTestResult.Failed;
|
||||
}
|
||||
|
||||
public sealed override void PushDirectory(DirectoryInfoBase directory)
|
||||
{
|
||||
// copy the current frame
|
||||
var frame = Frame;
|
||||
|
||||
if (IsStackEmpty())
|
||||
{
|
||||
// initializing
|
||||
frame.SegmentGroupIndex = -1;
|
||||
frame.SegmentGroup = Pattern.StartsWith;
|
||||
}
|
||||
else if (Frame.IsNotApplicable)
|
||||
{
|
||||
// no change
|
||||
}
|
||||
else if (IsStartingGroup())
|
||||
{
|
||||
if (!TestMatchingSegment(directory.Name))
|
||||
{
|
||||
// nothing down this path is affected by this pattern
|
||||
frame.IsNotApplicable = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// starting path incrementally satisfied
|
||||
frame.SegmentIndex += 1;
|
||||
}
|
||||
}
|
||||
else if (!IsStartingGroup() && directory.Name == "..")
|
||||
{
|
||||
// any parent path segment is not applicable in **
|
||||
frame.IsNotApplicable = true;
|
||||
}
|
||||
else if (!IsStartingGroup() && !IsEndingGroup() && TestMatchingGroup(directory))
|
||||
{
|
||||
frame.SegmentIndex = Frame.SegmentGroup.Count;
|
||||
frame.BacktrackAvailable = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// increase directory backtrack length
|
||||
frame.BacktrackAvailable += 1;
|
||||
}
|
||||
|
||||
if (frame.InStem)
|
||||
{
|
||||
frame.StemItems.Add(directory.Name);
|
||||
}
|
||||
|
||||
while (
|
||||
frame.SegmentIndex == frame.SegmentGroup.Count &&
|
||||
frame.SegmentGroupIndex != Pattern.Contains.Count)
|
||||
{
|
||||
frame.SegmentGroupIndex += 1;
|
||||
frame.SegmentIndex = 0;
|
||||
if (frame.SegmentGroupIndex < Pattern.Contains.Count)
|
||||
{
|
||||
frame.SegmentGroup = Pattern.Contains[frame.SegmentGroupIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
frame.SegmentGroup = Pattern.EndsWith;
|
||||
}
|
||||
|
||||
// We now care about the stem
|
||||
frame.InStem = true;
|
||||
}
|
||||
|
||||
PushDataFrame(frame);
|
||||
}
|
||||
|
||||
public override void PopDirectory()
|
||||
{
|
||||
base.PopDirectory();
|
||||
if (Frame.StemItems.Count > 0)
|
||||
{
|
||||
Frame.StemItems.RemoveAt(Frame.StemItems.Count - 1);
|
||||
}
|
||||
}
|
||||
|
||||
public struct FrameData
|
||||
{
|
||||
public bool IsNotApplicable;
|
||||
|
||||
public int SegmentGroupIndex;
|
||||
|
||||
public IList<IPathSegment> SegmentGroup;
|
||||
|
||||
public int BacktrackAvailable;
|
||||
|
||||
public int SegmentIndex;
|
||||
|
||||
public bool InStem;
|
||||
|
||||
private IList<string> _stemItems;
|
||||
|
||||
public IList<string> StemItems
|
||||
{
|
||||
get { return _stemItems ?? (_stemItems = new List<string>()); }
|
||||
}
|
||||
|
||||
public string Stem
|
||||
{
|
||||
get { return _stemItems == null ? null : string.Join("/", _stemItems); }
|
||||
}
|
||||
}
|
||||
|
||||
protected IRaggedPattern Pattern { get; }
|
||||
|
||||
protected bool IsStartingGroup()
|
||||
{
|
||||
return Frame.SegmentGroupIndex == -1;
|
||||
}
|
||||
|
||||
protected bool IsEndingGroup()
|
||||
{
|
||||
return Frame.SegmentGroupIndex == Pattern.Contains.Count;
|
||||
}
|
||||
|
||||
protected bool TestMatchingSegment(string value)
|
||||
{
|
||||
if (Frame.SegmentIndex >= Frame.SegmentGroup.Count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return Frame.SegmentGroup[Frame.SegmentIndex].Match(value);
|
||||
}
|
||||
|
||||
protected bool TestMatchingGroup(FileSystemInfoBase value)
|
||||
{
|
||||
var groupLength = Frame.SegmentGroup.Count;
|
||||
var backtrackLength = Frame.BacktrackAvailable + 1;
|
||||
if (backtrackLength < groupLength)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var scan = value;
|
||||
for (int index = 0; index != groupLength; ++index)
|
||||
{
|
||||
var segment = Frame.SegmentGroup[groupLength - index - 1];
|
||||
if (!segment.Match(scan.Name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
scan = scan.ParentDirectory;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected string CalculateStem(FileInfoBase matchedFile)
|
||||
{
|
||||
return MatcherContext.CombinePath(Frame.Stem, matchedFile.Name);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Abstractions;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal.PatternContexts
|
||||
{
|
||||
public class PatternContextRaggedExclude : PatternContextRagged
|
||||
{
|
||||
public PatternContextRaggedExclude(IRaggedPattern pattern)
|
||||
: base(pattern)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Test(DirectoryInfoBase directory)
|
||||
{
|
||||
if (IsStackEmpty())
|
||||
{
|
||||
throw new InvalidOperationException("Can't test directory before entering a directory.");
|
||||
}
|
||||
|
||||
if (Frame.IsNotApplicable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsEndingGroup() && TestMatchingGroup(directory))
|
||||
{
|
||||
// directory excluded with file-like pattern
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Pattern.EndsWith.Count == 0 &&
|
||||
Frame.SegmentGroupIndex == Pattern.Contains.Count - 1 &&
|
||||
TestMatchingGroup(directory))
|
||||
{
|
||||
// directory excluded by matching up to final '/**'
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Abstractions;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal.PathSegments;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal.PatternContexts
|
||||
{
|
||||
public class PatternContextRaggedInclude : PatternContextRagged
|
||||
{
|
||||
public PatternContextRaggedInclude(IRaggedPattern pattern)
|
||||
: base(pattern)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Declare(Action<IPathSegment, bool> onDeclare)
|
||||
{
|
||||
if (IsStackEmpty())
|
||||
{
|
||||
throw new InvalidOperationException("Can't declare path segment before entering a directory.");
|
||||
}
|
||||
|
||||
if (Frame.IsNotApplicable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsStartingGroup() && Frame.SegmentIndex < Frame.SegmentGroup.Count)
|
||||
{
|
||||
onDeclare(Frame.SegmentGroup[Frame.SegmentIndex], false);
|
||||
}
|
||||
else
|
||||
{
|
||||
onDeclare(WildcardPathSegment.MatchAll, false);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Test(DirectoryInfoBase directory)
|
||||
{
|
||||
if (IsStackEmpty())
|
||||
{
|
||||
throw new InvalidOperationException("Can't test directory before entering a directory.");
|
||||
}
|
||||
|
||||
if (Frame.IsNotApplicable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsStartingGroup() && !TestMatchingSegment(directory.Name))
|
||||
{
|
||||
// deterministic not-included
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal
|
||||
{
|
||||
public struct PatternTestResult
|
||||
{
|
||||
public static readonly PatternTestResult Failed = new PatternTestResult(isSuccessful: false, stem: null);
|
||||
|
||||
public bool IsSuccessful { get; }
|
||||
public string Stem { get; }
|
||||
|
||||
private PatternTestResult(bool isSuccessful, string stem)
|
||||
{
|
||||
IsSuccessful = isSuccessful;
|
||||
Stem = stem;
|
||||
}
|
||||
|
||||
public static PatternTestResult Success(string stem)
|
||||
{
|
||||
return new PatternTestResult(isSuccessful: true, stem: stem);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,272 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal.PathSegments;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal.PatternContexts;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal.Patterns
|
||||
{
|
||||
public class PatternBuilder
|
||||
{
|
||||
private static readonly char[] _slashes = new[] { '/', '\\' };
|
||||
private static readonly char[] _star = new[] { '*' };
|
||||
|
||||
public PatternBuilder()
|
||||
{
|
||||
ComparisonType = StringComparison.OrdinalIgnoreCase;
|
||||
}
|
||||
|
||||
public PatternBuilder(StringComparison comparisonType)
|
||||
{
|
||||
ComparisonType = comparisonType;
|
||||
}
|
||||
|
||||
public StringComparison ComparisonType { get; }
|
||||
|
||||
public IPattern Build(string pattern)
|
||||
{
|
||||
if (pattern == null)
|
||||
{
|
||||
throw new ArgumentNullException("pattern");
|
||||
}
|
||||
|
||||
pattern = pattern.TrimStart(_slashes);
|
||||
|
||||
if (pattern.TrimEnd(_slashes).Length < pattern.Length)
|
||||
{
|
||||
// If the pattern end with a slash, it is considered as
|
||||
// a directory.
|
||||
pattern = pattern.TrimEnd(_slashes) + "/**";
|
||||
}
|
||||
|
||||
var allSegments = new List<IPathSegment>();
|
||||
var isParentSegmentLegal = true;
|
||||
|
||||
IList<IPathSegment> segmentsPatternStartsWith = null;
|
||||
IList<IList<IPathSegment>> segmentsPatternContains = null;
|
||||
IList<IPathSegment> segmentsPatternEndsWith = null;
|
||||
|
||||
var endPattern = pattern.Length;
|
||||
for (int scanPattern = 0; scanPattern < endPattern;)
|
||||
{
|
||||
var beginSegment = scanPattern;
|
||||
var endSegment = NextIndex(pattern, _slashes, scanPattern, endPattern);
|
||||
|
||||
IPathSegment segment = null;
|
||||
|
||||
if (segment == null && endSegment - beginSegment == 3)
|
||||
{
|
||||
if (pattern[beginSegment] == '*' &&
|
||||
pattern[beginSegment + 1] == '.' &&
|
||||
pattern[beginSegment + 2] == '*')
|
||||
{
|
||||
// turn *.* into *
|
||||
beginSegment += 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (segment == null && endSegment - beginSegment == 2)
|
||||
{
|
||||
if (pattern[beginSegment] == '*' &&
|
||||
pattern[beginSegment + 1] == '*')
|
||||
{
|
||||
// recognized **
|
||||
segment = new RecursiveWildcardSegment();
|
||||
}
|
||||
else if (pattern[beginSegment] == '.' &&
|
||||
pattern[beginSegment + 1] == '.')
|
||||
{
|
||||
// recognized ..
|
||||
|
||||
if (!isParentSegmentLegal)
|
||||
{
|
||||
throw new ArgumentException("\"..\" can be only added at the beginning of the pattern.");
|
||||
}
|
||||
segment = new ParentPathSegment();
|
||||
}
|
||||
}
|
||||
|
||||
if (segment == null && endSegment - beginSegment == 1)
|
||||
{
|
||||
if (pattern[beginSegment] == '.')
|
||||
{
|
||||
// recognized .
|
||||
segment = new CurrentPathSegment();
|
||||
}
|
||||
}
|
||||
|
||||
if (segment == null && endSegment - beginSegment > 2)
|
||||
{
|
||||
if (pattern[beginSegment] == '*' &&
|
||||
pattern[beginSegment + 1] == '*' &&
|
||||
pattern[beginSegment + 2] == '.')
|
||||
{
|
||||
// recognize **.
|
||||
// swallow the first *, add the recursive path segment and
|
||||
// the remaining part will be treat as wild card in next loop.
|
||||
segment = new RecursiveWildcardSegment();
|
||||
endSegment = beginSegment;
|
||||
}
|
||||
}
|
||||
|
||||
if (segment == null)
|
||||
{
|
||||
var beginsWith = string.Empty;
|
||||
var contains = new List<string>();
|
||||
var endsWith = string.Empty;
|
||||
|
||||
for (int scanSegment = beginSegment; scanSegment < endSegment;)
|
||||
{
|
||||
var beginLiteral = scanSegment;
|
||||
var endLiteral = NextIndex(pattern, _star, scanSegment, endSegment);
|
||||
|
||||
if (beginLiteral == beginSegment)
|
||||
{
|
||||
if (endLiteral == endSegment)
|
||||
{
|
||||
// and the only bit
|
||||
segment = new LiteralPathSegment(Portion(pattern, beginLiteral, endLiteral), ComparisonType);
|
||||
}
|
||||
else
|
||||
{
|
||||
// this is the first bit
|
||||
beginsWith = Portion(pattern, beginLiteral, endLiteral);
|
||||
}
|
||||
}
|
||||
else if (endLiteral == endSegment)
|
||||
{
|
||||
// this is the last bit
|
||||
endsWith = Portion(pattern, beginLiteral, endLiteral);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (beginLiteral != endLiteral)
|
||||
{
|
||||
// this is a middle bit
|
||||
contains.Add(Portion(pattern, beginLiteral, endLiteral));
|
||||
}
|
||||
else
|
||||
{
|
||||
// note: NOOP here, adjacent *'s are collapsed when they
|
||||
// are mixed with literal text in a path segment
|
||||
}
|
||||
}
|
||||
|
||||
scanSegment = endLiteral + 1;
|
||||
}
|
||||
|
||||
if (segment == null)
|
||||
{
|
||||
segment = new WildcardPathSegment(beginsWith, contains, endsWith, ComparisonType);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(segment is ParentPathSegment))
|
||||
{
|
||||
isParentSegmentLegal = false;
|
||||
}
|
||||
|
||||
if (segment is CurrentPathSegment)
|
||||
{
|
||||
// ignore ".\"
|
||||
}
|
||||
else
|
||||
{
|
||||
if (segment is RecursiveWildcardSegment)
|
||||
{
|
||||
if (segmentsPatternStartsWith == null)
|
||||
{
|
||||
segmentsPatternStartsWith = new List<IPathSegment>(allSegments);
|
||||
segmentsPatternEndsWith = new List<IPathSegment>();
|
||||
segmentsPatternContains = new List<IList<IPathSegment>>();
|
||||
}
|
||||
else if (segmentsPatternEndsWith.Count != 0)
|
||||
{
|
||||
segmentsPatternContains.Add(segmentsPatternEndsWith);
|
||||
segmentsPatternEndsWith = new List<IPathSegment>();
|
||||
}
|
||||
}
|
||||
else if (segmentsPatternEndsWith != null)
|
||||
{
|
||||
segmentsPatternEndsWith.Add(segment);
|
||||
}
|
||||
|
||||
allSegments.Add(segment);
|
||||
}
|
||||
|
||||
scanPattern = endSegment + 1;
|
||||
}
|
||||
|
||||
if (segmentsPatternStartsWith == null)
|
||||
{
|
||||
return new LinearPattern(allSegments);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new RaggedPattern(allSegments, segmentsPatternStartsWith, segmentsPatternEndsWith, segmentsPatternContains);
|
||||
}
|
||||
}
|
||||
|
||||
private static int NextIndex(string pattern, char[] anyOf, int beginIndex, int endIndex)
|
||||
{
|
||||
var index = pattern.IndexOfAny(anyOf, beginIndex, endIndex - beginIndex);
|
||||
return index == -1 ? endIndex : index;
|
||||
}
|
||||
|
||||
private static string Portion(string pattern, int beginIndex, int endIndex)
|
||||
{
|
||||
return pattern.Substring(beginIndex, endIndex - beginIndex);
|
||||
}
|
||||
|
||||
private class LinearPattern : ILinearPattern
|
||||
{
|
||||
public LinearPattern(List<IPathSegment> allSegments)
|
||||
{
|
||||
Segments = allSegments;
|
||||
}
|
||||
|
||||
public IList<IPathSegment> Segments { get; }
|
||||
|
||||
public IPatternContext CreatePatternContextForInclude()
|
||||
{
|
||||
return new PatternContextLinearInclude(this);
|
||||
}
|
||||
|
||||
public IPatternContext CreatePatternContextForExclude()
|
||||
{
|
||||
return new PatternContextLinearExclude(this);
|
||||
}
|
||||
}
|
||||
|
||||
private class RaggedPattern : IRaggedPattern
|
||||
{
|
||||
public RaggedPattern(List<IPathSegment> allSegments, IList<IPathSegment> segmentsPatternStartsWith, IList<IPathSegment> segmentsPatternEndsWith, IList<IList<IPathSegment>> segmentsPatternContains)
|
||||
{
|
||||
Segments = allSegments;
|
||||
StartsWith = segmentsPatternStartsWith;
|
||||
Contains = segmentsPatternContains;
|
||||
EndsWith = segmentsPatternEndsWith;
|
||||
}
|
||||
|
||||
public IList<IList<IPathSegment>> Contains { get; }
|
||||
|
||||
public IList<IPathSegment> EndsWith { get; }
|
||||
|
||||
public IList<IPathSegment> Segments { get; }
|
||||
|
||||
public IList<IPathSegment> StartsWith { get; }
|
||||
|
||||
public IPatternContext CreatePatternContextForInclude()
|
||||
{
|
||||
return new PatternContextRaggedInclude(this);
|
||||
}
|
||||
|
||||
public IPatternContext CreatePatternContextForExclude()
|
||||
{
|
||||
return new PatternContextRaggedExclude(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Abstractions;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal.Patterns;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing
|
||||
{
|
||||
public class Matcher
|
||||
{
|
||||
private IList<IPattern> _includePatterns = new List<IPattern>();
|
||||
private IList<IPattern> _excludePatterns = new List<IPattern>();
|
||||
private readonly PatternBuilder _builder;
|
||||
private readonly StringComparison _comparison;
|
||||
|
||||
public Matcher()
|
||||
: this(StringComparison.OrdinalIgnoreCase)
|
||||
{
|
||||
}
|
||||
|
||||
public Matcher(StringComparison comparisonType)
|
||||
{
|
||||
_comparison = comparisonType;
|
||||
_builder = new PatternBuilder(comparisonType);
|
||||
}
|
||||
|
||||
public virtual Matcher AddInclude(string pattern)
|
||||
{
|
||||
_includePatterns.Add(_builder.Build(pattern));
|
||||
return this;
|
||||
}
|
||||
|
||||
public virtual Matcher AddExclude(string pattern)
|
||||
{
|
||||
_excludePatterns.Add(_builder.Build(pattern));
|
||||
return this;
|
||||
}
|
||||
|
||||
public virtual PatternMatchingResult Execute(DirectoryInfoBase directoryInfo)
|
||||
{
|
||||
var context = new MatcherContext(_includePatterns, _excludePatterns, directoryInfo, _comparison);
|
||||
return context.Execute();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Abstractions;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing
|
||||
{
|
||||
public static class MatcherExtensions
|
||||
{
|
||||
public static void AddExcludePatterns(this Matcher matcher, params IEnumerable<string>[] excludePatternsGroups)
|
||||
{
|
||||
foreach (var group in excludePatternsGroups)
|
||||
{
|
||||
foreach (var pattern in group)
|
||||
{
|
||||
matcher.AddExclude(pattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddIncludePatterns(this Matcher matcher, params IEnumerable<string>[] includePatternsGroups)
|
||||
{
|
||||
foreach (var group in includePatternsGroups)
|
||||
{
|
||||
foreach (var pattern in group)
|
||||
{
|
||||
matcher.AddInclude(pattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<string> GetResultsInFullPath(this Matcher matcher, string directoryPath)
|
||||
{
|
||||
var matches = matcher.Execute(new DirectoryInfoWrapper(new DirectoryInfo(directoryPath))).Files;
|
||||
var result = matches.Select(match => Path.GetFullPath(Path.Combine(directoryPath, match.Path))).ToArray();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing
|
||||
{
|
||||
public class PatternMatchingResult
|
||||
{
|
||||
public PatternMatchingResult(IEnumerable<FilePatternMatch> files)
|
||||
{
|
||||
Files = files;
|
||||
}
|
||||
|
||||
public IEnumerable<FilePatternMatch> Files { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Util
|
||||
{
|
||||
internal static class StringComparisonHelper
|
||||
{
|
||||
public static StringComparer GetStringComparer(StringComparison comparisonType)
|
||||
{
|
||||
switch (comparisonType)
|
||||
{
|
||||
case StringComparison.CurrentCulture:
|
||||
return StringComparer.CurrentCulture;
|
||||
case StringComparison.CurrentCultureIgnoreCase:
|
||||
return StringComparer.CurrentCultureIgnoreCase;
|
||||
case StringComparison.Ordinal:
|
||||
return StringComparer.Ordinal;
|
||||
case StringComparison.OrdinalIgnoreCase:
|
||||
return StringComparer.OrdinalIgnoreCase;
|
||||
#if NET451
|
||||
case StringComparison.InvariantCulture:
|
||||
return StringComparer.InvariantCulture;
|
||||
case StringComparison.InvariantCultureIgnoreCase:
|
||||
return StringComparer.InvariantCultureIgnoreCase;
|
||||
#endif
|
||||
default:
|
||||
throw new InvalidOperationException($"Unexpected StringComparison type: {comparisonType}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.Extensions.Internal;
|
||||
using Microsoft.DotNet.InternalAbstractions;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.Files
|
||||
{
|
||||
|
|
|
@ -6,7 +6,7 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.DotNet.ProjectModel.Utilities;
|
||||
using Microsoft.Extensions.FileSystemGlobbing;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.Files
|
||||
{
|
||||
|
|
|
@ -5,7 +5,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.FileSystemGlobbing;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.Files
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.Extensions.Internal;
|
||||
using NuGet;
|
||||
using Microsoft.DotNet.InternalAbstractions;
|
||||
using NuGet.Versioning;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.Graph
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Text;
|
||||
using Microsoft.Extensions.Internal;
|
||||
using Microsoft.DotNet.InternalAbstractions;
|
||||
using NuGet.Versioning;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.Graph
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.DotNet.InternalAbstractions;
|
||||
using Microsoft.DotNet.ProjectModel.Graph;
|
||||
using Microsoft.Extensions.Internal;
|
||||
using NuGet.Frameworks;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel
|
||||
|
|
|
@ -9,7 +9,6 @@ using System.Text;
|
|||
using Microsoft.DotNet.InternalAbstractions;
|
||||
using Microsoft.DotNet.ProjectModel.Graph;
|
||||
using Microsoft.DotNet.ProjectModel.Resolution;
|
||||
using Microsoft.Extensions.Internal;
|
||||
using NuGet.Frameworks;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using Microsoft.Extensions.Internal;
|
||||
using Microsoft.DotNet.InternalAbstractions;
|
||||
using NuGet.Frameworks;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel
|
||||
|
|
|
@ -6,11 +6,6 @@
|
|||
"description": "Types to model a .NET Project",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyModel": "1.0.0-*",
|
||||
"Microsoft.Extensions.FileSystemGlobbing": "1.0.0-rc2-20581",
|
||||
"Microsoft.Extensions.HashCodeCombiner.Sources": {
|
||||
"type": "build",
|
||||
"version": "1.0.0-rc2-20459"
|
||||
},
|
||||
"Newtonsoft.Json": "7.0.1",
|
||||
"NuGet.Packaging": "3.5.0-beta-1199",
|
||||
"NuGet.RuntimeModel": "3.5.0-beta-1199",
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.Extensions.Internal;
|
||||
using Microsoft.DotNet.InternalAbstractions;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyModel
|
||||
{
|
||||
|
|
|
@ -14,10 +14,6 @@
|
|||
"target": "project",
|
||||
"version": "1.0.0-*"
|
||||
},
|
||||
"Microsoft.Extensions.HashCodeCombiner.Sources": {
|
||||
"type": "build",
|
||||
"version": "1.0.0-rc2-20459"
|
||||
},
|
||||
"Newtonsoft.Json": "7.0.1"
|
||||
},
|
||||
"frameworks": {
|
||||
|
|
|
@ -5,9 +5,9 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.FileSystemGlobbing;
|
||||
using Microsoft.Extensions.FileSystemGlobbing.Abstractions;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Abstractions;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Compiler
|
||||
{
|
||||
|
|
|
@ -8,12 +8,12 @@ using System.Linq;
|
|||
using Microsoft.DotNet.Cli.Utils;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using Microsoft.DotNet.ProjectModel.Files;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Abstractions;
|
||||
using Microsoft.DotNet.ProjectModel.Graph;
|
||||
using Microsoft.DotNet.ProjectModel.Resources;
|
||||
using Microsoft.DotNet.ProjectModel.Utilities;
|
||||
using Microsoft.DotNet.Tools.Pack;
|
||||
using Microsoft.Extensions.FileSystemGlobbing;
|
||||
using Microsoft.Extensions.FileSystemGlobbing.Abstractions;
|
||||
using NuGet;
|
||||
using NuGet.Frameworks;
|
||||
using NuGet.Packaging.Core;
|
||||
|
@ -167,7 +167,11 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
}
|
||||
}
|
||||
|
||||
internal static IEnumerable<PhysicalPackageFile> CollectAdditionalFiles(DirectoryInfoBase rootDirectory, IEnumerable<PackIncludeEntry> projectFileGlobs, string projectFilePath, IList<DiagnosticMessage> diagnostics)
|
||||
internal static IEnumerable<PhysicalPackageFile> CollectAdditionalFiles(
|
||||
DirectoryInfoBase rootDirectory,
|
||||
IEnumerable<PackIncludeEntry> projectFileGlobs,
|
||||
string projectFilePath,
|
||||
IList<DiagnosticMessage> diagnostics)
|
||||
{
|
||||
foreach (var entry in projectFileGlobs)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Abstractions;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Tests.TestUtility;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Tests
|
||||
{
|
||||
public class FileAbstractionsTests
|
||||
{
|
||||
[Fact]
|
||||
public void TempFolderStartsInitiallyEmpty()
|
||||
{
|
||||
using (var scenario = new DisposableFileSystem())
|
||||
{
|
||||
var contents = scenario.DirectoryInfo.EnumerateFileSystemInfos();
|
||||
|
||||
Assert.Equal(Path.GetFileName(scenario.RootPath), scenario.DirectoryInfo.Name);
|
||||
Assert.Equal(scenario.RootPath, scenario.DirectoryInfo.FullName);
|
||||
Assert.Equal(0, contents.Count());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FilesAreEnumerated()
|
||||
{
|
||||
using (var scenario = new DisposableFileSystem()
|
||||
.CreateFile("alpha.txt"))
|
||||
{
|
||||
var contents = new DirectoryInfoWrapper(scenario.DirectoryInfo).EnumerateFileSystemInfos();
|
||||
var alphaTxt = contents.OfType<FileInfoBase>().Single();
|
||||
|
||||
Assert.Equal(1, contents.Count());
|
||||
Assert.Equal("alpha.txt", alphaTxt.Name);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FoldersAreEnumerated()
|
||||
{
|
||||
using (var scenario = new DisposableFileSystem()
|
||||
.CreateFolder("beta"))
|
||||
{
|
||||
var contents1 = new DirectoryInfoWrapper(scenario.DirectoryInfo).EnumerateFileSystemInfos();
|
||||
var beta = contents1.OfType<DirectoryInfoBase>().Single();
|
||||
var contents2 = beta.EnumerateFileSystemInfos();
|
||||
|
||||
Assert.Equal(1, contents1.Count());
|
||||
Assert.Equal("beta", beta.Name);
|
||||
Assert.Equal(0, contents2.Count());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SubFoldersAreEnumerated()
|
||||
{
|
||||
using (var scenario = new DisposableFileSystem()
|
||||
.CreateFolder("beta")
|
||||
.CreateFile(Path.Combine("beta", "alpha.txt")))
|
||||
{
|
||||
var contents1 = new DirectoryInfoWrapper(scenario.DirectoryInfo).EnumerateFileSystemInfos();
|
||||
var beta = contents1.OfType<DirectoryInfoBase>().Single();
|
||||
var contents2 = beta.EnumerateFileSystemInfos();
|
||||
var alphaTxt = contents2.OfType<FileInfoBase>().Single();
|
||||
|
||||
Assert.Equal(1, contents1.Count());
|
||||
Assert.Equal("beta", beta.Name);
|
||||
Assert.Equal(1, contents2.Count());
|
||||
Assert.Equal("alpha.txt", alphaTxt.Name);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetDirectoryCanTakeDotDot()
|
||||
{
|
||||
using (var scenario = new DisposableFileSystem()
|
||||
.CreateFolder("gamma")
|
||||
.CreateFolder("beta")
|
||||
.CreateFile(Path.Combine("beta", "alpha.txt")))
|
||||
{
|
||||
var directoryInfoBase = new DirectoryInfoWrapper(scenario.DirectoryInfo);
|
||||
var gamma = directoryInfoBase.GetDirectory("gamma");
|
||||
var dotdot = gamma.GetDirectory("..");
|
||||
var contents1 = dotdot.EnumerateFileSystemInfos();
|
||||
var beta = dotdot.GetDirectory("beta");
|
||||
var contents2 = beta.EnumerateFileSystemInfos();
|
||||
var alphaTxt = contents2.OfType<FileInfoBase>().Single();
|
||||
|
||||
Assert.Equal("..", dotdot.Name);
|
||||
Assert.Equal(2, contents1.Count());
|
||||
Assert.Equal("beta", beta.Name);
|
||||
Assert.Equal(1, contents2.Count());
|
||||
Assert.Equal("alpha.txt", alphaTxt.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,469 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Abstractions;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Tests.TestUtility;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Tests
|
||||
{
|
||||
public class FunctionalTests : IDisposable
|
||||
{
|
||||
private readonly DisposableFileSystem _context;
|
||||
|
||||
public FunctionalTests()
|
||||
{
|
||||
_context = CreateContext();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_context.Dispose();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("sub/source2.cs", "sub/source2.cs")]
|
||||
[InlineData("sub\\source2.cs", "sub\\source2.cs")]
|
||||
[InlineData("sub/source2.cs", "sub\\source2.cs")]
|
||||
public void DuplicatePatterns(string pattern1, string pattern2)
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
matcher.AddInclude(pattern1);
|
||||
matcher.AddInclude(pattern2);
|
||||
|
||||
ExecuteAndVerify(matcher, @"src/project",
|
||||
"src/project/sub/source2.cs");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("src/project", "source1.cs", new string[] { "source1.cs" })]
|
||||
[InlineData("src/project", "Source1.cs", new string[] { })]
|
||||
[InlineData("src/project", "compiler/preprocess/**/*.cs", new string[] { "compiler/preprocess/preprocess-source1.cs",
|
||||
"compiler/preprocess/sub/preprocess-source2.cs",
|
||||
"compiler/preprocess/sub/sub/preprocess-source3.cs" })]
|
||||
[InlineData("src/project", "compiler/Preprocess/**.cs", new string[] { })]
|
||||
public void IncludeCaseSensitive(string root, string includePattern, string[] expectedFiles)
|
||||
{
|
||||
var matcher = new Matcher(StringComparison.Ordinal);
|
||||
matcher.AddInclude(includePattern);
|
||||
|
||||
ExecuteAndVerify(matcher, root, expectedFiles.Select(f => root + "/" + f).ToArray());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("src/project", "source1.cs", new string[] { "source1.cs" })]
|
||||
[InlineData("src/project", "Source1.cs", new string[] { "Source1.cs" })]
|
||||
[InlineData("src/project", "compiler/preprocess/**/*.cs", new string[] { "compiler/preprocess/preprocess-source1.cs",
|
||||
"compiler/preprocess/sub/preprocess-source2.cs",
|
||||
"compiler/preprocess/sub/sub/preprocess-source3.cs" })]
|
||||
[InlineData("src/project", "compiler/Preprocess/**.cs", new string[] { "compiler/Preprocess/preprocess-source1.cs",
|
||||
"compiler/Preprocess/sub/preprocess-source2.cs",
|
||||
"compiler/Preprocess/sub/sub/preprocess-source3.cs" })]
|
||||
public void IncludeCaseInsensitive(string root, string includePattern, string[] expectedFiles)
|
||||
{
|
||||
var matcher = new Matcher(StringComparison.OrdinalIgnoreCase);
|
||||
matcher.AddInclude(includePattern);
|
||||
|
||||
ExecuteAndVerify(matcher, root, expectedFiles.Select(f => root + "/" + f).ToArray());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("src/project/compiler/preprocess/", "source.cs", new string[] { "preprocess-source1.cs",
|
||||
"sub/preprocess-source2.cs",
|
||||
"sub/sub/preprocess-source3.cs",
|
||||
"sub/sub/preprocess-source3.txt" })]
|
||||
[InlineData("src/project/compiler/preprocess/", "preprocess-source1.cs", new string[] {
|
||||
"sub/preprocess-source2.cs",
|
||||
"sub/sub/preprocess-source3.cs",
|
||||
"sub/sub/preprocess-source3.txt" })]
|
||||
[InlineData("src/project/compiler/preprocess/", "preprocesS-source1.cs", new string[] {
|
||||
"preprocess-source1.cs",
|
||||
"sub/preprocess-source2.cs",
|
||||
"sub/sub/preprocess-source3.cs",
|
||||
"sub/sub/preprocess-source3.txt" })]
|
||||
[InlineData("src/project/compiler/preprocess/", "**/Preprocess*", new string[] { "preprocess-source1.cs",
|
||||
"sub/preprocess-source2.cs",
|
||||
"sub/sub/preprocess-source3.cs",
|
||||
"sub/sub/preprocess-source3.txt" })]
|
||||
[InlineData("src/project/compiler/preprocess/", "**/preprocess*", new string[] { })]
|
||||
[InlineData("src/project/compiler/preprocess/", "**/*source*.cs", new string[] { "sub/sub/preprocess-source3.txt" })]
|
||||
[InlineData("src/project/compiler/preprocess/", "**/*Source*.cs", new string[] {
|
||||
"preprocess-source1.cs",
|
||||
"sub/preprocess-source2.cs",
|
||||
"sub/sub/preprocess-source3.cs",
|
||||
"sub/sub/preprocess-source3.txt" })]
|
||||
[InlineData("src/project/compiler/preprocess/", "sub/sub/*", new string[] { "preprocess-source1.cs",
|
||||
"sub/preprocess-source2.cs" })]
|
||||
[InlineData("src/project/compiler/preprocess/", "sub/Sub/*", new string[] { "preprocess-source1.cs",
|
||||
"sub/preprocess-source2.cs",
|
||||
"sub/sub/preprocess-source3.cs",
|
||||
"sub/sub/preprocess-source3.txt" })]
|
||||
public void ExcludeCaseSensitive(string root, string excludePattern, string[] expectedFiles)
|
||||
{
|
||||
var matcher = new Matcher(StringComparison.Ordinal);
|
||||
matcher.AddInclude("**/*.*");
|
||||
matcher.AddExclude(excludePattern);
|
||||
|
||||
ExecuteAndVerify(matcher, root, expectedFiles.Select(f => root + "/" + f).ToArray());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("src/project/compiler/preprocess/", "source.cs", new string[] { "preprocess-source1.cs",
|
||||
"sub/preprocess-source2.cs",
|
||||
"sub/sub/preprocess-source3.cs",
|
||||
"sub/sub/preprocess-source3.txt" })]
|
||||
[InlineData("src/project/compiler/preprocess/", "preprocess-source1.cs", new string[] {
|
||||
"sub/preprocess-source2.cs",
|
||||
"sub/sub/preprocess-source3.cs",
|
||||
"sub/sub/preprocess-source3.txt" })]
|
||||
[InlineData("src/project/compiler/preprocess/", "preprocesS-source1.cs", new string[] {
|
||||
"sub/preprocess-source2.cs",
|
||||
"sub/sub/preprocess-source3.cs",
|
||||
"sub/sub/preprocess-source3.txt" })]
|
||||
[InlineData("src/project/compiler/preprocess/", "**/Preprocess*", new string[] { })]
|
||||
[InlineData("src/project/compiler/preprocess/", "**/preprocess*", new string[] { })]
|
||||
[InlineData("src/project/compiler/preprocess/", "**/*source*.cs", new string[] { "sub/sub/preprocess-source3.txt" })]
|
||||
[InlineData("src/project/compiler/preprocess/", "**/*Source*.cs", new string[] { "sub/sub/preprocess-source3.txt" })]
|
||||
[InlineData("src/project/compiler/preprocess/", "sub/sub/*", new string[] { "preprocess-source1.cs",
|
||||
"sub/preprocess-source2.cs" })]
|
||||
[InlineData("src/project/compiler/preprocess/", "sub/Sub/*", new string[] { "preprocess-source1.cs",
|
||||
"sub/preprocess-source2.cs" })]
|
||||
public void ExcludeCaseInsensitive(string root, string excludePattern, string[] expectedFiles)
|
||||
{
|
||||
var matcher = new Matcher(StringComparison.OrdinalIgnoreCase);
|
||||
matcher.AddInclude("**/*.*");
|
||||
matcher.AddExclude(excludePattern);
|
||||
|
||||
ExecuteAndVerify(matcher, root, expectedFiles.Select(f => root + "/" + f).ToArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RecursiveAndDoubleParentsWithRecursiveSearch()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
matcher.AddInclude("**/*.cs")
|
||||
.AddInclude(@"../../lib/**/*.cs");
|
||||
|
||||
ExecuteAndVerify(matcher, @"src/project",
|
||||
"src/project/source1.cs",
|
||||
"src/project/sub/source2.cs",
|
||||
"src/project/sub/source3.cs",
|
||||
"src/project/sub2/source4.cs",
|
||||
"src/project/sub2/source5.cs",
|
||||
"src/project/compiler/preprocess/preprocess-source1.cs",
|
||||
"src/project/compiler/preprocess/sub/preprocess-source2.cs",
|
||||
"src/project/compiler/preprocess/sub/sub/preprocess-source3.cs",
|
||||
"src/project/compiler/shared/shared1.cs",
|
||||
"src/project/compiler/shared/sub/shared2.cs",
|
||||
"src/project/compiler/shared/sub/sub/sharedsub.cs",
|
||||
"lib/source6.cs",
|
||||
"lib/sub3/source7.cs",
|
||||
"lib/sub4/source8.cs");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RecursiveAndDoubleParentsSearch()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
matcher.AddInclude("**/*.cs")
|
||||
.AddInclude(@"../../lib/*.cs");
|
||||
|
||||
ExecuteAndVerify(matcher, @"src/project",
|
||||
"src/project/source1.cs",
|
||||
"src/project/sub/source2.cs",
|
||||
"src/project/sub/source3.cs",
|
||||
"src/project/sub2/source4.cs",
|
||||
"src/project/sub2/source5.cs",
|
||||
"src/project/compiler/preprocess/preprocess-source1.cs",
|
||||
"src/project/compiler/preprocess/sub/preprocess-source2.cs",
|
||||
"src/project/compiler/preprocess/sub/sub/preprocess-source3.cs",
|
||||
"src/project/compiler/shared/shared1.cs",
|
||||
"src/project/compiler/shared/sub/shared2.cs",
|
||||
"src/project/compiler/shared/sub/sub/sharedsub.cs",
|
||||
"lib/source6.cs");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WildcardAndDoubleParentWithRecursiveSearch()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
matcher.AddInclude(@"..\..\lib\**\*.cs");
|
||||
matcher.AddInclude(@"*.cs");
|
||||
|
||||
ExecuteAndVerify(matcher, @"src/project",
|
||||
"src/project/source1.cs",
|
||||
"lib/source6.cs",
|
||||
"lib/sub3/source7.cs",
|
||||
"lib/sub4/source8.cs");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WildcardAndDoubleParentsSearch()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
matcher.AddInclude(@"..\..\lib\*.cs");
|
||||
matcher.AddInclude(@"*.cs");
|
||||
|
||||
ExecuteAndVerify(matcher, @"src/project",
|
||||
"src/project/source1.cs",
|
||||
"lib/source6.cs");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DoubleParentsWithRecursiveSearch()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
matcher.AddInclude(@"..\..\lib\**\*.cs");
|
||||
|
||||
ExecuteAndVerify(matcher, @"src/project",
|
||||
"lib/source6.cs",
|
||||
"lib/sub3/source7.cs",
|
||||
"lib/sub4/source8.cs");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OneLevelParentAndRecursiveSearch()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
matcher.AddInclude(@"../project2/**/*.cs");
|
||||
|
||||
ExecuteAndVerify(matcher, @"src/project",
|
||||
"src/project2/source1.cs",
|
||||
"src/project2/sub/source2.cs",
|
||||
"src/project2/sub/source3.cs",
|
||||
"src/project2/sub2/source4.cs",
|
||||
"src/project2/sub2/source5.cs",
|
||||
"src/project2/compiler/preprocess/preprocess-source1.cs",
|
||||
"src/project2/compiler/preprocess/sub/preprocess-source2.cs",
|
||||
"src/project2/compiler/preprocess/sub/sub/preprocess-source3.cs",
|
||||
"src/project2/compiler/shared/shared1.cs",
|
||||
"src/project2/compiler/shared/sub/shared2.cs",
|
||||
"src/project2/compiler/shared/sub/sub/sharedsub.cs");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RecursiveSuffixSearch()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
matcher.AddInclude(@"**.txt");
|
||||
|
||||
ExecuteAndVerify(matcher, @"src/project",
|
||||
"src/project/compiler/preprocess/sub/sub/preprocess-source3.txt",
|
||||
"src/project/compiler/shared/shared1.txt",
|
||||
"src/project/compiler/shared/sub/shared2.txt",
|
||||
"src/project/content1.txt");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FolderExclude()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
matcher.AddInclude(@"**/*.*");
|
||||
matcher.AddExclude(@"obj");
|
||||
matcher.AddExclude(@"bin");
|
||||
matcher.AddExclude(@".*");
|
||||
|
||||
ExecuteAndVerify(matcher, @"src/project",
|
||||
"src/project/source1.cs",
|
||||
"src/project/sub/source2.cs",
|
||||
"src/project/sub/source3.cs",
|
||||
"src/project/sub2/source4.cs",
|
||||
"src/project/sub2/source5.cs",
|
||||
"src/project/compiler/preprocess/preprocess-source1.cs",
|
||||
"src/project/compiler/preprocess/sub/preprocess-source2.cs",
|
||||
"src/project/compiler/preprocess/sub/sub/preprocess-source3.cs",
|
||||
"src/project/compiler/preprocess/sub/sub/preprocess-source3.txt",
|
||||
"src/project/compiler/shared/shared1.cs",
|
||||
"src/project/compiler/shared/shared1.txt",
|
||||
"src/project/compiler/shared/sub/shared2.cs",
|
||||
"src/project/compiler/shared/sub/shared2.txt",
|
||||
"src/project/compiler/shared/sub/sub/sharedsub.cs",
|
||||
"src/project/compiler/resources/resource.res",
|
||||
"src/project/compiler/resources/sub/resource2.res",
|
||||
"src/project/compiler/resources/sub/sub/resource3.res",
|
||||
"src/project/content1.txt");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FolderInclude()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
matcher.AddInclude(@"compiler/");
|
||||
ExecuteAndVerify(matcher, @"src/project",
|
||||
"src/project/compiler/preprocess/preprocess-source1.cs",
|
||||
"src/project/compiler/preprocess/sub/preprocess-source2.cs",
|
||||
"src/project/compiler/preprocess/sub/sub/preprocess-source3.cs",
|
||||
"src/project/compiler/preprocess/sub/sub/preprocess-source3.txt",
|
||||
"src/project/compiler/shared/shared1.cs",
|
||||
"src/project/compiler/shared/shared1.txt",
|
||||
"src/project/compiler/shared/sub/shared2.cs",
|
||||
"src/project/compiler/shared/sub/shared2.txt",
|
||||
"src/project/compiler/shared/sub/sub/sharedsub.cs",
|
||||
"src/project/compiler/resources/resource.res",
|
||||
"src/project/compiler/resources/sub/resource2.res",
|
||||
"src/project/compiler/resources/sub/sub/resource3.res");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("source1.cs", "src/project/source1.cs")]
|
||||
[InlineData("../project2/source1.cs", "src/project2/source1.cs")]
|
||||
public void SingleFile(string pattern, string expect)
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
matcher.AddInclude(pattern);
|
||||
ExecuteAndVerify(matcher, "src/project", expect);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SingleFileAndRecursive()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
matcher.AddInclude("**/*.cs");
|
||||
matcher.AddInclude("../project2/source1.cs");
|
||||
ExecuteAndVerify(matcher, "src/project",
|
||||
"src/project/source1.cs",
|
||||
"src/project/sub/source2.cs",
|
||||
"src/project/sub/source3.cs",
|
||||
"src/project/sub2/source4.cs",
|
||||
"src/project/sub2/source5.cs",
|
||||
"src/project/compiler/preprocess/preprocess-source1.cs",
|
||||
"src/project/compiler/preprocess/sub/preprocess-source2.cs",
|
||||
"src/project/compiler/preprocess/sub/sub/preprocess-source3.cs",
|
||||
"src/project/compiler/shared/shared1.cs",
|
||||
"src/project/compiler/shared/sub/shared2.cs",
|
||||
"src/project/compiler/shared/sub/sub/sharedsub.cs",
|
||||
"src/project2/source1.cs");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StemCorrectWithDifferentWildCards()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
matcher.AddInclude("sub/*.cs");
|
||||
matcher.AddInclude("**/*.cs");
|
||||
|
||||
var directoryPath = Path.Combine(_context.RootPath, "src/project");
|
||||
var results = matcher.Execute(new DirectoryInfoWrapper(new DirectoryInfo(directoryPath)));
|
||||
|
||||
var actual = results.Files.Select(match => match.Stem);
|
||||
var expected = new string[] {
|
||||
"source1.cs",
|
||||
"source2.cs",
|
||||
"source3.cs",
|
||||
"sub2/source4.cs",
|
||||
"sub2/source5.cs",
|
||||
"compiler/preprocess/preprocess-source1.cs",
|
||||
"compiler/preprocess/sub/preprocess-source2.cs",
|
||||
"compiler/preprocess/sub/sub/preprocess-source3.cs",
|
||||
"compiler/shared/shared1.cs",
|
||||
"compiler/shared/sub/shared2.cs",
|
||||
"compiler/shared/sub/sub/sharedsub.cs"
|
||||
};
|
||||
|
||||
Assert.Equal(
|
||||
expected.OrderBy(e => e),
|
||||
actual.OrderBy(e => e),
|
||||
StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MultipleSubDirsAfterFirstWildcardMatch_HasCorrectStem()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
matcher.AddInclude("compiler/**/*.cs");
|
||||
|
||||
var directoryPath = Path.Combine(_context.RootPath, "src/project");
|
||||
var results = matcher.Execute(new DirectoryInfoWrapper(new DirectoryInfo(directoryPath)));
|
||||
|
||||
var actual = results.Files.Select(match => match.Stem);
|
||||
var expected = new string[] {
|
||||
"preprocess/preprocess-source1.cs",
|
||||
"preprocess/sub/preprocess-source2.cs",
|
||||
"preprocess/sub/sub/preprocess-source3.cs",
|
||||
"shared/shared1.cs",
|
||||
"shared/sub/shared2.cs",
|
||||
"shared/sub/sub/sharedsub.cs"
|
||||
};
|
||||
|
||||
Assert.Equal(
|
||||
expected.OrderBy(e => e),
|
||||
actual.OrderBy(e => e),
|
||||
StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private DisposableFileSystem CreateContext()
|
||||
{
|
||||
var context = new DisposableFileSystem();
|
||||
context.CreateFiles(
|
||||
"src/project/source1.cs",
|
||||
"src/project/sub/source2.cs",
|
||||
"src/project/sub/source3.cs",
|
||||
"src/project/sub2/source4.cs",
|
||||
"src/project/sub2/source5.cs",
|
||||
"src/project/compiler/preprocess/preprocess-source1.cs",
|
||||
"src/project/compiler/preprocess/sub/preprocess-source2.cs",
|
||||
"src/project/compiler/preprocess/sub/sub/preprocess-source3.cs",
|
||||
"src/project/compiler/preprocess/sub/sub/preprocess-source3.txt",
|
||||
"src/project/compiler/shared/shared1.cs",
|
||||
"src/project/compiler/shared/shared1.txt",
|
||||
"src/project/compiler/shared/sub/shared2.cs",
|
||||
"src/project/compiler/shared/sub/shared2.txt",
|
||||
"src/project/compiler/shared/sub/sub/sharedsub.cs",
|
||||
"src/project/compiler/resources/resource.res",
|
||||
"src/project/compiler/resources/sub/resource2.res",
|
||||
"src/project/compiler/resources/sub/sub/resource3.res",
|
||||
"src/project/content1.txt",
|
||||
"src/project/obj/object.o",
|
||||
"src/project/bin/object",
|
||||
"src/project/.hidden/file1.hid",
|
||||
"src/project/.hidden/sub/file2.hid",
|
||||
"src/project2/source1.cs",
|
||||
"src/project2/sub/source2.cs",
|
||||
"src/project2/sub/source3.cs",
|
||||
"src/project2/sub2/source4.cs",
|
||||
"src/project2/sub2/source5.cs",
|
||||
"src/project2/compiler/preprocess/preprocess-source1.cs",
|
||||
"src/project2/compiler/preprocess/sub/preprocess-source2.cs",
|
||||
"src/project2/compiler/preprocess/sub/sub/preprocess-source3.cs",
|
||||
"src/project2/compiler/preprocess/sub/sub/preprocess-source3.txt",
|
||||
"src/project2/compiler/shared/shared1.cs",
|
||||
"src/project2/compiler/shared/shared1.txt",
|
||||
"src/project2/compiler/shared/sub/shared2.cs",
|
||||
"src/project2/compiler/shared/sub/shared2.txt",
|
||||
"src/project2/compiler/shared/sub/sub/sharedsub.cs",
|
||||
"src/project2/compiler/resources/resource.res",
|
||||
"src/project2/compiler/resources/sub/resource2.res",
|
||||
"src/project2/compiler/resources/sub/sub/resource3.res",
|
||||
"src/project2/content1.txt",
|
||||
"src/project2/obj/object.o",
|
||||
"src/project2/bin/object",
|
||||
"lib/source6.cs",
|
||||
"lib/sub3/source7.cs",
|
||||
"lib/sub4/source8.cs",
|
||||
"res/resource1.text",
|
||||
"res/resource2.text",
|
||||
"res/resource3.text",
|
||||
".hidden/file1.hid",
|
||||
".hidden/sub/file2.hid");
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
private void ExecuteAndVerify(Matcher matcher, string directoryPath, params string[] expectFiles)
|
||||
{
|
||||
directoryPath = Path.Combine(_context.RootPath, directoryPath);
|
||||
var results = matcher.Execute(new DirectoryInfoWrapper(new DirectoryInfo(directoryPath)));
|
||||
|
||||
var actual = results.Files.Select(match => Path.GetFullPath(Path.Combine(_context.RootPath, directoryPath, match.Path)));
|
||||
var expected = expectFiles.Select(relativePath => Path.GetFullPath(Path.Combine(_context.RootPath, relativePath)));
|
||||
|
||||
Assert.Equal(
|
||||
expected.OrderBy(e => e),
|
||||
actual.OrderBy(e => e),
|
||||
StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Abstractions;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal.PatternContexts;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Tests.TestUtility;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Tests.PatternContexts
|
||||
{
|
||||
public class PatternContextLinearIncludeTests
|
||||
{
|
||||
[Fact]
|
||||
public void PredictBeforeEnterDirectoryShouldThrow()
|
||||
{
|
||||
var pattern = MockLinearPatternBuilder.New().Add("a").Build();
|
||||
var context = new PatternContextLinearInclude(pattern);
|
||||
|
||||
Assert.Throws<InvalidOperationException>(() =>
|
||||
{
|
||||
context.Declare((segment, last) =>
|
||||
{
|
||||
Assert.False(true, "No segment should be declared.");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new string[] { "a", "b" }, new string[] { "root" }, "a", false)]
|
||||
[InlineData(new string[] { "a", "b" }, new string[] { "root", "a" }, "b", true)]
|
||||
[InlineData(new string[] { "a", "b", "c" }, new string[] { "root" }, "a", false)]
|
||||
[InlineData(new string[] { "a", "b", "c" }, new string[] { "root", "a" }, "b", false)]
|
||||
[InlineData(new string[] { "a", "b", "c" }, new string[] { "root", "a", "b" }, "c", true)]
|
||||
public void PredictReturnsCorrectResult(string[] testSegments, string[] pushDirectory, string expectSegment, bool expectLast)
|
||||
{
|
||||
var pattern = MockLinearPatternBuilder.New().Add(testSegments).Build();
|
||||
var context = new PatternContextLinearInclude(pattern);
|
||||
PatternContextHelper.PushDirectory(context, pushDirectory);
|
||||
|
||||
context.Declare((segment, last) =>
|
||||
{
|
||||
var literal = segment as MockNonRecursivePathSegment;
|
||||
|
||||
Assert.NotNull(segment);
|
||||
Assert.Equal(expectSegment, literal.Value);
|
||||
Assert.Equal(expectLast, last);
|
||||
});
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new string[] { "a", "b", "c" }, new string[] { "root", "b" })]
|
||||
[InlineData(new string[] { "a", "b", "c" }, new string[] { "root", "a", "c" })]
|
||||
[InlineData(new string[] { "a", "b", "c" }, new string[] { "root", "a", "b", "d" })]
|
||||
[InlineData(new string[] { "a", "b", "c" }, new string[] { "root", "a", "b", "c" })]
|
||||
public void PredictNotCallBackWhenEnterUnmatchDirectory(string[] testSegments, string[] pushDirectory)
|
||||
{
|
||||
var pattern = MockLinearPatternBuilder.New().Add(testSegments).Build();
|
||||
var context = new PatternContextLinearInclude(pattern);
|
||||
PatternContextHelper.PushDirectory(context, pushDirectory);
|
||||
|
||||
context.Declare((segment, last) =>
|
||||
{
|
||||
Assert.False(true, "No segment should be declared.");
|
||||
});
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new string[] { "a", "b", "c" }, new string[] { "root", "a", }, "b", false)]
|
||||
[InlineData(new string[] { "a", "b", "c" }, new string[] { "root", "a", "b" }, "d", false)]
|
||||
[InlineData(new string[] { "a", "b", "c" }, new string[] { "root", "a", "b" }, "c", true)]
|
||||
[InlineData(new string[] { "a", "b", "c" }, new string[] { "root", "a", "b", "c" }, "d", false)]
|
||||
public void TestFileForIncludeReturnsCorrectResult(string[] testSegments, string[] pushDirectory, string filename, bool expectResult)
|
||||
{
|
||||
var pattern = MockLinearPatternBuilder.New().Add(testSegments).Build();
|
||||
var context = new PatternContextLinearInclude(pattern);
|
||||
PatternContextHelper.PushDirectory(context, pushDirectory);
|
||||
|
||||
var result = context.Test(new FakeFileInfo(filename));
|
||||
|
||||
Assert.Equal(expectResult, result.IsSuccessful);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new string[] { "a", "b", "c" }, new string[] { "root", "a", }, "b", false)]
|
||||
[InlineData(new string[] { "a", "b", "c" }, new string[] { "root", "a", "b" }, "c", true)]
|
||||
[InlineData(new string[] { "a", "b", "c" }, new string[] { "root", "a", "b" }, "d", false)]
|
||||
[InlineData(new string[] { "a", "b", "c" }, new string[] { "root", "a", "b", "c" }, "d", false)]
|
||||
public void TestFileForExcludeReturnsCorrectResult(string[] testSegments, string[] pushDirectory, string filename, bool expectResult)
|
||||
{
|
||||
var pattern = MockLinearPatternBuilder.New().Add(testSegments).Build();
|
||||
var context = new PatternContextLinearExclude(pattern);
|
||||
PatternContextHelper.PushDirectory(context, pushDirectory);
|
||||
|
||||
var result = context.Test(new FakeFileInfo(filename));
|
||||
|
||||
Assert.Equal(expectResult, result.IsSuccessful);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new string[] { "a", "b", "c" }, new string[] { "root" }, "a", true)]
|
||||
[InlineData(new string[] { "a", "b", "c" }, new string[] { "root", "a" }, "b", true)]
|
||||
[InlineData(new string[] { "a", "b", "c" }, new string[] { "root", "a" }, "c", false)]
|
||||
[InlineData(new string[] { "a", "b", "c" }, new string[] { "root", "a", "b" }, "c", false)]
|
||||
public void TestDirectoryForIncludeReturnsCorrectResult(string[] testSegments, string[] pushDirectory, string directoryName, bool expectResult)
|
||||
{
|
||||
var pattern = MockLinearPatternBuilder.New().Add(testSegments).Build();
|
||||
var context = new PatternContextLinearInclude(pattern);
|
||||
PatternContextHelper.PushDirectory(context, pushDirectory);
|
||||
|
||||
var result = context.Test(new FakeDirectoryInfo(directoryName));
|
||||
|
||||
Assert.Equal(expectResult, result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new string[] { "a", "b", "c" }, new string[] { "root" }, "a", false)]
|
||||
[InlineData(new string[] { "a", "b", "c" }, new string[] { "root", "a" }, "b", false)]
|
||||
[InlineData(new string[] { "a", "b", "c" }, new string[] { "root", "a" }, "c", false)]
|
||||
[InlineData(new string[] { "a", "b", "c" }, new string[] { "root", "a", "b" }, "c", true)]
|
||||
public void TestDirectoryForExcludeReturnsCorrectResult(string[] testSegments, string[] pushDirectory, string directoryName, bool expectResult)
|
||||
{
|
||||
var pattern = MockLinearPatternBuilder.New().Add(testSegments).Build();
|
||||
var context = new PatternContextLinearExclude(pattern);
|
||||
PatternContextHelper.PushDirectory(context, pushDirectory);
|
||||
|
||||
var result = context.Test(new FakeDirectoryInfo(directoryName));
|
||||
|
||||
Assert.Equal(expectResult, result);
|
||||
}
|
||||
|
||||
private class FakeDirectoryInfo : DirectoryInfoBase
|
||||
{
|
||||
public FakeDirectoryInfo(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public override string FullName { get { throw new NotImplementedException(); } }
|
||||
|
||||
public override string Name { get; }
|
||||
|
||||
public override DirectoryInfoBase ParentDirectory { get { throw new NotImplementedException(); } }
|
||||
|
||||
public override IEnumerable<FileSystemInfoBase> EnumerateFileSystemInfos() { throw new NotImplementedException(); }
|
||||
|
||||
public override DirectoryInfoBase GetDirectory(string path) { throw new NotImplementedException(); }
|
||||
|
||||
public override FileInfoBase GetFile(string path) { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
private class FakeFileInfo : FileInfoBase
|
||||
{
|
||||
public FakeFileInfo(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public override string FullName { get { throw new NotImplementedException(); } }
|
||||
|
||||
public override string Name { get; }
|
||||
|
||||
public override DirectoryInfoBase ParentDirectory { get { throw new NotImplementedException(); } }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal.PathSegments;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal.PatternContexts;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal.Patterns;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Tests.TestUtility;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Tests.PatternContexts
|
||||
{
|
||||
public class PatternContextRaggedIncludeTests
|
||||
{
|
||||
[Fact]
|
||||
public void PredictBeforeEnterDirectoryShouldThrow()
|
||||
{
|
||||
var builder = new PatternBuilder();
|
||||
var pattern = builder.Build("**") as IRaggedPattern;
|
||||
var context = new PatternContextRaggedInclude(pattern);
|
||||
|
||||
Assert.Throws<InvalidOperationException>(() =>
|
||||
{
|
||||
context.Declare((segment, last) =>
|
||||
{
|
||||
Assert.False(true, "No segment should be declared.");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("/a/b/**/c/d", new string[] { "root" }, "a", false)]
|
||||
[InlineData("/a/b/**/c/d", new string[] { "root", "a" }, "b", false)]
|
||||
[InlineData("/a/b/**/c/d", new string[] { "root", "a", "b" }, null, false)]
|
||||
[InlineData("/a/b/**/c/d", new string[] { "root", "a", "b", "whatever" }, null, false)]
|
||||
[InlineData("/a/b/**/c/d", new string[] { "root", "a", "b", "whatever", "anything" }, null, false)]
|
||||
public void PredictReturnsCorrectResult(string patternString, string[] pushDirectory, string expectSegment, bool expectWildcard)
|
||||
{
|
||||
var builder = new PatternBuilder();
|
||||
var pattern = builder.Build(patternString) as IRaggedPattern;
|
||||
Assert.NotNull(pattern);
|
||||
|
||||
var context = new PatternContextRaggedInclude(pattern);
|
||||
PatternContextHelper.PushDirectory(context, pushDirectory);
|
||||
|
||||
context.Declare((segment, last) =>
|
||||
{
|
||||
if (expectSegment != null)
|
||||
{
|
||||
var mockSegment = segment as LiteralPathSegment;
|
||||
|
||||
Assert.NotNull(mockSegment);
|
||||
Assert.Equal(false, last);
|
||||
Assert.Equal(expectSegment, mockSegment.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Equal(Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal.PathSegments.WildcardPathSegment.MatchAll, segment);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("/a/b/**/c/d", new string[] { "root", "b" })]
|
||||
[InlineData("/a/b/**/c/d", new string[] { "root", "a", "c" })]
|
||||
public void PredictNotCallBackWhenEnterUnmatchDirectory(string patternString, string[] pushDirectory)
|
||||
{
|
||||
var builder = new PatternBuilder();
|
||||
var pattern = builder.Build(patternString) as IRaggedPattern;
|
||||
var context = new PatternContextRaggedInclude(pattern);
|
||||
PatternContextHelper.PushDirectory(context, pushDirectory);
|
||||
|
||||
context.Declare((segment, last) =>
|
||||
{
|
||||
Assert.False(true, "No segment should be declared.");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,472 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Linq;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Tests.TestUtility;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Tests
|
||||
{
|
||||
public class PatternMatchingTests
|
||||
{
|
||||
[Fact]
|
||||
public void EmptyCollectionWhenNoFilesPresent()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include("alpha.txt")
|
||||
.Execute();
|
||||
|
||||
scenario.AssertExact();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchingFileIsFound()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include("alpha.txt")
|
||||
.Files("alpha.txt")
|
||||
.Execute();
|
||||
|
||||
scenario.AssertExact("alpha.txt");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MismatchedFileIsIgnored()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include("alpha.txt")
|
||||
.Files("omega.txt")
|
||||
.Execute();
|
||||
|
||||
scenario.AssertExact();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FolderNamesAreTraversed()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include("beta/alpha.txt")
|
||||
.Files("beta/alpha.txt")
|
||||
.Execute();
|
||||
|
||||
scenario.AssertExact("beta/alpha.txt");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(@"beta/alpha.txt", @"beta/alpha.txt")]
|
||||
[InlineData(@"beta\alpha.txt", @"beta/alpha.txt")]
|
||||
[InlineData(@"beta/alpha.txt", @"beta\alpha.txt")]
|
||||
[InlineData(@"beta\alpha.txt", @"beta\alpha.txt")]
|
||||
[InlineData(@"\beta\alpha.txt", @"beta\alpha.txt")]
|
||||
public void SlashPolarityIsIgnored(string includePattern, string filePath)
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include(includePattern)
|
||||
.Files("one/two.txt", filePath, "three/four.txt")
|
||||
.Execute();
|
||||
|
||||
scenario.AssertExact("beta/alpha.txt");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(@"*.txt", new[] { "alpha.txt", "beta.txt" })]
|
||||
[InlineData(@"alpha.*", new[] { "alpha.txt" })]
|
||||
[InlineData(@"*.*", new[] { "alpha.txt", "beta.txt", "gamma.dat" })]
|
||||
[InlineData(@"*", new[] { "alpha.txt", "beta.txt", "gamma.dat" })]
|
||||
[InlineData(@"*et*", new[] { "beta.txt" })]
|
||||
[InlineData(@"b*et*t", new[] { "beta.txt" })]
|
||||
[InlineData(@"b*et*x", new string[0])]
|
||||
public void PatternMatchingWorks(string includePattern, string[] matchesExpected)
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include(includePattern)
|
||||
.Files("alpha.txt", "beta.txt", "gamma.dat")
|
||||
.Execute();
|
||||
|
||||
scenario.AssertExact(matchesExpected);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(@"1234*5678", new[] { "12345678" })]
|
||||
[InlineData(@"12345*5678", new string[0])]
|
||||
[InlineData(@"12*3456*78", new[] { "12345678" })]
|
||||
[InlineData(@"12*23*", new string[0])]
|
||||
[InlineData(@"*67*78", new string[0])]
|
||||
[InlineData(@"*45*56", new string[0])]
|
||||
public void PatternBeginAndEndCantOverlap(string includePattern, string[] matchesExpected)
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include(includePattern)
|
||||
.Files("12345678")
|
||||
.Execute();
|
||||
|
||||
scenario.AssertExact(matchesExpected);
|
||||
}
|
||||
|
||||
|
||||
[Theory]
|
||||
[InlineData(@"*mm*/*", new[] { "gamma/hello.txt" })]
|
||||
[InlineData(@"/*mm*/*", new[] { "gamma/hello.txt" })]
|
||||
[InlineData(@"*alpha*/*", new[] { "alpha/hello.txt" })]
|
||||
[InlineData(@"/*alpha*/*", new[] { "alpha/hello.txt" })]
|
||||
[InlineData(@"*/*", new[] { "alpha/hello.txt", "beta/hello.txt", "gamma/hello.txt" })]
|
||||
[InlineData(@"/*/*", new[] { "alpha/hello.txt", "beta/hello.txt", "gamma/hello.txt" })]
|
||||
[InlineData(@"*.*/*", new[] { "alpha/hello.txt", "beta/hello.txt", "gamma/hello.txt" })]
|
||||
[InlineData(@"/*.*/*", new[] { "alpha/hello.txt", "beta/hello.txt", "gamma/hello.txt" })]
|
||||
public void PatternMatchingWorksInFolders(string includePattern, string[] matchesExpected)
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include(includePattern)
|
||||
.Files("alpha/hello.txt", "beta/hello.txt", "gamma/hello.txt")
|
||||
.Execute();
|
||||
|
||||
scenario.AssertExact(matchesExpected);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(@"", new string[] { })]
|
||||
[InlineData(@"./", new string[] { "alpha/hello.txt", "beta/hello.txt", "gamma/hello.txt" })]
|
||||
[InlineData(@"./alpha/hello.txt", new string[] { "alpha/hello.txt" })]
|
||||
[InlineData(@"./**/hello.txt", new string[] { "alpha/hello.txt", "beta/hello.txt", "gamma/hello.txt" })]
|
||||
[InlineData(@"././**/hello.txt", new string[] { "alpha/hello.txt", "beta/hello.txt", "gamma/hello.txt" })]
|
||||
[InlineData(@"././**/./hello.txt", new string[] { "alpha/hello.txt", "beta/hello.txt", "gamma/hello.txt" })]
|
||||
[InlineData(@"././**/./**/hello.txt", new string[] { "alpha/hello.txt", "beta/hello.txt", "gamma/hello.txt" })]
|
||||
[InlineData(@"./*mm*/hello.txt", new string[] { "gamma/hello.txt" })]
|
||||
[InlineData(@"./*mm*/*", new string[] { "gamma/hello.txt" })]
|
||||
public void PatternMatchingCurrent(string includePattern, string[] matchesExpected)
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include(includePattern)
|
||||
.Files("alpha/hello.txt", "beta/hello.txt", "gamma/hello.txt")
|
||||
.Execute();
|
||||
|
||||
scenario.AssertExact(matchesExpected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StarDotStarIsSameAsStar()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include("*.*")
|
||||
.Files("alpha.txt", "alpha.", ".txt", ".", "alpha", "txt")
|
||||
.Execute();
|
||||
|
||||
scenario.AssertExact("alpha.txt", "alpha.", ".txt", ".", "alpha", "txt");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IncompletePatternsDoNotInclude()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include("*/*.txt")
|
||||
.Files("one/x.txt", "two/x.txt", "x.txt")
|
||||
.Execute();
|
||||
|
||||
scenario.AssertExact("one/x.txt", "two/x.txt");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IncompletePatternsDoNotExclude()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include("*/*.txt")
|
||||
.Exclude("one/hello.txt")
|
||||
.Files("one/x.txt", "two/x.txt")
|
||||
.Execute();
|
||||
|
||||
scenario.AssertExact("one/x.txt", "two/x.txt");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TrailingRecursiveWildcardMatchesAllFiles()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include("one/**")
|
||||
.Files("one/x.txt", "two/x.txt", "one/x/y.txt")
|
||||
.Execute();
|
||||
|
||||
scenario.AssertExact("one/x.txt", "one/x/y.txt");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LeadingRecursiveWildcardMatchesAllLeadingPaths()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include("**/*.cs")
|
||||
.Files("one/x.cs", "two/x.cs", "one/two/x.cs", "x.cs")
|
||||
.Files("one/x.txt", "two/x.txt", "one/two/x.txt", "x.txt")
|
||||
.Execute();
|
||||
|
||||
scenario.AssertExact("one/x.cs", "two/x.cs", "one/two/x.cs", "x.cs");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InnerRecursiveWildcardMuseStartWithAndEndWith()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include("one/**/*.cs")
|
||||
.Files("one/x.cs", "two/x.cs", "one/two/x.cs", "x.cs")
|
||||
.Files("one/x.txt", "two/x.txt", "one/two/x.txt", "x.txt")
|
||||
.Execute();
|
||||
|
||||
scenario.AssertExact("one/x.cs", "one/two/x.cs");
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void ExcludeMayEndInDirectoryName()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include("*.cs", "*/*.cs", "*/*/*.cs")
|
||||
.Exclude("bin", "one/two")
|
||||
.Files("one/x.cs", "two/x.cs", "one/two/x.cs", "x.cs", "bin/x.cs", "bin/two/x.cs")
|
||||
.Execute();
|
||||
|
||||
scenario.AssertExact("one/x.cs", "two/x.cs", "x.cs");
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void RecursiveWildcardSurroundingContainsWith()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include("**/x/**")
|
||||
.Files("x/1", "1/x/2", "1/x", "x", "1", "1/2")
|
||||
.Execute();
|
||||
|
||||
scenario.AssertExact("x/1", "1/x/2");
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void SequentialFoldersMayBeRequired()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include("a/b/**/1/2/**/2/3/**")
|
||||
.Files("1/2/2/3/x", "1/2/3/y", "a/1/2/4/2/3/b", "a/2/3/1/2/b")
|
||||
.Files("a/b/1/2/2/3/x", "a/b/1/2/3/y", "a/b/a/1/2/4/2/3/b", "a/b/a/2/3/1/2/b")
|
||||
.Execute();
|
||||
|
||||
scenario.AssertExact("a/b/1/2/2/3/x", "a/b/a/1/2/4/2/3/b");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RecursiveAloneIncludesEverything()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include("**")
|
||||
.Files("1/2/2/3/x", "1/2/3/y")
|
||||
.Execute();
|
||||
|
||||
scenario.AssertExact("1/2/2/3/x", "1/2/3/y");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExcludeCanHaveSurroundingRecursiveWildcards()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include("**")
|
||||
.Exclude("**/x/**")
|
||||
.Files("x/1", "1/x/2", "1/x", "x", "1", "1/2")
|
||||
.Execute();
|
||||
|
||||
scenario.AssertExact("1/x", "x", "1", "1/2");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LeadingDotDotCanComeThroughPattern()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include("*.cs")
|
||||
.Include("../2/*.cs")
|
||||
.Files("1/x.cs", "1/x.txt", "2/x.cs", "2/x.txt")
|
||||
.SubDirectory("1")
|
||||
.Execute();
|
||||
|
||||
scenario.AssertExact("x.cs", "../2/x.cs");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LeadingDotDotWithRecursiveCanComeThroughPattern()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include("*.cs")
|
||||
.Include("../2/**/*.cs")
|
||||
.Files("1/x.cs", "1/x.txt", "2/x.cs", "2/x.txt", "2/3/x.cs", "2/3/4/z.cs", "2/3/x.txt")
|
||||
.SubDirectory("1")
|
||||
.Execute();
|
||||
|
||||
scenario.AssertExact("x.cs", "../2/x.cs", "../2/3/x.cs", "../2/3/4/z.cs");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExcludeFolderRecursively()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include("*.*")
|
||||
.Include("../sibling/**/*.*")
|
||||
.Exclude("../sibling/exc/**/*.*")
|
||||
.Exclude("../sibling/inc/2.txt")
|
||||
.Files("main/1.txt", "main/2.txt", "sibling/1.txt", "sibling/inc/1.txt", "sibling/inc/2.txt", "sibling/exc/1.txt", "sibling/exc/2.txt")
|
||||
.SubDirectory("main")
|
||||
.Execute();
|
||||
|
||||
scenario.AssertExact("1.txt", "2.txt", "../sibling/1.txt", "../sibling/inc/1.txt");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExcludeFolderByName()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include("*.*")
|
||||
.Include("../sibling/**/*.*")
|
||||
.Exclude("../sibling/exc/")
|
||||
.Exclude("../sibling/inc/2.txt")
|
||||
.Files("main/1.txt", "main/2.txt", "sibling/1.txt", "sibling/inc/1.txt", "sibling/inc/2.txt", "sibling/exc/1.txt", "sibling/exc/2.txt")
|
||||
.SubDirectory("main")
|
||||
.Execute();
|
||||
|
||||
scenario.AssertExact("1.txt", "2.txt", "../sibling/1.txt", "../sibling/inc/1.txt");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MultipleRecursiveWildcardStemMatch()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include("sub/**/bar/**/*.txt")
|
||||
.Files("root.txt", "sub/one.txt", "sub/two.txt", "sub/sub2/bar/baz/three.txt", "sub/sub3/sub4/bar/three.txt")
|
||||
.Execute();
|
||||
|
||||
// Check the stem of the matched items
|
||||
Assert.Equal(new[] {
|
||||
new FilePatternMatch(path: "sub/sub2/bar/baz/three.txt", stem: "sub2/bar/baz/three.txt"),
|
||||
new FilePatternMatch(path: "sub/sub3/sub4/bar/three.txt", stem: "sub3/sub4/bar/three.txt")
|
||||
}, scenario.Result.Files.ToArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RecursiveWildcardStemMatch()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include("sub/**/*.txt")
|
||||
.Files("root.txt", "sub/one.txt", "sub/two.txt", "sub/sub2/three.txt")
|
||||
.Execute();
|
||||
|
||||
// Check the stem of the matched items
|
||||
Assert.Equal(new[] {
|
||||
new FilePatternMatch(path: "sub/one.txt", stem: "one.txt"),
|
||||
new FilePatternMatch(path: "sub/two.txt", stem: "two.txt"),
|
||||
new FilePatternMatch(path: "sub/sub2/three.txt", stem: "sub2/three.txt")
|
||||
}, scenario.Result.Files.ToArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WildcardMidSegmentMatch()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include("sub/w*.txt")
|
||||
.Files("root.txt", "sub/woah.txt", "sub/wow.txt", "sub/blah.txt")
|
||||
.Execute();
|
||||
|
||||
// Check the stem of the matched items
|
||||
Assert.Equal(new[] {
|
||||
new FilePatternMatch(path: "sub/woah.txt", stem: "woah.txt"),
|
||||
new FilePatternMatch(path: "sub/wow.txt", stem: "wow.txt")
|
||||
}, scenario.Result.Files.ToArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StemMatchOnExactFile()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include("sub/sub/three.txt")
|
||||
.Files("root.txt", "sub/one.txt", "sub/two.txt", "sub/sub/three.txt")
|
||||
.Execute();
|
||||
|
||||
// Check the stem of the matched items
|
||||
Assert.Equal(new[] {
|
||||
new FilePatternMatch(path: "sub/sub/three.txt", stem: "three.txt"),
|
||||
}, scenario.Result.Files.ToArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SimpleStemMatching()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include("sub/*")
|
||||
.Files("root.txt", "sub/one.txt", "sub/two.txt", "sub/sub/three.txt")
|
||||
.Execute();
|
||||
|
||||
// Check the stem of the matched items
|
||||
Assert.Equal(new[] {
|
||||
new FilePatternMatch(path: "sub/one.txt", stem: "one.txt"),
|
||||
new FilePatternMatch(path: "sub/two.txt", stem: "two.txt")
|
||||
}, scenario.Result.Files.ToArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StemMatchingWithFileExtension()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include("sub/*.txt")
|
||||
.Files("root.txt", "sub/one.txt", "sub/two.txt", "sub/three.dat")
|
||||
.Execute();
|
||||
|
||||
// Check the stem of the matched items
|
||||
Assert.Equal(new[] {
|
||||
new FilePatternMatch(path: "sub/one.txt", stem: "one.txt"),
|
||||
new FilePatternMatch(path: "sub/two.txt", stem: "two.txt")
|
||||
}, scenario.Result.Files.ToArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StemMatchingWithParentDir()
|
||||
{
|
||||
var matcher = new Matcher();
|
||||
var scenario = new FileSystemGlobbingTestContext(@"c:\files\", matcher)
|
||||
.Include("../files/sub/*.txt")
|
||||
.Files("root.txt", "sub/one.txt", "sub/two.txt", "sub/three.dat")
|
||||
.Execute();
|
||||
|
||||
// Check the stem of the matched items
|
||||
Assert.Equal(new[] {
|
||||
new FilePatternMatch(path: "../files/sub/one.txt", stem: "one.txt"),
|
||||
new FilePatternMatch(path: "../files/sub/two.txt", stem: "two.txt")
|
||||
}, scenario.Result.Files.ToArray());
|
||||
}
|
||||
|
||||
// exclude: **/.*/**
|
||||
// exclude: node_modules/*
|
||||
// exclude: **/.cs
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal.PathSegments;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Tests.PatternSegments
|
||||
{
|
||||
public class CurrentPathSegmentTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("anything")]
|
||||
[InlineData("")]
|
||||
[InlineData(null)]
|
||||
public void Match(string testSample)
|
||||
{
|
||||
var pathSegment = new CurrentPathSegment();
|
||||
Assert.False(pathSegment.Match(testSample));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal.PathSegments;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Tests.PatternSegments
|
||||
{
|
||||
public class LiteralPathSegmentTests
|
||||
{
|
||||
[Fact]
|
||||
public void ThrowArgumentNullException()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() =>
|
||||
{
|
||||
var pathSegment = new LiteralPathSegment(value: null, comparisonType: StringComparison.OrdinalIgnoreCase);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllowEmptyInDefaultConstructor()
|
||||
{
|
||||
var pathSegment = new LiteralPathSegment(string.Empty, comparisonType: StringComparison.Ordinal);
|
||||
Assert.NotNull(pathSegment);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("something", "anything", StringComparison.Ordinal, false)]
|
||||
[InlineData("something", "Something", StringComparison.Ordinal, false)]
|
||||
[InlineData("something", "something", StringComparison.Ordinal, true)]
|
||||
[InlineData("something", "anything", StringComparison.OrdinalIgnoreCase, false)]
|
||||
[InlineData("something", "Something", StringComparison.OrdinalIgnoreCase, true)]
|
||||
[InlineData("something", "something", StringComparison.OrdinalIgnoreCase, true)]
|
||||
public void Match(string initialValue, string testSample, StringComparison comparisonType, bool expectation)
|
||||
{
|
||||
var pathSegment = new LiteralPathSegment(initialValue, comparisonType);
|
||||
Assert.Equal(initialValue, pathSegment.Value);
|
||||
Assert.Equal(expectation, pathSegment.Match(testSample));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal.PathSegments;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Tests.PatternSegments
|
||||
{
|
||||
public class ParentPathSegmentTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(".", false)]
|
||||
[InlineData("..", true)]
|
||||
[InlineData("...", false)]
|
||||
public void Match(string testSample, bool expectation)
|
||||
{
|
||||
var pathSegment = new ParentPathSegment();
|
||||
Assert.Equal(expectation, pathSegment.Match(testSample));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal.PathSegments;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Tests.PatternSegments
|
||||
{
|
||||
public class RecursiveWildcardSegmentTests
|
||||
{
|
||||
[Fact]
|
||||
public void Match()
|
||||
{
|
||||
var pathSegment = new RecursiveWildcardSegment();
|
||||
Assert.False(pathSegment.Match("Anything"));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal.PathSegments;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Tests.PatternSegments
|
||||
{
|
||||
public class WildcardPathSegmentTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(StringComparison.Ordinal)]
|
||||
[InlineData(StringComparison.OrdinalIgnoreCase)]
|
||||
public void DefaultConstructor(StringComparison comparisonType)
|
||||
{
|
||||
var paramBegin = "begin";
|
||||
var paramContains = new List<string> { "1", "2", "three" };
|
||||
var paramEnd = "end";
|
||||
|
||||
var segment = new WildcardPathSegment(paramBegin, paramContains, paramEnd, comparisonType);
|
||||
|
||||
Assert.Equal(paramBegin, segment.BeginsWith);
|
||||
Assert.Equal<string>(paramContains, segment.Contains);
|
||||
Assert.Equal(paramEnd, segment.EndsWith);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData("GetPositiveOrdinalIgnoreCaseDataSample")]
|
||||
public void PositiveOrdinalIgnoreCaseMatch(string testSample, object segment)
|
||||
{
|
||||
var wildcardPathSegment = (WildcardPathSegment)segment;
|
||||
Assert.True(
|
||||
wildcardPathSegment.Match(testSample),
|
||||
string.Format("[TestSample: {0}] [Wildcard: {1}]", testSample, Serialize(wildcardPathSegment)));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData("GetNegativeOrdinalIgnoreCaseDataSample")]
|
||||
public void NegativeOrdinalIgnoreCaseMatch(string testSample, object segment)
|
||||
{
|
||||
var wildcardPathSegment = (WildcardPathSegment)segment;
|
||||
Assert.False(
|
||||
wildcardPathSegment.Match(testSample),
|
||||
string.Format("[TestSample: {0}] [Wildcard: {1}]", testSample, Serialize(wildcardPathSegment)));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData("GetPositiveOrdinalDataSample")]
|
||||
public void PositiveOrdinalMatch(string testSample, object segment)
|
||||
{
|
||||
var wildcardPathSegment = (WildcardPathSegment)segment;
|
||||
Assert.True(
|
||||
wildcardPathSegment.Match(testSample),
|
||||
string.Format("[TestSample: {0}] [Wildcard: {1}]", testSample, Serialize(wildcardPathSegment)));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData("GetNegativeOrdinalDataSample")]
|
||||
public void NegativeOrdinalMatch(string testSample, object segment)
|
||||
{
|
||||
var wildcardPathSegment = (WildcardPathSegment)segment;
|
||||
Assert.False(
|
||||
wildcardPathSegment.Match(testSample),
|
||||
string.Format("[TestSample: {0}] [Wildcard: {1}]", testSample, Serialize(wildcardPathSegment)));
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> GetPositiveOrdinalIgnoreCaseDataSample()
|
||||
{
|
||||
yield return WrapResult(StringComparison.OrdinalIgnoreCase, "abc", "a", "c");
|
||||
yield return WrapResult(StringComparison.OrdinalIgnoreCase, "abBb123c", "a", "c");
|
||||
yield return WrapResult(StringComparison.OrdinalIgnoreCase, "aaac", "a", "c");
|
||||
yield return WrapResult(StringComparison.OrdinalIgnoreCase, "acccc", "a", "c");
|
||||
yield return WrapResult(StringComparison.OrdinalIgnoreCase, "aacc", "a", "c");
|
||||
yield return WrapResult(StringComparison.OrdinalIgnoreCase, "aacc", "aa", "c");
|
||||
yield return WrapResult(StringComparison.OrdinalIgnoreCase, "acc", "ac", "c");
|
||||
yield return WrapResult(StringComparison.OrdinalIgnoreCase, "abcdefgh", "ab", "cd", "ef", "gh");
|
||||
yield return WrapResult(StringComparison.OrdinalIgnoreCase, "abCDEfgh", "ab", "cd", "ef", "gh");
|
||||
yield return WrapResult(StringComparison.OrdinalIgnoreCase, "ab123cd321ef123gh", "ab", "cd", "ef", "gh");
|
||||
yield return WrapResult(StringComparison.OrdinalIgnoreCase, "abcd321ef123gh", "ab", "cd", "ef", "gh");
|
||||
yield return WrapResult(StringComparison.OrdinalIgnoreCase, "ababcd321ef123gh", "ab", "cd", "ef", "gh");
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> GetNegativeOrdinalIgnoreCaseDataSample()
|
||||
{
|
||||
yield return WrapResult(StringComparison.OrdinalIgnoreCase, "aa", "a", "c");
|
||||
yield return WrapResult(StringComparison.OrdinalIgnoreCase, "cc", "a", "c");
|
||||
yield return WrapResult(StringComparison.OrdinalIgnoreCase, "ab", "a", "c");
|
||||
yield return WrapResult(StringComparison.OrdinalIgnoreCase, "ab", "a", "b", "c");
|
||||
yield return WrapResult(StringComparison.OrdinalIgnoreCase, "bc", "a", "b", "c");
|
||||
yield return WrapResult(StringComparison.OrdinalIgnoreCase, "ac", "a", "b", "c");
|
||||
yield return WrapResult(StringComparison.OrdinalIgnoreCase, "abc", "a", "b", "b", "c");
|
||||
yield return WrapResult(StringComparison.OrdinalIgnoreCase, "ab", "ab", "c");
|
||||
yield return WrapResult(StringComparison.OrdinalIgnoreCase, "ab", "abb", "c");
|
||||
yield return WrapResult(StringComparison.OrdinalIgnoreCase, "ac", "ac", "c");
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> GetPositiveOrdinalDataSample()
|
||||
{
|
||||
yield return WrapResult(StringComparison.Ordinal, "abc", "a", "c");
|
||||
yield return WrapResult(StringComparison.Ordinal, "abBb123c", "a", "c");
|
||||
yield return WrapResult(StringComparison.Ordinal, "aaac", "a", "c");
|
||||
yield return WrapResult(StringComparison.Ordinal, "Aaac", "A", "c");
|
||||
yield return WrapResult(StringComparison.Ordinal, "acccC", "a", "C");
|
||||
yield return WrapResult(StringComparison.Ordinal, "aacc", "a", "c");
|
||||
yield return WrapResult(StringComparison.Ordinal, "aAcc", "aA", "c");
|
||||
yield return WrapResult(StringComparison.Ordinal, "acc", "ac", "c");
|
||||
yield return WrapResult(StringComparison.Ordinal, "abcDefgh", "ab", "cD", "ef", "gh");
|
||||
yield return WrapResult(StringComparison.Ordinal, "aB123cd321ef123gh", "aB", "cd", "ef", "gh");
|
||||
yield return WrapResult(StringComparison.Ordinal, "abcd321ef123gh", "ab", "cd", "ef", "gh");
|
||||
yield return WrapResult(StringComparison.Ordinal, "ababcdCD321ef123gh", "ab", "cd", "ef", "gh");
|
||||
yield return WrapResult(StringComparison.Ordinal, "ababcdCD321ef123gh", "ab", "CD", "ef", "gh");
|
||||
yield return WrapResult(StringComparison.Ordinal, "ababcd321eF123gh", "ab", "cd", "eF", "gh");
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> GetNegativeOrdinalDataSample()
|
||||
{
|
||||
yield return WrapResult(StringComparison.Ordinal, "aa", "a", "c");
|
||||
yield return WrapResult(StringComparison.Ordinal, "abc", "A", "c");
|
||||
yield return WrapResult(StringComparison.Ordinal, "cc", "a", "c");
|
||||
yield return WrapResult(StringComparison.Ordinal, "ab", "a", "c");
|
||||
yield return WrapResult(StringComparison.Ordinal, "ab", "a", "b", "c");
|
||||
yield return WrapResult(StringComparison.Ordinal, "bc", "a", "b", "c");
|
||||
yield return WrapResult(StringComparison.Ordinal, "ac", "a", "b", "c");
|
||||
yield return WrapResult(StringComparison.Ordinal, "abc", "a", "b", "b", "c");
|
||||
yield return WrapResult(StringComparison.Ordinal, "ab", "ab", "c");
|
||||
yield return WrapResult(StringComparison.Ordinal, "ab", "abb", "c");
|
||||
yield return WrapResult(StringComparison.Ordinal, "ac", "ac", "c");
|
||||
yield return WrapResult(StringComparison.Ordinal, "abBb123C", "a", "c");
|
||||
yield return WrapResult(StringComparison.Ordinal, "Aaac", "a", "c");
|
||||
yield return WrapResult(StringComparison.Ordinal, "aAac", "A", "c");
|
||||
yield return WrapResult(StringComparison.Ordinal, "aCc", "a", "C");
|
||||
yield return WrapResult(StringComparison.Ordinal, "aacc", "aA", "c");
|
||||
yield return WrapResult(StringComparison.Ordinal, "acc", "aC", "c");
|
||||
yield return WrapResult(StringComparison.Ordinal, "abcDefgh", "ab", "cd", "ef", "gh");
|
||||
yield return WrapResult(StringComparison.Ordinal, "aB123cd321ef123gh", "aB", "cd", "EF", "gh");
|
||||
yield return WrapResult(StringComparison.Ordinal, "abcd321ef123gh", "ab", "cd", "efF", "gh");
|
||||
yield return WrapResult(StringComparison.Ordinal, "ababcdCD321ef123gh", "AB", "cd", "ef", "gh");
|
||||
yield return WrapResult(StringComparison.Ordinal, "ababcdCD321ef123gh", "ab", "CD", "EF", "gh");
|
||||
}
|
||||
|
||||
private static object[] WrapResult(StringComparison comparisonType, params string[] values)
|
||||
{
|
||||
if (values == null || values.Length < 3)
|
||||
{
|
||||
throw new InvalidOperationException("At least three values are required to create a data sample");
|
||||
}
|
||||
|
||||
var beginWith = values[1];
|
||||
var endWith = values[values.Length - 1];
|
||||
var contains = values.Skip(2).Take(values.Length - 3);
|
||||
|
||||
return new object[] { values[0], new WildcardPathSegment(beginWith, contains.ToList(), endWith, comparisonType) };
|
||||
}
|
||||
|
||||
private static string Serialize(WildcardPathSegment segment)
|
||||
{
|
||||
return string.Format("{0}:{1}:{2}",
|
||||
segment.BeginsWith,
|
||||
string.Join(",", segment.Contains.ToArray()),
|
||||
segment.EndsWith);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal.Patterns;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Tests.Patterns
|
||||
{
|
||||
public class PatternTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("abc", 1)]
|
||||
[InlineData("/abc", 1)]
|
||||
[InlineData("abc/efg", 2)]
|
||||
[InlineData("abc/efg/h*j", 3)]
|
||||
[InlineData("abc/efg/h*j/*.*", 4)]
|
||||
[InlineData("abc/efg/hij", 3)]
|
||||
[InlineData("abc/efg/hij/klm", 4)]
|
||||
[InlineData("../abc/efg/hij/klm", 5)]
|
||||
[InlineData("../../abc/efg/hij/klm", 6)]
|
||||
public void BuildLinearPattern(string sample, int segmentCount)
|
||||
{
|
||||
var builder = new PatternBuilder();
|
||||
var pattern = builder.Build(sample);
|
||||
|
||||
Assert.True(pattern is ILinearPattern);
|
||||
Assert.Equal(segmentCount, (pattern as ILinearPattern).Segments.Count);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("abc/efg/**")]
|
||||
[InlineData("/abc/efg/**")]
|
||||
[InlineData("abc/efg/**/hij/klm")]
|
||||
[InlineData("abc/efg/**/hij/**/klm")]
|
||||
[InlineData("abc/efg/**/hij/**/klm/**")]
|
||||
[InlineData("abc/efg/**/hij/**/klm/**/")]
|
||||
[InlineData("**/hij/**/klm")]
|
||||
[InlineData("**/hij/**")]
|
||||
[InlineData("/**/hij/**")]
|
||||
[InlineData("**/**/hij/**")]
|
||||
[InlineData("ab/**/**/hij/**")]
|
||||
[InlineData("ab/**/**/hij/**/")]
|
||||
[InlineData("/ab/**/**/hij/**/")]
|
||||
[InlineData("/ab/**/**/hij/**")]
|
||||
public void BuildLinearPatternNegative(string sample)
|
||||
{
|
||||
var builder = new PatternBuilder();
|
||||
var pattern = builder.Build(sample) as ILinearPattern;
|
||||
|
||||
Assert.Null(pattern);
|
||||
}
|
||||
|
||||
|
||||
[Theory]
|
||||
[InlineData("/abc/", 2, 1, 0, 0)]
|
||||
[InlineData("abc/", 2, 1, 0, 0)]
|
||||
[InlineData("abc/efg/", 3, 2, 0, 0)]
|
||||
[InlineData("abc/efg/h*j/*.*/", 5, 4, 0, 0)]
|
||||
[InlineData("abc/efg/**", 3, 2, 0, 0)]
|
||||
[InlineData("/abc/efg/**", 3, 2, 0, 0)]
|
||||
[InlineData("abc/efg/**/hij/klm", 5, 2, 0, 2)]
|
||||
[InlineData("abc/efg/**/hij/**/klm", 6, 2, 1, 1)]
|
||||
[InlineData("abc/efg/**/hij/**/klm/**", 7, 2, 2, 0)]
|
||||
[InlineData("abc/efg/**/hij/**/klm/**/", 8, 2, 2, 0)]
|
||||
[InlineData("**/hij/**/klm", 4, 0, 1, 1)]
|
||||
[InlineData("**/hij/**", 3, 0, 1, 0)]
|
||||
[InlineData("/**/hij/**", 3, 0, 1, 0)]
|
||||
[InlineData("**/**/hij/**", 4, 0, 1, 0)]
|
||||
[InlineData("ab/**/**/hij/**", 5, 1, 1, 0)]
|
||||
[InlineData("ab/**/**/hij/**/", 6, 1, 1, 0)]
|
||||
[InlineData("/ab/**/**/hij/**/", 6, 1, 1, 0)]
|
||||
[InlineData("/ab/**/**/hij/**", 5, 1, 1, 0)]
|
||||
[InlineData("**/*.suffix", 2, 0, 0, 1)]
|
||||
[InlineData("**.suffix", 2, 0, 0, 1)]
|
||||
[InlineData("ab/**.suffix", 3, 1, 0, 1)]
|
||||
public void BuildRaggedPattern(string sample,
|
||||
int segmentCount,
|
||||
int startSegmentsCount,
|
||||
int containSegmentCount,
|
||||
int endSegmentCount)
|
||||
{
|
||||
var builder = new PatternBuilder();
|
||||
var pattern = builder.Build(sample) as IRaggedPattern;
|
||||
|
||||
Assert.NotNull(pattern);
|
||||
Assert.Equal(segmentCount, pattern.Segments.Count);
|
||||
Assert.Equal(startSegmentsCount, pattern.StartsWith.Count);
|
||||
Assert.Equal(endSegmentCount, pattern.EndsWith.Count);
|
||||
Assert.Equal(containSegmentCount, pattern.Contains.Count);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("abc")]
|
||||
[InlineData("/abc")]
|
||||
[InlineData("abc/efg")]
|
||||
[InlineData("abc/efg/h*j")]
|
||||
[InlineData("abc/efg/h*j/*.*")]
|
||||
[InlineData("abc/efg/hij")]
|
||||
[InlineData("abc/efg/hij/klm")]
|
||||
public void BuildRaggedPatternNegative(string sample)
|
||||
{
|
||||
var builder = new PatternBuilder();
|
||||
var pattern = builder.Build(sample) as IRaggedPattern;
|
||||
|
||||
Assert.Null(pattern);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("a/../")]
|
||||
[InlineData("a/..")]
|
||||
[InlineData("/a/../")]
|
||||
[InlineData("./a/../")]
|
||||
[InlineData("**/../")]
|
||||
[InlineData("*.cs/../")]
|
||||
public void ThrowExceptionForInvalidParentsPath(string sample)
|
||||
{
|
||||
// parent segment is only allowed at the beginning of the pattern
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
{
|
||||
var builder = new PatternBuilder();
|
||||
var pattern = builder.Build(sample);
|
||||
|
||||
Assert.Null(pattern);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ThrowExceptionForNull()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() =>
|
||||
{
|
||||
var builder = new PatternBuilder();
|
||||
builder.Build(null);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Tests.TestUtility
|
||||
{
|
||||
public class DisposableFileSystem : IDisposable
|
||||
{
|
||||
public DisposableFileSystem()
|
||||
{
|
||||
RootPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
|
||||
Directory.CreateDirectory(RootPath);
|
||||
DirectoryInfo = new DirectoryInfo(RootPath);
|
||||
}
|
||||
|
||||
public string RootPath { get; }
|
||||
|
||||
public DirectoryInfo DirectoryInfo { get; }
|
||||
|
||||
public DisposableFileSystem CreateFolder(string path)
|
||||
{
|
||||
Directory.CreateDirectory(Path.Combine(RootPath, path));
|
||||
return this;
|
||||
}
|
||||
|
||||
public DisposableFileSystem CreateFile(string path)
|
||||
{
|
||||
File.WriteAllText(Path.Combine(RootPath, path), "temp");
|
||||
return this;
|
||||
}
|
||||
|
||||
public DisposableFileSystem CreateFiles(params string[] fileRelativePaths)
|
||||
{
|
||||
foreach (var path in fileRelativePaths)
|
||||
{
|
||||
var fullPath = Path.Combine(RootPath, path);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
|
||||
|
||||
File.WriteAllText(
|
||||
fullPath,
|
||||
string.Format("Automatically generated for testing on {0:yyyy}/{0:MM}/{0:dd} {0:hh}:{0:mm}:{0:ss}", DateTime.UtcNow));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.Delete(RootPath, true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Don't throw if this fails.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Linq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Tests.TestUtility
|
||||
{
|
||||
internal class FileSystemGlobbingTestContext
|
||||
{
|
||||
private readonly string _basePath;
|
||||
private readonly FileSystemOperationRecorder _recorder;
|
||||
private readonly Matcher _patternMatching;
|
||||
|
||||
private MockDirectoryInfo _directoryInfo;
|
||||
|
||||
public PatternMatchingResult Result { get; private set; }
|
||||
|
||||
public FileSystemGlobbingTestContext(string basePath, Matcher matcher)
|
||||
{
|
||||
_basePath = basePath;
|
||||
_recorder = new FileSystemOperationRecorder();
|
||||
_patternMatching = matcher;
|
||||
|
||||
_directoryInfo = new MockDirectoryInfo(
|
||||
recorder: _recorder,
|
||||
parentDirectory: null,
|
||||
fullName: _basePath,
|
||||
name: ".",
|
||||
paths: new string[0]);
|
||||
}
|
||||
|
||||
public FileSystemGlobbingTestContext Include(params string[] patterns)
|
||||
{
|
||||
foreach (var pattern in patterns)
|
||||
{
|
||||
_patternMatching.AddInclude(pattern);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public FileSystemGlobbingTestContext Exclude(params string[] patterns)
|
||||
{
|
||||
foreach (var pattern in patterns)
|
||||
{
|
||||
_patternMatching.AddExclude(pattern);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public FileSystemGlobbingTestContext Files(params string[] files)
|
||||
{
|
||||
_directoryInfo = new MockDirectoryInfo(
|
||||
_directoryInfo.Recorder,
|
||||
_directoryInfo.ParentDirectory,
|
||||
_directoryInfo.FullName,
|
||||
_directoryInfo.Name,
|
||||
_directoryInfo.Paths.Concat(files.Select(file => _basePath + file)).ToArray());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public FileSystemGlobbingTestContext Execute()
|
||||
{
|
||||
Result = _patternMatching.Execute(_directoryInfo);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public FileSystemGlobbingTestContext AssertExact(params string[] files)
|
||||
{
|
||||
Assert.Equal(files.OrderBy(file => file), Result.Files.OrderBy(file => file.Path).Select(file => file.Path));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public FileSystemGlobbingTestContext SubDirectory(string name)
|
||||
{
|
||||
_directoryInfo = (MockDirectoryInfo)_directoryInfo.GetDirectory(name);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Tests.TestUtility
|
||||
{
|
||||
internal class FileSystemOperationRecorder
|
||||
{
|
||||
public IList<IDictionary<string, object>> Records = new List<IDictionary<string, object>>();
|
||||
|
||||
public void Add(string action, object values)
|
||||
{
|
||||
var record = new Dictionary<string, object>
|
||||
{
|
||||
{"action", action }
|
||||
};
|
||||
|
||||
foreach (var p in values.GetType().GetTypeInfo().DeclaredProperties)
|
||||
{
|
||||
record[p.Name] = p.GetValue(values);
|
||||
}
|
||||
|
||||
Records.Add(record);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Abstractions;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Tests.TestUtility
|
||||
{
|
||||
internal class MockDirectoryInfo : DirectoryInfoBase
|
||||
{
|
||||
public MockDirectoryInfo(
|
||||
FileSystemOperationRecorder recorder,
|
||||
DirectoryInfoBase parentDirectory,
|
||||
string fullName,
|
||||
string name,
|
||||
string[] paths)
|
||||
{
|
||||
ParentDirectory = parentDirectory;
|
||||
Recorder = recorder;
|
||||
FullName = fullName;
|
||||
Name = name;
|
||||
Paths = paths;
|
||||
}
|
||||
|
||||
public FileSystemOperationRecorder Recorder { get; }
|
||||
|
||||
public override string FullName { get; }
|
||||
|
||||
public override string Name { get; }
|
||||
|
||||
public override DirectoryInfoBase ParentDirectory { get; }
|
||||
|
||||
public string[] Paths { get; }
|
||||
|
||||
public override IEnumerable<FileSystemInfoBase> EnumerateFileSystemInfos()
|
||||
{
|
||||
Recorder.Add("EnumerateFileSystemInfos", new { FullName, Name });
|
||||
|
||||
var names = new HashSet<string>();
|
||||
|
||||
foreach (var path in Paths)
|
||||
{
|
||||
if (!path.Replace('\\', '/').StartsWith(FullName.Replace('\\', '/')))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var beginPath = FullName.Length;
|
||||
var endPath = path.Length;
|
||||
|
||||
var beginSegment = beginPath;
|
||||
var endSegment = NextIndex(path, new[] { '/', '\\' }, beginSegment, path.Length);
|
||||
|
||||
if (endPath == endSegment)
|
||||
{
|
||||
yield return new MockFileInfo(
|
||||
recorder: Recorder,
|
||||
parentDirectory: this,
|
||||
fullName: path,
|
||||
name: path.Substring(beginSegment, endSegment - beginSegment));
|
||||
}
|
||||
else
|
||||
{
|
||||
var name = path.Substring(beginSegment, endSegment - beginSegment);
|
||||
if (!names.Contains(name))
|
||||
{
|
||||
names.Add(name);
|
||||
yield return new MockDirectoryInfo(
|
||||
recorder: Recorder,
|
||||
parentDirectory: this,
|
||||
fullName: path.Substring(0, endSegment + 1),
|
||||
name: name,
|
||||
paths: Paths);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int NextIndex(string pattern, char[] anyOf, int startIndex, int endIndex)
|
||||
{
|
||||
var index = pattern.IndexOfAny(anyOf, startIndex, endIndex - startIndex);
|
||||
return index == -1 ? endIndex : index;
|
||||
}
|
||||
|
||||
public override DirectoryInfoBase GetDirectory(string name)
|
||||
{
|
||||
if (string.Equals(name, "..", StringComparison.Ordinal))
|
||||
{
|
||||
var indexOfPenultimateSlash = FullName.LastIndexOf('\\', FullName.Length - 2);
|
||||
var fullName = FullName.Substring(0, indexOfPenultimateSlash + 1);
|
||||
return new MockDirectoryInfo(
|
||||
recorder: Recorder,
|
||||
parentDirectory: this,
|
||||
fullName: FullName.Substring(0, indexOfPenultimateSlash + 1),
|
||||
name: name,
|
||||
paths: Paths);
|
||||
}
|
||||
return new MockDirectoryInfo(
|
||||
recorder: Recorder,
|
||||
parentDirectory: this,
|
||||
fullName: FullName + name + "\\",
|
||||
name: name,
|
||||
paths: Paths);
|
||||
}
|
||||
|
||||
public override FileInfoBase GetFile(string name)
|
||||
{
|
||||
return new MockFileInfo(
|
||||
recorder: Recorder,
|
||||
parentDirectory: this,
|
||||
fullName: FullName + name,
|
||||
name: name);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Abstractions;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Tests.TestUtility
|
||||
{
|
||||
internal class MockFileInfo : FileInfoBase
|
||||
{
|
||||
public MockFileInfo(
|
||||
FileSystemOperationRecorder recorder,
|
||||
DirectoryInfoBase parentDirectory,
|
||||
string fullName,
|
||||
string name)
|
||||
{
|
||||
Recorder = recorder;
|
||||
FullName = fullName;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public FileSystemOperationRecorder Recorder { get; }
|
||||
|
||||
public override DirectoryInfoBase ParentDirectory { get; }
|
||||
|
||||
public override string FullName { get; }
|
||||
|
||||
public override string Name { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Tests.PatternContexts
|
||||
{
|
||||
internal class MockLinearPatternBuilder
|
||||
{
|
||||
private List<IPathSegment> _segments;
|
||||
|
||||
public static MockLinearPatternBuilder New()
|
||||
{
|
||||
return new MockLinearPatternBuilder();
|
||||
}
|
||||
|
||||
private MockLinearPatternBuilder()
|
||||
{
|
||||
_segments = new List<IPathSegment>();
|
||||
}
|
||||
|
||||
public MockLinearPatternBuilder Add(string value)
|
||||
{
|
||||
_segments.Add(new MockNonRecursivePathSegment(value));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public MockLinearPatternBuilder Add(string[] values)
|
||||
{
|
||||
_segments.AddRange(values.Select(v => new MockNonRecursivePathSegment(v)));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ILinearPattern Build()
|
||||
{
|
||||
return new MockLinearPattern(_segments);
|
||||
}
|
||||
|
||||
class MockLinearPattern : ILinearPattern
|
||||
{
|
||||
public MockLinearPattern(List<IPathSegment> segments)
|
||||
{
|
||||
Segments = segments;
|
||||
}
|
||||
|
||||
public IList<IPathSegment> Segments { get; }
|
||||
|
||||
public IPatternContext CreatePatternContextForExclude()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IPatternContext CreatePatternContextForInclude()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Tests.PatternContexts
|
||||
{
|
||||
internal class MockNonRecursivePathSegment : IPathSegment
|
||||
{
|
||||
private readonly StringComparison _comparisonType;
|
||||
|
||||
public MockNonRecursivePathSegment(StringComparison comparisonType)
|
||||
{
|
||||
_comparisonType = comparisonType;
|
||||
}
|
||||
|
||||
public MockNonRecursivePathSegment(string value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public bool CanProduceStem { get { return false; } }
|
||||
|
||||
public string Value { get; }
|
||||
|
||||
public bool Match(string value)
|
||||
{
|
||||
return string.Compare(Value, value, _comparisonType) == 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Tests.PatternContexts
|
||||
{
|
||||
internal class MockRaggedPatternBuilder
|
||||
{
|
||||
private MockRaggedPattern _result;
|
||||
|
||||
public static MockRaggedPatternBuilder New()
|
||||
{
|
||||
return new MockRaggedPatternBuilder();
|
||||
}
|
||||
|
||||
private MockRaggedPatternBuilder()
|
||||
{
|
||||
_result = new MockRaggedPattern();
|
||||
}
|
||||
|
||||
public MockRaggedPatternBuilder AddStart(params string[] values)
|
||||
{
|
||||
foreach (var value in values)
|
||||
{
|
||||
var segment = new MockNonRecursivePathSegment(value);
|
||||
_result.StartsWith.Add(segment);
|
||||
_result.Segments.Add(segment);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public MockRaggedPatternBuilder AddContainsGroup(params string[] values)
|
||||
{
|
||||
var last = _result.Segments.Last();
|
||||
|
||||
if (!(last is MockRecursivePathSegment))
|
||||
{
|
||||
AddRecursive();
|
||||
}
|
||||
|
||||
var containSegment = new List<IPathSegment>();
|
||||
foreach (var value in values)
|
||||
{
|
||||
var segment = new MockNonRecursivePathSegment(value);
|
||||
containSegment.Add(segment);
|
||||
_result.Segments.Add(segment);
|
||||
}
|
||||
|
||||
_result.Contains.Add(containSegment);
|
||||
|
||||
AddRecursive();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public MockRaggedPatternBuilder AddEnd(params string[] values)
|
||||
{
|
||||
foreach (var value in values)
|
||||
{
|
||||
_result.EndsWith.Add(new MockNonRecursivePathSegment(value));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public MockRaggedPatternBuilder AddRecursive()
|
||||
{
|
||||
_result.Segments.Add(new MockRecursivePathSegment());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public IRaggedPattern Build()
|
||||
{
|
||||
return _result;
|
||||
}
|
||||
|
||||
class MockRaggedPattern : IRaggedPattern
|
||||
{
|
||||
public IList<IPathSegment> Segments { get; } = new List<IPathSegment>();
|
||||
|
||||
public IList<IPathSegment> StartsWith { get; } = new List<IPathSegment>();
|
||||
|
||||
public IList<IList<IPathSegment>> Contains { get; } = new List<IList<IPathSegment>>();
|
||||
|
||||
public IList<IPathSegment> EndsWith { get; } = new List<IPathSegment>();
|
||||
|
||||
public IPatternContext CreatePatternContextForExclude()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IPatternContext CreatePatternContextForInclude()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Tests.PatternContexts
|
||||
{
|
||||
internal class MockRecursivePathSegment : IPathSegment
|
||||
{
|
||||
public bool CanProduceStem { get { return false; } }
|
||||
|
||||
public bool Match(string value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Internal;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.FileSystemGlobbing.Tests.TestUtility
|
||||
{
|
||||
internal static class PatternContextHelper
|
||||
{
|
||||
public static void PushDirectory(IPatternContext context, params string[] directoryNames)
|
||||
{
|
||||
foreach (var each in directoryNames)
|
||||
{
|
||||
var directory = new MockDirectoryInfo(null, null, string.Empty, each, null);
|
||||
context.PushDirectory(directory);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
|
Loading…
Add table
Reference in a new issue