Skip to content

Commit

Permalink
Added more unit tests for string IndexOf in LINQ queries and fixed a …
Browse files Browse the repository at this point in the history
…couple edge cases.
  • Loading branch information
rstam committed Apr 11, 2012
1 parent 0ed1649 commit 3c814ca
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 12 deletions.
47 changes: 35 additions & 12 deletions Driver/Linq/Translators/SelectQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,12 @@ private IMongoQuery BuildQuery(Expression expression)

private IMongoQuery BuildStringIndexOfQuery(Expression variableExpression, ExpressionType operatorType, ConstantExpression constantExpression)
{
// TODO: support other comparison operators
if (operatorType != ExpressionType.Equal)
{
return null;
}

if (constantExpression.Type != typeof(int))
{
return null;
Expand Down Expand Up @@ -803,51 +809,68 @@ private IMongoQuery BuildStringIndexOfQuery(Expression variableExpression, Expre
string pattern = null;
if (value.GetType() == typeof(char))
{
var c = Regex.Escape(((char)value).ToString());
var escapedChar = Regex.Escape(((char)value).ToString());
if (startIndex == -1)
{
// the regex for: IndexOf(c) == index
// is: /^[^c]{index}c/
pattern = string.Format("^[^{0}]{{{1}}}{0}", c, index);
pattern = string.Format("^[^{0}]{{{1}}}{0}", escapedChar, index);
}
else
{
if (count == -1)
{
// the regex for: IndexOf(c, startIndex) == index
// is: /^.{startIndex}[^c]{index - startIndex}c/
pattern = string.Format("^.{{{1}}}[^{0}]{{{2}}}{0}", c, startIndex, index - startIndex);
pattern = string.Format("^.{{{1}}}[^{0}]{{{2}}}{0}", escapedChar, startIndex, index - startIndex);
}
else
{
// the regex for: IndexOf(c, startIndex, count) == index
// is: /^.{startIndex}(?=.{count})[^c]{index - startIndex}c/
pattern = string.Format("^.{{{1}}}(?=.{{{2}}})[^{0}]{{{3}}}{0}", c, startIndex, count, index - startIndex);
if (index >= startIndex + count)
{
// index is outside of the substring so no match is possible
return Query.Exists("_id", false); // matches no documents
}
else
{
// the regex for: IndexOf(c, startIndex, count) == index
// is: /^.{startIndex}(?=.{count})[^c]{index - startIndex}c/
pattern = string.Format("^.{{{1}}}(?=.{{{2}}})[^{0}]{{{3}}}{0}", escapedChar, startIndex, count, index - startIndex);
}
}
}
}
else if (value.GetType() == typeof(string))
{
var s = Regex.Escape((string)value);
var escapedString = Regex.Escape((string)value);
if (startIndex == -1)
{
// the regex for: IndexOf(s) == index
// is: /^(?!.{0,index - 1}s).{index}s/
pattern = string.Format("^(?!.{{0,{2}}}{0}).{{{1}}}{0}", s, index, index - 1);
pattern = string.Format("^(?!.{{0,{2}}}{0}).{{{1}}}{0}", escapedString, index, index - 1);
}
else
{
if (count == -1)
{
// the regex for: IndexOf(s, startIndex) == index
// is: /^.{startIndex}(?!.{0, index - startIndex - 1}s).{index - startIndex}s/
pattern = string.Format("^.{{{1}}}(?!.{{0,{2}}}{0}).{{{3}}}{0}", s, startIndex, index - startIndex - 1, index - startIndex);
pattern = string.Format("^.{{{1}}}(?!.{{0,{2}}}{0}).{{{3}}}{0}", escapedString, startIndex, index - startIndex - 1, index - startIndex);
}
else
{
// the regex for: IndexOf(s, startIndex, count) == index
// is: /^.{startIndex}(?=.{count})(?!.{0,index - startIndex - 1}s).{index - startIndex)s/
pattern = string.Format("^.{{{1}}}(?=.{{{2}}})(?!.{{0,{3}}}{0}).{{{4}}}{0}", s, startIndex, count, index - startIndex - 1, index - startIndex);
var unescapedLength = ((string)value).Length;
if (unescapedLength > startIndex + count - index)
{
// substring isn't long enough to match
return Query.Exists("_id", false); // matches no documents
}
else
{
// the regex for: IndexOf(s, startIndex, count) == index
// is: /^.{startIndex}(?=.{count})(?!.{0,index - startIndex - 1}s).{index - startIndex)s/
pattern = string.Format("^.{{{1}}}(?=.{{{2}}})(?!.{{0,{3}}}{0}).{{{4}}}{0}", escapedString, startIndex, count, index - startIndex - 1, index - startIndex);
}
}
}
}
Expand Down
75 changes: 75 additions & 0 deletions DriverUnitTests/Linq/SelectQueryTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4351,6 +4351,44 @@ public void TestWhereSEndsWithAbcNot()
Assert.AreEqual(4, Consume(query));
}

[Test]
public void TestWhereSIndexOfB()
{
var collection = _database.GetCollection("temp");
collection.Drop();
collection.Insert(new C { S = "bxxx" });
collection.Insert(new C { S = "xbxx" });
collection.Insert(new C { S = "xxbx" });
collection.Insert(new C { S = "xxxb" });
collection.Insert(new C { S = "bxbx" });
collection.Insert(new C { S = "xbbx" });
collection.Insert(new C { S = "xxbb" });

var query1 =
from c in collection.AsQueryable<C>()
where c.S.IndexOf('b') == 2
select c;
Assert.AreEqual(2, Consume(query1));

var query2 =
from c in collection.AsQueryable<C>()
where c.S.IndexOf('b', 1) == 2
select c;
Assert.AreEqual(3, Consume(query2));

var query3 =
from c in collection.AsQueryable<C>()
where c.S.IndexOf('b', 1, 1) == 2
select c;
Assert.AreEqual(0, Consume(query3));

var query4 =
from c in collection.AsQueryable<C>()
where c.S.IndexOf('b', 1, 2) == 2
select c;
Assert.AreEqual(3, Consume(query4));
}

[Test]
public void TestWhereSIndexOfBEquals1()
{
Expand Down Expand Up @@ -4420,6 +4458,43 @@ where c.S.IndexOf('b', 1, 2) == 1
Assert.AreEqual(1, Consume(query));
}

[Test]
public void TestWhereSIndexOfXyz()
{
var collection = _database.GetCollection("temp");
collection.Drop();
collection.Insert(new C { S = "xyzaaa" });
collection.Insert(new C { S = "axyzaa" });
collection.Insert(new C { S = "aaxyza" });
collection.Insert(new C { S = "aaaxyz" });
collection.Insert(new C { S = "aaaaxy" });
collection.Insert(new C { S = "xyzxyz" });

var query1 =
from c in collection.AsQueryable<C>()
where c.S.IndexOf("xyz") == 3
select c;
Assert.AreEqual(1, Consume(query1));

var query2 =
from c in collection.AsQueryable<C>()
where c.S.IndexOf("xyz", 1) == 3
select c;
Assert.AreEqual(2, Consume(query2));

var query3 =
from c in collection.AsQueryable<C>()
where c.S.IndexOf("xyz", 1, 4) == 3
select c;
Assert.AreEqual(0, Consume(query3)); // substring isn't long enough to match

var query4 =
from c in collection.AsQueryable<C>()
where c.S.IndexOf("xyz", 1, 5) == 3
select c;
Assert.AreEqual(2, Consume(query4));
}

[Test]
public void TestWhereSIndexOfXyzEquals3()
{
Expand Down

0 comments on commit 3c814ca

Please sign in to comment.