// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text.RegularExpressions;
using Xunit;
namespace Microsoft.TestCommon
{
///
/// Unit test utility for testing instances.
///
public class HttpAssert
{
private const string CommaSeperator = ", ";
private static readonly HttpAssert singleton = new HttpAssert();
public static HttpAssert Singleton { get { return singleton; } }
///
/// Asserts that the expected is equal to the actual .
///
/// The expected . Should not be null.
/// The actual . Should not be null.
public void Equal(HttpRequestMessage expected, HttpRequestMessage actual)
{
Assert.NotNull(expected);
Assert.NotNull(actual);
Assert.Equal(expected.Version, actual.Version);
Equal(expected.Headers, actual.Headers);
if (expected.Content == null)
{
Assert.Null(actual.Content);
}
else
{
string expectedContent = CleanContentString(expected.Content.ReadAsStringAsync().Result);
string actualContent = CleanContentString(actual.Content.ReadAsStringAsync().Result);
Assert.Equal(expectedContent, actualContent);
Equal(expected.Content.Headers, actual.Content.Headers);
}
}
///
/// Asserts that the expected is equal to the actual .
///
/// The expected . Should not be null.
/// The actual . Should not be null.
public void Equal(HttpResponseMessage expected, HttpResponseMessage actual)
{
Equal(expected, actual, null);
}
///
/// Asserts that the expected is equal to the actual .
///
/// The expected . Should not be null.
/// The actual . Should not be null.
/// The callback to verify the Content string. If it is null, Assert.Equal will be used.
public void Equal(HttpResponseMessage expected, HttpResponseMessage actual, Action verifyContentStringCallback)
{
Assert.NotNull(expected);
Assert.NotNull(actual);
Assert.Equal(expected.StatusCode, actual.StatusCode);
Assert.Equal(expected.ReasonPhrase, actual.ReasonPhrase);
Assert.Equal(expected.Version, actual.Version);
Equal(expected.Headers, actual.Headers);
if (expected.Content == null)
{
Assert.Null(actual.Content);
}
else
{
string expectedContent = CleanContentString(expected.Content.ReadAsStringAsync().Result);
string actualContent = CleanContentString(actual.Content.ReadAsStringAsync().Result);
if (verifyContentStringCallback != null)
{
verifyContentStringCallback(expectedContent, actualContent);
}
else
{
Assert.Equal(expectedContent, actualContent);
}
Equal(expected.Content.Headers, actual.Content.Headers);
}
}
///
/// Asserts that the expected instance is equal to the actual instance.
///
/// The expected instance. Should not be null.
/// The actual instance. Should not be null.
public void Equal(HttpHeaders expectedHeaders, HttpHeaders actualHeaders)
{
Assert.NotNull(expectedHeaders);
Assert.NotNull(actualHeaders);
Assert.Equal(expectedHeaders.Count(), actualHeaders.Count());
foreach (KeyValuePair> expectedHeader in expectedHeaders)
{
KeyValuePair> actualHeader = actualHeaders.FirstOrDefault(h => h.Key == expectedHeader.Key);
Assert.NotNull(actualHeader);
if (expectedHeader.Key == "Date")
{
HandleDateHeader(expectedHeader.Value.ToArray(), actualHeader.Value.ToArray());
}
else
{
string expectedHeaderStr = string.Join(CommaSeperator, expectedHeader.Value);
string actualHeaderStr = string.Join(CommaSeperator, actualHeader.Value);
Assert.Equal(expectedHeaderStr, actualHeaderStr);
}
}
}
///
/// Asserts the given contain the given
/// for the given .
///
/// The to examine. It cannot be null.
/// The name of the header. It cannot be empty.
/// The values that must all be present. It cannot be null.
public void Contains(HttpHeaders headers, string name, params string[] values)
{
Assert.NotNull(headers);
Assert.False(String.IsNullOrWhiteSpace(name), "Test error: name cannot be empty.");
Assert.NotNull(values);
IEnumerable headerValues = null;
bool foundIt = headers.TryGetValues(name, out headerValues);
Assert.True(foundIt);
foreach (string value in values)
{
Assert.Contains(value, headerValues);
}
}
public bool IsKnownUnserializableType(Type type, Func isTypeUnserializableCallback)
{
if (isTypeUnserializableCallback != null && isTypeUnserializableCallback(type))
{
return true;
}
if (type.IsGenericType)
{
if (typeof(IEnumerable).IsAssignableFrom(type))
{
if (type.GetMethod("Add") == null)
{
return true;
}
}
// Generic type -- recursively analyze generic arguments
return IsKnownUnserializableType(type.GetGenericArguments()[0], isTypeUnserializableCallback);
}
if (type.HasElementType && IsKnownUnserializableType(type.GetElementType(), isTypeUnserializableCallback))
{
return true;
}
return false;
}
public bool IsKnownUnserializable(Type type, object obj, Func isTypeUnserializableCallback)
{
if (IsKnownUnserializableType(type, isTypeUnserializableCallback))
{
return true;
}
return obj != null && IsKnownUnserializableType(obj.GetType(), isTypeUnserializableCallback);
}
public bool IsKnownUnserializable(Type type, object obj)
{
return IsKnownUnserializable(type, obj, null);
}
public bool CanRoundTrip(Type type)
{
if (typeof(TimeSpan).IsAssignableFrom(type))
{
return false;
}
if (typeof(DateTimeOffset).IsAssignableFrom(type))
{
return false;
}
if (type.IsGenericType)
{
foreach (Type genericParameterType in type.GetGenericArguments())
{
if (!CanRoundTrip(genericParameterType))
{
return false;
}
}
}
if (type.HasElementType)
{
return CanRoundTrip(type.GetElementType());
}
return true;
}
private static void HandleDateHeader(string[] expectedDateHeaderValues, string[] actualDateHeaderValues)
{
Assert.Equal(expectedDateHeaderValues.Length, actualDateHeaderValues.Length);
for (int i = 0; i < expectedDateHeaderValues.Length; i++)
{
DateTime expectedDateTime = DateTime.Parse(expectedDateHeaderValues[i]);
DateTime actualDateTime = DateTime.Parse(actualDateHeaderValues[i]);
Assert.Equal(expectedDateTime.Year, actualDateTime.Year);
Assert.Equal(expectedDateTime.Month, actualDateTime.Month);
Assert.Equal(expectedDateTime.Day, actualDateTime.Day);
int hourDifference = Math.Abs(actualDateTime.Hour - expectedDateTime.Hour);
Assert.True(hourDifference <= 1);
int minuteDifference = Math.Abs(actualDateTime.Minute - expectedDateTime.Minute);
Assert.True(minuteDifference <= 1);
}
}
private static string CleanContentString(string content)
{
Assert.Null(content);
string cleanedContent = null;
// remove any port numbers from Uri's
cleanedContent = Regex.Replace(content, ":\\d+", "");
return cleanedContent;
}
}
}