aspnetcore/test/Microsoft.AspNetCore.Mvc.We.../HttpErrorTest.cs

305 lines
14 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.Collections.Generic;
using System.IO;
using System.Net.Http.Formatting;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Testing.xunit;
using Newtonsoft.Json.Linq;
using Xunit;
namespace System.Web.Http.Dispatcher
{
public class HttpErrorTest
{
public static IEnumerable<object[]> ErrorKeyValue
{
get
{
var httpError = new HttpError();
yield return new object[] { httpError, (Func<string>)(() => httpError.Message), "Message", "Message_Value" };
yield return new object[] { httpError, (Func<string>)(() => httpError.MessageDetail), "MessageDetail", "MessageDetail_Value" };
yield return new object[] { httpError, (Func<string>)(() => httpError.ExceptionMessage), "ExceptionMessage", "ExceptionMessage_Value" };
yield return new object[] { httpError, (Func<string>)(() => httpError.ExceptionType), "ExceptionType", "ExceptionType_Value" };
yield return new object[] { httpError, (Func<string>)(() => httpError.StackTrace), "StackTrace", "StackTrace_Value" };
}
}
public static IEnumerable<object[]> HttpErrors
{
get
{
yield return new[] { new HttpError() };
yield return new[] { new HttpError("error") };
yield return new[] { new HttpError(new NotImplementedException(), true) };
var modelState = new ModelStateDictionary();
modelState.AddModelError("key", "error");
yield return new[] { new HttpError(modelState, true) };
}
}
[Fact]
public void StringConstructor_AddsCorrectDictionaryItems()
{
HttpError error = new HttpError("something bad happened");
Assert.Contains(new KeyValuePair<string, object>("Message", "something bad happened"), error);
}
[Fact]
public void ExceptionConstructorWithDetail_AddsCorrectDictionaryItems()
{
HttpError error = new HttpError(new ArgumentException("error", new Exception()), true);
Assert.Contains(new KeyValuePair<string, object>("Message", "An error has occurred."), error);
Assert.Contains(new KeyValuePair<string, object>("ExceptionMessage", "error"), error);
Assert.Contains(new KeyValuePair<string, object>("ExceptionType", "System.ArgumentException"), error);
Assert.True(error.ContainsKey("StackTrace"));
Assert.True(error.ContainsKey("InnerException"));
Assert.IsType<HttpError>(error["InnerException"]);
}
[Fact]
public void ModelStateConstructorWithDetail_AddsCorrectDictionaryItems()
{
// Arrange
ModelStateDictionary modelState = new ModelStateDictionary();
var provider = new EmptyModelMetadataProvider();
var metadata = provider.GetMetadataForProperty(typeof(string), nameof(string.Length));
modelState.AddModelError("[0].Name", "error1");
modelState.AddModelError("[0].Name", "error2");
modelState.AddModelError("[0].Address", "error");
modelState.AddModelError("[2].Name", new Exception("OH NO"), metadata);
// Act
HttpError error = new HttpError(modelState, true);
// Assert
HttpError modelStateError = error["ModelState"] as HttpError;
Assert.Contains(new KeyValuePair<string, object>("Message", "The request is invalid."), error);
Assert.Contains("error1", modelStateError["[0].Name"] as IEnumerable<string>);
Assert.Contains("error2", modelStateError["[0].Name"] as IEnumerable<string>);
Assert.Contains("error", modelStateError["[0].Address"] as IEnumerable<string>);
Assert.True(modelStateError.ContainsKey("[2].Name"));
Assert.Contains("OH NO", modelStateError["[2].Name"] as IEnumerable<string>);
}
[Fact]
public void ExceptionConstructorWithoutDetail_AddsCorrectDictionaryItems()
{
HttpError error = new HttpError(new ArgumentException("error", new Exception()), false);
Assert.Contains(new KeyValuePair<string, object>("Message", "An error has occurred."), error);
Assert.False(error.ContainsKey("ExceptionMessage"));
Assert.False(error.ContainsKey("ExceptionType"));
Assert.False(error.ContainsKey("StackTrace"));
Assert.False(error.ContainsKey("InnerException"));
}
[Fact]
public void ModelStateConstructorWithoutDetail_AddsCorrectDictionaryItems()
{
// Arrange
ModelStateDictionary modelState = new ModelStateDictionary();
var provider = new EmptyModelMetadataProvider();
var metadata = provider.GetMetadataForProperty(typeof(string), nameof(string.Length));
modelState.AddModelError("[0].Name", "error1");
modelState.AddModelError("[0].Name", "error2");
modelState.AddModelError("[0].Address", "error");
modelState.AddModelError("[2].Name", new Exception("OH NO"), metadata);
// Act
HttpError error = new HttpError(modelState, false);
// Assert
HttpError modelStateError = error["ModelState"] as HttpError;
Assert.Contains(new KeyValuePair<string, object>("Message", "The request is invalid."), error);
Assert.Contains("error1", modelStateError["[0].Name"] as IEnumerable<string>);
Assert.Contains("error2", modelStateError["[0].Name"] as IEnumerable<string>);
Assert.Contains("error", modelStateError["[0].Address"] as IEnumerable<string>);
Assert.True(modelStateError.ContainsKey("[2].Name"));
Assert.DoesNotContain("OH NO", modelStateError["[2].Name"] as IEnumerable<string>);
}
[Fact]
public void HttpError_Roundtrips_WithJsonFormatter()
{
HttpError error = new HttpError("error") { { "ErrorCode", 42 }, { "Data", new[] { "a", "b", "c" } } };
MediaTypeFormatter formatter = new JsonMediaTypeFormatter();
MemoryStream stream = new MemoryStream();
formatter.WriteToStreamAsync(typeof(HttpError), error, stream, content: null, transportContext: null).Wait();
stream.Position = 0;
HttpError roundtrippedError = formatter.ReadFromStreamAsync(typeof(HttpError), stream, content: null, formatterLogger: null).Result as HttpError;
Assert.NotNull(roundtrippedError);
Assert.Equal("error", roundtrippedError.Message);
Assert.Equal(42L, roundtrippedError["ErrorCode"]);
JArray data = roundtrippedError["Data"] as JArray;
Assert.Equal(3, data.Count);
Assert.Contains("a", data);
Assert.Contains("b", data);
Assert.Contains("c", data);
}
[ConditionalFact]
// Mono issue - https://github.com/aspnet/External/issues/25
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
public void HttpError_Roundtrips_WithXmlFormatter()
{
HttpError error = new HttpError("error") { { "ErrorCode", 42 }, { "Data", new[] { "a", "b", "c" } } };
MediaTypeFormatter formatter = new XmlMediaTypeFormatter();
MemoryStream stream = new MemoryStream();
formatter.WriteToStreamAsync(typeof(HttpError), error, stream, content: null, transportContext: null).Wait();
stream.Position = 0;
HttpError roundtrippedError = formatter.ReadFromStreamAsync(typeof(HttpError), stream, content: null, formatterLogger: null).Result as HttpError;
Assert.NotNull(roundtrippedError);
Assert.Equal("error", roundtrippedError.Message);
Assert.Equal("42", roundtrippedError["ErrorCode"]);
Assert.Equal("a b c", roundtrippedError["Data"]);
}
[Fact]
public void HttpErrorWithWhitespace_Roundtrips_WithXmlFormatter()
{
string message = " foo\n bar \n ";
HttpError error = new HttpError(message);
MediaTypeFormatter formatter = new XmlMediaTypeFormatter();
MemoryStream stream = new MemoryStream();
formatter.WriteToStreamAsync(typeof(HttpError), error, stream, content: null, transportContext: null).Wait();
stream.Position = 0;
HttpError roundtrippedError = formatter.ReadFromStreamAsync(typeof(HttpError), stream, content: null, formatterLogger: null).Result as HttpError;
Assert.NotNull(roundtrippedError);
Assert.Equal(message, roundtrippedError.Message);
}
[Fact]
public void HttpError_Roundtrips_WithXmlSerializer()
{
HttpError error = new HttpError("error") { { "ErrorCode", 42 }, { "Data", new[] { "a", "b", "c" } } };
MediaTypeFormatter formatter = new XmlMediaTypeFormatter() { UseXmlSerializer = true };
MemoryStream stream = new MemoryStream();
formatter.WriteToStreamAsync(typeof(HttpError), error, stream, content: null, transportContext: null).Wait();
stream.Position = 0;
HttpError roundtrippedError = formatter.ReadFromStreamAsync(typeof(HttpError), stream, content: null, formatterLogger: null).Result as HttpError;
Assert.NotNull(roundtrippedError);
Assert.Equal("error", roundtrippedError.Message);
Assert.Equal("42", roundtrippedError["ErrorCode"]);
Assert.Equal("a b c", roundtrippedError["Data"]);
}
[Fact]
public void HttpErrorForInnerException_Serializes_WithXmlSerializer()
{
HttpError error = new HttpError(new ArgumentException("error", new Exception("innerError")), includeErrorDetail: true);
MediaTypeFormatter formatter = new XmlMediaTypeFormatter() { UseXmlSerializer = true };
MemoryStream stream = new MemoryStream();
formatter.WriteToStreamAsync(typeof(HttpError), error, stream, content: null, transportContext: null).Wait();
stream.Position = 0;
string serializedError = new StreamReader(stream).ReadToEnd();
Assert.NotNull(serializedError);
Assert.Equal(
"<Error><Message>An error has occurred.</Message><ExceptionMessage>error</ExceptionMessage><ExceptionType>System.ArgumentException</ExceptionType><StackTrace /><InnerException><Message>An error has occurred.</Message><ExceptionMessage>innerError</ExceptionMessage><ExceptionType>System.Exception</ExceptionType><StackTrace /></InnerException></Error>",
serializedError);
}
[Fact]
public void GetPropertyValue_GetsValue_IfTypeMatches()
{
HttpError error = new HttpError();
error["key"] = "x";
Assert.Equal("x", error.GetPropertyValue<string>("key"));
Assert.Equal("x", error.GetPropertyValue<object>("key"));
}
[Fact]
public void GetPropertyValue_GetsDefault_IfTypeDoesNotMatch()
{
HttpError error = new HttpError();
error["key"] = "x";
Assert.Null(error.GetPropertyValue<Uri>("key"));
Assert.Equal(0, error.GetPropertyValue<int>("key"));
}
[Fact]
public void GetPropertyValue_GetsDefault_IfPropertyMissing()
{
HttpError error = new HttpError();
Assert.Null(error.GetPropertyValue<string>("key"));
Assert.Equal(0, error.GetPropertyValue<int>("key"));
}
[Theory]
[MemberData(nameof(ErrorKeyValue))]
public void HttpErrorStringProperties_UseCorrectHttpErrorKey(HttpError httpError, Func<string> productUnderTest, string key, string actualValue)
{
// Arrange
httpError[key] = actualValue;
// Act
string expectedValue = productUnderTest.Invoke();
// Assert
Assert.Equal(expectedValue, actualValue);
}
[Fact]
public void HttpErrorProperty_InnerException_UsesCorrectHttpErrorKey()
{
// Arrange
HttpError error = new HttpError(new ArgumentException("error", new Exception()), true);
// Act
HttpError innerException = error.InnerException;
// Assert
Assert.Same(error["InnerException"], innerException);
}
[Fact]
public void HttpErrorProperty_ModelState_UsesCorrectHttpErrorKey()
{
// Arrange
ModelStateDictionary modelState = new ModelStateDictionary();
modelState.AddModelError("[0].Name", "error1");
HttpError error = new HttpError(modelState, true);
// Act
HttpError actualModelStateError = error.ModelState;
// Assert
Assert.Same(error["ModelState"], actualModelStateError);
}
[Theory]
[MemberData(nameof(HttpErrors))]
public void HttpErrors_UseCaseInsensitiveComparer(HttpError httpError)
{
// Arrange
var lowercaseKey = "abcd";
var uppercaseKey = "ABCD";
httpError[lowercaseKey] = "error";
// Act & Assert
Assert.True(httpError.ContainsKey(lowercaseKey));
Assert.True(httpError.ContainsKey(uppercaseKey));
}
}
}