From bd82e584f0f9006af039ac9de7d6128f6588eb31 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 17 Oct 2014 15:30:19 -0700 Subject: [PATCH] Porting over unit tests for ViewDataDictionary.Eval Partial fix for #453 --- .../Properties/Resources.Designer.cs | 4 +- src/Microsoft.AspNet.Mvc.Core/Resources.resx | 2 +- .../ControllerTests.cs | 8 +- .../ViewDataDictionaryTest.cs | 347 ++++++++++++++++++ 4 files changed, 354 insertions(+), 7 deletions(-) diff --git a/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs b/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs index 3ac0ec9de0..ebeb1fbcea 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs @@ -443,7 +443,7 @@ namespace Microsoft.AspNet.Mvc.Core } /// - /// The value cannot be null or empty. + /// Value cannot be null or empty. /// internal static string ArgumentCannotBeNullOrEmpty { @@ -451,7 +451,7 @@ namespace Microsoft.AspNet.Mvc.Core } /// - /// The value cannot be null or empty. + /// Value cannot be null or empty. /// internal static string FormatArgumentCannotBeNullOrEmpty() { diff --git a/src/Microsoft.AspNet.Mvc.Core/Resources.resx b/src/Microsoft.AspNet.Mvc.Core/Resources.resx index cb633c1cca..9f9b9be8e3 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Resources.resx +++ b/src/Microsoft.AspNet.Mvc.Core/Resources.resx @@ -199,7 +199,7 @@ The action descriptor must be of type '{0}'. - The value cannot be null or empty. + Value cannot be null or empty. The '{0}' property of '{1}' must not be null. diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ControllerTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ControllerTests.cs index 326c56cebc..3631a53391 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ControllerTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ControllerTests.cs @@ -96,8 +96,8 @@ namespace Microsoft.AspNet.Mvc.Test var controller = new Controller(); // Act & Assert - ExceptionAssert.ThrowsArgument( - () => controller.Redirect(url: url), "url", "The value cannot be null or empty"); + ExceptionAssert.ThrowsArgumentNullOrEmpty( + () => controller.Redirect(url: url), "url"); } [Theory] @@ -109,8 +109,8 @@ namespace Microsoft.AspNet.Mvc.Test var controller = new Controller(); // Act & Assert - ExceptionAssert.ThrowsArgument( - () => controller.RedirectPermanent(url: url), "url", "The value cannot be null or empty"); + ExceptionAssert.ThrowsArgumentNullOrEmpty( + () => controller.RedirectPermanent(url: url), "url"); } [Fact] diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ViewDataDictionaryTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ViewDataDictionaryTest.cs index 4198c1ba7e..7223b235bd 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ViewDataDictionaryTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ViewDataDictionaryTest.cs @@ -2,7 +2,10 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections; +using System.Collections.Generic; using Microsoft.AspNet.Mvc.ModelBinding; +using Microsoft.AspNet.Testing; using Moq; using Xunit; @@ -156,6 +159,343 @@ namespace Microsoft.AspNet.Mvc.Core Assert.IsType>(viewData.Data); } + public static TheoryData Eval_EvaluatesExpressionsData + { + get + { + return new TheoryData + { + { + new { Foo = "Bar" }, + "Foo", + "Bar" + }, + { + new { Foo = new Dictionary { { "Bar", "Baz" } } }, + "Foo.Bar", + "Baz" + }, + { + new { Foo = new { Bar = "Baz" } }, + "Foo.Bar", + "Baz" + } + }; + } + } + + [Theory] + [MemberData(nameof(Eval_EvaluatesExpressionsData))] + public void Eval_EvaluatesExpressions(object model, string expression, object expected) + { + // Arrange + var viewData = GetViewDataDictionary(model); + + // Act + var result = viewData.Eval(expression); + + // Assert + Assert.Equal(expected, result); + } + + [Fact] + public void EvalReturnsNullIfExpressionDoesNotMatch() + { + // Arrange + var model = new { Foo = new { Biz = "Baz" } }; + var viewData = GetViewDataDictionary(model); + + // Act + var result = viewData.Eval("Foo.Bar"); + + // Assert + Assert.Null(result); + } + + [Fact] + public void EvalEvaluatesDictionaryThenModel() + { + // Arrange + var model = new { Foo = "NotBar" }; + var viewData = GetViewDataDictionary(model); + viewData.Add("Foo", "Bar"); + + // Act + var result = viewData.Eval("Foo"); + + // Assert + Assert.Equal("Bar", result); + } + + [Fact] + public void EvalReturnsValueJustAdded() + { + // Arrange + var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider()); + viewData.Add("Foo", "Blah"); + + // Act + var result = viewData.Eval("Foo"); + + // Assert + Assert.Equal("Blah", result); + } + + [Fact] + public void EvalWithCompoundExpressionReturnsIndexedValue() + { + // Arrange + var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider()); + viewData.Add("Foo.Bar", "Baz"); + + // Act + var result = viewData.Eval("Foo.Bar"); + + // Assert + Assert.Equal("Baz", result); + } + + [Fact] + public void EvalWithCompoundExpressionReturnsPropertyOfAddedObject() + { + // Arrange + var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider()); + viewData.Add("Foo", new { Bar = "Baz" }); + + // Act + var result = viewData.Eval("Foo.Bar"); + + // Assert + Assert.Equal("Baz", result); + } + + [Fact] + public void EvalWithCompoundIndexExpressionReturnsEval() + { + // Arrange + var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider()); + viewData.Add("Foo.Bar", new { Baz = "Quux" }); + + // Act + var result = viewData.Eval("Foo.Bar.Baz"); + + // Assert + Assert.Equal("Quux", result); + } + + [Fact] + public void EvalWithCompoundIndexAndCompoundExpressionReturnsValue() + { + // Arrange + var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider()); + viewData.Add("Foo.Bar", new { Baz = new { Blah = "Quux" } }); + + // Act + var result = viewData.Eval("Foo.Bar.Baz.Blah"); + + // Assert + Assert.Equal("Quux", result); + } + + // Make sure that dict["foo.bar"] gets chosen before dict["foo"]["bar"] + [Fact] + public void EvalChoosesValueInDictionaryOverOtherValue() + { + // Arrange + var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider()) + { + { "Foo", new { Bar = "Not Baz" } }, + { "Foo.Bar", "Baz" } + }; + + // Act + var result = viewData.Eval("Foo.Bar"); + + // Assert + Assert.Equal("Baz", result); + } + + // Make sure that dict["foo.bar"]["baz"] gets chosen before dict["foo"]["bar"]["baz"] + [Fact] + public void EvalChoosesCompoundValueInDictionaryOverOtherValues() + { + // Arrange + var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider()) + { + { "Foo", new { Bar = new { Baz = "Not Quux" } } }, + { "Foo.Bar", new { Baz = "Quux" } } + }; + + // Act + var result = viewData.Eval("Foo.Bar.Baz"); + + // Assert + Assert.Equal("Quux", result); + } + + // Make sure that dict["foo.bar"]["baz"] gets chosen before dict["foo"]["bar.baz"] + [Fact] + public void EvalChoosesCompoundValueInDictionaryOverOtherValuesWithCompoundProperty() + { + // Arrange + var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider()) + { + { "Foo", new Person() }, + { "Foo.Bar", new { Baz = "Quux" } } + }; + + // Act + var result = viewData.Eval("Foo.Bar.Baz"); + + // Assert + Assert.Equal("Quux", result); + } + + [Theory] + [InlineData(null)] + [InlineData("")] + public void EvalThrowsIfExpressionIsNullOrEmpty(string expression) + { + // Arrange + var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider()); + + // Act & Assert + ExceptionAssert.ThrowsArgumentNullOrEmpty(() => viewData.Eval(expression), "expression"); + } + + [Fact] + public void EvalWithCompoundExpressionAndDictionarySubExpressionChoosesDictionaryValue() + { + // Arrange + var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider()); + viewData.Add("Foo", new Dictionary { { "Bar", "Baz" } }); + + // Act + var result = viewData.Eval("Foo.Bar"); + + // Assert + Assert.Equal("Baz", result); + } + + [Fact] + public void EvalWithDictionaryAndNoMatchReturnsNull() + { + // Arrange + var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider()); + viewData.Add("Foo", new Dictionary { { "NotBar", "Baz" } }); + + // Act + var result = viewData.Eval("Foo.Bar"); + + // Assert + Assert.Null(result); + } + + [Fact] + public void EvalWithNestedDictionariesEvalCorrectly() + { + // Arrange + var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider()); + viewData.Add("Foo", new Dictionary { { "Bar", new Hashtable { { "Baz", "Quux" } } } }); + + // Act + var result = viewData.Eval("Foo.Bar.Baz"); + + // Assert + Assert.Equal("Quux", result); + } + + [Fact] + public void EvalFormatWithNullValueReturnsEmptyString() + { + // Arrange + var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider()); + + // Act + var formattedValue = viewData.Eval("foo", "for{0}mat"); + + // Assert + Assert.Empty(formattedValue); + } + + [Fact] + public void EvalFormatWithEmptyFormatReturnsViewData() + { + // Arrange + var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider()); + viewData["foo"] = "value"; + + // Act + var formattedValue = viewData.Eval("foo", string.Empty); + + // Assert + Assert.Equal("value", formattedValue); + } + + [Fact] + public void EvalFormatWithFormatReturnsFormattedViewData() + { + // Arrange + var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider()); + viewData["foo"] = "value"; + + // Act + var formattedValue = viewData.Eval("foo", "for{0}mat"); + + // Assert + Assert.Equal("forvaluemat", formattedValue); + } + + [Fact] + public void EvalPropertyNamedModel() + { + // Arrange + var model = new TheQueryStringParam + { + Name = "The Name", + Value = "The Value", + Model = "The Model", + }; + var viewData = GetViewDataDictionary(model); + viewData["Title"] = "Home Page"; + viewData["Message"] = "Welcome to ASP.NET MVC!"; + + // Act + var result = viewData.Eval("Model"); + + // Assert + Assert.Equal("The Model", result); + } + + [Fact] + public void EvalSubPropertyNamedValueInModel() + { + // Arrange + var model = new TheQueryStringParam + { + Name = "The Name", + Value = "The Value", + Model = "The Model", + }; + var viewData = GetViewDataDictionary(model); + viewData["Title"] = "Home Page"; + viewData["Message"] = "Welcome to ASP.NET MVC!"; + + // Act + var result = viewData.Eval("Value"); + + // Assert + Assert.Equal("The Value", result); + } + + private static ViewDataDictionary GetViewDataDictionary(object model) + { + return new ViewDataDictionary(new EmptyModelMetadataProvider()) + { + Model = model + }; + } + private class TestModel { } @@ -178,5 +518,12 @@ namespace Microsoft.AspNet.Mvc.Core SetModel(value); } } + + private class TheQueryStringParam + { + public string Name { get; set; } + public string Value { get; set; } + public string Model { get; set; } + } } } \ No newline at end of file