// Copyright (c) 2025 Tudor Stanciu using Bitip.Client.Models; using Bitip.Client.Tests.Helpers; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Xunit; namespace Bitip.Client.Tests { /// /// Unit tests for IBitipClient.GetBatchIpLocation method (batch lookup). /// public class GetBatchIpLocationTests { [Fact] public async Task GetBatchIpLocation_WithValidIps_ReturnsSucceeded() { // Arrange var ips = new List { "8.8.8.8", "1.1.1.1" }; var expectedResponse = new BatchIpLookupResponse { Succeeded = new List { new IpLocation { Ip = "8.8.8.8", Country = "United States", CountryCode = "US", IsInEuropeanUnion = false, Region = "California", City = "Mountain View", Latitude = 37.4056, Longitude = -122.0775, Timezone = "America/Los_Angeles" }, new IpLocation { Ip = "1.1.1.1", Country = "Australia", CountryCode = "AU", IsInEuropeanUnion = false, Region = "Queensland", City = "Brisbane", Latitude = -27.4679, Longitude = 153.0281, Timezone = "Australia/Brisbane" } }, Failed = new List() }; var client = BitipClientTestFixture.CreateMockedClientWithResponse(expectedResponse, "lookup/batch", HttpMethod.Post); // Act var result = await client.GetBatchIpLocation(ips); // Assert Assert.NotNull(result); var succeededList = result.Succeeded.ToList(); var failedList = result.Failed.ToList(); Assert.Equal(2, succeededList.Count); Assert.Empty(failedList); Assert.Equal("8.8.8.8", succeededList[0].Ip); Assert.Equal("United States", succeededList[0].Country); Assert.Equal("1.1.1.1", succeededList[1].Ip); Assert.Equal("Australia", succeededList[1].Country); } [Fact] public async Task GetBatchIpLocation_WithMixedSuccessAndErrors_ReturnsBoth() { // Arrange var ips = new List { "8.8.8.8", "192.168.1.1" }; var expectedResponse = new BatchIpLookupResponse { Succeeded = new List { new IpLocation { Ip = "8.8.8.8", Country = "United States", CountryCode = "US", IsInEuropeanUnion = false, Region = "California", City = "Mountain View" } }, Failed = new List { new BatchIpLookupError { Ip = "192.168.1.1", Error = "Private IP addresses are not supported" } } }; var client = BitipClientTestFixture.CreateMockedClientWithResponse(expectedResponse, "lookup/batch", HttpMethod.Post); // Act var result = await client.GetBatchIpLocation(ips); // Assert Assert.NotNull(result); var succeededList = result.Succeeded.ToList(); var failedList = result.Failed.ToList(); Assert.Single(succeededList); Assert.Single(failedList); Assert.Equal("United States", succeededList[0].Country); Assert.Contains("Private IP", failedList[0].Error); } [Fact] public async Task GetBatchIpLocation_WithNullList_ThrowsArgumentNullException() { // Arrange var client = BitipClientTestFixture.CreateMockedClient(mock => { }); // Act & Assert await Assert.ThrowsAsync(async () => await client.GetBatchIpLocation(null!)); } [Fact] public async Task GetBatchIpLocation_WithEmptyList_ThrowsArgumentException() { // Arrange var client = BitipClientTestFixture.CreateMockedClient(mock => { }); // Act & Assert await Assert.ThrowsAsync(async () => await client.GetBatchIpLocation(new List())); } [Fact] public async Task GetBatchIpLocation_WithInvalidIp_ReturnsInFailed() { // Arrange - Mix of valid and invalid IPs var ips = new List { "8.8.8.8", "invalid-ip", "1.1.1.1" }; // Mock response for the valid IPs only (invalid ones handled client-side) var expectedResponse = new BatchIpLookupResponse { Succeeded = new List { new IpLocation { Ip = "8.8.8.8", Country = "United States", CountryCode = "US", IsInEuropeanUnion = false, Region = "California", City = "Mountain View" }, new IpLocation { Ip = "1.1.1.1", Country = "Australia", CountryCode = "AU", IsInEuropeanUnion = false, Region = "Queensland", City = "Brisbane" } }, Failed = new List() }; var client = BitipClientTestFixture.CreateMockedClientWithResponse(expectedResponse, "lookup/batch", HttpMethod.Post); // Act var result = await client.GetBatchIpLocation(ips); // Assert Assert.NotNull(result); var succeededList = result.Succeeded.ToList(); var failedList = result.Failed.ToList(); Assert.Equal(2, succeededList.Count); // Valid IPs Assert.Single(failedList); // Invalid IP // Check valid IPs succeeded Assert.Equal("8.8.8.8", succeededList[0].Ip); Assert.Equal("1.1.1.1", succeededList[1].Ip); // Check invalid IP has error Assert.Equal("invalid-ip", failedList[0].Ip); Assert.Contains("Invalid IP", failedList[0].Error); } [Fact] public async Task GetBatchIpLocation_WithCancellation_ThrowsTaskCanceledException() { // Arrange var ips = new List { "8.8.8.8", "1.1.1.1" }; var client = BitipClientTestFixture.CreateCancelledClient(); var cts = new CancellationTokenSource(); cts.Cancel(); // Act & Assert await Assert.ThrowsAsync(async () => await client.GetBatchIpLocation(ips, cts.Token)); } [Fact] public async Task GetBatchIpLocation_WithServerError_ThrowsHttpRequestException() { // Arrange var ips = new List { "8.8.8.8" }; var client = BitipClientTestFixture.CreateClientWithError( HttpStatusCode.InternalServerError, "Internal Server Error", "Failed to process batch lookup"); // Act & Assert await Assert.ThrowsAsync(async () => await client.GetBatchIpLocation(ips)); } [Fact] public async Task GetBatchIpLocation_WithSingleIp_ReturnsResult() { // Arrange var ips = new List { "8.8.8.8" }; var expectedResponse = new BatchIpLookupResponse { Succeeded = new List { new IpLocation { Ip = "8.8.8.8", Country = "United States", CountryCode = "US", IsInEuropeanUnion = false, Region = "California", City = "Mountain View" } }, Failed = new List() }; var client = BitipClientTestFixture.CreateMockedClientWithResponse(expectedResponse, "lookup/batch", HttpMethod.Post); // Act var result = await client.GetBatchIpLocation(ips); // Assert Assert.NotNull(result); var succeededList = result.Succeeded.ToList(); Assert.Single(succeededList); Assert.Empty(result.Failed); Assert.Equal("8.8.8.8", succeededList[0].Ip); } [Fact] public async Task GetBatchIpLocation_WithMultipleIps_ReturnsAllResults() { // Arrange var ips = new List { "8.8.8.8", "1.1.1.1", "9.9.9.9" }; var expectedResponse = new BatchIpLookupResponse { Succeeded = new List { new IpLocation { Ip = "8.8.8.8", Country = "United States", CountryCode = "US", IsInEuropeanUnion = false, Region = "California", City = "Mountain View" }, new IpLocation { Ip = "1.1.1.1", Country = "Australia", CountryCode = "AU", IsInEuropeanUnion = false, Region = "Queensland", City = "Brisbane" }, new IpLocation { Ip = "9.9.9.9", Country = "United States", CountryCode = "US", IsInEuropeanUnion = false, Region = "California", City = "Oakland" } }, Failed = new List() }; var client = BitipClientTestFixture.CreateMockedClientWithResponse(expectedResponse, "lookup/batch", HttpMethod.Post); // Act var result = await client.GetBatchIpLocation(ips); // Assert Assert.NotNull(result); var succeededList = result.Succeeded.ToList(); Assert.Equal(3, succeededList.Count); Assert.Empty(result.Failed); Assert.All(succeededList, r => Assert.NotNull(r.Ip)); } [Fact] public async Task GetBatchIpLocation_WithOnlyInvalidIps_ReturnsAllInFailed() { // Arrange - Only invalid IPs (no API call should be made) var ips = new List { "invalid-ip", "not-an-ip", "xyz" }; var client = BitipClientTestFixture.CreateMockedClient(mock => { }); // Act var result = await client.GetBatchIpLocation(ips); // Assert Assert.NotNull(result); Assert.Empty(result.Succeeded); var failedList = result.Failed.ToList(); Assert.Equal(3, failedList.Count); Assert.All(failedList, r => { Assert.NotNull(r.Error); Assert.Contains("Invalid IP", r.Error); }); } } }