diff --git a/binding/csharp/IP2Region.Net.Test/SearcherTest.cs b/binding/csharp/IP2Region.Net.Test/SearcherTest.cs index 15a3364..bed1ccf 100644 --- a/binding/csharp/IP2Region.Net.Test/SearcherTest.cs +++ b/binding/csharp/IP2Region.Net.Test/SearcherTest.cs @@ -1,190 +1,90 @@ using IP2Region.Net.XDB; -using System.Buffers; -using System.Buffers.Binary; -using System.Net; -using System.Text; using Xunit; namespace IP2Region.Net.Test; public class SearcherTest { - private readonly string _xdbPath = Path.Combine(AppContext.BaseDirectory, "TestData", "ip2region_v6.xdb"); + private readonly string _xdbPathV4 = Path.Combine(AppContext.BaseDirectory, "TestData", "ip2region_v4.xdb"); + private readonly string _xdbPathV6 = Path.Combine(AppContext.BaseDirectory, "TestData", "ip2region_v6.xdb"); + + [Theory] + [InlineData("58.251.27.201", "中国|广东省|深圳市|联通", "v4")] + [InlineData("114.114.114.114", "中国|江苏省|南京市|0", "v4")] + [InlineData("119.29.29.29", "中国|北京|北京市|腾讯", "v4")] + [InlineData("223.5.5.5", "中国|浙江省|杭州市|阿里云", "v4")] + [InlineData("180.76.76.76", "中国|北京|北京市|百度", "v4")] + [InlineData("8.8.8.8", "", "v4")] + [InlineData("240e:3b7:3272:d8d0:db09:c067:8d59:539e", "中国|广东省|深圳市|家庭宽带", "v6")] + public void TestSearchCacheContent(string ip, string expected, string version) + { + var _xdbPath = version == "v4" ? _xdbPathV4 : _xdbPathV6; + var contentSearcher = new Searcher(CachePolicy.Content, _xdbPath); + var region = contentSearcher.Search(ip); + Assert.Equal(expected, region); + } + + [Theory] + [InlineData("58.251.27.201", "中国|广东省|深圳市|联通", "v4")] + [InlineData("114.114.114.114", "中国|江苏省|南京市|0", "v4")] + [InlineData("119.29.29.29", "中国|北京|北京市|腾讯", "v4")] + [InlineData("223.5.5.5", "中国|浙江省|杭州市|阿里云", "v4")] + [InlineData("180.76.76.76", "中国|北京|北京市|百度", "v4")] + [InlineData("8.8.8.8", "", "v4")] + [InlineData("240e:3b7:3272:d8d0:db09:c067:8d59:539e", "中国|广东省|深圳市|家庭宽带", "v6")] + public void TestSearchCacheVector(string ip, string expected, string version) + { + var _xdbPath = version == "v4" ? _xdbPathV4 : _xdbPathV6; + var vectorSearcher = new Searcher(CachePolicy.VectorIndex, _xdbPath); + var region = vectorSearcher.Search(ip); + Assert.Equal(expected, region); + } + + [Theory] + [InlineData("58.251.27.201", "中国|广东省|深圳市|联通", "v4")] + [InlineData("114.114.114.114", "中国|江苏省|南京市|0", "v4")] + [InlineData("119.29.29.29", "中国|北京|北京市|腾讯", "v4")] + [InlineData("223.5.5.5", "中国|浙江省|杭州市|阿里云", "v4")] + [InlineData("180.76.76.76", "中国|北京|北京市|百度", "v4")] + [InlineData("8.8.8.8", "", "v4")] + [InlineData("240e:3b7:3272:d8d0:db09:c067:8d59:539e", "中国|广东省|深圳市|家庭宽带", "v6")] + public void TestSearchCacheFile(string ip, string expected, string version) + { + var _xdbPath = version == "v4" ? _xdbPathV4 : _xdbPathV6; + var fileSearcher = new Searcher(CachePolicy.File, _xdbPath); + var region = fileSearcher.Search(ip); + Assert.Equal(expected, region); + } [Fact] public void Test() { - // 常量定义 - // 每个 vector 索引项的字节数 - var VectorIndexSize = 8; - - // vector 索引的列数 - var VectorIndexCols = 256; - - // vector 索引段整个的字节数 - var VectorIndexLength = 512; - - //var ipAddress = IPAddress.Parse("240e:3b7:3272:d8d0:db09:c067:8d59:539e"); - var ipAddress = IPAddress.Parse("2c0f:fda8:21::"); - // [36,14,3,183,50,114,216,208,219,9,192,103,141,89,83,158] - //var ipAddress = IPAddress.Parse("58.251.27.201"); - byte[] ip_bytes = ipAddress.GetAddressBytes(); - //Array.Reverse(bytes); - - //var ip = MemoryMarshal.Read(bytes); - - var il0 = ip_bytes[0] & 0xFF; - var il1 = ip_bytes[1] & 0xFF; - - var idx = il0 * VectorIndexCols * VectorIndexSize + il1 * VectorIndexSize; - - var data = Read(256 + idx, VectorIndexSize); - var sPtr = BinaryPrimitives.ReadUInt32LittleEndian(data.Span); - var ePtr = BinaryPrimitives.ReadUInt32LittleEndian(data.Span.Slice(4)); - - var indexSize = 38; - var l = 0; - var h = (ePtr - sPtr) / indexSize; - var dataLen = 0; - var dataPtr = 0l; - - var bytes = ip_bytes.Length; - var dBytes = ip_bytes.Length << 1; - var buff = new byte[indexSize]; - - while (l < h) - { - // 得到中间的索引项 - int m = (int)(l + h) >> 1; - - var p = (int)sPtr + m * indexSize; - - buff = Read(p, buff.Length).ToArray(); - - var s1 = BinaryPrimitives.ReadUInt32BigEndian(ip_bytes); - var s = BinaryPrimitives.ReadUInt32BigEndian(buff.AsSpan().Slice(0, ip_bytes.Length).ToArray()); - var e = BinaryPrimitives.ReadUInt32BigEndian(buff.AsSpan().Slice(ip_bytes.Length).ToArray()); - if (s1 < s) - { - h = m - 1; - } - else if (s1 > e) - { - l = m + 1; - } - else - { - dataLen = BinaryPrimitives.ReadUInt16LittleEndian(buff.AsSpan().Slice(dBytes, 2)); - dataPtr = BinaryPrimitives.ReadUInt32LittleEndian(buff.AsSpan().Slice(dBytes + 2)); - break; - } - } - - var regionBuff = Read((int)dataPtr, (int)dataLen); - var address = Encoding.UTF8.GetString(regionBuff.Span.ToArray()); - } - - private ReadOnlyMemory Read(int offset, int length) - { - int BufferSize = 4096; - - var stream = new FileStream(_xdbPath, FileMode.Open, FileAccess.Read, FileShare.Read, BufferSize, useAsync: true); - - byte[] buffer = ArrayPool.Shared.Rent(length); - int totalBytesRead = 0; - try - { - stream.Seek(offset, SeekOrigin.Begin); - - int bytesRead; - do - { - int bytesToRead = Math.Min(BufferSize, length - totalBytesRead); - bytesRead = stream.Read(buffer, totalBytesRead, bytesToRead); - totalBytesRead += bytesRead; - - } while (bytesRead > 0 && totalBytesRead < length); - } - finally - { - ArrayPool.Shared.Return(buffer); - } - - return new ReadOnlyMemory(buffer, 0, totalBytesRead); + var ip = XDB.Util.IpAddressToUInt32("58.251.27.201"); + var searcher = new Searcher(CachePolicy.File, _xdbPathV4); + var region = searcher.Search(ip); + Assert.Equal("中国|广东省|深圳市|联通", region); } [Theory] - [InlineData("114.114.114.114")] - [InlineData("119.29.29.29")] - [InlineData("223.5.5.5")] - [InlineData("180.76.76.76")] - [InlineData("8.8.8.8")] - public void TestSearchCacheContent(string ip) + [InlineData(CachePolicy.Content, "v4")] + [InlineData(CachePolicy.VectorIndex, "v4")] + [InlineData(CachePolicy.File, "v4")] + public void TestBenchSearch(CachePolicy cachePolicy, string version) { - var contentSearcher = new Searcher(CachePolicy.Content, _xdbPath); - var region = contentSearcher.Search(ip); - Console.WriteLine(region); - } + var _xdbPath = version == "v4" ? _xdbPathV4 : _xdbPathV6; + var searcher = new Searcher(cachePolicy, _xdbPath); + var srcPath = Path.Combine(AppContext.BaseDirectory, "TestData", $"ip{version}_source.txt"); - [Theory] - [InlineData("114.114.114.114")] - [InlineData("119.29.29.29")] - [InlineData("223.5.5.5")] - [InlineData("180.76.76.76")] - [InlineData("8.8.8.8")] - public void TestSearchCacheVector(string ip) - { - var vectorSearcher = new Searcher(CachePolicy.VectorIndex, _xdbPath); - var region = vectorSearcher.Search(ip); - Console.WriteLine(region); - } + //foreach (var line in File.ReadLines(srcPath)) + //{ + // var ps = line.Trim().Split("|", 3); + // var sip = ps[0]; + // var eip = ps[1]; - [Theory] - [InlineData("114.114.114.114")] - [InlineData("119.29.29.29")] - [InlineData("223.5.5.5")] - [InlineData("180.76.76.76")] - [InlineData("8.8.8.8")] - public void TestSearchCacheFile(string ip) - { - var fileSearcher = new Searcher(CachePolicy.File, _xdbPath); - var region = fileSearcher.Search(ip); - Console.WriteLine(region); - } - - [Theory] - [InlineData(CachePolicy.Content)] - [InlineData(CachePolicy.VectorIndex)] - [InlineData(CachePolicy.File)] - public void TestBenchSearch(CachePolicy cachePolicy) - { - Searcher searcher = new Searcher(cachePolicy, _xdbPath); - var srcPath = Path.Combine(AppContext.BaseDirectory, "TestData", "ipv4_source.txt"); - - foreach (var line in File.ReadLines(srcPath)) - { - var ps = line.Trim().Split("|", 3); - - if (ps.Length != 3) - { - throw new ArgumentException($"invalid ip segment line {line}", nameof(line)); - } - - var sip = Util.IpAddressToUInt32(ps[0]); - var eip = Util.IpAddressToUInt32(ps[1]); - var mip = Util.GetMidIp(sip, eip); - - uint[] temp = { sip, Util.GetMidIp(sip, mip), mip, Util.GetMidIp(mip, eip), eip }; - - foreach (var ip in temp) - { - //var region = searcher.Search(ip); - - //if (region != ps[2]) - //{ - // throw new Exception($"failed search {ip} with ({region}!={ps[2]})"); - //} - } - } + // var s1 = searcher.Search(sip); + // var s2 = searcher.Search(eip); + // //Assert.Equal(s1, ps[2]); + // //Assert.Equal(s2, ps[2]); + //} } } \ No newline at end of file diff --git a/binding/csharp/IP2Region.Net.Test/XdbTest.cs b/binding/csharp/IP2Region.Net.Test/XdbTest.cs index 07d91bd..b61c911 100644 --- a/binding/csharp/IP2Region.Net.Test/XdbTest.cs +++ b/binding/csharp/IP2Region.Net.Test/XdbTest.cs @@ -1,44 +1,76 @@ -using IP2Region.Net.XDB; -using System.Buffers; +using System.Buffers; using System.Buffers.Binary; -using System.Net; using Xunit; namespace IP2Region.Net.Test; public class XdbTest { - [Theory] - [InlineData("v4")] - [InlineData("v6")] - public async Task Version_Ok(string version) + [Fact] + public async Task VersionIPV4_Ok() { - var db = Path.Combine(AppContext.BaseDirectory, "TestData", $"ip2region_{version}.xdb"); + var db = Path.Combine(AppContext.BaseDirectory, "TestData", $"ip2region_v4.xdb"); using var reader = File.OpenRead(db); using var owner = MemoryPool.Shared.Rent(256); var length = await reader.ReadAsync(owner.Memory[0..256]); Assert.Equal(256, length); - var ver = BinaryPrimitives.ReadUInt16LittleEndian(owner.Memory[..2].ToArray()); - var indexPolicy = BinaryPrimitives.ReadUInt16LittleEndian(owner.Memory.Slice(2, 2).ToArray()); - var createdAt = BinaryPrimitives.ReadUInt16LittleEndian(owner.Memory.Slice(4, 4).ToArray()); - var startIndexPtr = BinaryPrimitives.ReadUInt16LittleEndian(owner.Memory.Slice(8, 4).ToArray()); - var endIndexPtr = BinaryPrimitives.ReadUInt16LittleEndian(owner.Memory.Slice(12, 4).ToArray()); + var ver = BinaryPrimitives.ReadUInt16LittleEndian(owner.Memory.Span[..2]); + Assert.Equal(3, ver); + + var indexPolicy = BinaryPrimitives.ReadUInt16LittleEndian(owner.Memory.Span.Slice(2, 2)); + Assert.Equal(1, indexPolicy); + + var createdAt = BinaryPrimitives.ReadUInt32LittleEndian(owner.Memory.Span.Slice(4, 4)); + var dtm = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + dtm = dtm.AddSeconds(createdAt); + Assert.Equal("2025-09-06 02:24:16", dtm.ToString("yyyy-MM-dd HH:mm:ss")); + + var startIndexPtr = BinaryPrimitives.ReadUInt32LittleEndian(owner.Memory.Span.Slice(8, 4)); + Assert.Equal((uint)955933, startIndexPtr); + + var endIndexPtr = BinaryPrimitives.ReadUInt32LittleEndian(owner.Memory.Span.Slice(12, 4)); + Assert.Equal((uint)11042415, endIndexPtr); // since IPv6 supporting - var ipVersion = BinaryPrimitives.ReadUInt16LittleEndian(owner.Memory.Slice(16, 2).ToArray()); - var runtimePtrBytes = BinaryPrimitives.ReadUInt16LittleEndian(owner.Memory.Slice(18, 2).ToArray()); + var ipVersion = BinaryPrimitives.ReadUInt16LittleEndian(owner.Memory.Span.Slice(16, 2)); + Assert.Equal(4, ipVersion); + + var runtimePtrBytes = BinaryPrimitives.ReadUInt16LittleEndian(owner.Memory.Span.Slice(18, 2)); + Assert.Equal(4, runtimePtrBytes); } [Fact] - public void ParseIp() + public async Task VersionIPV6_Ok() { - //var ip = IPAddress.Parse("2409:895a:8b4:2de4:20e7:5a15:fe6f:431c"); - var ip = IPAddress.Parse("183.160.236.53"); - var ipNum = Util.IpAddressToUInt32(ip); + var db = Path.Combine(AppContext.BaseDirectory, "TestData", $"ip2region_v6.xdb"); + using var reader = File.OpenRead(db); - var searcher = new Searcher(CachePolicy.Content, Path.Combine(AppContext.BaseDirectory, "TestData", "ip2region_v4.xdb")); - var result = searcher.Search(ip); + using var owner = MemoryPool.Shared.Rent(256); + var length = await reader.ReadAsync(owner.Memory[0..256]); + Assert.Equal(256, length); + + var ver = BinaryPrimitives.ReadUInt16LittleEndian(owner.Memory.Span[..2]); + Assert.Equal(3, ver); + + var indexPolicy = BinaryPrimitives.ReadUInt16LittleEndian(owner.Memory.Span.Slice(2, 2)); + var createdAt = BinaryPrimitives.ReadUInt32LittleEndian(owner.Memory.Span.Slice(4, 4)); + var dtm = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + dtm = dtm.AddSeconds(createdAt); + Assert.Equal("2025-10-17 04:41:04", dtm.ToString("yyyy-MM-dd HH:mm:ss")); + + var startIndexPtr = BinaryPrimitives.ReadUInt32LittleEndian(owner.Memory.Span.Slice(8, 4)); + Assert.Equal((uint)3094259, startIndexPtr); + + var endIndexPtr = BinaryPrimitives.ReadUInt32LittleEndian(owner.Memory.Span.Slice(12, 4)); + Assert.Equal((uint)36258303, endIndexPtr); + + // since IPv6 supporting + var ipVersion = BinaryPrimitives.ReadUInt16LittleEndian(owner.Memory.Span.Slice(16, 2)); + Assert.Equal(6, ipVersion); + + var runtimePtrBytes = BinaryPrimitives.ReadUInt16LittleEndian(owner.Memory.Span.Slice(18, 2)); + Assert.Equal(4, runtimePtrBytes); } }