847 lines
28 KiB
C#
847 lines
28 KiB
C#
// Copyright (c) .NET Foundation. All rights reserved.
|
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
|
using Microsoft.Extensions.Internal;
|
|
using Moq;
|
|
using Xunit;
|
|
|
|
namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
|
{
|
|
public class ViewDataDictionaryTest
|
|
{
|
|
[Fact]
|
|
public void ConstructorWithOneParameterInitializesMembers()
|
|
{
|
|
// Arrange
|
|
var metadataProvider = new EmptyModelMetadataProvider();
|
|
|
|
// Act
|
|
var viewData = new ViewDataDictionary(metadataProvider);
|
|
|
|
// Assert
|
|
Assert.NotNull(viewData.ModelState);
|
|
Assert.NotNull(viewData.TemplateInfo);
|
|
Assert.Null(viewData.Model);
|
|
Assert.NotNull(viewData.ModelMetadata);
|
|
Assert.Empty(viewData);
|
|
}
|
|
|
|
[Fact]
|
|
public void ConstructorInitializesMembers()
|
|
{
|
|
// Arrange
|
|
var metadataProvider = new EmptyModelMetadataProvider();
|
|
var modelState = new ModelStateDictionary();
|
|
|
|
// Act
|
|
var viewData = new ViewDataDictionary(metadataProvider, modelState);
|
|
|
|
// Assert
|
|
Assert.Same(modelState, viewData.ModelState);
|
|
Assert.NotNull(viewData.TemplateInfo);
|
|
Assert.Null(viewData.Model);
|
|
Assert.NotNull(viewData.ModelMetadata);
|
|
Assert.Empty(viewData);
|
|
}
|
|
|
|
[Fact]
|
|
public void Constructor_GetsNewModelMetadata()
|
|
{
|
|
// Arrange
|
|
var metadataProvider = new Mock<IModelMetadataProvider>(MockBehavior.Strict);
|
|
metadataProvider
|
|
.Setup(m => m.GetMetadataForType(typeof(object)))
|
|
.Returns(new EmptyModelMetadataProvider().GetMetadataForType(typeof(object)))
|
|
.Verifiable();
|
|
var modelState = new ModelStateDictionary();
|
|
|
|
// Act
|
|
var viewData = new ViewDataDictionary(metadataProvider.Object, modelState);
|
|
|
|
// Assert
|
|
Assert.NotNull(viewData.ModelMetadata);
|
|
metadataProvider.Verify(m => m.GetMetadataForType(typeof(object)), Times.Once());
|
|
}
|
|
|
|
[Fact]
|
|
public void SetModel_DoesNotGetNewModelMetadata_IfTypeCompatible()
|
|
{
|
|
// Arrange
|
|
var metadataProvider = new Mock<IModelMetadataProvider>(MockBehavior.Strict);
|
|
metadataProvider
|
|
.Setup(m => m.GetMetadataForType(typeof(TestModel)))
|
|
.Returns(new EmptyModelMetadataProvider().GetMetadataForType(typeof(TestModel)))
|
|
.Verifiable();
|
|
var viewData = new TestViewDataDictionary(metadataProvider.Object, typeof(TestModel));
|
|
var model = new TestModel();
|
|
|
|
// Act
|
|
viewData.SetModelPublic(model);
|
|
|
|
// Assert
|
|
Assert.NotNull(viewData.ModelMetadata);
|
|
metadataProvider.Verify(m => m.GetMetadataForType(typeof(TestModel)), Times.Once());
|
|
}
|
|
|
|
[Fact]
|
|
public void SetModel_GetsNewModelMetadata_IfSourceTypeIsObject()
|
|
{
|
|
// Arrange
|
|
var metadataProvider = new Mock<IModelMetadataProvider>(MockBehavior.Strict);
|
|
metadataProvider
|
|
.Setup(m => m.GetMetadataForType(typeof(object)))
|
|
.Returns(new EmptyModelMetadataProvider().GetMetadataForType(typeof(object)))
|
|
.Verifiable();
|
|
metadataProvider
|
|
.Setup(m => m.GetMetadataForType(typeof(TestModel)))
|
|
.Returns(new EmptyModelMetadataProvider().GetMetadataForType(typeof(TestModel)))
|
|
.Verifiable();
|
|
var viewData = new TestViewDataDictionary(metadataProvider.Object);
|
|
var model = new TestModel();
|
|
|
|
// Act
|
|
viewData.SetModelPublic(model);
|
|
|
|
// Assert
|
|
Assert.NotNull(viewData.ModelMetadata);
|
|
|
|
// For the constructor.
|
|
metadataProvider.Verify(m => m.GetMetadataForType(typeof(object)), Times.Once());
|
|
|
|
// For SetModel().
|
|
metadataProvider.Verify(m => m.GetMetadataForType(typeof(TestModel)), Times.Once());
|
|
}
|
|
|
|
public static TheoryData<object, Type> IncompatibleModelData
|
|
{
|
|
get
|
|
{
|
|
// Small "anything but TestModel" grab bag of instances and expected types.
|
|
return new TheoryData<object, Type>
|
|
{
|
|
{ true, typeof(bool) },
|
|
{ 23, typeof(int) },
|
|
{ 43.78, typeof(double) },
|
|
{ "test string", typeof(string) },
|
|
{ new List<int>(), typeof(List<int>) },
|
|
{ new List<string>(), typeof(List<string>) },
|
|
{ new List<TestModel>(), typeof(List<TestModel>) },
|
|
};
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[MemberData(nameof(IncompatibleModelData))]
|
|
public void SetModel_Throws_IfModelIncompatibleWithDeclaredType(object model, Type expectedType)
|
|
{
|
|
// Arrange
|
|
var viewData = new TestViewDataDictionary(new EmptyModelMetadataProvider(), typeof(TestModel));
|
|
|
|
// Act & Assert
|
|
var exception = Assert.Throws<InvalidOperationException>(() => viewData.SetModelPublic(model));
|
|
Assert.Equal(
|
|
$"The model item passed into the ViewDataDictionary is of type '{ model.GetType() }', but this " +
|
|
$"ViewDataDictionary instance requires a model item of type '{ typeof(TestModel) }'.",
|
|
exception.Message);
|
|
}
|
|
|
|
public static TheoryData<object> EnumerableModelData
|
|
{
|
|
get
|
|
{
|
|
var model = new List<TestModel>()
|
|
{
|
|
new TestModel(),
|
|
new TestModel()
|
|
};
|
|
|
|
return new TheoryData<object>
|
|
{
|
|
{ model.Select(t => t) },
|
|
{ model.Where(t => t != null) },
|
|
{ model.SelectMany(t => t.ToString()) },
|
|
{ model.Take(2) },
|
|
{ model.TakeWhile(t => t != null) },
|
|
{ model.Union(model) }
|
|
};
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[MemberData(nameof(EnumerableModelData))]
|
|
public void ModelSetter_DoesNotThrowOnEnumerableModel(object model)
|
|
{
|
|
// Arrange
|
|
var vdd = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
|
|
|
// Act
|
|
vdd.Model = model;
|
|
|
|
// Assert
|
|
Assert.Same(model, vdd.Model);
|
|
}
|
|
|
|
[Fact]
|
|
public void CopyConstructorInitializesModelAndModelMetadataBasedOnSource()
|
|
{
|
|
// Arrange
|
|
var metadataProvider = new EmptyModelMetadataProvider();
|
|
var model = new TestModel();
|
|
var source = new ViewDataDictionary(metadataProvider)
|
|
{
|
|
ModelExplorer = metadataProvider.GetModelExplorerForType(typeof(TestModel), model),
|
|
};
|
|
source["foo"] = "bar";
|
|
source.TemplateInfo.HtmlFieldPrefix = "prefix";
|
|
|
|
// Act
|
|
var viewData = new ViewDataDictionary(source);
|
|
|
|
// Assert
|
|
Assert.NotNull(viewData.ModelState);
|
|
Assert.NotNull(viewData.TemplateInfo);
|
|
Assert.Equal("prefix", viewData.TemplateInfo.HtmlFieldPrefix);
|
|
Assert.NotSame(source.TemplateInfo, viewData.TemplateInfo);
|
|
Assert.Same(model, viewData.Model);
|
|
Assert.NotNull(viewData.ModelMetadata);
|
|
Assert.Equal(typeof(TestModel), viewData.ModelMetadata.ModelType);
|
|
Assert.Same(source.ModelMetadata, viewData.ModelMetadata);
|
|
Assert.Equal(source.Count, viewData.Count);
|
|
Assert.Equal("bar", viewData["foo"]);
|
|
Assert.IsType<CopyOnWriteDictionary<string, object>>(viewData.Data);
|
|
}
|
|
|
|
public static TheoryData<Type, object> CopyModelMetadataData
|
|
{
|
|
get
|
|
{
|
|
// Instances in this data set must have exactly the same type as the corresponding Type or be null.
|
|
// Otherwise the copy constructor ignores the source ModelMetadata.
|
|
return new TheoryData<Type, object>
|
|
{
|
|
{ typeof(int), 23 },
|
|
{ typeof(ulong?), 24ul },
|
|
{ typeof(ushort?), null },
|
|
{ typeof(string), "hello" },
|
|
{ typeof(string), null },
|
|
{ typeof(List<string>), new List<string>() },
|
|
{ typeof(string[]), new string[0] },
|
|
{ typeof(Dictionary<string, object>), new Dictionary<string, object>() },
|
|
};
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[MemberData(nameof(CopyModelMetadataData))]
|
|
public void CopyConstructor_CopiesModelMetadata(Type type, object instance)
|
|
{
|
|
// Arrange
|
|
var metadataProvider = new EmptyModelMetadataProvider();
|
|
var source = new ViewDataDictionary(metadataProvider)
|
|
{
|
|
Model = instance,
|
|
};
|
|
|
|
// Act
|
|
var viewData = new ViewDataDictionary(source);
|
|
|
|
// Assert
|
|
Assert.Same(source.ModelMetadata, viewData.ModelMetadata);
|
|
}
|
|
|
|
[Fact]
|
|
public void CopyConstructor_CopiesModelMetadata_ForTypeObject()
|
|
{
|
|
// Arrange
|
|
var metadataProvider = new EmptyModelMetadataProvider();
|
|
var source = new ViewDataDictionary(metadataProvider);
|
|
|
|
// Act
|
|
var viewData = new ViewDataDictionary(source);
|
|
|
|
// Assert
|
|
Assert.Same(source.ModelMetadata, viewData.ModelMetadata);
|
|
Assert.Equal(typeof(object), viewData.ModelMetadata.ModelType);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(typeof(int), "test string", typeof(string))]
|
|
[InlineData(typeof(string), 23, typeof(int))]
|
|
[InlineData(typeof(IEnumerable<string>), new object[] { "1", "2", "3" }, typeof(object[]))]
|
|
[InlineData(typeof(List<string>), new object[] { 1, 2, 3 }, typeof(object[]))]
|
|
public void ModelSetter_UpdatesModelMetadata_IfModelIncompatibleWithSourceMetadata(
|
|
Type sourceType,
|
|
object model,
|
|
Type expectedType)
|
|
{
|
|
// Arrange
|
|
var metadataProvider = new EmptyModelMetadataProvider();
|
|
var source = new ViewDataDictionary(metadataProvider)
|
|
{
|
|
ModelExplorer = metadataProvider.GetModelExplorerForType(sourceType, model: null),
|
|
};
|
|
var sourceMetadata = source.ModelMetadata;
|
|
var viewData = new ViewDataDictionary(source);
|
|
|
|
// Act
|
|
viewData.Model = model;
|
|
|
|
// Assert
|
|
Assert.NotSame(source.ModelExplorer, viewData.ModelExplorer);
|
|
Assert.NotSame(source.ModelMetadata, viewData.ModelMetadata);
|
|
Assert.Equal(expectedType, viewData.ModelMetadata.ModelType);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(typeof(int), 23)]
|
|
[InlineData(typeof(string), "test string")]
|
|
[InlineData(typeof(IEnumerable<string>), new string[] { "1", "2", "3" })]
|
|
public void ModelSetter_PreservesSourceMetadata_IfModelCompatible(Type sourceType, object model)
|
|
{
|
|
// Arrange
|
|
var metadataProvider = new EmptyModelMetadataProvider();
|
|
var source = new ViewDataDictionary(metadataProvider)
|
|
{
|
|
ModelExplorer = metadataProvider.GetModelExplorerForType(sourceType, model: null),
|
|
};
|
|
var viewData = new ViewDataDictionary(source);
|
|
|
|
// Act
|
|
viewData.Model = model;
|
|
|
|
// Assert
|
|
Assert.NotSame(source.ModelExplorer, viewData.ModelExplorer);
|
|
Assert.Same(source.ModelMetadata, viewData.ModelMetadata);
|
|
}
|
|
|
|
[Fact]
|
|
public void ModelSetter_SameType_UpdatesModelExplorer()
|
|
{
|
|
// Arrange
|
|
var metadataProvider = new EmptyModelMetadataProvider();
|
|
var viewData = new ViewDataDictionary(metadataProvider)
|
|
{
|
|
Model = 3,
|
|
};
|
|
|
|
var originalMetadata = viewData.ModelMetadata;
|
|
var originalExplorer = viewData.ModelExplorer;
|
|
|
|
// Act
|
|
viewData.Model = 5;
|
|
|
|
// Assert
|
|
Assert.NotNull(viewData.ModelMetadata);
|
|
Assert.NotNull(viewData.ModelExplorer);
|
|
Assert.Equal(5, viewData.Model);
|
|
Assert.Equal(5, viewData.ModelExplorer.Model);
|
|
Assert.Same(originalMetadata, viewData.ModelMetadata);
|
|
Assert.NotSame(originalExplorer, viewData.ModelExplorer);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(typeof(object))]
|
|
[InlineData(typeof(string))]
|
|
public void ModelSetter_DifferentType_UpdatesModelMetadata(Type originalMetadataType)
|
|
{
|
|
// Arrange
|
|
var metadataProvider = new EmptyModelMetadataProvider();
|
|
var metadata = metadataProvider.GetMetadataForType(originalMetadataType);
|
|
var explorer = new ModelExplorer(metadataProvider, metadata, model: null);
|
|
var viewData = new TestViewDataDictionary(metadataProvider)
|
|
{
|
|
ModelExplorer = explorer,
|
|
};
|
|
|
|
// Act
|
|
viewData.Model = true;
|
|
|
|
// Assert
|
|
Assert.NotNull(viewData.ModelExplorer);
|
|
Assert.NotNull(viewData.ModelMetadata);
|
|
Assert.NotSame(explorer, viewData.ModelExplorer);
|
|
Assert.Equal(typeof(bool), viewData.ModelMetadata.ModelType);
|
|
|
|
var model = Assert.IsType<bool>(viewData.Model);
|
|
Assert.True(model);
|
|
}
|
|
|
|
[Fact]
|
|
public void ModelSetter_SetNullableNonNull_UpdatesModelExplorer()
|
|
{
|
|
// Arrange
|
|
var metadataProvider = new EmptyModelMetadataProvider();
|
|
var metadata = metadataProvider.GetMetadataForType(typeof(bool?));
|
|
var explorer = new ModelExplorer(metadataProvider, metadata, model: null);
|
|
var viewData = new ViewDataDictionary(metadataProvider)
|
|
{
|
|
ModelExplorer = explorer,
|
|
};
|
|
|
|
// Act
|
|
viewData.Model = true;
|
|
|
|
// Assert
|
|
Assert.NotNull(viewData.ModelMetadata);
|
|
Assert.NotNull(viewData.ModelExplorer);
|
|
Assert.Same(metadata, viewData.ModelMetadata);
|
|
Assert.NotSame(explorer, viewData.ModelExplorer);
|
|
Assert.Equal(viewData.Model, viewData.ModelExplorer.Model);
|
|
|
|
var model = Assert.IsType<bool>(viewData.Model);
|
|
Assert.True(model);
|
|
}
|
|
|
|
[Fact]
|
|
public void ModelSetter_SetNonNullableToNull_Throws()
|
|
{
|
|
// Arrange
|
|
var viewData = new TestViewDataDictionary(new EmptyModelMetadataProvider(), typeof(int));
|
|
|
|
// Act & Assert
|
|
var exception = Assert.Throws<InvalidOperationException>(() => viewData.SetModelPublic(value: null));
|
|
Assert.Equal(
|
|
"The model item passed is null, but this ViewDataDictionary instance requires a non-null model item " +
|
|
$"of type '{ typeof(int) }'.",
|
|
exception.Message);
|
|
}
|
|
|
|
[Fact]
|
|
public void ModelSetter_SameType_BoxedValueTypeUpdatesModelExplorer()
|
|
{
|
|
// Arrange
|
|
var metadataProvider = new EmptyModelMetadataProvider();
|
|
var viewData = new ViewDataDictionary(metadataProvider)
|
|
{
|
|
Model = 3,
|
|
};
|
|
|
|
var originalMetadata = viewData.ModelMetadata;
|
|
var originalExplorer = viewData.ModelExplorer;
|
|
|
|
// Act
|
|
viewData.Model = 3; // This is the same value, but it's in a different box.
|
|
|
|
// Assert
|
|
Assert.NotNull(viewData.ModelMetadata);
|
|
Assert.NotNull(viewData.ModelExplorer);
|
|
Assert.Equal(3, viewData.Model);
|
|
Assert.Equal(3, viewData.ModelExplorer.Model);
|
|
Assert.Same(originalMetadata, viewData.ModelMetadata);
|
|
Assert.NotSame(originalExplorer, viewData.ModelExplorer);
|
|
}
|
|
|
|
[Fact]
|
|
public void ModelSetter_SameModel_NoChanges()
|
|
{
|
|
// Arrange
|
|
var model = "Hello";
|
|
|
|
var metadataProvider = new EmptyModelMetadataProvider();
|
|
var viewData = new ViewDataDictionary(metadataProvider)
|
|
{
|
|
Model = model,
|
|
};
|
|
|
|
var originalMetadata = viewData.ModelMetadata;
|
|
var originalExplorer = viewData.ModelExplorer;
|
|
|
|
// Act
|
|
viewData.Model = model;
|
|
|
|
// Assert
|
|
Assert.NotNull(viewData.ModelMetadata);
|
|
Assert.Equal("Hello", viewData.Model);
|
|
Assert.Same(originalMetadata, viewData.ModelMetadata);
|
|
Assert.Same(originalExplorer, viewData.ModelExplorer);
|
|
}
|
|
|
|
public static TheoryData<object, string, object> Eval_EvaluatesExpressionsData
|
|
{
|
|
get
|
|
{
|
|
return new TheoryData<object, string, object>
|
|
{
|
|
{
|
|
new { Foo = "Bar" },
|
|
"Foo",
|
|
"Bar"
|
|
},
|
|
{
|
|
new { Foo = new Dictionary<string, object> { { "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 Eval_ReturnsModel_IfExpressionIsNullOrEmpty(string expression)
|
|
{
|
|
// Arrange
|
|
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
|
var model = new object();
|
|
viewData.Model = model;
|
|
|
|
// Act
|
|
var result = viewData.Eval(expression);
|
|
|
|
// Assert
|
|
Assert.Same(model, result);
|
|
}
|
|
|
|
[Fact]
|
|
public void EvalWithCompoundExpressionAndDictionarySubExpressionChoosesDictionaryValue()
|
|
{
|
|
// Arrange
|
|
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
|
viewData.Add("Foo", new Dictionary<string, object> { { "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<string, object> { { "NotBar", "Baz" } });
|
|
|
|
// Act
|
|
var result = viewData.Eval("Foo.Bar");
|
|
|
|
// Assert
|
|
Assert.Null(result);
|
|
}
|
|
|
|
[Fact]
|
|
public void EvalWithNestedDictionariesEvalCorrectly()
|
|
{
|
|
// Arrange
|
|
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
|
var value = new Dictionary<string, object>
|
|
{
|
|
["Bar"] = new Dictionary<string, string>
|
|
{
|
|
{ "Baz", "Quux" }
|
|
}
|
|
};
|
|
viewData.Add("Foo", value);
|
|
|
|
// 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
|
|
{
|
|
}
|
|
|
|
private class Person
|
|
{
|
|
public string Name { get; set; }
|
|
}
|
|
|
|
private class TestViewDataDictionary : ViewDataDictionary
|
|
{
|
|
public TestViewDataDictionary(IModelMetadataProvider metadataProvider)
|
|
: base(metadataProvider)
|
|
{
|
|
}
|
|
|
|
public TestViewDataDictionary(IModelMetadataProvider metadataProvider, Type declaredModelType)
|
|
: base(metadataProvider, declaredModelType)
|
|
{
|
|
}
|
|
|
|
public void SetModelPublic(object value)
|
|
{
|
|
SetModel(value);
|
|
}
|
|
}
|
|
|
|
private class TheQueryStringParam
|
|
{
|
|
public string Name { get; set; }
|
|
public string Value { get; set; }
|
|
public string Model { get; set; }
|
|
}
|
|
}
|
|
}
|