Add unit tests

This commit is contained in:
Mayuresh Gaitonde
2020-12-17 17:25:53 -08:00
parent 3702339f44
commit 6be4d69d02
705 changed files with 120529 additions and 150051 deletions

6
vendor/github.com/k-sone/critbitgo/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,6 @@
language: go
go:
- 1.5
- 1.6
- 1.7

15
vendor/github.com/k-sone/critbitgo/CHANGES.md generated vendored Normal file
View File

@@ -0,0 +1,15 @@
## 1.3.0 (2019/09/30)
- Add Net.Walk [#9](https://github.com/k-sone/critbitgo/pull/9)
## 1.2.0 (2018/04/25)
- Add ContainedIP() as fast way to check an IP [#7](https://github.com/k-sone/critbitgo/pull/7)
## 1.1.0 (2016/12/29)
- Add `LongestPrefix ` and `Walk` functions
## 1.0.0 (2016/04/02)
- Initial release

22
vendor/github.com/k-sone/critbitgo/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Keita Sone
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

44
vendor/github.com/k-sone/critbitgo/README.md generated vendored Normal file
View File

@@ -0,0 +1,44 @@
[![Build Status](https://travis-ci.org/k-sone/critbitgo.svg?branch=master)](https://travis-ci.org/k-sone/critbitgo)
critbitgo
=========
[Crit-bit trees](http://cr.yp.to/critbit.html) in golang and its applications.
This implementation extended to handle the key that contains a null character from [C implementation](https://github.com/agl/critbit).
Usage
--------
```go
// Create Trie
trie := critbitgo.NewTrie()
// Insert
trie.Insert([]byte("aa"), "value1")
trie.Insert([]byte("bb"), "value2")
trie.Insert([]byte("ab"), "value3")
// Get
v, ok := trie.Get([]byte("aa"))
fmt.Println(v, ok) // -> value1 true
// Iterate containing keys
trie.Allprefixed([]byte{}, func(key []byte, value interface{}) bool {
fmt.Println(key, value) // -> [97 97] value1
// [97 98] value3
// [98 98] value2
return true
})
// Delete
v, ok = trie.Delete([]byte("aa"))
fmt.Println(v, ok) // -> value1 true
v, ok = trie.Delete([]byte("aa"))
fmt.Println(v, ok) // -> <nil> false
```
License
-------
MIT

393
vendor/github.com/k-sone/critbitgo/critbit.go generated vendored Normal file
View File

@@ -0,0 +1,393 @@
package critbitgo
import (
"bytes"
"encoding/hex"
"fmt"
"io"
"os"
"strconv"
)
// The matrix of most significant bit
var msbMatrix [256]byte
func buildMsbMatrix() {
for i := 0; i < len(msbMatrix); i++ {
b := byte(i)
b |= b >> 1
b |= b >> 2
b |= b >> 4
msbMatrix[i] = b &^ (b >> 1)
}
}
type node struct {
internal *internal
external *external
}
type internal struct {
child [2]node
offset int
bit byte
cont bool // if true, key of child[1] contains key of child[0]
}
type external struct {
key []byte
value interface{}
}
// finding the critical bit.
func (n *external) criticalBit(key []byte) (offset int, bit byte, cont bool) {
nlen := len(n.key)
klen := len(key)
mlen := nlen
if nlen > klen {
mlen = klen
}
// find first differing byte and bit
for offset = 0; offset < mlen; offset++ {
if a, b := key[offset], n.key[offset]; a != b {
bit = msbMatrix[a^b]
return
}
}
if nlen < klen {
bit = msbMatrix[key[offset]]
} else if nlen > klen {
bit = msbMatrix[n.key[offset]]
} else {
// two keys are equal
offset = -1
}
return offset, bit, true
}
// calculate direction.
func (n *internal) direction(key []byte) int {
if n.offset < len(key) && (key[n.offset]&n.bit != 0 || n.cont) {
return 1
}
return 0
}
// Crit-bit Tree
type Trie struct {
root node
size int
}
// searching the tree.
func (t *Trie) search(key []byte) *node {
n := &t.root
for n.internal != nil {
n = &n.internal.child[n.internal.direction(key)]
}
return n
}
// membership testing.
func (t *Trie) Contains(key []byte) bool {
if n := t.search(key); n.external != nil && bytes.Equal(n.external.key, key) {
return true
}
return false
}
// get member.
// if `key` is in Trie, `ok` is true.
func (t *Trie) Get(key []byte) (value interface{}, ok bool) {
if n := t.search(key); n.external != nil && bytes.Equal(n.external.key, key) {
return n.external.value, true
}
return
}
// insert into the tree (replaceable).
func (t *Trie) insert(key []byte, value interface{}, replace bool) bool {
// an empty tree
if t.size == 0 {
t.root.external = &external{
key: key,
value: value,
}
t.size = 1
return true
}
n := t.search(key)
newOffset, newBit, newCont := n.external.criticalBit(key)
// already exists in the tree
if newOffset == -1 {
if replace {
n.external.value = value
return true
}
return false
}
// allocate new node
newNode := &internal{
offset: newOffset,
bit: newBit,
cont: newCont,
}
direction := newNode.direction(key)
newNode.child[direction].external = &external{
key: key,
value: value,
}
// insert new node
wherep := &t.root
for in := wherep.internal; in != nil; in = wherep.internal {
if in.offset > newOffset || (in.offset == newOffset && in.bit < newBit) {
break
}
wherep = &in.child[in.direction(key)]
}
if wherep.internal != nil {
newNode.child[1-direction].internal = wherep.internal
} else {
newNode.child[1-direction].external = wherep.external
wherep.external = nil
}
wherep.internal = newNode
t.size += 1
return true
}
// insert into the tree.
// if `key` is alredy in Trie, return false.
func (t *Trie) Insert(key []byte, value interface{}) bool {
return t.insert(key, value, false)
}
// set into the tree.
func (t *Trie) Set(key []byte, value interface{}) {
t.insert(key, value, true)
}
// deleting elements.
// if `key` is in Trie, `ok` is true.
func (t *Trie) Delete(key []byte) (value interface{}, ok bool) {
// an empty tree
if t.size == 0 {
return
}
var direction int
var whereq *node // pointer to the grandparent
var wherep *node = &t.root
// finding the best candidate to delete
for in := wherep.internal; in != nil; in = wherep.internal {
direction = in.direction(key)
whereq = wherep
wherep = &in.child[direction]
}
// checking that we have the right element
if !bytes.Equal(wherep.external.key, key) {
return
}
value = wherep.external.value
ok = true
// removing the node
if whereq == nil {
wherep.external = nil
} else {
othern := whereq.internal.child[1-direction]
whereq.internal = othern.internal
whereq.external = othern.external
}
t.size -= 1
return
}
// clearing a tree.
func (t *Trie) Clear() {
t.root.internal = nil
t.root.external = nil
t.size = 0
}
// return the number of key in a tree.
func (t *Trie) Size() int {
return t.size
}
// fetching elements with a given prefix.
// handle is called with arguments key and value (if handle returns `false`, the iteration is aborted)
func (t *Trie) Allprefixed(prefix []byte, handle func(key []byte, value interface{}) bool) bool {
// an empty tree
if t.size == 0 {
return true
}
// walk tree, maintaining top pointer
p := &t.root
top := p
if len(prefix) > 0 {
for q := p.internal; q != nil; q = p.internal {
p = &q.child[q.direction(prefix)]
if q.offset < len(prefix) {
top = p
}
}
// check prefix
if !bytes.HasPrefix(p.external.key, prefix) {
return true
}
}
return allprefixed(top, handle)
}
func allprefixed(n *node, handle func([]byte, interface{}) bool) bool {
if n.internal != nil {
// dealing with an internal node while recursing
for i := 0; i < 2; i++ {
if !allprefixed(&n.internal.child[i], handle) {
return false
}
}
} else {
// dealing with an external node while recursing
return handle(n.external.key, n.external.value)
}
return true
}
// Search for the longest matching key from the beginning of the given key.
// if `key` is in Trie, `ok` is true.
func (t *Trie) LongestPrefix(given []byte) (key []byte, value interface{}, ok bool) {
// an empty tree
if t.size == 0 {
return
}
return longestPrefix(&t.root, given)
}
func longestPrefix(n *node, key []byte) ([]byte, interface{}, bool) {
if n.internal != nil {
direction := n.internal.direction(key)
if k, v, ok := longestPrefix(&n.internal.child[direction], key); ok {
return k, v, ok
}
if direction == 1 {
return longestPrefix(&n.internal.child[0], key)
}
} else {
if bytes.HasPrefix(key, n.external.key) {
return n.external.key, n.external.value, true
}
}
return nil, nil, false
}
// Iterating elements from a given start key.
// handle is called with arguments key and value (if handle returns `false`, the iteration is aborted)
func (t *Trie) Walk(start []byte, handle func(key []byte, value interface{}) bool) bool {
if t.size == 0 {
return true
}
var seek bool
if start != nil {
seek = true
}
return walk(&t.root, start, &seek, handle)
}
func walk(n *node, key []byte, seek *bool, handle func([]byte, interface{}) bool) bool {
if n.internal != nil {
var direction int
if *seek {
direction = n.internal.direction(key)
}
if !walk(&n.internal.child[direction], key, seek, handle) {
return false
}
if !(*seek) && direction == 0 {
// iteration another side
return walk(&n.internal.child[1], key, seek, handle)
}
return true
} else {
if *seek {
if bytes.Equal(n.external.key, key) {
// seek completed
*seek = false
} else {
// key is not in Trie
return false
}
}
return handle(n.external.key, n.external.value)
}
}
// dump tree. (for debugging)
func (t *Trie) Dump(w io.Writer) {
if t.root.internal == nil && t.root.external == nil {
return
}
if w == nil {
w = os.Stdout
}
dump(w, &t.root, true, "")
}
func dump(w io.Writer, n *node, right bool, prefix string) {
var ownprefix string
if right {
ownprefix = prefix
} else {
ownprefix = prefix[:len(prefix)-1] + "`"
}
if in := n.internal; in != nil {
fmt.Fprintf(w, "%s-- off=%d, bit=%08b(%02x), cont=%v\n", ownprefix, in.offset, in.bit, in.bit, in.cont)
for i := 0; i < 2; i++ {
var nextprefix string
switch i {
case 0:
nextprefix = prefix + " |"
right = true
case 1:
nextprefix = prefix + " "
right = false
}
dump(w, &in.child[i], right, nextprefix)
}
} else {
fmt.Fprintf(w, "%s-- key=%d (%s)\n", ownprefix, n.external.key, key2str(n.external.key))
}
return
}
func key2str(key []byte) string {
for _, c := range key {
if !strconv.IsPrint(rune(c)) {
return hex.EncodeToString(key)
}
}
return string(key)
}
// create a tree.
func NewTrie() *Trie {
return &Trie{}
}
func init() {
buildMsbMatrix()
}

57
vendor/github.com/k-sone/critbitgo/map.go generated vendored Normal file
View File

@@ -0,0 +1,57 @@
package critbitgo
import (
"unsafe"
)
// The map is sorted according to the natural ordering of its keys
type SortedMap struct {
trie *Trie
}
func (m *SortedMap) Contains(key string) bool {
return m.trie.Contains(*(*[]byte)(unsafe.Pointer(&key)))
}
func (m *SortedMap) Get(key string) (value interface{}, ok bool) {
return m.trie.Get(*(*[]byte)(unsafe.Pointer(&key)))
}
func (m *SortedMap) Set(key string, value interface{}) {
m.trie.Set([]byte(key), value)
}
func (m *SortedMap) Delete(key string) (value interface{}, ok bool) {
return m.trie.Delete(*(*[]byte)(unsafe.Pointer(&key)))
}
func (m *SortedMap) Clear() {
m.trie.Clear()
}
func (m *SortedMap) Size() int {
return m.trie.Size()
}
// Returns a slice of sorted keys
func (m *SortedMap) Keys() []string {
keys := make([]string, 0, m.Size())
m.trie.Allprefixed([]byte{}, func(k []byte, v interface{}) bool {
keys = append(keys, string(k))
return true
})
return keys
}
// Executes a provided function for each element that has a given prefix.
// if handle returns `false`, the iteration is aborted.
func (m *SortedMap) Each(prefix string, handle func(key string, value interface{}) bool) bool {
return m.trie.Allprefixed([]byte(prefix), func(k []byte, v interface{}) bool {
return handle(string(k), v)
})
}
// Create a SortedMap
func NewSortedMap() *SortedMap {
return &SortedMap{NewTrie()}
}

323
vendor/github.com/k-sone/critbitgo/net.go generated vendored Normal file
View File

@@ -0,0 +1,323 @@
package critbitgo
import (
"net"
)
var (
mask32 = net.IPMask{0xff, 0xff, 0xff, 0xff}
mask128 = net.IPMask{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
)
// IP routing table.
type Net struct {
trie *Trie
}
// Add a route.
// If `r` is not IPv4/IPv6 network, returns an error.
func (n *Net) Add(r *net.IPNet, value interface{}) (err error) {
var ip net.IP
if ip, _, err = netValidateIPNet(r); err == nil {
n.trie.Set(netIPNetToKey(ip, r.Mask), value)
}
return
}
// Add a route.
// If `s` is not CIDR notation, returns an error.
func (n *Net) AddCIDR(s string, value interface{}) (err error) {
var r *net.IPNet
if _, r, err = net.ParseCIDR(s); err == nil {
n.Add(r, value)
}
return
}
// Delete a specific route.
// If `r` is not IP4/IPv6 network or a route is not found, `ok` is false.
func (n *Net) Delete(r *net.IPNet) (value interface{}, ok bool, err error) {
var ip net.IP
if ip, _, err = netValidateIPNet(r); err == nil {
value, ok = n.trie.Delete(netIPNetToKey(ip, r.Mask))
}
return
}
// Delete a specific route.
// If `s` is not CIDR notation or a route is not found, `ok` is false.
func (n *Net) DeleteCIDR(s string) (value interface{}, ok bool, err error) {
var r *net.IPNet
if _, r, err = net.ParseCIDR(s); err == nil {
value, ok, err = n.Delete(r)
}
return
}
// Get a specific route.
// If `r` is not IPv4/IPv6 network or a route is not found, `ok` is false.
func (n *Net) Get(r *net.IPNet) (value interface{}, ok bool, err error) {
var ip net.IP
if ip, _, err = netValidateIPNet(r); err == nil {
value, ok = n.trie.Get(netIPNetToKey(ip, r.Mask))
}
return
}
// Get a specific route.
// If `s` is not CIDR notation or a route is not found, `ok` is false.
func (n *Net) GetCIDR(s string) (value interface{}, ok bool, err error) {
var r *net.IPNet
if _, r, err = net.ParseCIDR(s); err == nil {
value, ok, err = n.Get(r)
}
return
}
// Return a specific route by using the longest prefix matching.
// If `r` is not IPv4/IPv6 network or a route is not found, `route` is nil.
func (n *Net) Match(r *net.IPNet) (route *net.IPNet, value interface{}, err error) {
var ip net.IP
if ip, _, err = netValidateIP(r.IP); err == nil {
if k, v := n.match(netIPNetToKey(ip, r.Mask)); k != nil {
route = netKeyToIPNet(k)
value = v
}
}
return
}
// Return a specific route by using the longest prefix matching.
// If `s` is not CIDR notation, or a route is not found, `route` is nil.
func (n *Net) MatchCIDR(s string) (route *net.IPNet, value interface{}, err error) {
var r *net.IPNet
if _, r, err = net.ParseCIDR(s); err == nil {
route, value, err = n.Match(r)
}
return
}
// Return a bool indicating whether a route would be found
func (n *Net) ContainedIP(ip net.IP) (contained bool, err error) {
k, _, err := n.matchIP(ip)
contained = k != nil
return
}
// Return a specific route by using the longest prefix matching.
// If `ip` is invalid IP, or a route is not found, `route` is nil.
func (n *Net) MatchIP(ip net.IP) (route *net.IPNet, value interface{}, err error) {
k, v, err := n.matchIP(ip)
if k != nil {
route = netKeyToIPNet(k)
value = v
}
return
}
func (n *Net) matchIP(ip net.IP) (k []byte, v interface{}, err error) {
var isV4 bool
ip, isV4, err = netValidateIP(ip)
if err != nil {
return
}
var mask net.IPMask
if isV4 {
mask = mask32
} else {
mask = mask128
}
k, v = n.match(netIPNetToKey(ip, mask))
return
}
func (n *Net) match(key []byte) ([]byte, interface{}) {
if n.trie.size > 0 {
if node := lookup(&n.trie.root, key, false); node != nil {
return node.external.key, node.external.value
}
}
return nil, nil
}
func lookup(p *node, key []byte, backtracking bool) *node {
if p.internal != nil {
var direction int
if p.internal.offset == len(key)-1 {
// selecting the larger side when comparing the mask
direction = 1
} else if backtracking {
direction = 0
} else {
direction = p.internal.direction(key)
}
if c := lookup(&p.internal.child[direction], key, backtracking); c != nil {
return c
}
if direction == 1 {
// search other node
return lookup(&p.internal.child[0], key, true)
}
return nil
} else {
nlen := len(p.external.key)
if nlen != len(key) {
return nil
}
// check mask
mask := p.external.key[nlen-1]
if mask > key[nlen-1] {
return nil
}
// compare both keys with mask
div := int(mask >> 3)
for i := 0; i < div; i++ {
if p.external.key[i] != key[i] {
return nil
}
}
if mod := uint(mask & 0x07); mod > 0 {
bit := 8 - mod
if p.external.key[div] != key[div]&(0xff>>bit<<bit) {
return nil
}
}
return p
}
}
// Walk iterates routes from a given route.
// handle is called with arguments route and value (if handle returns `false`, the iteration is aborted)
func (n *Net) Walk(r *net.IPNet, handle func(*net.IPNet, interface{}) bool) {
var key []byte
if r != nil {
if ip, _, err := netValidateIPNet(r); err == nil {
key = netIPNetToKey(ip, r.Mask)
}
}
n.trie.Walk(key, func(key []byte, value interface{}) bool {
return handle(netKeyToIPNet(key), value)
})
}
// WalkPrefix interates routes that have a given prefix.
// handle is called with arguments route and value (if handle returns `false`, the iteration is aborted)
func (n *Net) WalkPrefix(r *net.IPNet, handle func(*net.IPNet, interface{}) bool) {
var prefix []byte
var div int
var bit uint
if r != nil {
if ip, _, err := netValidateIPNet(r); err == nil {
prefix = netIPNetToKey(ip, r.Mask)
mask := prefix[len(prefix)-1]
div = int(mask >> 3)
if mod := uint(mask & 0x07); mod != 0 {
bit = 8 - mod
}
}
}
wrapper := func(key []byte, value interface{}) bool {
if bit != 0 {
if prefix[div]>>bit != key[div]>>bit {
return false
}
}
return handle(netKeyToIPNet(key), value)
}
n.trie.Allprefixed(prefix[0:div], wrapper)
}
func walkMatch(p *node, key []byte, handle func(*net.IPNet, interface{}) bool) bool {
if p.internal != nil {
if !walkMatch(&p.internal.child[0], key, handle) {
return false
}
if p.internal.offset >= len(key)-1 || key[p.internal.offset]&p.internal.bit > 0 {
return walkMatch(&p.internal.child[1], key, handle)
}
return true
}
mask := p.external.key[len(p.external.key)-1]
if key[len(key)-1] < mask {
return true
}
div := int(mask >> 3)
for i := 0; i < div; i++ {
if p.external.key[i] != key[i] {
return true
}
}
if mod := uint(mask & 0x07); mod > 0 {
bit := 8 - mod
if p.external.key[div] != key[div]&(0xff>>bit<<bit) {
return true
}
}
return handle(netKeyToIPNet(p.external.key), p.external.value)
}
// WalkMatch interates routes that match a given route.
// handle is called with arguments route and value (if handle returns `false`, the iteration is aborted)
func (n *Net) WalkMatch(r *net.IPNet, handle func(*net.IPNet, interface{}) bool) {
if n.trie.size > 0 {
walkMatch(&n.trie.root, netIPNetToKey(r.IP, r.Mask), handle)
}
}
// Deletes all routes.
func (n *Net) Clear() {
n.trie.Clear()
}
// Returns number of routes.
func (n *Net) Size() int {
return n.trie.Size()
}
// Create IP routing table
func NewNet() *Net {
return &Net{NewTrie()}
}
func netValidateIP(ip net.IP) (nIP net.IP, isV4 bool, err error) {
if v4 := ip.To4(); v4 != nil {
nIP = v4
isV4 = true
} else if ip.To16() != nil {
nIP = ip
} else {
err = &net.AddrError{Err: "Invalid IP address", Addr: ip.String()}
}
return
}
func netValidateIPNet(r *net.IPNet) (nIP net.IP, isV4 bool, err error) {
if r == nil {
err = &net.AddrError{Err: "IP network is nil"}
return
}
return netValidateIP(r.IP)
}
func netIPNetToKey(ip net.IP, mask net.IPMask) []byte {
// +--------------+------+
// | ip address.. | mask |
// +--------------+------+
ones, _ := mask.Size()
return append(ip, byte(ones))
}
func netKeyToIPNet(k []byte) *net.IPNet {
iplen := len(k) - 1
return &net.IPNet{
IP: net.IP(k[:iplen]),
Mask: net.CIDRMask(int(k[iplen]), iplen*8),
}
}