This is the tenth part of the SQLxD series. For your convenience you can find other parts in the table of contents in Part 1 – XML Transformation

Today we are going to test our code. First, we need to have some mocks:

using Model;
using QueryLogic.RelationProviding;

namespace QueryLogic.Test.Mocks
{
    public class DummyRelationProvider : IRelationProvider
    {
        private readonly Relation _provider;

        public DummyRelationProvider(Relation provider)
        {
            _provider = provider;
        }

        public Relation CreateRelation(Node source)
        {
            return _provider;
        }
    }
}
using System.Collections.Generic;
using System.Linq;
using Model;
using QueryLogic.Selectors;

namespace QueryLogic.Test.Mocks
{
    internal class DummyFirstElementSelector : ISelector
    {
        public IEnumerable Select(Node parent)
        {
            if (parent.InnerNodes.Any())
            {
                yield return parent.InnerNodes.First();
            }
        }
    }
}
using System.Collections.Generic;
using Model;
using QueryLogic.Selectors;

namespace QueryLogic.Test.Mocks
{
    internal class DummyAllSelector : ISelector
    {
        public IEnumerable Select(Node parent)
        {
            return parent.InnerNodes;
        }
    }
}

We start with tests for WHERE clause:

using System.Collections.Generic;
using Model;
using NUnit.Framework;
using QueryLogic.Filtering;
using QueryLogic.Predicates;
using QueryLogic.Test.Mocks;
using Rhino.Mocks;

namespace QueryLogic.Test.Filtering
{
    [TestFixture]
    internal class WhereTests
    {
        [Test]
        public void CreateRelation_AlwaysFalsePredicatePassed_ShouldReturnEmptyRelation()
        {
            // Arrange
            var firstColumn = new ColumnHeader("schema", "Column1");

            var firstRow = new Row();
            firstRow.AddCell(new Cell(firstColumn, "value1"));

            var secondRow = new Row();
            secondRow.AddCell(new Cell(firstColumn, "value2"));

            var thirdRow = new Row();
            thirdRow.AddCell(new Cell(firstColumn, "value3"));

            var relation = new Relation();
            relation.AddRow(firstRow);
            relation.AddRow(secondRow);
            relation.AddRow(thirdRow);

            var mocks = new MockRepository();
            var predicate = mocks.Stub< IPredicate>();

            using (mocks.Record())
            {
                predicate.KeepRow(firstRow);
                LastCall.Return(false);

                predicate.KeepRow(secondRow);
                LastCall.Return(false);

                predicate.KeepRow(thirdRow);
                LastCall.Return(false);
            }

            var where = new Where(new DummyRelationProvider(relation), predicate);

            // Act
            Relation actualRelation = where.CreateRelation(null);
            IEnumerable< ColumnHeader> actualColumns = actualRelation.Columns;
            IEnumerable< Row> actualRows = actualRelation.Rows;

            // Assert
            CollectionAssert.IsEmpty(actualColumns);
            CollectionAssert.IsEmpty(actualRows);
        }

        [Test]
        public void CreateRelation_AlwaysTruePredicate_ShouldReturnIdenticalRelation()
        {
            // Arrange
            var firstColumn = new ColumnHeader("schema", "Column1");

            var firstRow = new Row();
            firstRow.AddCell(new Cell(firstColumn, "value1"));

            var secondRow = new Row();
            secondRow.AddCell(new Cell(firstColumn, "value2"));

            var thirdRow = new Row();
            thirdRow.AddCell(new Cell(firstColumn, "value3"));

            var relation = new Relation();
            relation.AddRow(firstRow);
            relation.AddRow(secondRow);
            relation.AddRow(thirdRow);

            var mocks = new MockRepository();
            var predicate = mocks.Stub< IPredicate>();

            using (mocks.Record())
            {
                predicate.KeepRow(firstRow);
                LastCall.Return(true);
                predicate.KeepRow(secondRow);
                LastCall.Return(true);
                predicate.KeepRow(thirdRow);
                LastCall.Return(true);
            }

            var where = new Where(new DummyRelationProvider(relation), predicate);

            IEnumerable< ColumnHeader> expectedColumns = relation.Columns;
            IEnumerable< Row> expectedRows = relation.Rows;

            // Act
            Relation actualRelation = where.CreateRelation(null);
            IEnumerable< ColumnHeader> actualColumns = actualRelation.Columns;
            IEnumerable< Row> actualRows = actualRelation.Rows;

            // Assert
            CollectionAssert.AreEquivalent(expectedColumns, actualColumns);
            CollectionAssert.AreEquivalent(expectedRows, actualRows);
        }

        [Test]
        public void CreateRelation_ShouldSkipRowsForWhichPredicateIsFalse()
        {
            // Arrange
            var firstColumn = new ColumnHeader("schema", "Column1");

            var firstRow = new Row();
            firstRow.AddCell(new Cell(firstColumn, "value1"));

            var secondRow = new Row();
            secondRow.AddCell(new Cell(firstColumn, "value2"));

            var thirdRow = new Row();
            thirdRow.AddCell(new Cell(firstColumn, "value3"));

            var relation = new Relation();
            relation.AddRow(firstRow);
            relation.AddRow(secondRow);
            relation.AddRow(thirdRow);

            var mocks = new MockRepository();
            var predicate = mocks.Stub< IPredicate>();

            using (mocks.Record())
            {
                predicate.KeepRow(firstRow);
                LastCall.Return(true);

                predicate.KeepRow(secondRow);
                LastCall.Return(false);

                predicate.KeepRow(thirdRow);
                LastCall.Return(true);
            }

            var where = new Where(new DummyRelationProvider(relation), predicate);

            var expectedColumns = new List< ColumnHeader> { firstColumn };
            var expectedRows = new List< Row> { firstRow, thirdRow };

            // Act
            Relation actualRelation = where.CreateRelation(null);
            IEnumerable< ColumnHeader> actualColumns = actualRelation.Columns;
            IEnumerable< Row> actualRows = actualRelation.Rows;

            // Assert
            CollectionAssert.AreEquivalent(expectedColumns, actualColumns);
            CollectionAssert.AreEquivalent(expectedRows, actualRows);
        }
    }
}

And now tests for simple predicates:

using Model;
using NUnit.Framework;
using QueryLogic.Expressions.RowExpressions;
using QueryLogic.Predicates.Simple;
using Rhino.Mocks;

namespace QueryLogic.Test.Predicates.Simple
{
    internal class GreaterEqualPredicateTests
    {
        [TestCase("13", "2013-12-13", false,
            Description =
                "Should compare as strings and return false when left rowExpression value is not greater than right rowExpression value and rowExpression types are different"
            )]
        [TestCase("13", "14", false,
            Description =
                "Should compare as doubles and return false when left rowExpression value is not greater than right rowExpression value"
            )]
        [TestCase("14", "13", true,
            Description =
                "Should compare as double, and return true when left rowExpression value is greater than right rowExpression value"
            )]
        [TestCase("14", "14", true,
            Description =
                "Should compare as doubles and return true when left rowExpression value is equal to right rowExpression value"
            )]
        [TestCase("2013-12-13", "2013-12-12", true,
            Description =
                "Should compare as dates and return true when left rowExpression value is greater than right rowExpression value"
            )]
        [TestCase("2013-12-12", "2013-12-13", false,
            Description =
                "Should compare as dates and return false when left rowExpression value is not greater than right rowExpression value"
            )]
        [TestCase("2013-12-12", "2013-12-12", true,
            Description =
                "Should compare as dates and return true when left rowExpression value is equal to right rowExpression value"
            )]
        [TestCase("false", "true", false,
            Description =
                "Should compare booleans as strings and return false when left rowExpression value is not greater than right rowExpression value"
            )]
        [TestCase("true", "true", true,
            Description = "Should compare booleans as strings and return true when they are equal")]
        [TestCase("firstValue", "firstValue", true,
            Description = "Should return true when rowExpression values are equal")
        ]
        [TestCase("firstValue", "secondValue", false,
            Description =
                "Should return false when left rowExpression value is not greater than right rowExpression value")]
        [TestCase("secondValue", "firstValue", true,
            Description = "Should return true when left rowExpression value is greater than right rowExpression value")]
        [TestCase(null, "secondValue", false, Description = "Should return false when left rowExpression returns null")]
        [TestCase("firstValue", null, false, Description = "Should return false when right rowExpression returns null")]
        [TestCase(null, null, false, Description = "Should return false when both expressions return null")]
        public void KeepRow(
            string leftExpressionResult, string rightExpressionResult,
            bool expectedResult)
        {
            //Arrange
            var mocks = new MockRepository();
            var row = new Row();
            var leftExpression = mocks.Stub< IRowExpression>();
            var rightExpression = mocks.Stub< IRowExpression>();

            Cell leftCell = (leftExpressionResult != null)
                ? new Cell(new ColumnHeader("left", "left"), leftExpressionResult)
                : null;
            Cell rightCell = (rightExpressionResult != null)
                ? new Cell(new ColumnHeader("right", "right"), rightExpressionResult)
                : null;

            using (mocks.Record())
            {
                leftExpression.Calculate(row);
                LastCall.Return(leftCell);
                rightExpression.Calculate(row);
                LastCall.Return(rightCell);
            }

            //Act
            var predicate = new GreaterEqualPredicate(leftExpression, rightExpression);
            bool result = predicate.KeepRow(row);

            //Assert
            Assert.That(expectedResult, Is.EqualTo(result));
        }
    }
}
using Model;
using NUnit.Framework;
using QueryLogic.Expressions.RowExpressions;
using QueryLogic.Predicates.Simple;
using Rhino.Mocks;

namespace QueryLogic.Test.Predicates.Simple
{
    internal class GreaterThanPredicateTests
    {
        [TestCase("13", "2013-12-13", false,
            Description =
                "Should compare as strings and return false when left rowExpression value is not greater than right rowExpression value and rowExpression types are different"
            )]
        [TestCase("13", "14", false,
            Description =
                "Should compare as doubles and return false when left rowExpression value is not greater than right rowExpression value"
            )]
        [TestCase("14", "13", true,
            Description =
                "Should compare as doubles and return true when left rowExpression value is greater than right rowExpression value"
            )]
        [TestCase("14", "14", false,
            Description =
                "Should compare as doubles and return false when left rowExpression value is equal to right rowExpression value"
            )]
        [TestCase("2013-12-13", "2013-12-12", true,
            Description =
                "Should compare as dates and return true when left rowExpression value is greater than right rowExpression value"
            )]
        [TestCase("2013-12-12", "2013-12-13", false,
            Description =
                "Should compare as dates and return false when left rowExpression value is not greater than right rowExpression value"
            )]
        [TestCase("2013-12-12", "2013-12-12", false,
            Description =
                "Should compare as dates and return false when left rowExpression value is equal to right rowExpression value"
            )]
        [TestCase("false", "true", false,
            Description =
                "Should compare booleans as strings and return false when left rowExpression value is not greater than right rowExpression value"
            )]
        [TestCase("true", "true", false,
            Description = "Should compare booleans as strings and return false when they are equal")]
        [TestCase("firstValue", "firstValue", false,
            Description = "Should return false when rowExpression values are equal")]
        [TestCase("firstValue", "secondValue", false,
            Description =
                "Should return false when left rowExpression value is not greater than right rowExpression value")]
        [TestCase("secondValue", "firstValue", true,
            Description = "Should return true when left rowExpression value is greater than right rowExpression value")]
        [TestCase(null, "secondValue", false, Description = "Should return false when left rowExpression returns null")]
        [TestCase("firstValue", null, false, Description = "Should return false when right rowExpression returns null")]
        [TestCase(null, null, false, Description = "Should return false when both expressions return null")]
        public void KeepRow(string leftExpressionResult,
            string rightExpressionResult,
            bool expectedResult)
        {
            //Arrange
            var mocks = new MockRepository();
            var row = new Row();
            var leftExpression = mocks.Stub< IRowExpression>();
            var rightExpression = mocks.Stub< IRowExpression>();

            Cell leftCell = (leftExpressionResult != null)
                ? new Cell(new ColumnHeader("left", "left"), leftExpressionResult)
                : null;
            Cell rightCell = (rightExpressionResult != null)
                ? new Cell(new ColumnHeader("right", "right"), rightExpressionResult)
                : null;

            using (mocks.Record())
            {
                leftExpression.Calculate(row);
                LastCall.Return(leftCell);
                rightExpression.Calculate(row);
                LastCall.Return(rightCell);
            }

            //Act
            var predicate = new GreaterThanPredicate(leftExpression, rightExpression);
            bool result = predicate.KeepRow(row);

            //Assert
            Assert.That(expectedResult, Is.EqualTo(result));
        }
    }
}
using Model;
using NUnit.Framework;
using QueryLogic.Expressions.RowExpressions;
using QueryLogic.Predicates.Simple;
using Rhino.Mocks;

namespace QueryLogic.Test.Predicates.Simple
{
    internal class LessEqualPredicateTests
    {
        [TestCase("23", "2013-12-13", false,
            Description =
                "Should compare as strings and return false when left rowExpression value is not lesser than right rowExpression value and rowExpression types are different"
            )]
        [TestCase("15", "14", false,
            Description =
                "Should compare as doubles and return false when left rowExpression value is not lesser than right rowExpression value"
            )]
        [TestCase("12", "13", true,
            Description =
                "Should compare as double, and return true when left rowExpression value is lesser than right rowExpression value"
            )]
        [TestCase("14", "14", true,
            Description =
                "Should compare as doubles and return true when left rowExpression value is equal to right rowExpression value"
            )]
        [TestCase("2013-12-11", "2013-12-12", true,
            Description =
                "Should compare as dates and return true when left rowExpression value is lesser than right rowExpression value"
            )]
        [TestCase("2013-12-14", "2013-12-13", false,
            Description =
                "Should compare as dates and return false when left rowExpression value is not lesser than right rowExpression value"
            )]
        [TestCase("2013-12-12", "2013-12-12", true,
            Description =
                "Should compare as dates and return true when left rowExpression value is equal to right rowExpression value"
            )]
        [TestCase("true", "false", false,
            Description =
                "Should compare booleans as strings and return false when left rowExpression value is not greater than right rowExpression value"
            )]
        [TestCase("true", "true", true,
            Description = "Should compare booleans as strings and return true when they are equal")]
        [TestCase("firstValue", "firstValue", true,
            Description = "Should return true when rowExpression values are equal")
        ]
        [TestCase("secondValue", "firstValue", false,
            Description =
                "Should return false when left rowExpression value is not lesser than right rowExpression value")]
        [TestCase("firstValue", "secondValue", true,
            Description = "Should return true when left rowExpression value is lesser than right rowExpression value")]
        [TestCase(null, "secondValue", false, Description = "Should return false when left rowExpression returns null")]
        [TestCase("firstValue", null, false, Description = "Should return false when right rowExpression returns null")]
        [TestCase(null, null, false, Description = "Should return false when both expressions return null")]
        public void KeepRow(string leftExpressionResult,
            string rightExpressionResult,
            bool expectedResult)
        {
            //Arrange
            var mocks = new MockRepository();
            var row = new Row();
            var leftExpression = mocks.Stub< IRowExpression>();
            var rightExpression = mocks.Stub< IRowExpression>();

            Cell leftCell = (leftExpressionResult != null)
                ? new Cell(new ColumnHeader("left", "left"), leftExpressionResult)
                : null;
            Cell rightCell = (rightExpressionResult != null)
                ? new Cell(new ColumnHeader("right", "right"), rightExpressionResult)
                : null;

            using (mocks.Record())
            {
                leftExpression.Calculate(row);
                LastCall.Return(leftCell);
                rightExpression.Calculate(row);
                LastCall.Return(rightCell);
            }

            //Act
            var predicate = new LessEqualPredicate(leftExpression, rightExpression);
            bool result = predicate.KeepRow(row);

            //Assert
            Assert.That(result, Is.EqualTo(expectedResult));
        }
    }
}
using Model;
using NUnit.Framework;
using QueryLogic.Expressions.RowExpressions;
using QueryLogic.Predicates.Simple;
using Rhino.Mocks;

namespace QueryLogic.Test.Predicates.Simple
{
    internal class LessThanPredicateTests
    {
        [TestCase("23", "2013-12-13", false,
            Description =
                "Should compare as strings and return false when left rowExpression value is not lesser than right rowExpression value and rowExpression types are different"
            )]
        [TestCase("15", "14", false,
            Description =
                "Should compare as doubles and return false when left rowExpression value is not lesser than right rowExpression value"
            )]
        [TestCase("12", "13", true,
            Description =
                "Should compare as double, and return true when left rowExpression value is lesser than right rowExpression value"
            )]
        [TestCase("14", "14", false,
            Description =
                "Should compare as doubles and return false when left rowExpression value is equal to right rowExpression value"
            )]
        [TestCase("2013-12-11", "2013-12-12", true,
            Description =
                "Should compare as dates and return true when left rowExpression value is lesser than right rowExpression value"
            )]
        [TestCase("2013-12-14", "2013-12-13", false,
            Description =
                "Should compare as dates and return false when left rowExpression value is not lesser than right rowExpression value"
            )]
        [TestCase("2013-12-12", "2013-12-12", false,
            Description =
                "Should compare as dates and return false when left rowExpression value is equal to right rowExpression value"
            )]
        [TestCase("true", "false", false,
            Description =
                "Should compare booleans as strings and return false when left rowExpression value is not greater than right rowExpression value"
            )]
        [TestCase("true", "true", false,
            Description = "Should compare booleans as strings and return false when they are equal")]
        [TestCase("firstValue", "firstValue", false,
            Description = "Should return false when rowExpression values are equal")
        ]
        [TestCase("secondValue", "firstValue", false,
            Description =
                "Should return false when left rowExpression value is not lesser than right rowExpression value")]
        [TestCase("firstValue", "secondValue", true,
            Description = "Should return true when left rowExpression value is lesser than right rowExpression value")]
        [TestCase(null, "secondValue", false, Description = "Should return false when left rowExpression returns null")]
        [TestCase("firstValue", null, false, Description = "Should return false when right rowExpression returns null")]
        [TestCase(null, null, false, Description = "Should return false when both expressions return null")]
        public void KeepRow(string leftExpressionResult,
            string rightExpressionResult,
            bool expectedResult)
        {
            //Arrange
            var mocks = new MockRepository();
            var row = new Row();
            var leftExpression = mocks.Stub< IRowExpression>();
            var rightExpression = mocks.Stub< IRowExpression>();

            Cell leftCell = (leftExpressionResult != null)
                ? new Cell(new ColumnHeader("left", "left"), leftExpressionResult)
                : null;
            Cell rightCell = (rightExpressionResult != null)
                ? new Cell(new ColumnHeader("right", "right"), rightExpressionResult)
                : null;

            using (mocks.Record())
            {
                leftExpression.Calculate(row);
                LastCall.Return(leftCell);
                rightExpression.Calculate(row);
                LastCall.Return(rightCell);
            }

            //Act
            var predicate = new LessThanPredicate(leftExpression, rightExpression);
            bool result = predicate.KeepRow(row);

            //Assert
            Assert.That(result, Is.EqualTo(expectedResult));
        }
    }
}
using Model;
using NUnit.Framework;
using QueryLogic.Expressions.RowExpressions;
using QueryLogic.Predicates.Simple;
using Rhino.Mocks;

namespace QueryLogic.Test.Predicates.Simple
{
    internal class EqualPredicateTests
    {
        [TestCase("firstValue", "firstValue", true,
            Description = "Should return true when rowExpression values are equal")]
        [TestCase("firstValue", "secondValue", false,
            Description = "Should return false when rowExpression values are not equal")]
        [TestCase(null, "secondValue", false, Description = "Should return false when left rowExpression returns null")]
        [TestCase("firstValue", null, false, Description = "Should return false when right rowExpression returns null")]
        [TestCase(null, null, false, Description = "Should return false when both expressions return null")]
        public void KeepRow(string leftExpressionResult, string rightExpressionResult,
            bool expectedResult)
        {
            //Arrange
            var mocks = new MockRepository();
            var row = new Row();
            var leftExpression = mocks.Stub< IRowExpression>();
            var rightExpression = mocks.Stub< IRowExpression>();

            Cell leftCell = (leftExpressionResult != null)
                ? new Cell(new ColumnHeader("left", "left"), leftExpressionResult)
                : null;
            Cell rightCell = (rightExpressionResult != null)
                ? new Cell(new ColumnHeader("right", "right"), rightExpressionResult)
                : null;

            using (mocks.Record())
            {
                leftExpression.Calculate(row);
                LastCall.Return(leftCell);
                rightExpression.Calculate(row);
                LastCall.Return(rightCell);
            }

            //Act
            var predicate = new EqualPredicate(leftExpression, rightExpression);
            bool result = predicate.KeepRow(row);

            //Assert
            Assert.That(expectedResult, Is.EqualTo(result));
        }
    }
}
using Model;
using NUnit.Framework;
using QueryLogic.Expressions.RowExpressions;
using QueryLogic.Predicates.Simple;
using Rhino.Mocks;

namespace QueryLogic.Test.Predicates.Simple
{
    internal class NotEqualPredicateTests
    {
        [TestCase("firstValue", "firstValue", false,
            Description = "Should return false when rowExpression values are equal")]
        [TestCase("firstValue", "secondValue", true,
            Description = "Should return true when rowExpression values are not equal")]
        [TestCase(null, "secondValue", false, Description = "Should return false when left rowExpression returns null")]
        [TestCase("firstValue", null, false, Description = "Should return false when right rowExpression returns null")]
        [TestCase(null, null, false, Description = "Should return false when both expressions return null")]
        public void KeepRow(string leftExpressionResult,
            string rightExpressionResult,
            bool expectedResult)
        {
            //Arrange
            var mocks = new MockRepository();
            var row = new Row();
            var leftExpression = mocks.Stub< IRowExpression>();
            var rightExpression = mocks.Stub< IRowExpression>();

            Cell leftCell = (leftExpressionResult != null)
                ? new Cell(new ColumnHeader("left", "left"), leftExpressionResult)
                : null;
            Cell rightCell = (rightExpressionResult != null)
                ? new Cell(new ColumnHeader("right", "right"), rightExpressionResult)
                : null;

            using (mocks.Record())
            {
                leftExpression.Calculate(row);
                LastCall.Return(leftCell);
                rightExpression.Calculate(row);
                LastCall.Return(rightCell);
            }

            //Act
            var predicate = new NotEqualPredicate(leftExpression, rightExpression);
            bool result = predicate.KeepRow(row);

            //Assert
            Assert.That(result, Is.EqualTo(expectedResult));
        }
    }
}
using Model;
using NUnit.Framework;
using QueryLogic.Expressions.RowExpressions;
using QueryLogic.Predicates.Simple;
using Rhino.Mocks;

namespace QueryLogic.Test.Predicates.Simple
{
    internal class IsNullPredicateTests
    {
        [Test]
        public void KeepRow_NotNullValue_ShouldReturnFalse()
        {
            //Arrange
            var mocks = new MockRepository();
            var row = new Row();
            var expression = mocks.Stub< IRowExpression>();

            var cell = new Cell(new ColumnHeader("left", "left"), "value");

            using (mocks.Record())
            {
                expression.Calculate(row);
                LastCall.Return(cell);
            }

            //Act
            var predicate = new IsNullPredicate(expression);
            bool result = predicate.KeepRow(row);

            //Assert
            Assert.That(result, Is.False);
        }

        [Test]
        public void KeepRow_NullValue_ShouldReturnTrue()
        {
            //Arrange
            var mocks = new MockRepository();
            var row = new Row();
            var expression = mocks.Stub< IRowExpression>();

            var cell = new Cell(new ColumnHeader("left", "left"), null);

            using (mocks.Record())
            {
                expression.Calculate(row);
                LastCall.Return(cell);
            }

            //Act
            var predicate = new IsNullPredicate(expression);
            bool result = predicate.KeepRow(row);

            //Assert
            Assert.That(result, Is.True);
        }

        [Test]
        public void KeepRow_NullCell_ShouldReturnTrue()
        {
            //Arrange
            var mocks = new MockRepository();
            var row = new Row();
            var expression = mocks.Stub< IRowExpression>();

            const Cell cell = null;

            using (mocks.Record())
            {
                expression.Calculate(row);
                LastCall.Return(cell);
            }

            //Act
            var predicate = new IsNullPredicate(expression);
            bool result = predicate.KeepRow(row);

            //Assert
            Assert.That(result, Is.True);
        }
    }
}

Now tests for logic operators:

using Model;
using NUnit.Framework;
using QueryLogic.Predicates;
using QueryLogic.Predicates.Complex;
using Rhino.Mocks;

namespace QueryLogic.Test.Predicates.Complex
{
    internal class AndPredicateTests
    {
        [TestCase(true, true, true)]
        [TestCase(true, false, false)]
        [TestCase(false, true, false)]
        [TestCase(false, false, false)]
        public void KeepRow_ShouldReturnConjuctionOfTwoPredicates(bool firstPredicateResult, bool secondPredicateResult,
            bool expectedResult)
        {
            //Arrange
            var mocks = new MockRepository();
            var row = new Row();
            var firstPredicate = mocks.Stub< IPredicate>();
            var secondPredicate = mocks.Stub< IPredicate>();

            using (mocks.Record())
            {
                firstPredicate.KeepRow(row);
                LastCall.Return(firstPredicateResult);
                secondPredicate.KeepRow(row);
                LastCall.Return(secondPredicateResult);
            }

            //Act
            var andPredicate = new AndPredicate(firstPredicate, secondPredicate);
            bool result = andPredicate.KeepRow(row);

            //Assert
            Assert.That(result, Is.EqualTo(expectedResult));
        }
    }
}
using Model;
using NUnit.Framework;
using QueryLogic.Predicates;
using QueryLogic.Predicates.Complex;
using Rhino.Mocks;

namespace QueryLogic.Test.Predicates.Complex
{
    internal class NotPredicateTests
    {
        [TestCase(true, false)]
        [TestCase(false, true)]
        public void KeepRow_ShouldReturnNegationOfSourcePredicate(bool predicateResult, bool expectedResult)
        {
            //Arrange
            var mocks = new MockRepository();
            var row = new Row();
            var predicate = mocks.Stub< IPredicate>();

            using (mocks.Record())
            {
                predicate.KeepRow(row);
                LastCall.Return(predicateResult);
            }

            //Act
            var notPredicate = new NotPredicate(predicate);
            bool result = notPredicate.KeepRow(row);

            //Assert
            Assert.That(result, Is.EqualTo(expectedResult));
        }
    }
}
using Model;
using NUnit.Framework;
using QueryLogic.Predicates;
using QueryLogic.Predicates.Complex;
using Rhino.Mocks;

namespace QueryLogic.Test.Predicates.Complex
{
    internal class OrPredicateTests
    {
        [TestCase(true, true, true)]
        [TestCase(true, false, true)]
        [TestCase(false, true, true)]
        [TestCase(false, false, false)]
        public void KeepRow_ShouldReturnAlternativeOfTwoPredicates(bool firstPredicateResult, bool secondPredicateResult,
            bool expectedResult)
        {
            //Arrange
            var mocks = new MockRepository();
            var row = new Row();
            var firstPredicate = mocks.Stub< IPredicate>();
            var secondPredicate = mocks.Stub< IPredicate>();

            using (mocks.Record())
            {
                firstPredicate.KeepRow(row);
                LastCall.Return(firstPredicateResult);
                secondPredicate.KeepRow(row);
                LastCall.Return(secondPredicateResult);
            }

            //Act
            var orPredicate = new OrPredicate(firstPredicate, secondPredicate);
            bool result = orPredicate.KeepRow(row);

            //Assert
            Assert.That(result, Is.EqualTo(expectedResult));
        }
    }
}

And finally tests for LIKE operator:

using Model;
using NUnit.Framework;
using QueryLogic.Expressions.RowExpressions;
using QueryLogic.Predicates.Simple;
using Rhino.Mocks;

namespace QueryLogic.Test.Predicates.Simple
{
    internal class LikePredicateTests
    {
        [TestCase("-v-", "v", '\0', false, Description = "Should match whole expression", Category = "Whole expression")]
        [TestCase("v-", "v", '\0', false, Description = "Should match whole expression", Category = "Whole expression")]
        [TestCase("-v", "v", '\0', false, Description = "Should match whole expression", Category = "Whole expression")]

        [TestCase("v", "v", '\0', true, Description = "Should handle ordinary character", Category = "Character")]
        [TestCase("v", "&v", '&', true, Description = "Should handle escaped character", Category = "Character")]
        [TestCase("&v", "&v", '&', false, Description = "Should handle escaped character", Category = "Character")]
        [TestCase("&", "&&", '&', true, Description = "Should handle escaped character", Category = "Character")]
        [TestCase("&&", "&&", '&', false, Description = "Should handle escaped character", Category = "Character")]
        [TestCase("v", "[v]", '\0', true, Description = "Should handle ordinary character in group", Category = "Character")]
        [TestCase("v", "[&v]", '&', true, Description = "Should handle escaped character in group", Category = "Character")]
        [TestCase("&v", "[&v]", '&', false, Description = "Should handle escaped character in group", Category = "Character")]
        [TestCase("&", "[&&]", '&', true, Description = "Should handle escaped character same as escape character in group", Category = "Character")]
        [TestCase("&&", "[&&]", '&', false, Description = "Should handle escaped character in group", Category = "Character")]
        [TestCase("v", "[^v]", '\0', false, Description = "Should handle ordinary character in negated group", Category = "Character")]
        [TestCase("a", "[^v]", '\0', true, Description = "Should handle ordinary character in negated group", Category = "Character")]
        [TestCase("v", "[^&v]", '&', false, Description = "Should handle escaped character in negated group", Category = "Character")]
        [TestCase("&", "[^&&]", '&', false, Description = "Should handle escaped character same as escape character in negated group", Category = "Character")]
        [TestCase("v", "[^&&]", '&', true, Description = "Should handle escaped character same as escape character in negated group", Category = "Character")]
        [TestCase(@"\", @"\", '\0', true, Description = "Should handle character same as regex escape character", Category = "Character")]
        [TestCase(@"\\", @"\\", '\0', true, Description = "Should handle character same as regex escape character", Category = "Character")]
        [TestCase(@"\", @"[\]", '\0', true, Description = "Should handle character same as regex escape character in group", Category = "Character")]
        [TestCase(@"\", @"[\\]", '\0', true, Description = "Should handle character same as regex escape character in group", Category = "Character")]
        [TestCase(@"\", @"\\", '\\', true, Description = "Should handle escaped character same as regex escape character", Category = "Character")]
        [TestCase(@"\", @"[\\]", '\\', true, Description = "Should handle escaped character same as regex escape character in group", Category = "Character")]

        [TestCase("a", "_", '\0', true, Description = "Should handle underscore", Category = "Underscore")]
        [TestCase("_", "_", '\0', true, Description = "Should handle underscore", Category = "Underscore")]
        [TestCase("bb", "_", '\0', false, Description = "Should handle underscore", Category = "Underscore")]
        [TestCase("a", "&_", '&', false, Description = "Should handle escaped underscore", Category = "Underscore")]
        [TestCase("_", "&_", '&', true, Description = "Should handle escaped underscore", Category = "Underscore")]
        [TestCase("_", "[_]", '\0', true, Description = "Should handle underscore in group", Category = "Underscore")]
        [TestCase("a", "[_]", '\0', false, Description = "Should handle underscore in group", Category = "Underscore")]
        [TestCase("a", "[&_]", '&', false, Description = "Should handle escaped underscore in group", Category = "Underscore")]
        [TestCase("_", "[&_]", '&', true, Description = "Should handle escaped underscore in group", Category = "Underscore")]
        [TestCase("_", "[^_]", '\0', false, Description = "Should handle underscore in negated group", Category = "Underscore")]
        [TestCase("a", "[^_]", '\0', true, Description = "Should handle underscore in negated group", Category = "Underscore")]
        [TestCase("a", "[^&_]", '&', true, Description = "Should handle escaped underscore in negated group", Category = "Underscore")]
        [TestCase("_", "[^&_]", '&', false, Description = "Should handle escaped underscore in negated group", Category = "Underscore")]

        [TestCase("a", "%", '\0', true, Description = "Should handle percent", Category = "Percent")]
        [TestCase("%", "%", '\0', true, Description = "Should handle percent", Category = "Percent")]
        [TestCase("bb", "%", '\0', true, Description = "Should handle percent", Category = "Percent")]
        [TestCase("a", "&%", '&', false, Description = "Should handle escaped percent", Category = "Percent")]
        [TestCase("%", "&%", '&', true, Description = "Should handle escaped percent", Category = "Percent")]
        [TestCase("%", "[%]", '\0', true, Description = "Should handle percent in group", Category = "Percent")]
        [TestCase("a", "[%]", '\0', false, Description = "Should handle percent in group", Category = "Percent")]
        [TestCase("a", "[&%]", '&', false, Description = "Should handle escaped percent in group", Category = "Percent")]
        [TestCase("%", "[&%]", '&', true, Description = "Should handle escaped percent in group", Category = "Percent")]
        [TestCase("%", "[^%]", '\0', false, Description = "Should handle percent in negated group", Category = "Percent")]
        [TestCase("a", "[^%]", '\0', true, Description = "Should handle percent in negated group", Category = "Percent")]
        [TestCase("a", "[^&%]", '&', true, Description = "Should handle escaped percent in negated group", Category = "Percent")]
        [TestCase("%", "[^&%]", '&', false, Description = "Should handle escaped percent in negated group", Category = "Percent")]

        [TestCase("a", "[a-z]", '\0', true, Description = "Should handle range", Category = "Range")]
        [TestCase("e", "[a-z]", '\0', true, Description = "Should handle range", Category = "Range")]
        [TestCase("z", "[a-z]", '\0', true, Description = "Should handle range", Category = "Range")]
        [TestCase("A", "[a-z]", '\0', false, Description = "Should handle range", Category = "Range")]
        [TestCase("a", "[z-a]", '\0', false, Description = "Should handle range", Category = "Range")]
        [TestCase("e", "[z-a]", '\0', false, Description = "Should handle range", Category = "Range")]
        [TestCase("z", "[z-a]", '\0', false, Description = "Should handle range", Category = "Range")]
        [TestCase("A", "[z-a]", '\0', false, Description = "Should handle range", Category = "Range")]
        [TestCase("c", "[a-b]", '\0', false, Description = "Should handle range", Category = "Range")]
        [TestCase("c", "[-b]", '\0', false, Description = "Should handle specious range", Category = "Range")]
        [TestCase("-", "[-b]", '\0', true, Description = "Should handle specious range", Category = "Range")]
        [TestCase("b", "[-b]", '\0', true, Description = "Should handle specious range", Category = "Range")]
        [TestCase("-b", "[-b]", '\0', false, Description = "Should handle specious range", Category = "Range")]
        [TestCase("a", "[^b-e]", '\0', true, Description = "Should handle negated range", Category = "Range")]
        [TestCase("f", "[^b-e]", '\0', true, Description = "Should handle negated range", Category = "Range")]
        [TestCase("b", "[^b-e]", '\0', false, Description = "Should handle negated range", Category = "Range")]
        [TestCase("c", "[^b-e]", '\0', false, Description = "Should handle negated range", Category = "Range")]
        [TestCase("e", "[^b-e]", '\0', false, Description = "Should handle negated range", Category = "Range")]
        [TestCase("a", "[^-e]", '\0', true, Description = "Should handle negated specious range", Category = "Range")]
        [TestCase("f", "[^-e]", '\0', true, Description = "Should handle negated specious range", Category = "Range")]
        [TestCase("b", "[^-e]", '\0', true, Description = "Should handle negated specious range", Category = "Range")]
        [TestCase("c", "[^-e]", '\0', true, Description = "Should handle negated specious range", Category = "Range")]
        [TestCase("e", "[^-e]", '\0', false, Description = "Should handle negated specious range", Category = "Range")]
        [TestCase("-", "[^-e]", '\0', false, Description = "Should handle negated specious range", Category = "Range")]
        [TestCase("-e", "[^-e]", '\0', false, Description = "Should handle negated specious range", Category = "Range")]
        [TestCase("b", "[^b-e]", '^', true, Description = "Should handle specious negated range when escape character is negation", Category = "Range")]
        [TestCase("-", "[^b-e]", '^', false, Description = "Should handle specious negated range when escape character is negation", Category = "Range")]
        [TestCase("e", "[^b-e]", '^', true, Description = "Should handle specious negated range when escape character is negation", Category = "Range")]
        [TestCase("a", "[^b-e]", '^', false, Description = "Should handle specious negated range when escape character is negation", Category = "Range")]
        [TestCase("a", "[^^b-e]", '^', false, Description = "Should handle negated range when escape character is negation", Category = "Range")]
        [TestCase("b", "[^^b-e]", '^', true, Description = "Should handle negated range when escape character is negation", Category = "Range")]
        [TestCase("c", "[^^b-e]", '^', true, Description = "Should handle negated range when escape character is negation", Category = "Range")]
        [TestCase("e", "[^^b-e]", '^', true, Description = "Should handle negated range when escape character is negation", Category = "Range")]
        [TestCase("^", "[^^b-e]", '^', true, Description = "Should handle negated range when escape character is negation", Category = "Range")]

        [TestCase("a", "[a]", '\0', true, Description = "Should handle group", Category = "Group")]
        [TestCase("[", "[[]", '\0', true, Description = "Should handle opening group bracket in group", Category = "Group")]
        [TestCase("[[", "[[]", '\0', false, Description = "Should handle opening group bracket in group", Category = "Group")]
        [TestCase("[[]", "[[]", '\0', false, Description = "Should handle opening group bracket in group", Category = "Group")]
        [TestCase("[a]", "&[a]", '&', true, Description = "Should handle escaped opening bracket", Category = "Group")]
        [TestCase("a]", "&[a]", '&', false, Description = "Should handle escaped opening bracket", Category = "Group")]
        [TestCase("a", "&[a]", '&', false, Description = "Should handle escaped opening bracket", Category = "Group")]
        [TestCase("a]", "[a&]", '&', false, Description = "Should handle escaped closing bracket", Category = "Group")]
        [TestCase("a&]", "[a&]", '&', false, Description = "Should handle escaped closing bracket", Category = "Group")]
        [TestCase("a", "[a&]", '&', false, Description = "Should handle escaped closing bracket", Category = "Group")]
        [TestCase("a", "[a&]]", '&', true, Description = "Should handle escaped closing bracket in group", Category = "Group")]
        [TestCase("]", "[a&]]", '&', true, Description = "Should handle escaped closing bracket in group", Category = "Group")]
        [TestCase("&", "[a&]]", '&', false, Description = "Should handle escaped closing bracket in group", Category = "Group")]
        [TestCase("a", "[a]", '[', false, Description = "Should handle opening group bracket when opening bracket is escape character", Category = "Group")]
        [TestCase("a]", "[a]", '[', true, Description = "Should handle opening group bracket when opening bracket is escape character", Category = "Group")]
        [TestCase("a", "[[a]", '[', false, Description = "Should handle opening group bracket when opening bracket is escape character", Category = "Group")]
        [TestCase("[", "[[a]", '[', false, Description = "Should handle opening group bracket when opening bracket is escape character", Category = "Group")]
        [TestCase("[a", "[[a]", '[', false, Description = "Should handle opening group bracket when opening bracket is escape character", Category = "Group")]
        [TestCase("[a]", "[[a]", '[', true, Description = "Should handle opening group bracket when opening bracket is escape character", Category = "Group")]
        [TestCase("a", "[a]", ']', false, Description = "Should handle closing group bracket when closing bracket is escape character", Category = "Group")]
        [TestCase("a]", "[a]", ']', false, Description = "Should handle closing group bracket when closing bracket is escape character", Category = "Group")]
        [TestCase("a", "[a]]", ']', false, Description = "Should handle closing group bracket when closing bracket is escape character", Category = "Group")]
        [TestCase("]", "[a]]", ']', false, Description = "Should handle closing group bracket when closing bracket is escape character", Category = "Group")]
        [TestCase("a]", "[a]]", ']', false, Description = "Should handle closing group bracket when closing bracket is escape character", Category = "Group")]
        [TestCase("[", "[][]]", ']', false, Description = "Should handle escaped brackets in group", Category = "Group")]
        [TestCase("]", "[][]]", ']', false, Description = "Should handle escaped brackets in group", Category = "Group")]
        [TestCase("[]", "[][]]", ']', false, Description = "Should handle escaped brackets in group", Category = "Group")]
        [TestCase("1b2", "1[a-c]2", '\0', true, Description = "Should handle ordinary character after group", Category = "Group")]
        [TestCase("1b33", "1[a-c]%", '\0', true, Description = "Should handle percent after group", Category = "Group")]
        [TestCase("1b4", "1[a-c]_", '\0', true, Description = "Should handle underscore after group", Category = "Group")]
        [TestCase("a!h", "[a-c]![g-h]", '\0', true, Description = "Should handle many groups", Category = "Group")]

        [TestCase(null, "secondValue", '\0', false, Description = "Should return false when left side is null", Category = "Incorrect values")]
        [TestCase("firstValue", null, '\0', false, Description = "Should return false when pattern is null", Category = "Incorrect values")]
        [TestCase(null, null, '\0', false, Description = "Should return false when all is null", Category = "Incorrect values")]
        [TestCase("a", "[]", '&', false, Description = "Should return false when expression is incorrect", Category = "Incorrect values")]
        [TestCase("[[", "[[", '&', false, Description = "Should return false when pattern is invalid", Category = "Incorrect values")]


        [TestCase("a", "_", '\0', true, Description = "Should match _ character", Category = "Underscore")]
        [TestCase("aa", "_", '\0', false, Description = "Should match _ only in place", Category = "Underscore")]
        [TestCase("anything_first", "%first", '\0', true,
            Description = "Should match %", Category = "Percent")]
        [TestCase("anything_first", "fi%st", '\0', false,
            Description = "Should match % only in place", Category = "Percent")]
        [TestCase("first", "fi[a-z]st", '\\', true,
            Description = "Should match characters group", Category = "Characters groups")]
        [TestCase("first", "fi[a-d]st", '\\', false,
            Description = "Should match only characters from group", Category = "Characters groups")]
        [TestCase("first", "fi[^a-d]st", '\\', true,
            Description = "Should match group negation", Category = "Characters groups")]
        [TestCase("-", "[-a]", '&', true,
            Description = "Should correctly match - in group", Category = "Characters groups")]
        [TestCase("%", "[%]", '&', true,
            Description = "Should match % when % is in []", Category = "Characters groups")]
        [TestCase("*", "[%]", '&', false,
            Description = "Should not match * when % is in []", Category = "Characters groups")]
        [TestCase("_", "[_]", '&', true,
            Description = "Should match _ when _ is in []", Category = "Characters groups")]
        [TestCase("first", "fi[^a-z]st", '\\', false,
            Description = "Should match only characters from group completion", Category = "Characters groups")]
        [TestCase(".", "[_]", '&', false,
            Description = "Should not match . when _ is in []", Category = "Characters groups")]
        [TestCase("fi*st", "fi*st", '\\', true,
            Description = "Should not treat * as a special character",
            Category = "Pattern in regexp, normal string in SQL")]
        [TestCase("fi.st", "fi.st", '\\', true,
            Description = "Should not treat . as a special character",
            Category = "Pattern in regexp, normal string in SQL")]
        [TestCase("fi()st", "fi()st", '\\', true,
            Description = "Should not treat parenthesis as a special characters",
            Category = "Pattern in regexp, normal string in SQL")]
        [TestCase(@"fi\dst", @"fi\dst", '\0', true,
            Description = @"Should not treat \d as a special character",
            Category = "Pattern in regexp, normal string in SQL")]
        [TestCase(@"fidst", @"fi[\d]st", '\\', true,
            Description = @"Should not treat \d in group as a special character",
            Category = "Pattern in regexp, normal string in SQL")]
        [TestCase("1", "#", '&', false,
            Description = "Should not treat # as number", Category = "Pattern in regexp, normal string in SQL")]
        [TestCase("#", "#", '&', true,
            Description = "Should match # as #", Category = "Pattern in regexp, normal string in SQL")]
        [TestCase("fi%st", "fi&%st", '&', true,
            Description = "Should escape %", Category = "Escape character")]
        [TestCase("%blabla", "&%", '&', false,
            Description = "Should escape %", Category = "Escape character")]
        [TestCase("%", "%%", '%', true,
            Description = "Should match % when escape character is %", Category = "Escape character")]
        [TestCase("#", "%%", '%', false,
            Description = "Should not match % when escape character is %", Category = "Escape character")]
        [TestCase(null, "secondValue", '\\', false,
            Description = "Should return false when left side is null", Category = "Incorrect values")]
        [TestCase("firstValue", null, '\\', false,
            Description = "Should return false when pattern is null", Category = "Incorrect values")]
        [TestCase(null, null, '\\', false,
            Description = "Should return false when all is null", Category = "Incorrect values")]
        [TestCase("a", "[]", '&', false,
            Description = "Should return false when rowExpression is incorrect", Category = "Incorrect values")]
        [TestCase("[[", "[[", '&', false,
            Description = "Should return false when pattern is invalid", Category = "Incorrect values")]
        public void KeepRow(string leftExpressionResult,
                                                                   string rightExpressionResult, char escapeCharacter,
                                                                   bool expectedResult)
        {
            //Arrange
            var mocks = new MockRepository();
            var row = new Row();
            var leftExpression = mocks.Stub();
            var rightExpression = mocks.Stub();

            Cell leftCell = (leftExpressionResult != null)
                                ? new Cell(new ColumnHeader("left", "left"), leftExpressionResult)
                                : null;
            Cell rightCell = (rightExpressionResult != null)
                                 ? new Cell(new ColumnHeader("right", "right"), rightExpressionResult)
                                 : null;

            using (mocks.Record())
            {
                leftExpression.Calculate(row);
                LastCall.Return(leftCell);
                rightExpression.Calculate(row);
                LastCall.Return(rightCell);
            }

            //Act
            var predicate = new LikePredicate(leftExpression, rightExpression, escapeCharacter);
            bool result = predicate.KeepRow(row);

            //Assert
            Assert.That(result, Is.EqualTo(expectedResult));
        }

        //tests from stackoverflow http://stackoverflow.com/questions/5417070/c-sharp-version-of-sql-like/5419155#5419155
        [TestCase(true, "%", "", Category = "Tests from StackOverflow")]
        [TestCase(true, "%", " ", Category = "Tests from StackOverflow")]
        [TestCase(true, "%", "asdfa asdf asdf", Category = "Tests from StackOverflow")]
        [TestCase(true, "%", "%", Category = "Tests from StackOverflow")]
        [TestCase(false, "_", "", Category = "Tests from StackOverflow")]
        [TestCase(true, "_", " ", Category = "Tests from StackOverflow")]
        [TestCase(true, "_", "4", Category = "Tests from StackOverflow")]
        [TestCase(true, "_", "C", Category = "Tests from StackOverflow")]
        [TestCase(false, "_", "CX", Category = "Tests from StackOverflow")]
        [TestCase(false, "[ABCD]", "", Category = "Tests from StackOverflow")]
        [TestCase(true, "[ABCD]", "A", Category = "Tests from StackOverflow")]
        [TestCase(true, "[abcd]", "b", Category = "Tests from StackOverflow")]
        [TestCase(false, "[ABCD]", "X", Category = "Tests from StackOverflow")]
        [TestCase(false, "[ABCD]", "AB", Category = "Tests from StackOverflow")]
        [TestCase(true, "[B-D]", "C", Category = "Tests from StackOverflow")]
        [TestCase(true, "[B-D]", "D", Category = "Tests from StackOverflow")]
        [TestCase(false, "[B-D]", "A", Category = "Tests from StackOverflow")]
        [TestCase(false, "[^B-D]", "C", Category = "Tests from StackOverflow")]
        [TestCase(false, "[^B-D]", "D", Category = "Tests from StackOverflow")]
        [TestCase(true, "[^B-D]", "A", Category = "Tests from StackOverflow")]
        [TestCase(true, "%TEST[ABCD]XXX", "lolTESTBXXX", Category = "Tests from StackOverflow")]
        [TestCase(false, "%TEST[ABCD]XXX", "lolTESTZXXX", Category = "Tests from StackOverflow")]
        [TestCase(false, "%TEST[^ABCD]XXX", "lolTESTBXXX", Category = "Tests from StackOverflow")]
        [TestCase(true, "%TEST[^ABCD]XXX", "lolTESTZXXX", Category = "Tests from StackOverflow")]
        [TestCase(true, "%TEST[B-D]XXX", "lolTESTBXXX", Category = "Tests from StackOverflow")]
        [TestCase(true, "%TEST[^B-D]XXX", "lolTESTZXXX", Category = "Tests from StackOverflow")]
        [TestCase(true, "%Stuff.txt", "Stuff.txt", Category = "Tests from StackOverflow")]
        [TestCase(true, "%Stuff.txt", "MagicStuff.txt", Category = "Tests from StackOverflow")]
        [TestCase(false, "%Stuff.txt", "MagicStuff.txt.img", Category = "Tests from StackOverflow")]
        [TestCase(false, "%Stuff.txt", "Stuff.txt.img", Category = "Tests from StackOverflow")]
        [TestCase(false, "%Stuff.txt", "MagicStuff001.txt.img", Category = "Tests from StackOverflow")]
        [TestCase(true, "Stuff.txt%", "Stuff.txt", Category = "Tests from StackOverflow")]
        [TestCase(false, "Stuff.txt%", "MagicStuff.txt", Category = "Tests from StackOverflow")]
        [TestCase(false, "Stuff.txt%", "MagicStuff.txt.img", Category = "Tests from StackOverflow")]
        [TestCase(true, "Stuff.txt%", "Stuff.txt.img", Category = "Tests from StackOverflow")]
        [TestCase(false, "Stuff.txt%", "MagicStuff001.txt.img", Category = "Tests from StackOverflow")]
        [TestCase(true, "%Stuff.txt%", "Stuff.txt", Category = "Tests from StackOverflow")]
        [TestCase(true, "%Stuff.txt%", "MagicStuff.txt", Category = "Tests from StackOverflow")]
        [TestCase(true, "%Stuff.txt%", "MagicStuff.txt.img", Category = "Tests from StackOverflow")]
        [TestCase(true, "%Stuff.txt%", "Stuff.txt.img", Category = "Tests from StackOverflow")]
        [TestCase(false, "%Stuff.txt%", "MagicStuff001.txt.img", Category = "Tests from StackOverflow")]
        [TestCase(true, "%Stuff%.txt", "Stuff.txt", Category = "Tests from StackOverflow")]
        [TestCase(true, "%Stuff%.txt", "MagicStuff.txt", Category = "Tests from StackOverflow")]
        [TestCase(false, "%Stuff%.txt", "MagicStuff.txt.img", Category = "Tests from StackOverflow")]
        [TestCase(false, "%Stuff%.txt", "Stuff.txt.img", Category = "Tests from StackOverflow")]
        [TestCase(false, "%Stuff%.txt", "MagicStuff001.txt.img", Category = "Tests from StackOverflow")]
        [TestCase(true, "%Stuff%.txt", "MagicStuff001.txt", Category = "Tests from StackOverflow")]
        [TestCase(true, "Stuff%.txt%", "Stuff.txt", Category = "Tests from StackOverflow")]
        [TestCase(false, "Stuff%.txt%", "MagicStuff.txt", Category = "Tests from StackOverflow")]
        [TestCase(false, "Stuff%.txt%", "MagicStuff.txt.img", Category = "Tests from StackOverflow")]
        [TestCase(true, "Stuff%.txt%", "Stuff.txt.img", Category = "Tests from StackOverflow")]
        [TestCase(false, "Stuff%.txt%", "MagicStuff001.txt.img", Category = "Tests from StackOverflow")]
        [TestCase(false, "Stuff%.txt%", "MagicStuff001.txt", Category = "Tests from StackOverflow")]
        [TestCase(true, "%Stuff%.txt%", "Stuff.txt", Category = "Tests from StackOverflow")]
        [TestCase(true, "%Stuff%.txt%", "MagicStuff.txt", Category = "Tests from StackOverflow")]
        [TestCase(true, "%Stuff%.txt%", "MagicStuff.txt.img", Category = "Tests from StackOverflow")]
        [TestCase(true, "%Stuff%.txt%", "Stuff.txt.img", Category = "Tests from StackOverflow")]
        [TestCase(true, "%Stuff%.txt%", "MagicStuff001.txt.img", Category = "Tests from StackOverflow")]
        [TestCase(true, "%Stuff%.txt%", "MagicStuff001.txt", Category = "Tests from StackOverflow")]
        [TestCase(true, "_Stuff_.txt_", "1Stuff3.txt4", Category = "Tests from StackOverflow")]
        [TestCase(false, "_Stuff_.txt_", "1Stuff.txt4", Category = "Tests from StackOverflow")]
        [TestCase(false, "_Stuff_.txt_", "1Stuff3.txt", Category = "Tests from StackOverflow")]
        [TestCase(false, "_Stuff_.txt_", "Stuff3.txt4", Category = "Tests from StackOverflow")]
        public void KeepRow_TestsFromStackOverflow(bool expectedResult, string regex,
                                                                                     string value)
        {
            //Arrange
            var mocks = new MockRepository();
            var row = new Row();
            var leftExpression = mocks.Stub();
            var rightExpression = mocks.Stub();

            Cell leftCell = (value != null) ? new Cell(new ColumnHeader("left", "left"), value) : null;
            Cell rightCell = (regex != null) ? new Cell(new ColumnHeader("right", "right"), regex) : null;

            using (mocks.Record())
            {
                leftExpression.Calculate(row);
                LastCall.Return(leftCell);
                rightExpression.Calculate(row);
                LastCall.Return(rightCell);
            }

            //Act
            var predicate = new LikePredicate(leftExpression, rightExpression, '\0');
            bool result = predicate.KeepRow(row);

            //Assert
            Assert.That(result, Is.EqualTo(expectedResult));
        }
    }
}

That’s all.