using System.Linq; using System.Net.Http; using System.Reflection; using AMWD.Net.Api.Cloudflare; using Moq; using Moq.Protected; namespace Cloudflare.Core.Tests { [TestClass] public class CloudflareClientTest { private Mock _httpHandlerMock; private Mock _clientOptionsMock; private Mock _authenticationMock; [TestInitialize] public void Initialize() { _httpHandlerMock = new Mock(); _authenticationMock = new Mock(); _clientOptionsMock = new Mock(); _clientOptionsMock.Setup(o => o.BaseUrl).Returns("http://localhost/api/v4/"); _clientOptionsMock.Setup(o => o.Timeout).Returns(TimeSpan.FromSeconds(60)); _clientOptionsMock.Setup(o => o.MaxRetries).Returns(2); _clientOptionsMock.Setup(o => o.DefaultHeaders).Returns(new Dictionary()); _clientOptionsMock.Setup(o => o.DefaultQueryParams).Returns(new Dictionary()); _clientOptionsMock.Setup(o => o.AllowRedirects).Returns(false); _clientOptionsMock.Setup(o => o.UseProxy).Returns(false); } [TestMethod] public void ShouldInitializeWithEmailAndKey() { // Arrange string email = "test@example.com"; string apiKey = "some-api-key"; // Act using var client = new CloudflareClient(email, apiKey); // Assert var httpClient = client.GetType() .GetField("_httpClient", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(client) as HttpClient; Assert.IsNotNull(httpClient); Assert.AreEqual(email, httpClient.DefaultRequestHeaders.GetValues("X-Auth-Email").First()); Assert.AreEqual(apiKey, httpClient.DefaultRequestHeaders.GetValues("X-Auth-Key").First()); VerifyNoOtherCalls(); } [TestMethod] public void ShouldInitializeWithApiToken() { // Arrange string token = "some-special-api-token"; // Act using var client = new CloudflareClient(token); // Assert var httpClient = client.GetType() .GetField("_httpClient", BindingFlags.NonPublic | BindingFlags.Instance) .GetValue(client) as HttpClient; Assert.IsNotNull(httpClient); Assert.AreEqual($"Bearer {token}", httpClient.DefaultRequestHeaders.GetValues("Authorization").First()); VerifyNoOtherCalls(); } [TestMethod] [ExpectedException(typeof(ArgumentNullException))] public void ShouldThrowArgumentNullOnMissingAuthentication() { // Arrange // Act using var client = new CloudflareClient((IAuthentication)null); // Assert - ArgumentNullException } [TestMethod] public void ShouldAddCustomDefaultHeaders() { // Arrange var clientOptions = new ClientOptions(); clientOptions.DefaultHeaders.Add("SomeKey", "SomeValue"); // Act using var client = new CloudflareClient("token", clientOptions); // Assert var httpClient = client.GetType() .GetField("_httpClient", BindingFlags.NonPublic | BindingFlags.Instance) .GetValue(client) as HttpClient; Assert.IsNotNull(httpClient); Assert.IsTrue(httpClient.DefaultRequestHeaders.Contains("SomeKey")); Assert.AreEqual("SomeValue", httpClient.DefaultRequestHeaders.GetValues("SomeKey").First()); VerifyNoOtherCalls(); } [TestMethod] public void ShouldDisposeHttpClient() { // Arrange var client = GetClient(); // Act client.Dispose(); // Assert _httpHandlerMock.Protected().Verify("Dispose", Times.Once(), exactParameterMatch: true, true); VerifyDefault(); VerifyNoOtherCalls(); } [TestMethod] public void ShouldAllowMultipleDispose() { // Arrange var client = GetClient(); // Act client.Dispose(); client.Dispose(); // Assert _httpHandlerMock.Protected().Verify("Dispose", Times.Once(), exactParameterMatch: true, true); VerifyDefault(); VerifyNoOtherCalls(); } [TestMethod] public void ShouldAssertClientOptions() { // Arrange + Act var client = GetClient(); // Assert VerifyDefault(); VerifyNoOtherCalls(); } [TestMethod] [ExpectedException(typeof(ArgumentNullException))] public void ShouldThrowArgumentNullForBaseUrlOnAssertClientOptions() { // Arrange _clientOptionsMock .Setup(o => o.BaseUrl) .Returns((string)null); // Act var client = GetClient(); // Assert - ArgumentNullException } [TestMethod] [ExpectedException(typeof(ArgumentOutOfRangeException))] public void ShouldThrowArgumentOutOfRangeForTimeoutOnAssertClientOptions() { // Arrange _clientOptionsMock .Setup(o => o.Timeout) .Returns(TimeSpan.Zero); // Act var client = GetClient(); // Assert - ArgumentOutOfRangeException } [DataTestMethod] [DataRow(-1)] [DataRow(11)] [ExpectedException(typeof(ArgumentOutOfRangeException))] public void ShouldThrowArgumentOutOfRangeForMaxRetriesOnAssertClientOptions(int maxRetries) { // Arrange _clientOptionsMock .Setup(o => o.MaxRetries) .Returns(maxRetries); // Act var client = GetClient(); // Assert - ArgumentOutOfRangeException } [TestMethod] [ExpectedException(typeof(ArgumentNullException))] public void ShouldThrowArgumentNullForUseProxyOnAssertClientOptions() { // Arrange _clientOptionsMock .Setup(o => o.UseProxy) .Returns(true); // Act var client = GetClient(); // Assert - ArgumentNullException } private void VerifyDefault() { _clientOptionsMock.VerifyGet(o => o.AllowRedirects, Times.Once); _clientOptionsMock.VerifyGet(o => o.BaseUrl, Times.Exactly(2)); _clientOptionsMock.VerifyGet(o => o.DefaultHeaders, Times.Once); _clientOptionsMock.VerifyGet(o => o.MaxRetries, Times.Exactly(2)); _clientOptionsMock.VerifyGet(o => o.Proxy, Times.Once); _clientOptionsMock.VerifyGet(o => o.Timeout, Times.Exactly(2)); _clientOptionsMock.VerifyGet(o => o.UseProxy, Times.Exactly(2)); _authenticationMock.Verify(a => a.AddHeader(It.IsAny()), Times.Once); } private void VerifyNoOtherCalls() { _httpHandlerMock.VerifyNoOtherCalls(); _clientOptionsMock.VerifyNoOtherCalls(); _authenticationMock.VerifyNoOtherCalls(); } private CloudflareClient GetClient() { var httpClient = new HttpClient(_httpHandlerMock.Object); var client = new CloudflareClient(_authenticationMock.Object, _clientOptionsMock.Object); var httpClientField = client.GetType() .GetField("_httpClient", BindingFlags.NonPublic | BindingFlags.Instance); (httpClientField.GetValue(client) as HttpClient).Dispose(); httpClientField.SetValue(client, httpClient); return client; } } }