// Copyright (c) Microsoft Open Technologies, Inc. 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; using System.Collections.Generic; using Microsoft.AspNet.Http; using Moq; using Xunit; namespace Microsoft.AspNet.Mvc { public class SessionStateTempDataProviderTest { [Fact] public void Load_NullSession_ReturnsEmptyDictionary() { // Arrange var testProvider = new SessionStateTempDataProvider(); // Act var tempDataDictionary = testProvider.LoadTempData( GetHttpContext(session: null, sessionEnabled: true)); // Assert Assert.Empty(tempDataDictionary); } [Fact] public void Load_NonNullSession_NoSessionData_ReturnsEmptyDictionary() { // Arrange var testProvider = new SessionStateTempDataProvider(); // Act var tempDataDictionary = testProvider.LoadTempData( GetHttpContext(Mock.Of())); // Assert Assert.Empty(tempDataDictionary); } [Fact] public void Save_NullSession_NullDictionary_DoesNotThrow() { // Arrange var testProvider = new SessionStateTempDataProvider(); // Act & Assert (does not throw) testProvider.SaveTempData(GetHttpContext(session: null, sessionEnabled: false), null); } [Fact] public void Save_NullSession_EmptyDictionary_DoesNotThrow() { // Arrange var testProvider = new SessionStateTempDataProvider(); // Act & Assert (does not throw) testProvider.SaveTempData( GetHttpContext(session: null, sessionEnabled: false), new Dictionary()); } [Fact] public void Save_NullSession_NonEmptyDictionary_Throws() { // Arrange var testProvider = new SessionStateTempDataProvider(); // Act & Assert Assert.Throws(() => { testProvider.SaveTempData( GetHttpContext(session: null, sessionEnabled: false), new Dictionary { { "foo", "bar" } } ); }); } public static TheoryData InvalidTypes { get { return new TheoryData { { new object(), typeof(object) }, { new object[3], typeof(object) }, { new TestItem(), typeof(TestItem) }, { new List(), typeof(TestItem) }, { new Dictionary(), typeof(TestItem) }, }; } } [Theory] [MemberData(nameof(InvalidTypes))] public void EnsureObjectCanBeSerialized_InvalidType_Throws(object value, Type type) { // Arrange var testProvider = new SessionStateTempDataProvider(); // Act & Assert var exception = Assert.Throws(() => { testProvider.EnsureObjectCanBeSerialized(value); }); Assert.Equal($"The '{typeof(SessionStateTempDataProvider).FullName}' cannot serialize an object of type '{type}' to session state.", exception.Message); } public static TheoryData InvalidDictionaryTypes { get { return new TheoryData { { new Dictionary(), typeof(int) }, { new Dictionary(), typeof(Uri) }, { new Dictionary(), typeof(object) }, { new Dictionary(), typeof(TestItem) } }; } } [Theory] [MemberData(nameof(InvalidDictionaryTypes))] public void EnsureObjectCanBeSerialized_InvalidDictionaryType_Throws(object value, Type type) { // Arrange var testProvider = new SessionStateTempDataProvider(); // Act & Assert var exception = Assert.Throws(() => { testProvider.EnsureObjectCanBeSerialized(value); }); Assert.Equal($"The '{typeof(SessionStateTempDataProvider).FullName}' cannot serialize a dictionary with a key of type '{type}' to session state.", exception.Message); } public static TheoryData ValidTypes { get { return new TheoryData { { 10 }, { new int[]{ 10, 20 } }, { "FooValue" }, { new Uri("http://Foo") }, { Guid.NewGuid() }, { new List { "foo", "bar" } }, { new DateTimeOffset() }, { 100.1m }, { new Dictionary() }, { new Uri[] { new Uri("http://Foo"), new Uri("http://Bar") } } }; } } [Theory] [MemberData(nameof(ValidTypes))] public void EnsureObjectCanBeSerialized_ValidType_DoesNotThrow(object value) { // Arrange var testProvider = new SessionStateTempDataProvider(); // Act & Assert (Does not throw) testProvider.EnsureObjectCanBeSerialized(value); } [Fact] public void SaveAndLoad_SimpleTypesCanBeStoredAndLoaded() { // Arrange var testProvider = new SessionStateTempDataProvider(); var inputGuid = Guid.NewGuid(); var inputDictionary = new Dictionary { { "Hello", "World" }, }; var input = new Dictionary { { "string", "value" }, { "int", 10 }, { "bool", false }, { "DateTime", new DateTime() }, { "Guid", inputGuid }, { "List`string", new List { "one", "two" } }, { "Dictionary", inputDictionary }, { "EmptyDictionary", new Dictionary() } }; var context = GetHttpContext(new TestSessionCollection(), true); // Act testProvider.SaveTempData(context, input); var TempData = testProvider.LoadTempData(context); // Assert var stringVal = Assert.IsType(TempData["string"]); Assert.Equal("value", stringVal); var intVal = Convert.ToInt32(TempData["int"]); Assert.Equal(10, intVal); var boolVal = Assert.IsType(TempData["bool"]); Assert.Equal(false, boolVal); var datetimeVal = Assert.IsType(TempData["DateTime"]); Assert.Equal(new DateTime().ToString(), datetimeVal.ToString()); var guidVal = Assert.IsType(TempData["Guid"]); Assert.Equal(inputGuid.ToString(), guidVal.ToString()); var list = (IList)TempData["List`string"]; Assert.Equal(2, list.Count); Assert.Equal("one", list[0]); Assert.Equal("two", list[1]); var dictionary = Assert.IsType>(TempData["Dictionary"]); Assert.Equal("World", dictionary["Hello"]); var emptyDictionary = (IDictionary)TempData["EmptyDictionary"]; Assert.Null(emptyDictionary); } private class TestItem { public int DummyInt { get; set; } } private HttpContext GetHttpContext(ISessionCollection session, bool sessionEnabled=true) { var httpContext = new Mock(); if (session != null) { httpContext.Setup(h => h.Session).Returns(session); } else if (!sessionEnabled) { httpContext.Setup(h => h.Session).Throws(); } else { httpContext.Setup(h => h.Session[It.IsAny()]); } if (sessionEnabled) { httpContext.Setup(h => h.GetFeature()).Returns(Mock.Of()); } return httpContext.Object; } private class TestSessionCollection : ISessionCollection { private Dictionary _innerDictionary = new Dictionary(); public byte[] this[string key] { get { return _innerDictionary[key]; } set { _innerDictionary[key] = value; } } public void Clear() { _innerDictionary.Clear(); } public IEnumerator> GetEnumerator() { return _innerDictionary.GetEnumerator(); } public void Remove(string key) { _innerDictionary.Remove(key); } public void Set(string key, ArraySegment value) { _innerDictionary[key] = value.AsArray(); } public bool TryGetValue(string key, out byte[] value) { return _innerDictionary.TryGetValue(key, out value); } IEnumerator IEnumerable.GetEnumerator() { return _innerDictionary.GetEnumerator(); } } } }