Skip to content

Commit fd72d54

Browse files
committed
Merge pull request #39 from ByteBlast/master
Beginnings of #25.
2 parents ed98e0e + 10cee9b commit fd72d54

File tree

7 files changed

+234
-6
lines changed

7 files changed

+234
-6
lines changed
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
using NUnit.Framework;
2+
using System;
3+
using System.Linq.Expressions;
4+
using TestStack.FluentMVCTesting.Internal;
5+
6+
namespace TestStack.FluentMVCTesting.Tests.Internal
7+
{
8+
[TestFixture]
9+
public class ExpressionInspectorShould
10+
{
11+
[Test]
12+
public void Correctly_parse_equality_comparison_with_string_operands()
13+
{
14+
Expression<Func<string, bool>> func = text => text == "any";
15+
ExpressionInspector sut = new ExpressionInspector();
16+
var actual = sut.Inspect(func);
17+
Assert.AreEqual("text => (text == \"any\")", actual);
18+
}
19+
20+
[Test]
21+
public void Correctly_parse_equality_comparison_with_int_operands()
22+
{
23+
Expression<Func<int, bool>> func = number => number == 5;
24+
ExpressionInspector sut = new ExpressionInspector();
25+
var actual = sut.Inspect(func);
26+
Assert.AreEqual("number => (number == 5)", actual);
27+
}
28+
29+
[Test]
30+
public void Correctly_parse_equality_comparison_with_property_operand()
31+
{
32+
Expression<Func<PostViewModel, bool>> func = post => post.Title == "A";
33+
ExpressionInspector sut = new ExpressionInspector();
34+
var actual = sut.Inspect(func);
35+
Assert.AreEqual("post => (post.Title == \"A\")", actual);
36+
}
37+
38+
[Test]
39+
public void Correctly_parse_equality_comparison_with_two_property_operands()
40+
{
41+
Expression<Func<PostViewModel, bool>> func = post =>
42+
post.Title == post.Slug;
43+
ExpressionInspector sut = new ExpressionInspector();
44+
var actual = sut.Inspect(func);
45+
Assert.AreEqual("post => (post.Title == post.Slug)", actual);
46+
}
47+
48+
[Test]
49+
public void Correctly_parse_equality_comparison_with_captured_constant_operand()
50+
{
51+
const int Number = 5;
52+
Expression<Func<int, bool>> func = number => number == Number;
53+
ExpressionInspector sut = new ExpressionInspector();
54+
var actual = sut.Inspect(func);
55+
Assert.AreEqual(string.Concat("number => (number == ", Number, ")"), actual);
56+
}
57+
58+
[Test]
59+
public void Correctly_parse_inequality_comparison()
60+
{
61+
Expression<Func<int, bool>> func = number => number != 5;
62+
ExpressionInspector sut = new ExpressionInspector();
63+
var actual = sut.Inspect(func);
64+
Assert.AreEqual("number => (number != 5)", actual);
65+
}
66+
67+
[Test]
68+
public void Correctly_parse_relational_comparison()
69+
{
70+
Expression<Func<int, bool>> func = number => number < 5;
71+
ExpressionInspector sut = new ExpressionInspector();
72+
var actual = sut.Inspect(func);
73+
Assert.AreEqual("number => (number < 5)", actual);
74+
}
75+
76+
[Test]
77+
public void Correctly_parse_expression_whose_source_text_contains_parentheses()
78+
{
79+
Expression<Func<PostViewModel, bool>> func = post => post.Title.Contains("");
80+
ExpressionInspector sut = new ExpressionInspector();
81+
var actual = sut.Inspect(func);
82+
Assert.AreEqual("post => post.Title.Contains(\"\")", actual);
83+
}
84+
85+
[Test]
86+
public void Correctly_parse_null_coalescing_operator()
87+
{
88+
Expression<Func<string, bool>> func =
89+
text => text == ("" ?? "a");
90+
ExpressionInspector sut = new ExpressionInspector();
91+
var actual = sut.Inspect(func);
92+
Assert.AreEqual("text => (text == (\"\" ?? \"a\"))", actual);
93+
}
94+
95+
[Test]
96+
public void Correctly_parse_conditional_or_operator()
97+
{
98+
Expression<Func<string, bool>> func =
99+
text => text == "any" || text.Length == 3;
100+
ExpressionInspector sut = new ExpressionInspector();
101+
var actual = sut.Inspect(func);
102+
Assert.AreEqual("text => ((text == \"any\") || (text.Length == 3))", actual);
103+
}
104+
105+
[Test]
106+
public void Correctly_parse_two_conditional_or_operators()
107+
{
108+
Expression<Func<string, bool>> func =
109+
text => text == "any" || text.Length == 3 || text.Length == 9;
110+
ExpressionInspector sut = new ExpressionInspector();
111+
var actual = sut.Inspect(func);
112+
Assert.AreEqual(
113+
"text => (((text == \"any\") || (text.Length == 3)) || (text.Length == 9))", actual);
114+
}
115+
116+
[Test]
117+
public void Correctly_parse_conditional_and_operator()
118+
{
119+
Expression<Func<string, bool>> func =
120+
text => text == "any" && text.Length == 3;
121+
ExpressionInspector sut = new ExpressionInspector();
122+
var actual = sut.Inspect(func);
123+
Assert.AreEqual("text => ((text == \"any\") && (text.Length == 3))", actual);
124+
}
125+
126+
[Test]
127+
public void Correctly_parse_logical_and_operator()
128+
{
129+
Expression<Func<string, bool>> func =
130+
text => text == "any" & text.Length == 3;
131+
ExpressionInspector sut = new ExpressionInspector();
132+
var actual = sut.Inspect(func);
133+
Assert.AreEqual("text => ((text == \"any\") & (text.Length == 3))", actual);
134+
}
135+
136+
[Test]
137+
public void Correctly_parse_logical_or_operator()
138+
{
139+
Expression<Func<string, bool>> func =
140+
text => text == "any" | text.Length == 3;
141+
ExpressionInspector sut = new ExpressionInspector();
142+
var actual = sut.Inspect(func);
143+
Assert.AreEqual("text => ((text == \"any\") | (text.Length == 3))", actual);
144+
}
145+
146+
[Test]
147+
public void Not_mistake_property_called_OrElse_for_conditional_or_operator()
148+
{
149+
Expression<Func<PostViewModel, bool>> func =
150+
post => post.Title == "" || post.OrElse == "";
151+
ExpressionInspector sut = new ExpressionInspector();
152+
var actual = sut.Inspect(func);
153+
Assert.AreEqual("post => ((post.Title == \"\") || (post.OrElse == \"\"))", actual);
154+
}
155+
156+
[Test]
157+
public void Correctly_parse_logical_xor_operator()
158+
{
159+
Expression<Func<string, bool>> func =
160+
text => text == "any" ^ text.Length == 3;
161+
ExpressionInspector sut = new ExpressionInspector();
162+
var actual = sut.Inspect(func);
163+
Assert.AreEqual("text => ((text == \"any\") ^ (text.Length == 3))", actual);
164+
}
165+
}
166+
167+
public class PostViewModel
168+
{
169+
public string Title { get; set; }
170+
public string Slug { get; set; }
171+
172+
public string OrElse { get; set; }
173+
}
174+
}

TestStack.FluentMVCTesting.Tests/TestStack.FluentMVCTesting.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
<Compile Include="ControllerResultTestTests\ShouldReturnEmptyResultTests.cs" />
9090
<Compile Include="ControllerResultTestTests\ShouldReturnJsonTests.cs" />
9191
<Compile Include="ControllerResultTestTests\ShouldReturnContentTests.cs" />
92+
<Compile Include="Internal\ExpressionInspectorTests.cs" />
9293
<Compile Include="RouteValueDictionaryExtensionsTests.cs" />
9394
<Compile Include="TempDataResultTest.cs" />
9495
<Compile Include="TestControllers\AsyncController.cs" />

TestStack.FluentMVCTesting.Tests/ViewResultTestTests.cs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Web.Mvc;
1+
using System.Text.RegularExpressions;
2+
using System.Web.Mvc;
23
using NUnit.Framework;
34

45
namespace TestStack.FluentMVCTesting.Tests
@@ -71,7 +72,26 @@ public void Check_for_invalid_model_using_predicate()
7172
var exception = Assert.Throws<ViewResultModelAssertionException>(() =>
7273
_viewResultTest.WithModel<TestViewModel>(m => m.Property1 == null)
7374
);
74-
Assert.That(exception.Message, Is.EqualTo("Expected view model to pass the given condition, but it failed."));
75+
Assert.That(exception.Message, Is.EqualTo(string.Format("Expected view model {{\"Property1\":\"{0}\",\"Property2\":{1}}} to pass the given condition (m => (m.Property1 == null)), but it failed.", _model.Property1, _model.Property2)));
76+
}
77+
78+
[Test]
79+
public void Check_for_invalid_model_using_predicate_with_conditional_or()
80+
{
81+
var exception = Assert.Throws<ViewResultModelAssertionException>(() =>
82+
_viewResultTest.WithModel<TestViewModel>(m => m.Property1 == null || m.Property2 == 1)
83+
);
84+
Assert.That(exception.Message, Is.EqualTo(string.Format("Expected view model {{\"Property1\":\"{0}\",\"Property2\":{1}}} to pass the given condition (m => ((m.Property1 == null) || (m.Property2 == 1))), but it failed.", _model.Property1, _model.Property2)));
85+
}
86+
87+
[Test]
88+
public void Check_for_invalid_model_using_predicate_with_primitive_operand()
89+
{
90+
_viewResult.ViewData.Model = "abc";
91+
var exception = Assert.Throws<ViewResultModelAssertionException>(() =>
92+
_viewResultTest.WithModel<string>(m => m == "ab")
93+
);
94+
Assert.That(exception.Message, Is.EqualTo(string.Format("Expected view model \"{0}\" to pass the given condition (m => (m == \"ab\")), but it failed.", _viewResult.ViewData.Model)));
7595
}
7696

7797
[Test]
@@ -94,7 +114,7 @@ public void Run_any_assertions_on_the_model()
94114
}
95115
}
96116

97-
class InvalidViewModel {}
117+
class InvalidViewModel { }
98118
public class TestViewModel
99119
{
100120
public string Property1 { get; set; }
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System.Linq.Expressions;
2+
3+
namespace TestStack.FluentMVCTesting.Internal
4+
{
5+
internal class ExpressionInspector
6+
{
7+
internal string Inspect(LambdaExpression expression)
8+
{
9+
return expression.ToString()
10+
.Replace(" OrElse ", " || ")
11+
.Replace(" AndAlso ", " && ")
12+
.Replace(" Or ", " | ")
13+
.Replace(" And ", " & ");
14+
}
15+
}
16+
}

TestStack.FluentMvcTesting/Properties/AssemblyInfo.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,6 @@
3434
// [assembly: AssemblyVersion("1.0.*")]
3535
[assembly: AssemblyVersion("1.0.0.0")]
3636
[assembly: AssemblyFileVersion("1.0.0.0")]
37+
[assembly: InternalsVisibleTo("TestStack.FluentMVCTesting.Tests")]
38+
[assembly: InternalsVisibleTo("TestStack.FluentMVCTesting.Mvc3.Tests")]
39+
[assembly: InternalsVisibleTo("TestStack.FluentMVCTesting.Mvc4.Tests")]

TestStack.FluentMvcTesting/TestStack.FluentMVCTesting.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
<Compile Include="ControllerResultTest\ShouldReturnContent.cs" />
8484
<Compile Include="ControllerResultTest\ShouldReturnEmptyResult.cs" />
8585
<Compile Include="ControllerResultTest\ShouldReturnJson.cs" />
86+
<Compile Include="Internal\ExpressionInspector.cs" />
8687
<Compile Include="RouteValueDictionaryExtension.cs" />
8788
<Compile Include="ControllerExtensions.cs" />
8889
<Compile Include="ControllerResultTest\ControllerResultTest.cs" />

TestStack.FluentMvcTesting/ViewResultTest.cs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
using System;
2+
using System.Linq.Expressions;
3+
using System.Text.RegularExpressions;
4+
using System.Web.Helpers;
25
using System.Web.Mvc;
6+
using TestStack.FluentMVCTesting.Internal;
37

48
namespace TestStack.FluentMVCTesting
59
{
@@ -37,13 +41,22 @@ public ModelTest<TModel> WithModel<TModel>(TModel expectedModel) where TModel :
3741
return test;
3842
}
3943

40-
public ModelTest<TModel> WithModel<TModel>(Func<TModel, bool> predicate) where TModel : class
44+
public ModelTest<TModel> WithModel<TModel>(Expression<Func<TModel, bool>> predicate) where TModel : class
4145
{
4246
var test = WithModel<TModel>();
4347

4448
var model = _viewResult.Model as TModel;
45-
if (!predicate(model))
46-
throw new ViewResultModelAssertionException("Expected view model to pass the given condition, but it failed.");
49+
50+
var inspector = new ExpressionInspector();
51+
var modelLex = Json.Encode(model);
52+
var predicateLex = inspector.Inspect(predicate);
53+
var compiledPredicate = predicate.Compile();
54+
55+
if (!compiledPredicate(model))
56+
throw new ViewResultModelAssertionException(string.Format(
57+
"Expected view model {0} to pass the given condition ({1}), but it failed.",
58+
modelLex,
59+
predicateLex));
4760

4861
return test;
4962
}

0 commit comments

Comments
 (0)