github.com/hairyhenderson/gomplate/v4@v4.0.0-pre-2.0.20240520121557-362f058f0c93/internal/cidr/cidr_test.go (about) 1 package cidr 2 3 import ( 4 "fmt" 5 "math/big" 6 "net/netip" 7 "testing" 8 9 "github.com/stretchr/testify/assert" 10 "github.com/stretchr/testify/require" 11 ) 12 13 func TestSubnetBig(t *testing.T) { 14 cases := []struct { 15 base string 16 num *big.Int 17 out string 18 bits int 19 err bool 20 }{ 21 { 22 base: "192.168.2.0/20", 23 bits: 4, 24 num: big.NewInt(int64(6)), 25 out: "192.168.6.0/24", 26 }, 27 { 28 base: "192.168.2.0/20", 29 bits: 4, 30 num: big.NewInt(int64(0)), 31 out: "192.168.0.0/24", 32 }, 33 { 34 base: "192.168.0.0/31", 35 bits: 1, 36 num: big.NewInt(int64(1)), 37 out: "192.168.0.1/32", 38 }, 39 { 40 base: "192.168.0.0/21", 41 bits: 4, 42 num: big.NewInt(int64(7)), 43 out: "192.168.3.128/25", 44 }, 45 { 46 base: "fe80::/48", 47 bits: 16, 48 num: big.NewInt(int64(6)), 49 out: "fe80:0:0:6::/64", 50 }, 51 { 52 base: "fe80::/48", 53 bits: 33, 54 num: big.NewInt(int64(6)), 55 out: "fe80::3:0:0:0/81", 56 }, 57 { 58 base: "fe80::/49", 59 bits: 16, 60 num: big.NewInt(int64(7)), 61 out: "fe80:0:0:3:8000::/65", 62 }, 63 { 64 base: "192.168.2.0/31", 65 bits: 2, 66 num: big.NewInt(int64(0)), 67 err: true, // not enough bits to expand into 68 }, 69 { 70 base: "fe80::/126", 71 bits: 4, 72 num: big.NewInt(int64(0)), 73 err: true, // not enough bits to expand into 74 }, 75 { 76 base: "192.168.2.0/24", 77 bits: 4, 78 num: big.NewInt(int64(16)), 79 err: true, // can't fit 16 into 4 bits 80 }, 81 } 82 83 for _, testCase := range cases { 84 t.Run(fmt.Sprintf("SubnetBig(%#v,%#v,%#v)", testCase.base, testCase.bits, testCase.num), func(t *testing.T) { 85 base := netip.MustParsePrefix(testCase.base) 86 87 subnet, err := SubnetBig(base, testCase.bits, testCase.num) 88 if testCase.err { 89 require.Error(t, err) 90 } else { 91 require.NoError(t, err) 92 assert.Equal(t, testCase.out, subnet.String()) 93 } 94 }) 95 } 96 } 97 98 func TestHostBig(t *testing.T) { 99 cases := []struct { 100 prefix string 101 num *big.Int 102 out string 103 err bool 104 }{ 105 { 106 prefix: "192.168.2.0/20", 107 num: big.NewInt(int64(6)), 108 out: "192.168.0.6", 109 }, 110 { 111 prefix: "192.168.0.0/20", 112 num: big.NewInt(int64(257)), 113 out: "192.168.1.1", 114 }, 115 { 116 prefix: "2001:db8::/32", 117 num: big.NewInt(int64(1)), 118 out: "2001:db8::1", 119 }, 120 { 121 prefix: "192.168.1.0/24", 122 num: big.NewInt(int64(256)), 123 err: true, // only 0-255 will fit in 8 bits 124 }, 125 { 126 prefix: "192.168.0.0/30", 127 num: big.NewInt(int64(-3)), 128 out: "192.168.0.1", // 4 address (0-3) in 2 bits; 3rd from end = 1 129 }, 130 { 131 prefix: "192.168.0.0/30", 132 num: big.NewInt(int64(-4)), 133 out: "192.168.0.0", // 4 address (0-3) in 2 bits; 4th from end = 0 134 }, 135 { 136 prefix: "192.168.0.0/30", 137 num: big.NewInt(int64(-5)), 138 err: true, // 4 address (0-3) in 2 bits; cannot accommodate 5 139 }, 140 { 141 prefix: "fd9d:bc11:4020::/64", 142 num: big.NewInt(int64(2)), 143 out: "fd9d:bc11:4020::2", 144 }, 145 { 146 prefix: "fd9d:bc11:4020::/64", 147 num: big.NewInt(int64(-2)), 148 out: "fd9d:bc11:4020:0:ffff:ffff:ffff:fffe", 149 }, 150 } 151 152 for _, testCase := range cases { 153 t.Run(fmt.Sprintf("HostBig(%v,%v)", testCase.prefix, testCase.num), func(t *testing.T) { 154 network := netip.MustParsePrefix(testCase.prefix) 155 156 gotIP, err := HostBig(network, testCase.num) 157 if testCase.err { 158 require.Error(t, err) 159 } else { 160 require.NoError(t, err) 161 assert.Equal(t, testCase.out, gotIP.String()) 162 } 163 }) 164 } 165 } 166 167 func TestPreviousNextSubnet(t *testing.T) { 168 testCases := []struct { 169 next, prev string 170 overflow bool 171 }{ 172 {"10.0.0.0/24", "9.255.255.0/24", false}, 173 {"100.0.0.0/26", "99.255.255.192/26", false}, 174 {"0.0.0.0/26", "255.255.255.192/26", true}, 175 {"2001:db8:e000::/36", "2001:db8:d000::/36", false}, 176 {"::/64", "ffff:ffff:ffff:ffff::/64", true}, 177 } 178 for _, tc := range testCases { 179 c1 := netip.MustParsePrefix(tc.next) 180 c2 := netip.MustParsePrefix(tc.prev) 181 mask := c1.Bits() 182 183 p1, rollback := PreviousSubnet(c1, mask) 184 if tc.overflow { 185 assert.True(t, rollback) 186 continue 187 } 188 189 assert.Equal(t, c2.String(), p1.String()) 190 } 191 192 for _, tc := range testCases { 193 c1 := netip.MustParsePrefix(tc.next) 194 c2 := netip.MustParsePrefix(tc.prev) 195 mask := c1.Bits() 196 197 n1, rollover := NextSubnet(c2, mask) 198 if tc.overflow { 199 assert.True(t, rollover) 200 continue 201 } 202 assert.Equal(t, c1, n1) 203 } 204 }