1
0

Solution restructured to use multiple test projects

This commit is contained in:
2024-07-04 18:22:26 +02:00
parent 508379d704
commit df6763b99b
144 changed files with 387 additions and 1693 deletions

View File

@@ -0,0 +1,477 @@
using System;
using System.Collections.Generic;
using System.Net;
using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.Http;
using Moq;
namespace AMWD.Common.AspNetCore.Tests.Extensions
{
[TestClass]
public class HttpContextExtensionsTest
{
private Mock<ISession> _sessionMock;
private string _tokenFormName;
private string _tokenHeaderName;
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()
{
_tokenFormName = null;
_tokenHeaderName = null;
_tokenValue = null;
_requestHeaders = [];
_requestQueries = [];
_items = [];
_remote = IPAddress.Loopback;
}
#region Antiforgery
[TestMethod]
public void ShouldReturnAntiforgery()
{
// arrange
_tokenFormName = "af-token";
_tokenHeaderName = "af-header";
_tokenValue = "security_first";
var context = GetContext();
// act
var (formName, headerName, value) = context.GetAntiforgeryToken();
// assert
Assert.AreEqual(_tokenFormName, formName);
Assert.AreEqual(_tokenHeaderName, headerName);
Assert.AreEqual(_tokenValue, value);
}
[TestMethod]
public void ShouldReturnAntiforgeryNullService()
{
// arrange
_tokenFormName = "af-token";
_tokenHeaderName = "af-header";
_tokenValue = "security_first";
var context = GetContext(hasAntiforgery: false);
// act
var (formName, headerName, value) = context.GetAntiforgeryToken();
// assert
Assert.IsNull(formName);
Assert.IsNull(headerName);
Assert.IsNull(value);
}
[TestMethod]
public void ShouldReturnAntiforgeryNullToken()
{
// arrange
var context = GetContext();
// act
var (formName, headerName, value) = context.GetAntiforgeryToken();
// assert
Assert.IsNull(formName);
Assert.IsNull(headerName);
Assert.IsNull(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);
}
[DataTestMethod]
[DataRow("Cf-Connecting-Ip")]
[DataRow("X-Real-IP")]
[DataRow("X-Forwarded-For")]
public void ShouldReturnDefaultHeader(string headerName)
{
// arrange
_remote = IPAddress.Parse("1.2.3.4");
var header = IPAddress.Parse("5.6.7.8");
_requestHeaders.Add(headerName, 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());
_requestHeaders.Add("X-Forwarded-For", _remote.ToString());
var context = GetContext();
// act
var result = context.GetRemoteIpAddress(ipHeaderName: 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);
}
[TestMethod]
public void ShouldReturnFirstAddressOnMultipleProxies()
{
// arrange
_remote = IPAddress.Parse("1.2.3.4");
var header = IPAddress.Parse("5.6.7.8");
_requestHeaders.Add("X-Forwarded-For", $"{header}, 111.222.111.222");
var context = GetContext();
// act
var result = context.GetRemoteIpAddress();
// assert
Assert.AreNotEqual(_remote, result);
Assert.AreEqual(header, result);
}
[TestMethod]
public void ShouldReturnV4AddressOnMapped()
{
// arrange
_remote = IPAddress.Parse("1.2.3.4");
var header = IPAddress.Parse("::ffff:127.0.0.1");
_requestHeaders.Add("X-Forwarded-For", "::ffff:127.0.0.1");
var context = GetContext();
// act
var result = context.GetRemoteIpAddress();
// assert
Assert.AreNotEqual(_remote, result);
Assert.AreNotEqual(header, result);
Assert.AreEqual(header.MapToIPv4(), 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(ipHeaderName: 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(ipHeaderName: 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(_tokenValue) ? null : new AntiforgeryTokenSet(_tokenValue, _tokenValue, _tokenFormName, _tokenHeaderName));
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,95 @@
using System;
using System.Linq;
using Microsoft.AspNetCore.Mvc.ModelBinding;
namespace AMWD.Common.AspNetCore.Tests.Extensions
{
[TestClass]
public class ModelStateDictionaryExtensionsTest
{
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,157 @@
using System.Text;
using Microsoft.AspNetCore.Http;
using Moq;
using Newtonsoft.Json;
namespace AMWD.Common.AspNetCore.Tests.Extensions
{
[TestClass]
public class SessionExtensionsTest
{
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 = [_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;
}
}
}