Skip to content

Commit d203c3d

Browse files
committed
Fixes #13
**/ is now tokenised as a single token, rather than two tokens (a directory wildcard and a path seperator). This addresses an issue where /**/somefile.txt would tokenise into having 2 path seperator tokens, so wouldnt match against a string with only one like /somefile.txt.
1 parent e171c4e commit d203c3d

12 files changed

+87
-18
lines changed

src/DotNet.Glob.Benchmarks/Utils/GlobToRegexFormatter.cs

+4
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ public string Format(IEnumerable<IGlobToken> tokens)
3535
public void Visit(WildcardDirectoryToken wildcardDirectoryToken)
3636
{
3737
_stringBuilder.Append(".*");
38+
if(wildcardDirectoryToken.TrailingPathSeperator != null)
39+
{
40+
_stringBuilder.Append(@"[/\\]");
41+
}
3842
}
3943

4044
void IGlobTokenVisitor.Visit(CharacterListToken token)

src/DotNet.Glob.Tests/FormatterTests.cs

+1-2
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@ public void Can_Format_Glob_Pattern()
2323
new WildcardToken(),
2424
new CharacterListToken(new char[] { 'a', 'b', 'c' }, false),
2525
new PathSeperatorToken('/'),
26-
new WildcardDirectoryToken(),
27-
new PathSeperatorToken('/'),
26+
new WildcardDirectoryToken('/'),
2827
new NumberRangeToken('1', '3', true),
2928
new LiteralToken(".txt"));
3029

src/DotNet.Glob.Tests/GlobBuilderTests.cs

+6-8
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public void Can_Build_Glob_Pattern()
1414
{
1515
//
1616
// build the following glob pattern using glob builder:
17-
// /foo?\\*[abc][!1-3].txt
17+
// /foo?\\*[abc][!1-3]/**/*.txt
1818
var tokens = new GlobBuilder()
1919
.PathSeperator()
2020
.Literal("foo")
@@ -24,13 +24,12 @@ public void Can_Build_Glob_Pattern()
2424
.OneOf('a', 'b', 'c')
2525
.NumberNotInRange('1', '3')
2626
.PathSeperator()
27-
.DirectoryWildcard()
28-
.PathSeperator()
27+
.DirectoryWildcard(PathSeperatorKind.ForwardSlash)
2928
.Wildcard()
3029
.Literal(".txt")
3130
.Tokens;
3231

33-
Assert.Equal(12, tokens.Count);
32+
Assert.Equal(11, tokens.Count);
3433
Assert.True(tokens[0] is PathSeperatorToken);
3534
Assert.True(tokens[1] is LiteralToken);
3635
Assert.True(tokens[2] is AnyCharacterToken);
@@ -39,10 +38,9 @@ public void Can_Build_Glob_Pattern()
3938
Assert.True(tokens[5] is CharacterListToken);
4039
Assert.True(tokens[6] is NumberRangeToken);
4140
Assert.True(tokens[7] is PathSeperatorToken);
42-
Assert.True(tokens[8] is WildcardDirectoryToken);
43-
Assert.True(tokens[9] is PathSeperatorToken);
44-
Assert.True(tokens[10] is WildcardToken);
45-
Assert.True(tokens[11] is LiteralToken);
41+
Assert.True(tokens[8] is WildcardDirectoryToken);
42+
Assert.True(tokens[9] is WildcardToken);
43+
Assert.True(tokens[10] is LiteralToken);
4644
}
4745

4846
}

src/DotNet.Glob.Tests/GlobTests.cs

+13-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public class GlobTests
1919
[InlineData("literal", "fliteral", "foo/literal", "literals", "literals/foo")]
2020
[InlineData("path/hats*nd", "path/hatsblahn", "path/hatsblahndt")]
2121
[InlineData("path/?atstand", "path/moatstand", "path/batstands")]
22+
[InlineData("/**/file.csv", "/file.txt")]
2223
public void Does_Not_Match(string pattern, params string[] testStrings)
2324
{
2425
var glob = Glob.Parse(pattern);
@@ -45,6 +46,10 @@ public void Does_Not_Match(string pattern, params string[] testStrings)
4546
[InlineData("p?th/*a[bcd]b[e-g]a[1-4][!wxyz][!a-c][!1-3].*", "pAth/fooooacbfa2vd4.txt")]
4647
[InlineData("path/**/somefile.txt", "path/foo/bar/baz/somefile.txt")]
4748
[InlineData("p?th/*a[bcd]b[e-g]a[1-4][!wxyz][!a-c][!1-3].*", "pGth/yGKNY6acbea3rm8.")]
49+
[InlineData("/**/file.*", "/folder/file.csv")]
50+
[InlineData("/**/file.*","/file.txt")]
51+
[InlineData("/**/file.*", "/file.txt")]
52+
[InlineData("**/file.*", "/file.txt")]
4853
public void Can_IsMatch(string pattern, params string[] testStrings)
4954
{
5055
var glob = Glob.Parse(pattern);
@@ -61,7 +66,7 @@ public void Can_IsMatch(string pattern, params string[] testStrings)
6166
[Fact]
6267
public void To_String_Returns_Pattern()
6368
{
64-
var pattern = "p?th/*a[bcd]b[e-g]a[1-4][!wxyz][!a-c][!1-3].*";
69+
var pattern = "p?th/*a[bcd]b[e-g]/**/a[1-4][!wxyz][!a-c][!1-3].*";
6570
var glob = Glob.Parse(pattern);
6671
var resultPattern = glob.ToString();
6772
Assert.Equal(pattern, resultPattern);
@@ -72,6 +77,7 @@ public void To_String_Returns_Pattern()
7277
/// <summary>
7378
/// Tests for the InMemoryDirectory sub system.
7479
/// </summary>
80+
/// <Remarks>These tests are for another library that I am using to compare againts.</Remarks>
7581
[Theory]
7682
[InlineData("literal", "literal")]
7783
[InlineData("a/literal", "a/literal")]
@@ -85,8 +91,14 @@ public void To_String_Returns_Pattern()
8591
[InlineData("p?th/*a[bcd]b[e-g]a[1-4][!wxyz][!a-c][!1-3].*", "pAth/fooooacbfa2vd4.txt")]
8692
[InlineData("path/**/somefile.txt", "path/foo/bar/baz/somefile.txt")]
8793
[InlineData("p?th/*a[bcd]b[e-g]a[1-4][!wxyz][!a-c][!1-3].*", "pGth/yGKNY6acbea3rm8.")]
94+
[InlineData("/**/file.*", "/folder/file.csv")]
95+
//[InlineData("/**/file.*", "/file.txt")]
96+
//[InlineData("**/file.*", "/file.txt")]
97+
//[InlineData("/**/file.*", "/file.txt")]
8898
public void Glob_IsMatch(string pattern, params string[] testStrings)
8999
{
100+
// This is a different glob library, I am seeing if it matches the same patterns as my library.
101+
// The three tests above commented out show it currently has some limitations, that this library doesn't.
90102
var glob = new global::Glob.Glob(pattern);
91103
foreach (var testString in testStrings)
92104
{

src/DotNet.Glob.Tests/TokeniserTests.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public class TokeniserTests
2020
typeof(NumberRangeToken), typeof(CharacterListToken), typeof(LetterRangeToken),
2121
typeof(NumberRangeToken), typeof(LiteralToken),
2222
typeof(WildcardToken))]
23-
[InlineData("path/**/*.*", typeof(LiteralToken), typeof(PathSeperatorToken), typeof(WildcardDirectoryToken), typeof(PathSeperatorToken), typeof(WildcardToken), typeof(LiteralToken), typeof(WildcardToken))]
23+
[InlineData("path/**/*.*", typeof(LiteralToken), typeof(PathSeperatorToken), typeof(WildcardDirectoryToken), typeof(WildcardToken), typeof(LiteralToken), typeof(WildcardToken))]
2424
public void Can_Tokenise_Glob_Pattern(string testString, params Type[] expectedTokens)
2525
{
2626
// Arrange

src/DotNet.Glob/Evaluation/WildcardDirectoryTokenEvaluator.cs

+8
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ public bool IsMatch(string allChars, int currentPosition, out int newPosition)
2727
{
2828
// The remaining tokens match against a fixed length string, so wildcard **must** consume
2929
// a known amount of characters in order for this to have a chance of successful match.
30+
// but can't consume past current position!
31+
// var matchLength = (allChars.Length - _subEvaluator.ConsumesMinLength);
32+
//if(matchLength < currentPosition)
33+
//{
34+
// return false;
35+
//}
36+
//var isMatch = _subEvaluator.IsMatch(allChars, matchLength, out newPosition);
37+
//return isMatch;
3038
var isMatch = _subEvaluator.IsMatch(allChars, (allChars.Length - _subEvaluator.ConsumesMinLength), out newPosition);
3139
return isMatch;
3240
}

src/DotNet.Glob/Evaluation/WildcardTokenEvaluator.cs

+8
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ public bool IsMatch(string allChars, int currentPosition, out int newPosition)
2626
{
2727
// The remaining tokens match against a fixed length string, so wildcard **must** consume
2828
// a known amount of characters in order for this to have a chance of successful match.
29+
// but can't consume past / behind current position!
30+
//var matchLength = (allChars.Length - _subEvaluator.ConsumesMinLength);
31+
//if (matchLength < currentPosition)
32+
//{
33+
// return false;
34+
//}
35+
//var isMatch = _subEvaluator.IsMatch(allChars, matchLength, out newPosition);
36+
//return isMatch;
2937
var isMatch = _subEvaluator.IsMatch(allChars, (allChars.Length - _subEvaluator.ConsumesMinLength), out newPosition);
3038
return isMatch;
3139
}

src/DotNet.Glob/Formatting/GlobTokenFormatter.cs

+4
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ public string Format(IEnumerable<IGlobToken> tokens)
2929
public void Visit(WildcardDirectoryToken wildcardDirectoryToken)
3030
{
3131
_stringBuilder.Append("**");
32+
if(wildcardDirectoryToken.TrailingPathSeperator != null)
33+
{
34+
_stringBuilder.Append(wildcardDirectoryToken.TrailingPathSeperator);
35+
}
3236
}
3337

3438
void IGlobTokenVisitor.Visit(CharacterListToken token)

src/DotNet.Glob/GlobBuilder.cs

+21-2
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,28 @@ public IGlobBuilder Wildcard()
6363
return this;
6464
}
6565

66-
public IGlobBuilder DirectoryWildcard()
66+
public IGlobBuilder DirectoryWildcard(PathSeperatorKind? trailingSeperatorKind = PathSeperatorKind.ForwardSlash)
6767
{
68-
_tokens.Add(new WildcardDirectoryToken());
68+
if (trailingSeperatorKind == null)
69+
{
70+
_tokens.Add(new WildcardDirectoryToken(null));
71+
}
72+
else
73+
{
74+
switch (trailingSeperatorKind)
75+
{
76+
case PathSeperatorKind.BackwardSlash:
77+
_tokens.Add(new WildcardDirectoryToken('\\'));
78+
break;
79+
case PathSeperatorKind.ForwardSlash:
80+
_tokens.Add(new WildcardDirectoryToken('/'));
81+
break;
82+
default:
83+
break;
84+
}
85+
}
86+
87+
6988
return this;
7089
}
7190

src/DotNet.Glob/GlobTokeniser.cs

+11-3
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public GlobTokeniser()
1818
public IList<IGlobToken> Tokenise(string globText)
1919
{
2020
var tokens = new List<IGlobToken>();
21-
21+
string starstartpeak;
2222
using (var reader = new GlobStringReader(globText))
2323
{
2424
while (reader.ReadChar())
@@ -34,7 +34,7 @@ public IList<IGlobToken> Tokenise(string globText)
3434
else if (reader.IsWildcardCharacterMatch)
3535
{
3636
tokens.Add(ReadWildcardToken());
37-
}
37+
}
3838
else if (reader.IsPathSeperator())
3939
{
4040
tokens.Add(ReadPathSeperatorToken(reader));
@@ -60,7 +60,15 @@ public IList<IGlobToken> Tokenise(string globText)
6060
private IGlobToken ReadDirectoryWildcardToken(GlobStringReader reader)
6161
{
6262
reader.ReadChar();
63-
return new WildcardDirectoryToken();
63+
64+
if (GlobStringReader.IsPathSeperator(reader.PeekChar()))
65+
{
66+
reader.ReadChar();
67+
return new WildcardDirectoryToken(reader.CurrentChar);
68+
}
69+
70+
return new WildcardDirectoryToken(null); // this shouldn't happen unless a pattern ends with ** which is weird. **sometext is not legal.
71+
6472
}
6573

6674
private IGlobToken ReadLiteralToken(GlobStringReader reader)

src/DotNet.Glob/IGlobBuilder.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ public interface IGlobBuilder
99
IGlobBuilder Literal(string text);
1010
IGlobBuilder AnyCharacter();
1111
IGlobBuilder Wildcard();
12-
IGlobBuilder DirectoryWildcard();
12+
IGlobBuilder DirectoryWildcard(PathSeperatorKind? trailingSeperatorKind = PathSeperatorKind.ForwardSlash);
1313
IGlobBuilder OneOf(params char[] characters);
1414
IGlobBuilder NotOneOf(params char[] characters);
1515
IGlobBuilder LetterInRange(char start, char end);

src/DotNet.Glob/Token/WildcardDirectoryToken.cs

+9
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22
{
33
public class WildcardDirectoryToken : IGlobToken
44
{
5+
6+
public WildcardDirectoryToken(char? trailingPathSeperator)
7+
{
8+
TrailingPathSeperator = trailingPathSeperator;
9+
}
10+
11+
//public PathSeperatorKind? TrailingPathSeperatorKind { get; set; }
12+
public char? TrailingPathSeperator { get; set; }
13+
514
public void Accept(IGlobTokenVisitor Visitor)
615
{
716
Visitor.Visit(this);

0 commit comments

Comments
 (0)