84 lines
3.2 KiB
Go
84 lines
3.2 KiB
Go
package reconcile
|
|
|
|
import (
|
|
"net"
|
|
"net/netip"
|
|
"slices"
|
|
"testing"
|
|
)
|
|
|
|
func TestPrefixFromIPNet(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
in net.IPNet
|
|
want string // empty: invalid
|
|
}{
|
|
{"v4 4-byte", net.IPNet{IP: net.IP{10, 1, 2, 0}, Mask: net.CIDRMask(24, 32)}, "10.1.2.0/24"},
|
|
{"v4 16-byte ip", net.IPNet{IP: net.ParseIP("10.1.2.0"), Mask: net.CIDRMask(24, 32)}, "10.1.2.0/24"},
|
|
{"v4 default as synthesized", net.IPNet{IP: net.IPv4zero, Mask: net.CIDRMask(0, 32)}, "0.0.0.0/0"},
|
|
{"v4 default as wgctrl", net.IPNet{IP: net.IP{0, 0, 0, 0}, Mask: net.CIDRMask(0, 32)}, "0.0.0.0/0"},
|
|
{"v4 4-byte ip with 128-bit mask", net.IPNet{IP: net.IP{10, 1, 2, 0}, Mask: net.CIDRMask(120, 128)}, "10.1.2.0/24"},
|
|
{"v4 4-byte ip with short 128-bit mask", net.IPNet{IP: net.IP{10, 1, 2, 0}, Mask: net.CIDRMask(64, 128)}, ""},
|
|
{"v4-mapped v6 stays v6", net.IPNet{IP: net.ParseIP("10.1.2.0"), Mask: net.CIDRMask(120, 128)}, "::ffff:10.1.2.0/120"},
|
|
{"v4-mapped v6 default range", net.IPNet{IP: net.ParseIP("::ffff:0:0"), Mask: net.CIDRMask(96, 128)}, "::ffff:0.0.0.0/96"},
|
|
{"v6", net.IPNet{IP: net.ParseIP("fd00::"), Mask: net.CIDRMask(64, 128)}, "fd00::/64"},
|
|
{"v6 default", net.IPNet{IP: net.IPv6zero, Mask: net.CIDRMask(0, 128)}, "::/0"},
|
|
{"host bits are cleared", net.IPNet{IP: net.IP{10, 1, 2, 77}, Mask: net.CIDRMask(24, 32)}, "10.1.2.0/24"},
|
|
{"non-canonical mask", net.IPNet{IP: net.IP{10, 1, 2, 0}, Mask: net.IPMask{255, 0, 255, 0}}, ""},
|
|
{"no ip", net.IPNet{Mask: net.CIDRMask(24, 32)}, ""},
|
|
{"v4 with 32-bit mask is unmapped", net.IPNet{IP: net.ParseIP("::ffff:10.1.2.0"), Mask: net.CIDRMask(24, 32)}, "10.1.2.0/24"},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, ok := PrefixFromIPNet(tt.in)
|
|
if ok != (tt.want != "") {
|
|
t.Fatalf("ok = %v, want %v (got %s)", ok, tt.want != "", got)
|
|
}
|
|
if ok && got != netip.MustParsePrefix(tt.want) {
|
|
t.Errorf("got %s, want %s", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestToIPNetRoundTrip(t *testing.T) {
|
|
for _, s := range []string{"10.1.2.0/24", "0.0.0.0/0", "fd00::/64", "::/0", "192.0.2.1/32", "::ffff:0.0.0.0/96"} {
|
|
want := netip.MustParsePrefix(s)
|
|
n := ToIPNet(want)
|
|
if want.Addr().Is4() && (len(n.IP) != 4 || len(n.Mask) != 4) {
|
|
t.Errorf("%s: IPv4 is not 4 bytes: %v", s, n)
|
|
}
|
|
got, ok := PrefixFromIPNet(n)
|
|
if !ok || got != want {
|
|
t.Errorf("%s: round trip gave %s", s, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestParsePrefixes(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
in string
|
|
want []string
|
|
wantErr bool
|
|
}{
|
|
{name: "empty", in: ""},
|
|
{name: "one", in: "10.0.0.0/8", want: []string{"10.0.0.0/8"}},
|
|
{name: "spaces and trailing comma", in: " 10.0.0.0/8 , fd00::/8,", want: []string{"10.0.0.0/8", "fd00::/8"}},
|
|
{name: "host bits are cleared", in: "10.1.2.3/8", want: []string{"10.0.0.0/8"}},
|
|
{name: "not a prefix", in: "10.0.0.0", wantErr: true},
|
|
{name: "one bad entry", in: "10.0.0.0/8,nope", wantErr: true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := ParsePrefixes(tt.in)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Fatalf("error = %v, wantErr %v", err, tt.wantErr)
|
|
}
|
|
if !slices.Equal(sorted(got), tt.want) {
|
|
t.Errorf("got %v, want %v", sorted(got), tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|