* Add Virtual Kubelet provider for VIC Initial virtual kubelet provider for VMware VIC. This provider currently handles creating and starting of a pod VM via the VIC portlayer and persona server. Image store handling via the VIC persona server. This provider currently requires the feature/wolfpack branch of VIC. * Added pod stop and delete. Also added node capacity. Added the ability to stop and delete pod VMs via VIC. Also retrieve node capacity information from the VCH. * Cleanup and readme file Some file clean up and added a Readme.md markdown file for the VIC provider. * Cleaned up errors, added function comments, moved operation code 1. Cleaned up error handling. Set standard for creating errors. 2. Added method prototype comments for all interface functions. 3. Moved PodCreator, PodStarter, PodStopper, and PodDeleter to a new folder. * Add mocking code and unit tests for podcache, podcreator, and podstarter Used the unit test framework used in VIC to handle assertions in the provider's unit test. Mocking code generated using OSS project mockery, which is compatible with the testify assertion framework. * Vendored packages for the VIC provider Requires feature/wolfpack branch of VIC and a few specific commit sha of projects used within VIC. * Implementation of POD Stopper and Deleter unit tests (#4) * Updated files for initial PR
691 lines
17 KiB
Go
691 lines
17 KiB
Go
// Copyright (c) 2014 The go-patricia AUTHORS
|
|
//
|
|
// Use of this source code is governed by The MIT License
|
|
// that can be found in the LICENSE file.
|
|
|
|
package patricia
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
const (
|
|
success = true
|
|
failure = false
|
|
)
|
|
|
|
type testData struct {
|
|
key string
|
|
value interface{}
|
|
retVal bool
|
|
}
|
|
|
|
// Tests -----------------------------------------------------------------------
|
|
|
|
func TestTrie_InsertDifferentPrefixes(t *testing.T) {
|
|
trie := NewTrie()
|
|
|
|
data := []testData{
|
|
{"Pepaneeeeeeeeeeeeee", "Pepan Zdepan", success},
|
|
{"Honzooooooooooooooo", "Honza Novak", success},
|
|
{"Jenikuuuuuuuuuuuuuu", "Jenik Poustevnicek", success},
|
|
}
|
|
|
|
for _, v := range data {
|
|
t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal)
|
|
if ok := trie.Insert(Prefix(v.key), v.value); ok != v.retVal {
|
|
t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTrie_InsertDuplicatePrefixes(t *testing.T) {
|
|
trie := NewTrie()
|
|
|
|
data := []testData{
|
|
{"Pepan", "Pepan Zdepan", success},
|
|
{"Pepan", "Pepan Zdepan", failure},
|
|
}
|
|
|
|
for _, v := range data {
|
|
t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal)
|
|
if ok := trie.Insert(Prefix(v.key), v.value); ok != v.retVal {
|
|
t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTrie_InsertVariousPrefixes(t *testing.T) {
|
|
trie := NewTrie()
|
|
|
|
data := []testData{
|
|
{"Pepan", "Pepan Zdepan", success},
|
|
{"Pepin", "Pepin Omacka", success},
|
|
{"Honza", "Honza Novak", success},
|
|
{"Jenik", "Jenik Poustevnicek", success},
|
|
{"Pepan", "Pepan Dupan", failure},
|
|
{"Karel", "Karel Pekar", success},
|
|
{"Jenik", "Jenik Poustevnicek", failure},
|
|
{"Pepanek", "Pepanek Zemlicka", success},
|
|
}
|
|
|
|
for _, v := range data {
|
|
t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal)
|
|
if ok := trie.Insert(Prefix(v.key), v.value); ok != v.retVal {
|
|
t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTrie_InsertAndMatchPrefix(t *testing.T) {
|
|
trie := NewTrie()
|
|
t.Log("INSERT prefix=by week")
|
|
trie.Insert(Prefix("by week"), 2)
|
|
t.Log("INSERT prefix=by")
|
|
trie.Insert(Prefix("by"), 1)
|
|
|
|
if !trie.Match(Prefix("by")) {
|
|
t.Error("MATCH prefix=by, expected=true, got=false")
|
|
}
|
|
}
|
|
|
|
func TestTrie_SetGet(t *testing.T) {
|
|
trie := NewTrie()
|
|
|
|
data := []testData{
|
|
{"Pepan", "Pepan Zdepan", success},
|
|
{"Pepin", "Pepin Omacka", success},
|
|
{"Honza", "Honza Novak", success},
|
|
{"Jenik", "Jenik Poustevnicek", success},
|
|
{"Pepan", "Pepan Dupan", failure},
|
|
{"Karel", "Karel Pekar", success},
|
|
{"Jenik", "Jenik Poustevnicek", failure},
|
|
{"Pepanek", "Pepanek Zemlicka", success},
|
|
}
|
|
|
|
for _, v := range data {
|
|
t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal)
|
|
if ok := trie.Insert(Prefix(v.key), v.value); ok != v.retVal {
|
|
t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok)
|
|
}
|
|
}
|
|
|
|
for _, v := range data {
|
|
t.Logf("SET %q to 10", v.key)
|
|
trie.Set(Prefix(v.key), 10)
|
|
}
|
|
|
|
for _, v := range data {
|
|
value := trie.Get(Prefix(v.key))
|
|
t.Logf("GET %q => %v", v.key, value)
|
|
if value.(int) != 10 {
|
|
t.Errorf("Unexpected return value, %v != 10", value)
|
|
}
|
|
}
|
|
|
|
if value := trie.Get(Prefix("random crap")); value != nil {
|
|
t.Errorf("Unexpected return value, %v != <nil>", value)
|
|
}
|
|
}
|
|
|
|
func TestTrie_Match(t *testing.T) {
|
|
trie := NewTrie()
|
|
|
|
data := []testData{
|
|
{"Pepan", "Pepan Zdepan", success},
|
|
{"Pepin", "Pepin Omacka", success},
|
|
{"Honza", "Honza Novak", success},
|
|
{"Jenik", "Jenik Poustevnicek", success},
|
|
{"Pepan", "Pepan Dupan", failure},
|
|
{"Karel", "Karel Pekar", success},
|
|
{"Jenik", "Jenik Poustevnicek", failure},
|
|
{"Pepanek", "Pepanek Zemlicka", success},
|
|
}
|
|
|
|
for _, v := range data {
|
|
t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal)
|
|
if ok := trie.Insert(Prefix(v.key), v.value); ok != v.retVal {
|
|
t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok)
|
|
}
|
|
}
|
|
|
|
for _, v := range data {
|
|
matched := trie.Match(Prefix(v.key))
|
|
t.Logf("MATCH %q => %v", v.key, matched)
|
|
if !matched {
|
|
t.Errorf("Inserted key %q was not matched", v.key)
|
|
}
|
|
}
|
|
|
|
if trie.Match(Prefix("random crap")) {
|
|
t.Errorf("Key that was not inserted matched: %q", "random crap")
|
|
}
|
|
}
|
|
|
|
func TestTrie_MatchFalsePositive(t *testing.T) {
|
|
trie := NewTrie()
|
|
|
|
if ok := trie.Insert(Prefix("A"), 1); !ok {
|
|
t.Fatal("INSERT prefix=A, item=1 not ok")
|
|
}
|
|
|
|
resultMatchSubtree := trie.MatchSubtree(Prefix("A extra"))
|
|
resultMatch := trie.Match(Prefix("A extra"))
|
|
|
|
if resultMatchSubtree != false {
|
|
t.Error("MatchSubtree returned false positive")
|
|
}
|
|
|
|
if resultMatch != false {
|
|
t.Error("Match returned false positive")
|
|
}
|
|
}
|
|
|
|
func TestTrie_MatchSubtree(t *testing.T) {
|
|
trie := NewTrie()
|
|
|
|
data := []testData{
|
|
{"Pepan", "Pepan Zdepan", success},
|
|
{"Pepin", "Pepin Omacka", success},
|
|
{"Honza", "Honza Novak", success},
|
|
{"Jenik", "Jenik Poustevnicek", success},
|
|
{"Pepan", "Pepan Dupan", failure},
|
|
{"Karel", "Karel Pekar", success},
|
|
{"Jenik", "Jenik Poustevnicek", failure},
|
|
{"Pepanek", "Pepanek Zemlicka", success},
|
|
}
|
|
|
|
for _, v := range data {
|
|
t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal)
|
|
if ok := trie.Insert(Prefix(v.key), v.value); ok != v.retVal {
|
|
t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok)
|
|
}
|
|
}
|
|
|
|
for _, v := range data {
|
|
key := Prefix(v.key[:3])
|
|
matched := trie.MatchSubtree(key)
|
|
t.Logf("MATCH_SUBTREE %q => %v", key, matched)
|
|
if !matched {
|
|
t.Errorf("Subtree %q was not matched", v.key)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTrie_Visit(t *testing.T) {
|
|
trie := NewTrie()
|
|
|
|
data := []testData{
|
|
{"Pepa", 0, success},
|
|
{"Pepa Zdepa", 1, success},
|
|
{"Pepa Kuchar", 2, success},
|
|
{"Honza", 3, success},
|
|
{"Jenik", 4, success},
|
|
}
|
|
|
|
for _, v := range data {
|
|
t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal)
|
|
if ok := trie.Insert([]byte(v.key), v.value); ok != v.retVal {
|
|
t.Fatalf("Unexpected return value, expected=%v, got=%v", v.retVal, ok)
|
|
}
|
|
}
|
|
|
|
if err := trie.Visit(func(prefix Prefix, item Item) error {
|
|
name := data[item.(int)].key
|
|
t.Logf("VISITING prefix=%q, item=%v", prefix, item)
|
|
if !strings.HasPrefix(string(prefix), name) {
|
|
t.Errorf("Unexpected prefix encountered, %q not a prefix of %q", prefix, name)
|
|
}
|
|
return nil
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestTrie_VisitSkipSubtree(t *testing.T) {
|
|
trie := NewTrie()
|
|
|
|
data := []testData{
|
|
{"Pepa", 0, success},
|
|
{"Pepa Zdepa", 1, success},
|
|
{"Pepa Kuchar", 2, success},
|
|
{"Honza", 3, success},
|
|
{"Jenik", 4, success},
|
|
}
|
|
|
|
for _, v := range data {
|
|
t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal)
|
|
if ok := trie.Insert([]byte(v.key), v.value); ok != v.retVal {
|
|
t.Fatalf("Unexpected return value, expected=%v, got=%v", v.retVal, ok)
|
|
}
|
|
}
|
|
|
|
if err := trie.Visit(func(prefix Prefix, item Item) error {
|
|
t.Logf("VISITING prefix=%q, item=%v", prefix, item)
|
|
if item.(int) == 0 {
|
|
t.Logf("SKIP %q", prefix)
|
|
return SkipSubtree
|
|
}
|
|
if strings.HasPrefix(string(prefix), "Pepa") {
|
|
t.Errorf("Unexpected prefix encountered, %q", prefix)
|
|
}
|
|
return nil
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestTrie_VisitReturnError(t *testing.T) {
|
|
trie := NewTrie()
|
|
|
|
data := []testData{
|
|
{"Pepa", 0, success},
|
|
{"Pepa Zdepa", 1, success},
|
|
{"Pepa Kuchar", 2, success},
|
|
{"Honza", 3, success},
|
|
{"Jenik", 4, success},
|
|
}
|
|
|
|
for _, v := range data {
|
|
t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal)
|
|
if ok := trie.Insert([]byte(v.key), v.value); ok != v.retVal {
|
|
t.Fatalf("Unexpected return value, expected=%v, got=%v", v.retVal, ok)
|
|
}
|
|
}
|
|
|
|
someErr := errors.New("Something exploded")
|
|
if err := trie.Visit(func(prefix Prefix, item Item) error {
|
|
t.Logf("VISITING prefix=%q, item=%v", prefix, item)
|
|
if item.(int) == 3 {
|
|
return someErr
|
|
}
|
|
if item.(int) != 3 {
|
|
t.Errorf("Unexpected prefix encountered, %q", prefix)
|
|
}
|
|
return nil
|
|
}); err != nil && err != someErr {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestTrie_VisitSubtree(t *testing.T) {
|
|
trie := NewTrie()
|
|
|
|
data := []testData{
|
|
{"Pepa", 0, success},
|
|
{"Pepa Zdepa", 1, success},
|
|
{"Pepa Kuchar", 2, success},
|
|
{"Honza", 3, success},
|
|
{"Jenik", 4, success},
|
|
}
|
|
|
|
for _, v := range data {
|
|
t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal)
|
|
if ok := trie.Insert([]byte(v.key), v.value); ok != v.retVal {
|
|
t.Fatalf("Unexpected return value, expected=%v, got=%v", v.retVal, ok)
|
|
}
|
|
}
|
|
|
|
var counter int
|
|
subtreePrefix := []byte("Pep")
|
|
t.Log("VISIT Pep")
|
|
if err := trie.VisitSubtree(subtreePrefix, func(prefix Prefix, item Item) error {
|
|
t.Logf("VISITING prefix=%q, item=%v", prefix, item)
|
|
if !bytes.HasPrefix(prefix, subtreePrefix) {
|
|
t.Errorf("Unexpected prefix encountered, %q does not extend %q",
|
|
prefix, subtreePrefix)
|
|
}
|
|
if len(prefix) > len(data[item.(int)].key) {
|
|
t.Fatalf("Something is rather fishy here, prefix=%q", prefix)
|
|
}
|
|
counter++
|
|
return nil
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if counter != 3 {
|
|
t.Error("Unexpected number of nodes visited")
|
|
}
|
|
}
|
|
|
|
func TestTrie_VisitPrefixes(t *testing.T) {
|
|
trie := NewTrie()
|
|
|
|
data := []testData{
|
|
{"P", 0, success},
|
|
{"Pe", 1, success},
|
|
{"Pep", 2, success},
|
|
{"Pepa", 3, success},
|
|
{"Pepa Zdepa", 4, success},
|
|
{"Pepa Kuchar", 5, success},
|
|
{"Honza", 6, success},
|
|
{"Jenik", 7, success},
|
|
}
|
|
|
|
for _, v := range data {
|
|
t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal)
|
|
if ok := trie.Insert([]byte(v.key), v.value); ok != v.retVal {
|
|
t.Fatalf("Unexpected return value, expected=%v, got=%v", v.retVal, ok)
|
|
}
|
|
}
|
|
|
|
var counter int
|
|
word := []byte("Pepa")
|
|
if err := trie.VisitPrefixes(word, func(prefix Prefix, item Item) error {
|
|
t.Logf("VISITING prefix=%q, item=%v", prefix, item)
|
|
if !bytes.HasPrefix(word, prefix) {
|
|
t.Errorf("Unexpected prefix encountered, %q is not a prefix of %q",
|
|
prefix, word)
|
|
}
|
|
counter++
|
|
return nil
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if counter != 4 {
|
|
t.Error("Unexpected number of nodes visited")
|
|
}
|
|
}
|
|
|
|
func TestParticiaTrie_Delete(t *testing.T) {
|
|
trie := NewTrie()
|
|
|
|
data := []testData{
|
|
{"Pepan", "Pepan Zdepan", success},
|
|
{"Honza", "Honza Novak", success},
|
|
{"Jenik", "Jenik Poustevnicek", success},
|
|
}
|
|
|
|
for _, v := range data {
|
|
t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal)
|
|
if ok := trie.Insert([]byte(v.key), v.value); ok != v.retVal {
|
|
t.Fatalf("Unexpected return value, expected=%v, got=%v", v.retVal, ok)
|
|
}
|
|
}
|
|
|
|
for _, v := range data {
|
|
t.Logf("DELETE word=%v, success=%v", v.key, v.retVal)
|
|
if ok := trie.Delete([]byte(v.key)); ok != v.retVal {
|
|
t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestParticiaTrie_DeleteLeakageSparse(t *testing.T) {
|
|
trie := NewTrie()
|
|
|
|
data := []testData{
|
|
{"Pepan", "Pepan Zdepan", success},
|
|
{"Honza", "Honza Novak", success},
|
|
{"Jenik", "Jenik Poustevnicek", success},
|
|
}
|
|
|
|
oldBytes := heapAllocatedBytes()
|
|
|
|
for i := 0; i < 10000; i++ {
|
|
for _, v := range data {
|
|
if ok := trie.Insert([]byte(v.key), v.value); ok != v.retVal {
|
|
t.Fatalf("Unexpected return value, expected=%v, got=%v", v.retVal, ok)
|
|
}
|
|
}
|
|
|
|
for _, v := range data {
|
|
if ok := trie.Delete([]byte(v.key)); ok != v.retVal {
|
|
t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok)
|
|
}
|
|
}
|
|
}
|
|
|
|
if newBytes := heapAllocatedBytes(); newBytes > oldBytes+overhead {
|
|
t.Logf("Size=%d, Total=%d, Trie state:\n%s\n", trie.size(), trie.total(), trie.dump())
|
|
t.Errorf("Heap space leak, grew %d bytes (from %d to %d)\n", newBytes-oldBytes, oldBytes, newBytes)
|
|
}
|
|
}
|
|
|
|
func TestParticiaTrie_DeleteNonExistent(t *testing.T) {
|
|
trie := NewTrie()
|
|
|
|
insertData := []testData{
|
|
{"Pepan", "Pepan Zdepan", success},
|
|
{"Honza", "Honza Novak", success},
|
|
{"Jenik", "Jenik Poustevnicek", success},
|
|
}
|
|
deleteData := []testData{
|
|
{"Pepan", "Pepan Zdepan", success},
|
|
{"Honza", "Honza Novak", success},
|
|
{"Pepan", "Pepan Zdepan", failure},
|
|
{"Jenik", "Jenik Poustevnicek", success},
|
|
{"Honza", "Honza Novak", failure},
|
|
}
|
|
|
|
for _, v := range insertData {
|
|
t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal)
|
|
if ok := trie.Insert([]byte(v.key), v.value); ok != v.retVal {
|
|
t.Fatalf("Unexpected return value, expected=%v, got=%v", v.retVal, ok)
|
|
}
|
|
}
|
|
|
|
for _, v := range deleteData {
|
|
t.Logf("DELETE word=%v, success=%v", v.key, v.retVal)
|
|
if ok := trie.Delete([]byte(v.key)); ok != v.retVal {
|
|
t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestParticiaTrie_DeleteSubtree(t *testing.T) {
|
|
trie := NewTrie()
|
|
|
|
insertData := []testData{
|
|
{"P", 0, success},
|
|
{"Pe", 1, success},
|
|
{"Pep", 2, success},
|
|
{"Pepa", 3, success},
|
|
{"Pepa Zdepa", 4, success},
|
|
{"Pepa Kuchar", 5, success},
|
|
{"Honza", 6, success},
|
|
{"Jenik", 7, success},
|
|
}
|
|
deleteData := []testData{
|
|
{"Pe", -1, success},
|
|
{"Pe", -1, failure},
|
|
{"Honzik", -1, failure},
|
|
{"Honza", -1, success},
|
|
{"Honza", -1, failure},
|
|
{"Pep", -1, failure},
|
|
{"P", -1, success},
|
|
{"Nobody", -1, failure},
|
|
{"", -1, success},
|
|
}
|
|
|
|
for _, v := range insertData {
|
|
t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal)
|
|
if ok := trie.Insert([]byte(v.key), v.value); ok != v.retVal {
|
|
t.Fatalf("Unexpected return value, expected=%v, got=%v", v.retVal, ok)
|
|
}
|
|
}
|
|
|
|
for _, v := range deleteData {
|
|
t.Logf("DELETE_SUBTREE prefix=%v, success=%v", v.key, v.retVal)
|
|
if ok := trie.DeleteSubtree([]byte(v.key)); ok != v.retVal {
|
|
t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok)
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
func TestTrie_Dump(t *testing.T) {
|
|
trie := NewTrie()
|
|
|
|
data := []testData{
|
|
{"Honda", nil, success},
|
|
{"Honza", nil, success},
|
|
{"Jenik", nil, success},
|
|
{"Pepan", nil, success},
|
|
{"Pepin", nil, success},
|
|
}
|
|
|
|
for i, v := range data {
|
|
if _, ok := trie.Insert([]byte(v.key), v.value); ok != v.retVal {
|
|
t.Logf("INSERT %v %v", v.key, v.value)
|
|
t.Fatalf("Unexpected return value, expected=%v, got=%v", i, ok)
|
|
}
|
|
}
|
|
|
|
dump := `
|
|
+--+--+ Hon +--+--+ da
|
|
| |
|
|
| +--+ za
|
|
|
|
|
+--+ Jenik
|
|
|
|
|
+--+ Pep +--+--+ an
|
|
|
|
|
+--+ in
|
|
`
|
|
|
|
var buf bytes.Buffer
|
|
trie.Dump(buf)
|
|
|
|
if !bytes.Equal(buf.Bytes(), dump) {
|
|
t.Logf("DUMP")
|
|
t.Fatalf("Unexpected dump generated, expected\n\n%v\ngot\n\n%v", dump, buf.String())
|
|
}
|
|
}
|
|
*/
|
|
|
|
func TestTrie_compact(t *testing.T) {
|
|
trie := NewTrie()
|
|
|
|
trie.Insert(Prefix("a"), 0)
|
|
trie.Insert(Prefix("ab"), 0)
|
|
trie.Insert(Prefix("abc"), 0)
|
|
trie.Insert(Prefix("abcd"), 0)
|
|
trie.Insert(Prefix("abcde"), 0)
|
|
trie.Insert(Prefix("abcdef"), 0)
|
|
trie.Insert(Prefix("abcdefg"), 0)
|
|
trie.Insert(Prefix("abcdefgi"), 0)
|
|
trie.Insert(Prefix("abcdefgij"), 0)
|
|
trie.Insert(Prefix("abcdefgijk"), 0)
|
|
|
|
trie.Delete(Prefix("abcdef"))
|
|
trie.Delete(Prefix("abcde"))
|
|
trie.Delete(Prefix("abcdefg"))
|
|
|
|
trie.Delete(Prefix("a"))
|
|
trie.Delete(Prefix("abc"))
|
|
trie.Delete(Prefix("ab"))
|
|
|
|
trie.Visit(func(prefix Prefix, item Item) error {
|
|
// 97 ~~ 'a',
|
|
for ch := byte(97); ch <= 107; ch++ {
|
|
if c := bytes.Count(prefix, []byte{ch}); c > 1 {
|
|
t.Errorf("%q appeared in %q %v times", ch, prefix, c)
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func TestTrie_longestCommonPrefixLenght(t *testing.T) {
|
|
trie := NewTrie()
|
|
trie.prefix = []byte("1234567890")
|
|
|
|
switch {
|
|
case trie.longestCommonPrefixLength([]byte("")) != 0:
|
|
t.Fail()
|
|
case trie.longestCommonPrefixLength([]byte("12345")) != 5:
|
|
t.Fail()
|
|
case trie.longestCommonPrefixLength([]byte("123789")) != 3:
|
|
t.Fail()
|
|
case trie.longestCommonPrefixLength([]byte("12345678901")) != 10:
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
// Examples --------------------------------------------------------------------
|
|
|
|
func ExampleTrie() {
|
|
// Create a new tree.
|
|
trie := NewTrie()
|
|
|
|
// Insert some items.
|
|
trie.Insert(Prefix("Pepa Novak"), 1)
|
|
trie.Insert(Prefix("Pepa Sindelar"), 2)
|
|
trie.Insert(Prefix("Karel Macha"), 3)
|
|
trie.Insert(Prefix("Karel Hynek Macha"), 4)
|
|
|
|
// Just check if some things are present in the tree.
|
|
key := Prefix("Pepa Novak")
|
|
fmt.Printf("%q present? %v\n", key, trie.Match(key))
|
|
key = Prefix("Karel")
|
|
fmt.Printf("Anybody called %q here? %v\n", key, trie.MatchSubtree(key))
|
|
|
|
// Walk the tree.
|
|
trie.Visit(printItem)
|
|
// "Karel Hynek Macha": 4
|
|
// "Karel Macha": 3
|
|
// "Pepa Novak": 1
|
|
// "Pepa Sindelar": 2
|
|
|
|
// Walk a subtree.
|
|
trie.VisitSubtree(Prefix("Pepa"), printItem)
|
|
// "Pepa Novak": 1
|
|
// "Pepa Sindelar": 2
|
|
|
|
// Modify an item, then fetch it from the tree.
|
|
trie.Set(Prefix("Karel Hynek Macha"), 10)
|
|
key = Prefix("Karel Hynek Macha")
|
|
fmt.Printf("%q: %v\n", key, trie.Get(key))
|
|
// "Karel Hynek Macha": 10
|
|
|
|
// Walk prefixes.
|
|
prefix := Prefix("Karel Hynek Macha je kouzelnik")
|
|
trie.VisitPrefixes(prefix, printItem)
|
|
// "Karel Hynek Macha": 10
|
|
|
|
// Delete some items.
|
|
trie.Delete(Prefix("Pepa Novak"))
|
|
trie.Delete(Prefix("Karel Macha"))
|
|
|
|
// Walk again.
|
|
trie.Visit(printItem)
|
|
// "Karel Hynek Macha": 10
|
|
// "Pepa Sindelar": 2
|
|
|
|
// Delete a subtree.
|
|
trie.DeleteSubtree(Prefix("Pepa"))
|
|
|
|
// Print what is left.
|
|
trie.Visit(printItem)
|
|
// "Karel Hynek Macha": 10
|
|
|
|
// Output:
|
|
// "Pepa Novak" present? true
|
|
// Anybody called "Karel" here? true
|
|
// "Karel Hynek Macha": 4
|
|
// "Karel Macha": 3
|
|
// "Pepa Novak": 1
|
|
// "Pepa Sindelar": 2
|
|
// "Pepa Novak": 1
|
|
// "Pepa Sindelar": 2
|
|
// "Karel Hynek Macha": 10
|
|
// "Karel Hynek Macha": 10
|
|
// "Karel Hynek Macha": 10
|
|
// "Pepa Sindelar": 2
|
|
// "Karel Hynek Macha": 10
|
|
}
|
|
|
|
// Helpers ---------------------------------------------------------------------
|
|
|
|
func printItem(prefix Prefix, item Item) error {
|
|
fmt.Printf("%q: %v\n", prefix, item)
|
|
return nil
|
|
}
|