// 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; } } }