How to verify that an expression is short-circuited

I have an extension method with the following signature:

public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) { ... } 

I wrote a test case for it, which ensures that both expressions are actually combined. At least so that the new expression I get works.

Now, I would like to write another test case that simply ensures that the method uses a short-circuited version of and . Any clue how can I do this?

I thought I could just do something like this:

  [Test] public void And_PredicatesAreShortCircuited() { var predicateNotUsed = true; Expression<Func<int, bool>> a = x => false; Expression<Func<int, bool>> b = x => { predicateNotUsed = false; return true; }; var foo = new[] { 1, 2, 3, 4, 5, 6, 7 } .Where(a.And(b).Compile()) .ToArray(); Assert.That(predicateNotUsed); } 

But I get a giant red squiggly under this whole body for b , stating that "a lambda expression with an operator body cannot be converted to an expression tree." So ... any options? Or is it an impossible test to write?

+4
source share
1 answer

A simple suggestion: use a reference type instead of a value type and look for it along a path that you do not want to follow. Pass a null value and see if it throws an exception :)

 [Test] public void And_PredicatesAreShortCircuited() { Expression<Func<string, bool>> a = x => false; Expression<Func<string, bool>> b = x => x.Length > 10; var foo = new[] { null, null } .Where(a.And(b).Compile()) .ToArray(); } 

Another alternative could be to use some side function on the input (for example, passing to something that can be modified by the expression tree), but I think this will probably be the easiest way :)

Or another idea:

 public T NonVoidFail(T x) { Assert.Fail("I shouldn't be called"); return x; // Will never happen } 

Then:

 [Test] public void And_PredicatesAreShortCircuited() { Expression<Func<int, bool>> a = x => false; Expression<Func<int, bool>> b = x => NonVoidFail(x); var foo = new[] { 1, 2, 3, 4, 5, 6, 7 } .Where(a.And(b).Compile()) .ToArray(); } 

This is the same principle, but it will give you a more pleasant exception :)

+8
source

All Articles