diff --git a/src/test/test_ipv4.ts b/src/test/test_ipv4.ts index dd7ef4b..d313af6 100644 --- a/src/test/test_ipv4.ts +++ b/src/test/test_ipv4.ts @@ -1,4 +1,6 @@ import Ipv4ToRegion from "../lib/ipv4"; +import * as fs from "fs"; +import * as path from "path"; const queryInMemoey = new Ipv4ToRegion(); @@ -42,6 +44,25 @@ describe("search", function () { const res = queryInMemoey.search(NEIWAN_IP, false); expect(res).toMatchObject(NEIWAN); }); + + // Test for an IP that is valid but not expected to be in the database + // Assuming "0.0.0.1" is not in the ip2region.db or resolves to a default/null entry + // If this test fails because "0.0.0.1" IS in the database, pick another IP. + // For example, an IP from a reserved range like "240.0.0.1" + // Using an IP from 240.0.0.0/4 (Class E, reserved) + const UNKNOWN_IP = "250.250.250.250"; + + it("Not Found - Valid IP not in DB (parsed result)", function () { + const res = queryInMemoey.search(UNKNOWN_IP); + // Expecting null because if searchLong returns null, parseResult(null) is null + expect(res).toBeNull(); + }); + + it("Not Found - Valid IP not in DB (raw result)", function () { + const res = queryInMemoey.search(UNKNOWN_IP, false); + // Expecting null because searchLong should return null + expect(res).toBeNull(); + }); }); describe("More Tests", function () { @@ -60,6 +81,58 @@ describe("More Tests", function () { }); }); +describe("Initialization Tests", function () { + const tempDbPath = path.join("/tmp", "ip2region_test.db"); + const originalDbPath = path.resolve(__dirname, "../../data/ip2region.db"); // Corrected path to project root data + + beforeAll(() => { + // Copy the original database to a temporary location + try { + fs.copyFileSync(originalDbPath, tempDbPath); + } catch (err) { + console.error("Error copying DB for test:", err); + // If copy fails, we might want to skip or fail the test suite for this block + throw new Error(`Failed to copy DB from ${originalDbPath} to ${tempDbPath}: ${err}`); + } + }); + + afterAll(() => { + // Clean up the temporary database file + try { + if (fs.existsSync(tempDbPath)) { + fs.unlinkSync(tempDbPath); + } + } catch (err) { + console.error("Error deleting temporary DB:", err); + } + }); + + it("should instantiate with an absolute path to a valid DB file", function () { + let queryWithAbsolutePath: Ipv4ToRegion | null = null; + // Attempt to instantiate + try { + queryWithAbsolutePath = new Ipv4ToRegion(tempDbPath); + } catch (e) { + // Let Jest handle unexpected errors during instantiation + throw e; + } + + // Assert that instantiation was successful and the object is not null + expect(queryWithAbsolutePath).not.toBeNull(); + + // Perform checks only if queryWithAbsolutePath is confirmed to be non-null + if (queryWithAbsolutePath) { + const res = queryWithAbsolutePath.search(ALIYUN_IP); + expect(res).toMatchObject(ALIYUN2); // Check if a known IP lookup works + } else { + // This path should ideally not be reached if instantiation is expected to succeed. + // Explicitly fail if queryWithAbsolutePath is null, which means instantiation failed silently + // or the logic is flawed. + fail("Ipv4ToRegion instantiation with absolute path resulted in a null object without throwing an error."); + } + }); +}); + describe("BugFix - 1", function () { const ip = "218.70.78.68"; const ret = Object.freeze({ city: 2430, region: "中国|0|重庆|重庆市|电信" }); diff --git a/src/test/test_ipv6.ts b/src/test/test_ipv6.ts index 91a80d0..afe1869 100644 --- a/src/test/test_ipv6.ts +++ b/src/test/test_ipv6.ts @@ -100,6 +100,14 @@ describe("More Tests", function () { }); describe("Parse Tests", function () { + it("should return null for IPv4-style input if ipv4 instance is not set", function () { + const ipv6InstanceWithoutV4 = new Ipv6ToRegion(); // No setIpv4Ins + const ipv4StyleResult = { city: 123, region: "Some|Region|String" }; + // Type assertion needed as 'city' is not in Ipv6ToRegionRes + const result = (ipv6InstanceWithoutV4 as any).parseResult(ipv4StyleResult as any); + expect(result).toBeNull(); + }); + it("parse gover", function () { const ret = (queryInMemoey as any).parseResult({ cArea: "中国北京市", aArea: "" }); expect(ret).toMatchObject({ isp: "", data: "中国北京市", country: "中国", province: "北京市", city: "" }); @@ -123,7 +131,50 @@ describe("Parse Tests", function () { data: "中国湖北省恩施土家族苗族自治州恩施市", country: "中国", province: "湖北省", - city: "恩施土家族苗族自治州", + city: "恩施土家族苗族自治州", // Correctly extracts the full autonomous prefecture + }); + }); + + it("parse city with '市' before '州' (Scenario B1)", function () { + // Example: 中国测试省石家庄市辛集自治州 (hypothetical) + // Here, "石家庄市" is city1, "辛集自治州" contains city2='州'. city1 is before city2. + const cArea = "中国测试省石家庄市辛集自治州"; + const ret = (queryInMemoey as any).parseResult({ cArea, aArea: "TestISP_B1" }); + expect(ret).toMatchObject({ + isp: "TestISP_B1", + data: cArea, + country: "中国", + province: "测试省", + city: "石家庄市", // Expects to extract "石家庄市" + }); + }); + + it("parse city with '市' immediately after '州' (Scenario B2, city1 - city2 == 1)", function () { + // Example: 中国测试省测试州市开发区 (hypothetical: "测试州市" is the city) + // Here, city2 is '州', city1 is '市'. city1 - city2 == 1. + const cArea = "中国测试省测试州市开发区"; + const ret = (queryInMemoey as any).parseResult({ cArea, aArea: "TestISP_B2" }); + expect(ret).toMatchObject({ + isp: "TestISP_B2", + data: cArea, + country: "中国", + province: "测试省", + city: "测试州市", // Expects to extract "测试州市" due to city1 - city2 == 1 logic + }); + }); + + it("parse city with '市' after '州' but not immediately (Scenario B2, city1 - city2 != 1 false path)", function () { + // Example from existing tests: "中国湖北省恩施土家族苗族自治州恩施市" + // city2 is '州' in "自治州", city1 is '市' in "恩施市". city1 > city2, but city1 - city2 is not 1. + // This will take the `else` of `if (city1 - city2 == 1)` + const cArea = "中国湖北省恩施土家族苗族自治州恩施市"; // Existing complex case + const ret = (queryInMemoey as any).parseResult({ cArea, aArea: "TestISP_B2_else" }); + expect(ret).toMatchObject({ + isp: "TestISP_B2_else", + data: cArea, + country: "中国", + province: "湖北省", + city: "恩施土家族苗族自治州", // Extracts "恩施土家族苗族自治州" }); }); }); diff --git a/src/test/test_lib.ts b/src/test/test_lib.ts index bc39a83..eed2e61 100644 --- a/src/test/test_lib.ts +++ b/src/test/test_lib.ts @@ -57,3 +57,27 @@ describe("More Tests", function () { expect(ins.search(ALIYUN_IP)).toMatchObject(ALIYUN2); }); }); + +describe("Invalid Inputs", function () { + const INVALID_IP_STRING_1 = "not-an-ip"; + const INVALID_IP_STRING_2 = "123.456.789.0"; // Invalid octet + const INVALID_IP_STRING_3 = ""; // Empty string + + it("searchRaw should return null for invalid IP string with parse=true", function () { + expect(queryInMemoey.searchRaw(INVALID_IP_STRING_1, true)).toBeNull(); + expect(queryInMemoey.searchRaw(INVALID_IP_STRING_2, true)).toBeNull(); + expect(queryInMemoey.searchRaw(INVALID_IP_STRING_3, true)).toBeNull(); + }); + + it("searchRaw should return null for invalid IP string with parse=false", function () { + expect(queryInMemoey.searchRaw(INVALID_IP_STRING_1, false)).toBeNull(); + expect(queryInMemoey.searchRaw(INVALID_IP_STRING_2, false)).toBeNull(); + expect(queryInMemoey.searchRaw(INVALID_IP_STRING_3, false)).toBeNull(); + }); + + it("search should return null for invalid IP string", function () { + expect(queryInMemoey.search(INVALID_IP_STRING_1)).toBeNull(); + expect(queryInMemoey.search(INVALID_IP_STRING_2)).toBeNull(); + expect(queryInMemoey.search(INVALID_IP_STRING_3)).toBeNull(); + }); +});