1
0

Moved all UnitTests to a single project. Implemented parts of AspNetCore UnitTests.

This commit is contained in:
2022-07-17 12:21:05 +02:00
parent 73038bbe5a
commit a26d6a0036
46 changed files with 2411 additions and 105 deletions

View File

@@ -0,0 +1,346 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using AMWD.Common.AspNetCore.BasicAuthentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Primitives;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
namespace UnitTests.AspNetCore.Attributes
{
[TestClass]
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
public class BasicAuthenticationAttributeTests
{
private Mock<IHeaderDictionary> requestHeaderMock;
private Mock<IHeaderDictionary> responseHeaderMock;
private Mock<HttpRequest> requestMock;
private Mock<HttpResponse> responseMock;
private Mock<HttpContext> contextMock;
private Dictionary<string, string> requestHeaders;
private string validatorRealm;
private ClaimsPrincipal validatorResult;
private string responseHeaderAuthCallback;
[TestInitialize]
public void InitializeTest()
{
requestHeaders = new Dictionary<string, string>();
validatorRealm = null;
validatorResult = null;
responseHeaderAuthCallback = null;
}
[TestMethod]
public async Task ShouldValidateViaUsernamePassword()
{
// arrange
var attribute = new BasicAuthenticationAttribute
{
Username = "user",
Password = "password"
};
requestHeaders.Add("Authorization", $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes($"{attribute.Username}:{attribute.Password}"))}");
var context = GetContext();
// act
await attribute.OnAuthorizationAsync(context);
// assert
Assert.IsNull(context.Result);
Assert.IsTrue(string.IsNullOrWhiteSpace(responseHeaderAuthCallback));
}
[TestMethod]
public async Task ShouldValidateViaValidator()
{
// arrange
var attribute = new BasicAuthenticationAttribute();
requestHeaders.Add("Authorization", $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes($"{attribute.Username}:{attribute.Password}"))}");
validatorResult = new ClaimsPrincipal();
var context = GetContext(hasValidator: true);
// act
await attribute.OnAuthorizationAsync(context);
// assert
Assert.IsNull(context.Result);
Assert.IsTrue(string.IsNullOrWhiteSpace(responseHeaderAuthCallback));
}
[TestMethod]
public async Task ShouldAllowAnonymous()
{
// arrange
var attribute = new BasicAuthenticationAttribute
{
Username = "user",
Password = "password"
};
var context = GetContext(isAnonymousAllowed: true);
// act
await attribute.OnAuthorizationAsync(context);
// assert
Assert.IsNull(context.Result);
Assert.IsTrue(string.IsNullOrWhiteSpace(responseHeaderAuthCallback));
}
[TestMethod]
public async Task ShouldAskOnUsernamePasswordWithoutRealm()
{
// arrange
var attribute = new BasicAuthenticationAttribute
{
Username = "user",
Password = "password"
};
var context = GetContext();
// act
await attribute.OnAuthorizationAsync(context);
// assert
Assert.IsNotNull(context.Result);
Assert.IsTrue(context.Result is StatusCodeResult);
Assert.AreEqual(401, ((StatusCodeResult)context.Result).StatusCode);
Assert.IsFalse(string.IsNullOrWhiteSpace(responseHeaderAuthCallback));
Assert.AreEqual("Basic", responseHeaderAuthCallback);
}
[TestMethod]
public async Task ShouldAskOnUsernamePasswordWithRealm()
{
// arrange
var attribute = new BasicAuthenticationAttribute
{
Username = "user",
Password = "password",
Realm = "re:al\"m"
};
var context = GetContext();
// act
await attribute.OnAuthorizationAsync(context);
// assert
Assert.IsNotNull(context.Result);
Assert.IsTrue(context.Result is StatusCodeResult);
Assert.AreEqual(401, ((StatusCodeResult)context.Result).StatusCode);
Assert.IsFalse(string.IsNullOrWhiteSpace(responseHeaderAuthCallback));
Assert.AreEqual("Basic realm=\"re:alm\"", responseHeaderAuthCallback);
}
[TestMethod]
public async Task ShouldAskOnUsernamePasswordWrongUser()
{
// arrange
var attribute = new BasicAuthenticationAttribute
{
Username = "user",
Password = "password"
};
requestHeaders.Add("Authorization", $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes($"{attribute.Username}a:{attribute.Password}"))}");
var context = GetContext();
// act
await attribute.OnAuthorizationAsync(context);
// assert
Assert.IsNotNull(context.Result);
Assert.IsTrue(context.Result is StatusCodeResult);
Assert.AreEqual(401, ((StatusCodeResult)context.Result).StatusCode);
Assert.IsFalse(string.IsNullOrWhiteSpace(responseHeaderAuthCallback));
Assert.AreEqual("Basic", responseHeaderAuthCallback);
}
[TestMethod]
public async Task ShouldAskOnUsernamePasswordWrongPassword()
{
// arrange
var attribute = new BasicAuthenticationAttribute
{
Username = "user",
Password = "password"
};
requestHeaders.Add("Authorization", $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes($"{attribute.Username}:{attribute.Password}a"))}");
var context = GetContext();
// act
await attribute.OnAuthorizationAsync(context);
// assert
Assert.IsNotNull(context.Result);
Assert.IsTrue(context.Result is StatusCodeResult);
Assert.AreEqual(401, ((StatusCodeResult)context.Result).StatusCode);
Assert.IsFalse(string.IsNullOrWhiteSpace(responseHeaderAuthCallback));
Assert.AreEqual("Basic", responseHeaderAuthCallback);
}
[TestMethod]
public async Task ShouldAskOnValidatorWithRealmOnAttribute()
{
// arrange
var attribute = new BasicAuthenticationAttribute
{
Realm = "attribute"
};
requestHeaders.Add("Authorization", $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes($"{attribute.Username}:{attribute.Password}"))}");
var context = GetContext(hasValidator: true);
// act
await attribute.OnAuthorizationAsync(context);
// assert
Assert.IsNotNull(context.Result);
Assert.IsTrue(context.Result is StatusCodeResult);
Assert.AreEqual(401, ((StatusCodeResult)context.Result).StatusCode);
Assert.IsFalse(string.IsNullOrWhiteSpace(responseHeaderAuthCallback));
Assert.AreEqual("Basic realm=\"attribute\"", responseHeaderAuthCallback);
}
[TestMethod]
public async Task ShouldAskOnValidatorWithRealmOnValidator()
{
// arrange
validatorRealm = "validator";
var attribute = new BasicAuthenticationAttribute();
requestHeaders.Add("Authorization", $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes($"{attribute.Username}:{attribute.Password}"))}");
var context = GetContext(hasValidator: true);
// act
await attribute.OnAuthorizationAsync(context);
// assert
Assert.IsNotNull(context.Result);
Assert.IsTrue(context.Result is StatusCodeResult);
Assert.AreEqual(401, ((StatusCodeResult)context.Result).StatusCode);
Assert.IsFalse(string.IsNullOrWhiteSpace(responseHeaderAuthCallback));
Assert.AreEqual("Basic realm=\"validator\"", responseHeaderAuthCallback);
}
[TestMethod]
public async Task ShouldReturnInternalError()
{
// arrange
var attribute = new BasicAuthenticationAttribute();
requestHeaders.Add("Authorization", $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes($"{attribute.Username}"))}");
var context = GetContext();
// act
await attribute.OnAuthorizationAsync(context);
// assert
Assert.IsNotNull(context.Result);
Assert.IsTrue(context.Result is StatusCodeResult);
Assert.AreEqual(500, ((StatusCodeResult)context.Result).StatusCode);
}
private AuthorizationFilterContext GetContext(bool isAnonymousAllowed = false, bool hasValidator = false)
{
requestHeaderMock = new Mock<IHeaderDictionary>();
foreach (var header in requestHeaders)
{
requestHeaderMock
.Setup(h => h.ContainsKey(header.Key))
.Returns(true);
requestHeaderMock
.Setup(h => h[header.Key])
.Returns(header.Value);
}
responseHeaderMock = new Mock<IHeaderDictionary>();
responseHeaderMock
.SetupSet(h => h["WWW-Authenticate"] = It.IsAny<StringValues>())
.Callback<string, StringValues>((key, value) =>
{
responseHeaderAuthCallback = value;
});
requestMock = new Mock<HttpRequest>();
requestMock
.Setup(r => r.Headers)
.Returns(requestHeaderMock.Object);
responseMock = new Mock<HttpResponse>();
responseMock
.Setup(r => r.Headers)
.Returns(responseHeaderMock.Object);
var requestServicesMock = new Mock<IServiceProvider>();
if (hasValidator)
{
var validatorMock = new Mock<IBasicAuthenticationValidator>();
validatorMock
.Setup(v => v.Realm)
.Returns(validatorRealm);
validatorMock
.Setup(v => v.ValidateAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<IPAddress>()))
.ReturnsAsync(validatorResult);
requestServicesMock
.Setup(rs => rs.GetService(typeof(IBasicAuthenticationValidator)))
.Returns(validatorMock.Object);
}
var connectionInfoMock = new Mock<ConnectionInfo>();
connectionInfoMock
.Setup(ci => ci.RemoteIpAddress)
.Returns(IPAddress.Loopback);
contextMock = new Mock<HttpContext>();
contextMock
.Setup(c => c.Request)
.Returns(requestMock.Object);
contextMock
.Setup(c => c.Response)
.Returns(responseMock.Object);
contextMock
.Setup(c => c.RequestServices)
.Returns(requestServicesMock.Object);
contextMock
.Setup(c => c.Connection)
.Returns(connectionInfoMock.Object);
var routeDataMock = new Mock<RouteData>();
var actionDescriptor = new ActionDescriptor
{
EndpointMetadata = new List<object>()
};
if (isAnonymousAllowed)
actionDescriptor.EndpointMetadata.Add(new AllowAnonymousAttribute());
return new AuthorizationFilterContext(new ActionContext
{
HttpContext = contextMock.Object,
RouteData = routeDataMock.Object,
ActionDescriptor = actionDescriptor,
}, new List<IFilterMetadata>());
}
}
}

View File

@@ -0,0 +1,340 @@
using System;
using System.Collections.Generic;
using System.Net;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Configuration;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
namespace UnitTests.AspNetCore.Attributes
{
[TestClass]
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
public class IPBlacklistAttributeTests
{
private Dictionary<string, string> requestHeaders;
private Dictionary<object, object> itemsCallback;
private string configKey;
private bool configExists;
private List<string> restrictedIpsConfig;
[TestInitialize]
public void InitializeTest()
{
requestHeaders = new Dictionary<string, string>();
itemsCallback = new Dictionary<object, object>();
configKey = null;
configExists = false;
restrictedIpsConfig = new List<string>();
}
[TestMethod]
public void ShouldAllowOnNoConfiguration()
{
// arrange
var remote = IPAddress.Parse("192.168.178.1");
var attribute = new IPBlacklistAttribute();
var context = GetContext(remote);
// act
attribute.OnActionExecuting(context);
// assert
Assert.IsNull(context.Result);
Assert.AreEqual(1, itemsCallback.Count);
Assert.AreEqual(remote, itemsCallback["RemoteAddress"]);
}
[TestMethod]
public void ShouldAllowOnWrongConfiguration()
{
// arrange
var remote = IPAddress.Parse("192.168.178.1");
var attribute = new IPBlacklistAttribute
{
RestrictedIpAddresses = "192.168.178:1"
};
var context = GetContext(remote);
// act
attribute.OnActionExecuting(context);
// assert
Assert.IsNull(context.Result);
Assert.AreEqual(1, itemsCallback.Count);
Assert.AreEqual(remote, itemsCallback["RemoteAddress"]);
}
[TestMethod]
public void ShouldAllowLocalAccess()
{
// arrange
var attribute = new IPBlacklistAttribute
{
RestrictLocalAccess = false,
RestrictedIpAddresses = "127.0.0.0/8"
};
var context = GetContext();
// act
attribute.OnActionExecuting(context);
// assert
Assert.IsNull(context.Result);
Assert.AreEqual(1, itemsCallback.Count);
Assert.AreEqual(IPAddress.Loopback, itemsCallback["RemoteAddress"]);
}
[TestMethod]
public void ShouldBlockLocalAccess()
{
// arrange
var attribute = new IPBlacklistAttribute
{
RestrictLocalAccess = true,
RestrictedIpAddresses = ",127.0.0.0/8"
};
var context = GetContext();
// act
attribute.OnActionExecuting(context);
// assert
Assert.IsNotNull(context.Result);
Assert.IsTrue(context.Result is StatusCodeResult);
Assert.AreEqual(403, ((StatusCodeResult)context.Result).StatusCode);
Assert.AreEqual(1, itemsCallback.Count);
Assert.AreEqual(IPAddress.Loopback, itemsCallback["RemoteAddress"]);
}
[DataTestMethod]
[DataRow("192.168.178.10")]
[DataRow("192.168.178.20")]
public void ShouldBlockSpecificAddress(string address)
{
// arrange
var remote = IPAddress.Parse(address);
var attribute = new IPBlacklistAttribute
{
RestrictLocalAccess = true,
RestrictedIpAddresses = "127.0.0.0/8,192.168.178.10"
};
var context = GetContext(remote);
// act
attribute.OnActionExecuting(context);
// assert
if (address == "192.168.178.10")
{
Assert.IsNotNull(context.Result);
Assert.IsTrue(context.Result is StatusCodeResult);
Assert.AreEqual(403, ((StatusCodeResult)context.Result).StatusCode);
}
else
{
Assert.IsNull(context.Result);
}
Assert.AreEqual(1, itemsCallback.Count);
Assert.AreEqual(remote, itemsCallback["RemoteAddress"]);
}
[TestMethod]
public void ShouldAllowLocalAccessConfig()
{
// arrange
configKey = "Black:List";
configExists = true;
restrictedIpsConfig.Add("127.0.0.0/8");
restrictedIpsConfig.Add("192.168.178.10");
var attribute = new IPBlacklistAttribute
{
RestrictLocalAccess = false,
ConfigurationKey = configKey
};
var context = GetContext();
// act
attribute.OnActionExecuting(context);
// assert
Assert.IsNull(context.Result);
Assert.AreEqual(1, itemsCallback.Count);
Assert.AreEqual(IPAddress.Loopback, itemsCallback["RemoteAddress"]);
}
[TestMethod]
public void ShouldBlockLocalAccessConfig()
{
// arrange
configKey = "Black:List";
configExists = true;
restrictedIpsConfig.Add("");
restrictedIpsConfig.Add("127.0.0.0/8");
restrictedIpsConfig.Add("192.168.178.10");
var attribute = new IPBlacklistAttribute
{
RestrictLocalAccess = true,
ConfigurationKey = configKey
};
var context = GetContext();
// act
attribute.OnActionExecuting(context);
// assert
Assert.IsNotNull(context.Result);
Assert.IsTrue(context.Result is StatusCodeResult);
Assert.AreEqual(403, ((StatusCodeResult)context.Result).StatusCode);
Assert.AreEqual(1, itemsCallback.Count);
Assert.AreEqual(IPAddress.Loopback, itemsCallback["RemoteAddress"]);
}
[DataTestMethod]
[DataRow("192.168.178.10")]
[DataRow("192.168.178.20")]
public void ShouldBlockSpecificAddressConfig(string address)
{
// arrange
configKey = "Black:List";
configExists = true;
restrictedIpsConfig.Add("127.0.0.0/8");
restrictedIpsConfig.Add("192.168.178.10");
var attribute = new IPBlacklistAttribute
{
RestrictLocalAccess = true,
ConfigurationKey = configKey
};
var remote = IPAddress.Parse(address);
var context = GetContext(remote);
// act
attribute.OnActionExecuting(context);
// assert
if (address == "192.168.178.10")
{
Assert.IsNotNull(context.Result);
Assert.IsTrue(context.Result is StatusCodeResult);
Assert.AreEqual(403, ((StatusCodeResult)context.Result).StatusCode);
}
else
{
Assert.IsNull(context.Result);
}
Assert.AreEqual(1, itemsCallback.Count);
Assert.AreEqual(remote, itemsCallback["RemoteAddress"]);
}
[TestMethod]
public void ShouldAllowOnMissingConfiguration()
{
// arrange
configKey = "Black:List";
configExists = false;
var attribute = new IPBlacklistAttribute
{
RestrictLocalAccess = true,
ConfigurationKey = configKey
};
var context = GetContext();
// act
attribute.OnActionExecuting(context);
// assert
Assert.IsNull(context.Result);
Assert.AreEqual(1, itemsCallback.Count);
Assert.AreEqual(IPAddress.Loopback, itemsCallback["RemoteAddress"]);
}
private ActionExecutingContext GetContext(IPAddress remote = null)
{
var requestHeaderMock = new Mock<IHeaderDictionary>();
foreach (var header in requestHeaders)
{
requestHeaderMock
.Setup(h => h.ContainsKey(header.Key))
.Returns(true);
requestHeaderMock
.Setup(h => h[header.Key])
.Returns(header.Value);
}
var requestMock = new Mock<HttpRequest>();
requestMock
.Setup(r => r.Headers)
.Returns(requestHeaderMock.Object);
var connectionInfoMock = new Mock<ConnectionInfo>();
connectionInfoMock
.Setup(ci => ci.LocalIpAddress)
.Returns(IPAddress.Loopback);
connectionInfoMock
.Setup(ci => ci.RemoteIpAddress)
.Returns(remote ?? IPAddress.Loopback);
var itemsMock = new Mock<IDictionary<object, object>>();
itemsMock
.SetupSet(i => i[It.IsAny<object>()] = It.IsAny<object>())
.Callback<object, object>((key, val) => itemsCallback.Add(key, val));
var configurationMock = new Mock<IConfiguration>();
var children = new List<IConfigurationSection>();
foreach (string ipAddress in restrictedIpsConfig)
{
var csm = new Mock<IConfigurationSection>();
csm.Setup(cs => cs.Value).Returns(ipAddress);
children.Add(csm.Object);
}
var configSectionMock = new Mock<IConfigurationSection>();
configSectionMock
.Setup(cs => cs.GetChildren())
.Returns(children);
configurationMock
.Setup(c => c.GetSection(configKey))
.Returns(configExists ? configSectionMock.Object : null);
var requestServicesMock = new Mock<IServiceProvider>();
requestServicesMock
.Setup(s => s.GetService(typeof(IConfiguration)))
.Returns(configurationMock.Object);
var contextMock = new Mock<HttpContext>();
contextMock
.Setup(c => c.Request)
.Returns(requestMock.Object);
contextMock
.Setup(c => c.RequestServices)
.Returns(requestServicesMock.Object);
contextMock
.Setup(c => c.Items)
.Returns(itemsMock.Object);
contextMock
.Setup(c => c.Connection)
.Returns(connectionInfoMock.Object);
var routeDataMock = new Mock<RouteData>();
var actionDescriptorMock = new Mock<ActionDescriptor>();
return new ActionExecutingContext(new ActionContext
{
HttpContext = contextMock.Object,
RouteData = routeDataMock.Object,
ActionDescriptor = actionDescriptorMock.Object,
}, new List<IFilterMetadata>(), new Dictionary<string, object>(), null);
}
}
}

View File

@@ -0,0 +1,341 @@
using System;
using System.Collections.Generic;
using System.Net;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Configuration;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
namespace UnitTests.AspNetCore.Attributes
{
[TestClass]
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
public class IPWhitelistAttributeTests
{
private Dictionary<string, string> requestHeaders;
private Dictionary<object, object> itemsCallback;
private string configKey;
private bool configExists;
private List<string> allowedIpsConfig;
[TestInitialize]
public void InitializeTest()
{
requestHeaders = new Dictionary<string, string>();
itemsCallback = new Dictionary<object, object>();
configKey = null;
configExists = false;
allowedIpsConfig = new List<string>();
}
[TestMethod]
public void ShouldDenyOnNoConfiguration()
{
// arrange
var remote = IPAddress.Parse("192.168.178.1");
var attribute = new IPWhitelistAttribute();
var context = GetContext(remote);
// act
attribute.OnActionExecuting(context);
// assert
Assert.IsNotNull(context.Result);
Assert.IsTrue(context.Result is StatusCodeResult);
Assert.AreEqual(403, ((StatusCodeResult)context.Result).StatusCode);
Assert.AreEqual(1, itemsCallback.Count);
Assert.AreEqual(remote, itemsCallback["RemoteAddress"]);
}
[TestMethod]
public void ShouldDenyOnWrongConfiguration()
{
// arrange
var remote = IPAddress.Parse("192.168.178.1");
var attribute = new IPWhitelistAttribute
{
AllowedIpAddresses = "192.168.178:1"
};
var context = GetContext(remote);
// act
attribute.OnActionExecuting(context);
// assert
Assert.IsNotNull(context.Result);
Assert.IsTrue(context.Result is StatusCodeResult);
Assert.AreEqual(403, ((StatusCodeResult)context.Result).StatusCode);
Assert.AreEqual(1, itemsCallback.Count);
Assert.AreEqual(remote, itemsCallback["RemoteAddress"]);
}
[TestMethod]
public void ShouldAllowLocalAccess()
{
// arrange
var attribute = new IPWhitelistAttribute();
var context = GetContext();
// act
attribute.OnActionExecuting(context);
// assert
Assert.IsNull(context.Result);
Assert.AreEqual(1, itemsCallback.Count);
Assert.AreEqual(IPAddress.Loopback, itemsCallback["RemoteAddress"]);
}
[TestMethod]
public void ShouldDenyLocalAccess()
{
// arrange
var attribute = new IPWhitelistAttribute
{
AllowLocalAccess = false
};
var context = GetContext();
// act
attribute.OnActionExecuting(context);
// assert
Assert.IsNotNull(context.Result);
Assert.IsTrue(context.Result is StatusCodeResult);
Assert.AreEqual(403, ((StatusCodeResult)context.Result).StatusCode);
Assert.AreEqual(1, itemsCallback.Count);
Assert.AreEqual(IPAddress.Loopback, itemsCallback["RemoteAddress"]);
}
[DataTestMethod]
[DataRow("192.168.178.10")]
[DataRow("192.168.178.20")]
public void ShouldAllowSpecificAddress(string address)
{
// arrange
var remote = IPAddress.Parse(address);
var attribute = new IPWhitelistAttribute
{
AllowLocalAccess = false,
AllowedIpAddresses = ",127.0.0.0/8,192.168.178.10"
};
var context = GetContext(remote);
// act
attribute.OnActionExecuting(context);
// assert
if (address == "192.168.178.10")
{
Assert.IsNull(context.Result);
}
else
{
Assert.IsNotNull(context.Result);
Assert.IsTrue(context.Result is StatusCodeResult);
Assert.AreEqual(403, ((StatusCodeResult)context.Result).StatusCode);
}
Assert.AreEqual(1, itemsCallback.Count);
Assert.AreEqual(remote, itemsCallback["RemoteAddress"]);
}
[TestMethod]
public void ShouldAllowLocalAccessConfig()
{
// arrange
configKey = "White:List";
configExists = true;
allowedIpsConfig.Add("127.0.0.0/8");
allowedIpsConfig.Add("192.168.178.10");
var attribute = new IPWhitelistAttribute
{
AllowLocalAccess = true,
ConfigurationKey = configKey
};
var context = GetContext();
// act
attribute.OnActionExecuting(context);
// assert
Assert.IsNull(context.Result);
Assert.AreEqual(1, itemsCallback.Count);
Assert.AreEqual(IPAddress.Loopback, itemsCallback["RemoteAddress"]);
}
[TestMethod]
public void ShouldDenyLocalAccessConfig()
{
// arrange
configKey = "White:List";
configExists = true;
allowedIpsConfig.Add("");
allowedIpsConfig.Add("192.168.178.10");
var attribute = new IPWhitelistAttribute
{
AllowLocalAccess = false,
ConfigurationKey = configKey
};
var context = GetContext();
// act
attribute.OnActionExecuting(context);
// assert
Assert.IsNotNull(context.Result);
Assert.IsTrue(context.Result is StatusCodeResult);
Assert.AreEqual(403, ((StatusCodeResult)context.Result).StatusCode);
Assert.AreEqual(1, itemsCallback.Count);
Assert.AreEqual(IPAddress.Loopback, itemsCallback["RemoteAddress"]);
}
[DataTestMethod]
[DataRow("192.168.178.10")]
[DataRow("192.168.178.20")]
public void ShouldAllowSpecificAddressConfig(string address)
{
// arrange
configKey = "White:List";
configExists = true;
allowedIpsConfig.Add("192.168.178.10");
var attribute = new IPWhitelistAttribute
{
AllowLocalAccess = false,
ConfigurationKey = configKey
};
var remote = IPAddress.Parse(address);
var context = GetContext(remote);
// act
attribute.OnActionExecuting(context);
// assert
if (address == "192.168.178.10")
{
Assert.IsNull(context.Result);
}
else
{
Assert.IsNotNull(context.Result);
Assert.IsTrue(context.Result is StatusCodeResult);
Assert.AreEqual(403, ((StatusCodeResult)context.Result).StatusCode);
}
Assert.AreEqual(1, itemsCallback.Count);
Assert.AreEqual(remote, itemsCallback["RemoteAddress"]);
}
[TestMethod]
public void ShouldDenyOnMissingConfiguration()
{
// arrange
configKey = "White:List";
configExists = false;
var attribute = new IPWhitelistAttribute
{
AllowLocalAccess = false,
ConfigurationKey = configKey
};
var context = GetContext();
// act
attribute.OnActionExecuting(context);
// assert
Assert.IsNotNull(context.Result);
Assert.IsTrue(context.Result is StatusCodeResult);
Assert.AreEqual(403, ((StatusCodeResult)context.Result).StatusCode);
Assert.AreEqual(1, itemsCallback.Count);
Assert.AreEqual(IPAddress.Loopback, itemsCallback["RemoteAddress"]);
}
private ActionExecutingContext GetContext(IPAddress remote = null)
{
var requestHeaderMock = new Mock<IHeaderDictionary>();
foreach (var header in requestHeaders)
{
requestHeaderMock
.Setup(h => h.ContainsKey(header.Key))
.Returns(true);
requestHeaderMock
.Setup(h => h[header.Key])
.Returns(header.Value);
}
var requestMock = new Mock<HttpRequest>();
requestMock
.Setup(r => r.Headers)
.Returns(requestHeaderMock.Object);
var connectionInfoMock = new Mock<ConnectionInfo>();
connectionInfoMock
.Setup(ci => ci.LocalIpAddress)
.Returns(IPAddress.Loopback);
connectionInfoMock
.Setup(ci => ci.RemoteIpAddress)
.Returns(remote ?? IPAddress.Loopback);
var itemsMock = new Mock<IDictionary<object, object>>();
itemsMock
.SetupSet(i => i[It.IsAny<object>()] = It.IsAny<object>())
.Callback<object, object>((key, val) => itemsCallback.Add(key, val));
var configurationMock = new Mock<IConfiguration>();
var children = new List<IConfigurationSection>();
foreach (string ipAddress in allowedIpsConfig)
{
var csm = new Mock<IConfigurationSection>();
csm.Setup(cs => cs.Value).Returns(ipAddress);
children.Add(csm.Object);
}
var configSectionMock = new Mock<IConfigurationSection>();
configSectionMock
.Setup(cs => cs.GetChildren())
.Returns(children);
configurationMock
.Setup(c => c.GetSection(configKey))
.Returns(configExists ? configSectionMock.Object : null);
var requestServicesMock = new Mock<IServiceProvider>();
requestServicesMock
.Setup(s => s.GetService(typeof(IConfiguration)))
.Returns(configurationMock.Object);
var contextMock = new Mock<HttpContext>();
contextMock
.Setup(c => c.Request)
.Returns(requestMock.Object);
contextMock
.Setup(c => c.RequestServices)
.Returns(requestServicesMock.Object);
contextMock
.Setup(c => c.Items)
.Returns(itemsMock.Object);
contextMock
.Setup(c => c.Connection)
.Returns(connectionInfoMock.Object);
var routeDataMock = new Mock<RouteData>();
var actionDescriptorMock = new Mock<ActionDescriptor>();
return new ActionExecutingContext(new ActionContext
{
HttpContext = contextMock.Object,
RouteData = routeDataMock.Object,
ActionDescriptor = actionDescriptorMock.Object,
}, new List<IFilterMetadata>(), new Dictionary<string, object>(), null);
}
}
}

View File

@@ -0,0 +1,214 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using AMWD.Common.AspNetCore.BasicAuthentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
namespace UnitTests.AspNetCore.BasicAuthentication
{
[TestClass]
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
public class BasicAuthenticationMiddlewareTests
{
private Dictionary<string, string> requestHeaders;
private Dictionary<string, string> responseHeadersCallback;
private int responseStatusCodeCallback;
private string validatorRealm;
private ClaimsPrincipal validatorResponse;
private List<(string username, string password, IPAddress ipAddr)> validatorCallback;
[TestInitialize]
public void InitializeTests()
{
requestHeaders = new Dictionary<string, string>();
responseHeadersCallback = new Dictionary<string, string>();
responseStatusCodeCallback = 0;
validatorRealm = null;
validatorResponse = null;
validatorCallback = new List<(string username, string password, IPAddress ipAddr)>();
}
[TestMethod]
public async Task ShouldAllowAccess()
{
// arrange
string username = "user";
string password = "pass:word";
requestHeaders.Add("Authorization", $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes($"{username}:{password}"))}");
validatorResponse = new ClaimsPrincipal();
var middleware = GetMiddleware();
var context = GetContext();
// act
await middleware.InvokeAsync(context);
// assert
Assert.AreEqual(0, responseStatusCodeCallback); // not triggered
Assert.AreEqual(0, responseHeadersCallback.Count);
Assert.AreEqual(1, validatorCallback.Count);
Assert.AreEqual(username, validatorCallback.First().username);
Assert.AreEqual(password, validatorCallback.First().password);
Assert.AreEqual(IPAddress.Loopback, validatorCallback.First().ipAddr);
}
[TestMethod]
public async Task ShouldDenyMissingHeader()
{
// arrange
var middleware = GetMiddleware();
var context = GetContext();
// act
await middleware.InvokeAsync(context);
// assert
Assert.AreEqual(401, responseStatusCodeCallback);
Assert.AreEqual(0, validatorCallback.Count);
Assert.AreEqual(1, responseHeadersCallback.Count);
Assert.AreEqual("WWW-Authenticate", responseHeadersCallback.Keys.First());
Assert.AreEqual("Basic", responseHeadersCallback.Values.First());
}
[TestMethod]
public async Task ShouldDenyNoResult()
{
// arrange
string username = "user";
string password = "pw";
validatorRealm = "TEST";
var remote = IPAddress.Parse("1.2.3.4");
requestHeaders.Add("Authorization", $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes($"{username}:{password}"))}");
var middleware = GetMiddleware();
var context = GetContext(remote);
// act
await middleware.InvokeAsync(context);
// assert
Assert.AreEqual(401, responseStatusCodeCallback);
Assert.AreEqual(1, responseHeadersCallback.Count);
Assert.AreEqual("WWW-Authenticate", responseHeadersCallback.Keys.First());
Assert.AreEqual($"Basic realm=\"{validatorRealm}\"", responseHeadersCallback.Values.First());
Assert.AreEqual(1, validatorCallback.Count);
Assert.AreEqual(username, validatorCallback.First().username);
Assert.AreEqual(password, validatorCallback.First().password);
Assert.AreEqual(remote, validatorCallback.First().ipAddr);
}
[TestMethod]
public async Task ShouldBreakOnException()
{
// arrange
string username = "user";
requestHeaders.Add("Authorization", $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes($"{username}"))}");
var middleware = GetMiddleware();
var context = GetContext();
// act
await middleware.InvokeAsync(context);
// assert
Assert.AreEqual(500, responseStatusCodeCallback);
}
private BasicAuthenticationMiddleware GetMiddleware()
{
var nextMock = new Mock<RequestDelegate>();
var validatorMock = new Mock<IBasicAuthenticationValidator>();
validatorMock
.Setup(v => v.Realm)
.Returns(validatorRealm);
validatorMock
.Setup(v => v.ValidateAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<IPAddress>()))
.Callback<string, string, IPAddress>((username, password, ipAddress) => validatorCallback.Add((username, password, ipAddress)))
.ReturnsAsync(validatorResponse);
return new BasicAuthenticationMiddleware(nextMock.Object, validatorMock.Object);
}
private HttpContext GetContext(IPAddress remote = null)
{
// Request
var requestHeaderMock = new Mock<IHeaderDictionary>();
foreach (var header in requestHeaders)
{
requestHeaderMock
.Setup(h => h.ContainsKey(header.Key))
.Returns(true);
requestHeaderMock
.Setup(h => h[header.Key])
.Returns(header.Value);
}
var requestMock = new Mock<HttpRequest>();
requestMock
.Setup(r => r.Headers)
.Returns(requestHeaderMock.Object);
// Response
var responseHeaderMock = new Mock<IHeaderDictionary>();
responseHeaderMock
.SetupSet(h => h[It.IsAny<string>()] = It.IsAny<StringValues>())
.Callback<string, StringValues>((key, value) => responseHeadersCallback[key] = value);
var responseMock = new Mock<HttpResponse>();
responseMock
.Setup(r => r.Headers)
.Returns(responseHeaderMock.Object);
responseMock
.SetupSet(r => r.StatusCode = It.IsAny<int>())
.Callback<int>((code) => responseStatusCodeCallback = code);
// Connection
var connectionInfoMock = new Mock<ConnectionInfo>();
connectionInfoMock
.Setup(ci => ci.LocalIpAddress)
.Returns(IPAddress.Loopback);
connectionInfoMock
.Setup(ci => ci.RemoteIpAddress)
.Returns(remote ?? IPAddress.Loopback);
// Request Services
var requestServicesMock = new Mock<IServiceProvider>();
var contextMock = new Mock<HttpContext>();
contextMock
.Setup(c => c.Request)
.Returns(requestMock.Object);
contextMock
.Setup(c => c.Response)
.Returns(responseMock.Object);
contextMock
.Setup(c => c.Connection)
.Returns(connectionInfoMock.Object);
contextMock
.Setup(c => c.RequestServices)
.Returns(requestServicesMock.Object);
return contextMock.Object;
}
}
}

View File

@@ -0,0 +1,430 @@
using System;
using System.Collections.Generic;
using System.Net;
using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.Http;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
namespace UnitTests.AspNetCore.Extensions
{
[TestClass]
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
public class HttpContextExtensionsTests
{
private Mock<ISession> sessionMock;
private string tokenName;
private string tokenValue;
private Dictionary<string, string> requestHeaders;
private Dictionary<string, string> requestQueries;
private Dictionary<object, object> items;
private IPAddress remote;
[TestInitialize]
public void InitializeTests()
{
tokenName = null;
tokenValue = null;
requestHeaders = new Dictionary<string, string>();
requestQueries = new Dictionary<string, string>();
items = new Dictionary<object, object>();
remote = IPAddress.Loopback;
}
#region Antiforgery
[TestMethod]
public void ShouldReturnAntiforgery()
{
// arrange
tokenName = "af-token";
tokenValue = "security_first";
var context = GetContext();
// act
var result = context.GetAntiforgeryToken();
// assert
Assert.AreEqual(tokenName, result.Name);
Assert.AreEqual(tokenValue, result.Value);
}
[TestMethod]
public void ShouldReturnAntiforgeryNullService()
{
// arrange
tokenName = "af-token";
tokenValue = "security_first";
var context = GetContext(hasAntiforgery: false);
// act
var result = context.GetAntiforgeryToken();
// assert
Assert.AreEqual(null, result.Name);
Assert.AreEqual(null, result.Value);
}
[TestMethod]
public void ShouldReturnAntiforgeryNullToken()
{
// arrange
var context = GetContext();
// act
var result = context.GetAntiforgeryToken();
// assert
Assert.AreEqual(null, result.Name);
Assert.AreEqual(null, result.Value);
}
#endregion Antiforgery
#region RemoteAddres
[TestMethod]
public void ShouldReturnRemoteAddress()
{
// arrange
remote = IPAddress.Parse("1.2.3.4");
var context = GetContext();
// act
var result = context.GetRemoteIpAddress();
// assert
Assert.AreEqual(remote, result);
}
[TestMethod]
public void ShouldReturnDefaultHeader()
{
// arrange
remote = IPAddress.Parse("1.2.3.4");
var header = IPAddress.Parse("5.6.7.8");
requestHeaders.Add("X-Forwarded-For", header.ToString());
var context = GetContext();
// act
var result = context.GetRemoteIpAddress();
// assert
Assert.AreNotEqual(remote, result);
Assert.AreEqual(header, result);
}
[TestMethod]
public void ShouldReturnCustomHeader()
{
// arrange
remote = IPAddress.Parse("1.2.3.4");
string headerName = "FooBar";
var headerIp = IPAddress.Parse("5.6.7.8");
requestHeaders.Add(headerName, headerIp.ToString());
var context = GetContext();
// act
var result = context.GetRemoteIpAddress(headerName: headerName);
// assert
Assert.AreNotEqual(remote, result);
Assert.AreEqual(headerIp, result);
}
[TestMethod]
public void ShouldReturnAddressInvalidHeader()
{
// arrange
remote = IPAddress.Parse("1.2.3.4");
requestHeaders.Add("X-Forwarded-For", "1.2.3:4");
var context = GetContext();
// act
var result = context.GetRemoteIpAddress();
// assert
Assert.AreEqual(remote, result);
}
#endregion RemoteAddres
#region Local Request
[TestMethod]
public void ShouldReturnTrueOnLocal()
{
// arrange
remote = IPAddress.Loopback;
var context = GetContext();
// act
bool result = context.IsLocalRequest();
// assert
Assert.IsTrue(result);
}
[TestMethod]
public void ShouldReturnFalseOnRemote()
{
// arrange
remote = IPAddress.Parse("1.2.3.4");
var context = GetContext();
// act
bool result = context.IsLocalRequest();
// assert
Assert.IsFalse(result);
}
[TestMethod]
public void ShouldReturnTrueOnDefaultHeader()
{
// arrange
remote = IPAddress.Parse("1.2.3.4");
var headerIp = IPAddress.Loopback;
requestHeaders.Add("X-Forwarded-For", headerIp.ToString());
var context = GetContext();
// act
bool result = context.IsLocalRequest();
// assert
Assert.IsTrue(result);
}
[TestMethod]
public void ShouldReturnTrueOnCustomHeader()
{
// arrange
remote = IPAddress.Parse("1.2.3.4");
string headerName = "FooBar";
var headerIp = IPAddress.Loopback;
requestHeaders.Add(headerName, headerIp.ToString());
var context = GetContext();
// act
bool result = context.IsLocalRequest(headerName: headerName);
// assert
Assert.IsTrue(result);
}
[TestMethod]
public void ShouldReturnFalseOnDefaultHeader()
{
// arrange
var headerIp = IPAddress.Parse("1.2.3.4");
requestHeaders.Add("X-Forwarded-For", headerIp.ToString());
var context = GetContext();
// act
bool result = context.IsLocalRequest();
// assert
Assert.IsFalse(result);
}
[TestMethod]
public void ShouldReturnFalseOnCustomHeader()
{
// arrange
string headerName = "FooBar";
var headerIp = IPAddress.Parse("1.2.3.4");
requestHeaders.Add(headerName, headerIp.ToString());
var context = GetContext();
// act
bool result = context.IsLocalRequest(headerName: headerName);
// assert
Assert.IsFalse(result);
}
#endregion Local Request
#region ReturnUrl
[TestMethod]
public void ShouldReturnNull()
{
// arrange
var context = GetContext();
// act
string result = context.GetReturnUrl();
// assert
Assert.IsNull(result);
}
[TestMethod]
public void ShouldReturnOriginalRequest()
{
// arrange
string request = "abc";
string query = "def";
items.Add("OriginalRequest", request);
requestQueries.Add("ReturnUrl", query);
var context = GetContext();
// act
string result = context.GetReturnUrl();
// assert
Assert.AreEqual(request, result);
Assert.AreNotEqual(query, result);
}
[TestMethod]
public void ShouldReturnUrl()
{
// arrange
string query = "def";
requestQueries.Add("ReturnUrl", query);
var context = GetContext();
// act
string result = context.GetReturnUrl();
// assert
Assert.AreEqual(query, result);
}
#endregion ReturnUrl
#region Session
[TestMethod]
public void ShouldClearSession()
{
// arrange
var context = GetContext();
// act
context.ClearSession();
// assert
sessionMock.Verify(s => s.Clear(), Times.Once);
}
[TestMethod]
public void ShouldSkipWhenNoSession()
{
// arrange
var context = GetContext(hasSession: false);
// act
context.ClearSession();
// assert
sessionMock.Verify(s => s.Clear(), Times.Never);
}
#endregion Session
private HttpContext GetContext(bool hasAntiforgery = true, bool hasSession = true)
{
// Request
var requestHeaderMock = new Mock<IHeaderDictionary>();
foreach (var header in requestHeaders)
{
requestHeaderMock
.Setup(h => h.ContainsKey(header.Key))
.Returns(true);
requestHeaderMock
.Setup(h => h[header.Key])
.Returns(header.Value);
}
var requestQueryMock = new Mock<IQueryCollection>();
foreach (var query in requestQueries)
{
requestQueryMock
.Setup(h => h.ContainsKey(query.Key))
.Returns(true);
requestQueryMock
.Setup(h => h[query.Key])
.Returns(query.Value);
}
var requestMock = new Mock<HttpRequest>();
requestMock
.Setup(r => r.Headers)
.Returns(requestHeaderMock.Object);
requestMock
.Setup(r => r.Query)
.Returns(requestQueryMock.Object);
// Request Services
var requestServicesMock = new Mock<IServiceProvider>();
if (hasAntiforgery)
{
var antiforgeryMock = new Mock<IAntiforgery>();
antiforgeryMock
.Setup(af => af.GetAndStoreTokens(It.IsAny<HttpContext>()))
.Returns(string.IsNullOrWhiteSpace(tokenName) ? null : new AntiforgeryTokenSet(tokenValue, tokenValue, tokenName, tokenName));
requestServicesMock
.Setup(rs => rs.GetService(typeof(IAntiforgery)))
.Returns(antiforgeryMock.Object);
}
// Connection
var connectionInfoMock = new Mock<ConnectionInfo>();
connectionInfoMock
.Setup(ci => ci.LocalIpAddress)
.Returns(IPAddress.Loopback);
connectionInfoMock
.Setup(ci => ci.RemoteIpAddress)
.Returns(remote);
// Session
sessionMock = new Mock<ISession>();
var contextMock = new Mock<HttpContext>();
contextMock
.Setup(c => c.Request)
.Returns(requestMock.Object);
contextMock
.Setup(c => c.RequestServices)
.Returns(requestServicesMock.Object);
contextMock
.Setup(c => c.Connection)
.Returns(connectionInfoMock.Object);
contextMock
.Setup(c => c.Items)
.Returns(items);
if (hasSession)
{
contextMock
.Setup(c => c.Session)
.Returns(sessionMock.Object);
}
return contextMock.Object;
}
}
}

View File

@@ -0,0 +1,97 @@
using System;
using System.Linq;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace UnitTests.AspNetCore.Extensions
{
[TestClass]
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
public class ModelStateDictionaryExtensionsTests
{
private TestModel testModel;
[TestInitialize]
public void InitializeTests()
{
testModel = new TestModel
{
ValueA = "A",
ValueB = "B",
SubModel = new TestSubModel
{
SubValueA = "a",
SubValueB = "b"
}
};
}
[TestMethod]
public void ShouldAddNormalModelError()
{
// arrange
var modelState = new ModelStateDictionary();
// act
modelState.AddModelError(testModel, m => m.ValueA, "ShitHappens");
// assert
Assert.AreEqual(1, modelState.Count);
Assert.AreEqual("ValueA", modelState.Keys.First());
Assert.AreEqual("ShitHappens", modelState.Values.First().Errors.First().ErrorMessage);
}
[TestMethod]
public void ShouldAddExtendedModelError()
{
// arrange
var modelState = new ModelStateDictionary();
// act
modelState.AddModelError(testModel, m => m.SubModel.SubValueB, "ShitHappens");
// assert
Assert.AreEqual(1, modelState.Count);
Assert.AreEqual("SubModel.SubValueB", modelState.Keys.First());
Assert.AreEqual("ShitHappens", modelState.Values.First().Errors.First().ErrorMessage);
}
[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void ShouldThrowArgumentNull()
{
// arrange
ModelStateDictionary modelState = null;
// act
modelState.AddModelError(testModel, m => m.SubModel.SubValueB, "ShitHappens");
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void ShouldThrowInvalidOperation()
{
// arrange
var modelState = new ModelStateDictionary();
// act
modelState.AddModelError(testModel, m => m, "ShitHappens");
}
internal class TestModel
{
public string ValueA { get; set; }
public string ValueB { get; set; }
public TestSubModel SubModel { get; set; }
}
internal class TestSubModel
{
public string SubValueA { get; set; }
public string SubValueB { get; set; }
}
}
}

View File

@@ -0,0 +1,159 @@
using System.Text;
using Microsoft.AspNetCore.Http;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Newtonsoft.Json;
namespace UnitTests.AspNetCore.Extensions
{
[TestClass]
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
public class SessionExtensionsTests
{
private Mock<ISession> sessionMock;
private string sessionKey;
private byte[] sessionValue;
private TestModel model;
internal class TestModel
{
public string ValueA { get; set; }
public string ValueB { get; set; }
}
[TestInitialize]
public void InitializeTests()
{
sessionKey = null;
sessionValue = null;
model = new TestModel
{
ValueA = "A",
ValueB = "B"
};
}
[TestMethod]
public void ShouldCheckKeyExists()
{
// arrange
sessionKey = "exists";
var session = GetSession();
// act
bool result1 = session.HasKey("exists");
bool result2 = session.HasKey("somewhere");
// assert
Assert.IsTrue(result1);
Assert.IsFalse(result2);
}
[TestMethod]
public void ShouldGetValue()
{
// arrange
sessionKey = "test";
sessionValue = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(model));
var session = GetSession();
// act
var result = session.GetValue<TestModel>(sessionKey);
// assert
Assert.IsNotNull(result);
Assert.AreEqual(model.ValueA, result.ValueA);
Assert.AreEqual(model.ValueB, result.ValueB);
}
[TestMethod]
public void ShouldGetNull()
{
// arrange
sessionKey = "foo";
sessionValue = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(model));
var session = GetSession();
// act
var result = session.GetValue<TestModel>("bar");
// assert
Assert.IsNull(result);
}
[TestMethod]
public void ShouldGetValueWithFallback()
{
// arrange
sessionKey = "test";
sessionValue = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(model));
var session = GetSession();
// act
var result = session.GetValue(sessionKey, new TestModel());
// assert
Assert.IsNotNull(result);
Assert.AreEqual(model.ValueA, result.ValueA);
Assert.AreEqual(model.ValueB, result.ValueB);
}
[TestMethod]
public void ShouldGetFallback()
{
// arrange
sessionKey = "foo";
sessionValue = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(model));
var session = GetSession();
// act
var result = session.GetValue("bar", new TestModel());
// assert
Assert.IsNotNull(result);
Assert.AreEqual(null, result.ValueA);
Assert.AreEqual(null, result.ValueB);
}
[TestMethod]
public void ShouldSetValue()
{
// arrange
string key = "foobar";
var session = GetSession();
// act
session.SetValue(key, model);
// arrange
Assert.AreEqual(key, sessionKey);
Assert.AreEqual(JsonConvert.SerializeObject(model), Encoding.UTF8.GetString(sessionValue));
}
private ISession GetSession()
{
string[] keys = new[] { sessionKey };
sessionMock = new Mock<ISession>();
sessionMock
.Setup(s => s.TryGetValue(It.IsAny<string>(), out sessionValue))
.Returns<string, byte[]>((key, value) => sessionKey == key);
sessionMock
.Setup(s => s.Set(It.IsAny<string>(), It.IsAny<byte[]>()))
.Callback<string, byte[]>((key, value) =>
{
sessionKey = key;
sessionValue = value;
});
sessionMock
.Setup(s => s.Keys)
.Returns(keys);
return sessionMock.Object;
}
}
}

View File

@@ -0,0 +1,155 @@
using System;
using AMWD.Common.AspNetCore.Utilities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace UnitTests.AspNetCore.Utilities
{
[TestClass]
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
public class HtmlHelperTests
{
[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void ShouldThrowErrorOnEmptyColor()
{
// arrange
// act
HtmlHelper.IsDarkColor("");
// assert
// exception thrown
}
[TestMethod]
[ExpectedException(typeof(NotSupportedException))]
public void ShouldThrowErrorOnUnsupportedColor()
{
// arrange
// act
HtmlHelper.IsDarkColor("hsv(1, 2, 3)");
// assert
// exception thrown
}
[DataTestMethod]
[DataRow("rgb(255, 255, 255)")]
[DataRow("rgba(255, 255, 255, .5)")]
public void ShouldReturnLightColorForWhiteRgb(string white)
{
// arrange
// act
bool isDark = HtmlHelper.IsDarkColor(white);
// assert
Assert.IsFalse(isDark);
}
[DataTestMethod]
[DataRow("#ffFFff")]
[DataRow("FFffFF")]
public void ShouldReturnLightColorForWhiteFullHex(string white)
{
// arrange
// act
bool isDark = HtmlHelper.IsDarkColor(white);
// assert
Assert.IsFalse(isDark);
}
[DataTestMethod]
[DataRow("#fFf")]
[DataRow("FfF")]
public void ShouldReturnLightColorForWhiteShortHex(string white)
{
// arrange
// act
bool isDark = HtmlHelper.IsDarkColor(white);
// assert
Assert.IsFalse(isDark);
}
[DataTestMethod]
[DataRow("rgb(0, 0, 0)")]
[DataRow("rgba(0, 0, 0, .5)")]
public void ShouldReturnDarkColorForBlackRgb(string black)
{
// arrange
// act
bool isDark = HtmlHelper.IsDarkColor(black);
// assert
Assert.IsTrue(isDark);
}
[DataTestMethod]
[DataRow("#000000")]
[DataRow("000000")]
public void ShouldReturnDarkColorForBlackFullHex(string black)
{
// arrange
// act
bool isDark = HtmlHelper.IsDarkColor(black);
// assert
Assert.IsTrue(isDark);
}
[DataTestMethod]
[DataRow("#000")]
[DataRow("000")]
public void ShouldReturnDarkColorForBlackShortHex(string black)
{
// arrange
// act
bool isDark = HtmlHelper.IsDarkColor(black);
// assert
Assert.IsTrue(isDark);
}
[DataTestMethod]
[DataRow("rgb(255, 88, 0)")]
[DataRow("rgb(0, 218, 0)")]
[DataRow("rgb(0, 168, 255)")]
[DataRow("rgb(255, 38, 255)")]
[DataRow("rgb(128, 128, 128)")]
public void ShouldReturnLightColorForBorderColors(string color)
{
// arrange
// act
bool isDark = HtmlHelper.IsDarkColor(color);
// assert
Assert.IsFalse(isDark);
}
[DataTestMethod]
[DataRow("rgb(253, 88, 0)")]
[DataRow("rgb(0, 217, 0)")]
[DataRow("rgb(0, 168, 253)")]
[DataRow("rgb(254, 38, 254)")]
[DataRow("rgb(127, 127, 127)")]
public void ShouldReturnDarkColorForBorderColors(string color)
{
// arrange
// act
bool isDark = HtmlHelper.IsDarkColor(color);
// assert
Assert.IsTrue(isDark);
}
}
}

View File

@@ -0,0 +1,164 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace UnitTests.AspNetCore.Utilities
{
[TestClass]
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
public class PasswordHelperTests
{
[TestMethod]
public void ShouldReturnNullHashWhenNullProvided()
{
// arrange
string password = null;
// act
string hash = PasswordHelper.HashPassword(password);
// assert
Assert.IsNull(hash);
}
[TestMethod]
public void ShouldReturnEmptyHashWhenSpacesProvided()
{
// arrange
string password = " ";
// act
string hash = PasswordHelper.HashPassword(password);
// assert
Assert.AreEqual("", hash);
}
[TestMethod]
public void ShouldReturnHashWhenTextProvided()
{
// arrange
string password = "password";
// act
string hash = PasswordHelper.HashPassword(password);
// assert
Assert.IsTrue(!string.IsNullOrWhiteSpace(hash));
}
[TestMethod]
public void ShouldReturnFalseOnNullPassword()
{
// arrange
string password = null;
string hash = PasswordHelper.HashPassword(password);
// act
bool isValid = PasswordHelper.VerifyPassword(password, hash, out bool rehashNeeded);
// assert
Assert.IsFalse(isValid);
Assert.IsFalse(rehashNeeded);
}
[TestMethod]
public void ShouldReturnFalseOnEmptyPassword()
{
// arrange
string password = " ";
string hash = PasswordHelper.HashPassword(password);
// act
bool isValid = PasswordHelper.VerifyPassword(password, hash, out bool rehashNeeded);
// assert
Assert.IsFalse(isValid);
Assert.IsFalse(rehashNeeded);
}
[TestMethod]
public void ShouldReturnFalseOnNullHash()
{
// arrange
string password = "password";
string hash = null;
// act
bool isValid = PasswordHelper.VerifyPassword(password, hash, out bool rehashNeeded);
// assert
Assert.IsFalse(isValid);
Assert.IsFalse(rehashNeeded);
}
[TestMethod]
public void ShouldReturnFalseOnEmptyHash()
{
// arrange
string password = "password";
string hash = "";
// act
bool isValid = PasswordHelper.VerifyPassword(password, hash, out bool rehashNeeded);
// assert
Assert.IsFalse(isValid);
Assert.IsFalse(rehashNeeded);
}
[TestMethod]
public void ShouldReturnTrueOnSuccess()
{
// arrange
string password = "password";
string hash = PasswordHelper.HashPassword(password);
// act
bool isValid = PasswordHelper.VerifyPassword(password, hash, out bool rehashNeeded);
// assert
Assert.IsTrue(isValid);
Assert.IsFalse(rehashNeeded);
}
[TestMethod]
public void ShouldReturnFalseOnError()
{
// arrange
string password = "pass";
string hash = PasswordHelper.HashPassword(password + "word");
// act
bool isValid = PasswordHelper.VerifyPassword(password, hash, out bool rehashNeeded);
// assert
Assert.IsFalse(isValid);
Assert.IsFalse(rehashNeeded);
}
[TestMethod]
public void ShouldReturnTrueWithRehash()
{
// arrange
var devHasher = new PasswordHasher<object>();
var field = devHasher.GetType().GetField("_compatibilityMode", BindingFlags.NonPublic | BindingFlags.Instance);
field.SetValue(devHasher, PasswordHasherCompatibilityMode.IdentityV2);
string password = "password";
string hash = devHasher.HashPassword(null, password);
// act
bool isValid = PasswordHelper.VerifyPassword(password, hash, out bool rehashNeeded);
// assert
Assert.IsTrue(isValid);
Assert.IsTrue(rehashNeeded);
}
}
}