package database import ( "net" "testing" ) func TestIPToUint32(t *testing.T) { tests := []struct { name string ip string expected uint32 }{ { name: "Simple IP", ip: "192.168.1.1", expected: 3232235777, // 192<<24 + 168<<16 + 1<<8 + 1 }, { name: "Minimum IP", ip: "0.0.0.0", expected: 0, }, { name: "Maximum IP", ip: "255.255.255.255", expected: 4294967295, }, { name: "10.0.0.0", ip: "10.0.0.0", expected: 167772160, }, { name: "172.16.0.0", ip: "172.16.0.0", expected: 2886729728, }, { name: "8.8.8.8", ip: "8.8.8.8", expected: 134744072, }, { name: "1.2.3.4", ip: "1.2.3.4", expected: 16909060, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ip := net.ParseIP(tt.ip) if ip == nil { t.Fatalf("Failed to parse IP: %s", tt.ip) } result := ipToUint32(ip) if result != tt.expected { t.Errorf("ipToUint32(%s) = %d, want %d", tt.ip, result, tt.expected) } // Test with IPv4-mapped IPv6 address ip6 := net.ParseIP(tt.ip).To16() if ip6 != nil { result6 := ipToUint32(ip6) if result6 != tt.expected { t.Errorf("ipToUint32(%s as IPv6) = %d, want %d", tt.ip, result6, tt.expected) } } }) } } func TestCalculateIPv4Range(t *testing.T) { tests := []struct { name string cidr string wantStart uint32 wantEnd uint32 wantErr bool }{ { name: "Single IP /32", cidr: "192.168.1.1/32", wantStart: 3232235777, wantEnd: 3232235777, }, { name: "Class C /24", cidr: "192.168.1.0/24", wantStart: 3232235776, // 192.168.1.0 wantEnd: 3232236031, // 192.168.1.255 }, { name: "Class B /16", cidr: "192.168.0.0/16", wantStart: 3232235520, // 192.168.0.0 wantEnd: 3232301055, // 192.168.255.255 }, { name: "Class A /8", cidr: "10.0.0.0/8", wantStart: 167772160, // 10.0.0.0 wantEnd: 184549375, // 10.255.255.255 }, { name: "Entire IPv4 space /0", cidr: "0.0.0.0/0", wantStart: 0, wantEnd: 4294967295, }, { name: "Small subnet /30", cidr: "192.168.1.0/30", wantStart: 3232235776, // 192.168.1.0 wantEnd: 3232235779, // 192.168.1.3 }, { name: "Medium subnet /20", cidr: "172.16.0.0/20", wantStart: 2886729728, // 172.16.0.0 wantEnd: 2886733823, // 172.16.15.255 }, { name: "Private range 172.16/12", cidr: "172.16.0.0/12", wantStart: 2886729728, // 172.16.0.0 wantEnd: 2887778303, // 172.31.255.255 }, { name: "Google DNS /29", cidr: "8.8.8.8/29", wantStart: 134744072, // 8.8.8.8 (network is actually 8.8.8.8 with /29) wantEnd: 134744079, // 8.8.8.15 }, { name: "Non-zero host bits", cidr: "192.168.1.5/24", wantStart: 3232235776, // 192.168.1.0 (network address) wantEnd: 3232236031, // 192.168.1.255 }, { name: "Invalid CIDR", cidr: "192.168.1.1/33", wantErr: true, }, { name: "Invalid IP", cidr: "256.256.256.256/24", wantErr: true, }, { name: "IPv6 CIDR", cidr: "2001:db8::/32", wantErr: true, }, { name: "Empty CIDR", cidr: "", wantErr: true, }, { name: "Missing mask", cidr: "192.168.1.1", wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { start, end, err := CalculateIPv4Range(tt.cidr) if tt.wantErr { if err == nil { t.Errorf("CalculateIPv4Range(%s) expected error, got nil", tt.cidr) } return } if err != nil { t.Errorf("CalculateIPv4Range(%s) unexpected error: %v", tt.cidr, err) return } if start != tt.wantStart { t.Errorf("CalculateIPv4Range(%s) start = %d, want %d", tt.cidr, start, tt.wantStart) } if end != tt.wantEnd { t.Errorf("CalculateIPv4Range(%s) end = %d, want %d", tt.cidr, end, tt.wantEnd) } // Verify that start <= end if start > end { t.Errorf("CalculateIPv4Range(%s) start (%d) > end (%d)", tt.cidr, start, end) } // Verify the range size matches the CIDR mask if !tt.wantErr && tt.cidr != "" { _, ipNet, _ := net.ParseCIDR(tt.cidr) if ipNet != nil { ones, bits := ipNet.Mask.Size() expectedSize := uint32(1) << uint(bits-ones) actualSize := end - start + 1 if actualSize != expectedSize { t.Errorf("CalculateIPv4Range(%s) range size = %d, want %d", tt.cidr, actualSize, expectedSize) } } } }) } } func TestIPv4RangeIntegration(t *testing.T) { // Test that our functions work correctly together tests := []struct { name string cidr string testIPs []string shouldContain []bool }{ { name: "192.168.1.0/24", cidr: "192.168.1.0/24", testIPs: []string{ "192.168.1.0", "192.168.1.1", "192.168.1.255", "192.168.0.255", "192.168.2.0", }, shouldContain: []bool{true, true, true, false, false}, }, { name: "10.0.0.0/8", cidr: "10.0.0.0/8", testIPs: []string{ "10.0.0.0", "10.255.255.255", "10.1.2.3", "9.255.255.255", "11.0.0.0", }, shouldContain: []bool{true, true, true, false, false}, }, { name: "172.16.0.0/12", cidr: "172.16.0.0/12", testIPs: []string{ "172.16.0.0", "172.31.255.255", "172.20.1.1", "172.15.255.255", "172.32.0.0", }, shouldContain: []bool{true, true, true, false, false}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { start, end, err := CalculateIPv4Range(tt.cidr) if err != nil { t.Fatalf("Failed to calculate range for %s: %v", tt.cidr, err) } for i, testIP := range tt.testIPs { ip := net.ParseIP(testIP) if ip == nil { t.Fatalf("Failed to parse test IP: %s", testIP) } ipUint := ipToUint32(ip) contained := ipUint >= start && ipUint <= end if contained != tt.shouldContain[i] { t.Errorf("IP %s in range %s: got %v, want %v", testIP, tt.cidr, contained, tt.shouldContain[i]) } } }) } } func BenchmarkIPToUint32(b *testing.B) { ip := net.ParseIP("192.168.1.1") b.ResetTimer() for i := 0; i < b.N; i++ { _ = ipToUint32(ip) } } func BenchmarkCalculateIPv4Range(b *testing.B) { cidr := "192.168.0.0/16" b.ResetTimer() for i := 0; i < b.N; i++ { _, _, _ = CalculateIPv4Range(cidr) } }