github.com/slspeek/camlistore_namedsearch@v0.0.0-20140519202248-ed6f70f7721a/pkg/gc/gc_test.go (about) 1 /* 2 Copyright 2014 The Camlistore Authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package gc 18 19 import ( 20 "reflect" 21 "sort" 22 "testing" 23 24 "camlistore.org/pkg/context" 25 ) 26 27 func sl(v ...string) []string { 28 if len(v) == 0 { 29 return nil 30 } 31 return v 32 } 33 34 var collectTests = []struct { 35 name string 36 world []string 37 roots []string 38 graph map[string][]string 39 wantWorld []string 40 }{ 41 { 42 name: "delete everything", 43 world: sl("a", "b", "c"), 44 wantWorld: sl(), 45 }, 46 47 { 48 name: "keep everything", 49 world: sl("a", "b", "c"), 50 roots: sl("a", "b", "c"), 51 wantWorld: sl("a", "b", "c"), 52 }, 53 54 { 55 name: "keep all via chain", 56 world: sl("a", "b", "c", "d", "e"), 57 roots: sl("a"), 58 graph: map[string][]string{ 59 "a": sl("b"), 60 "b": sl("c"), 61 "c": sl("d"), 62 "d": sl("e"), 63 }, 64 wantWorld: sl("a", "b", "c", "d", "e"), 65 }, 66 67 { 68 name: "keep all via fan", 69 world: sl("a", "b", "c", "d", "e"), 70 roots: sl("a"), 71 graph: map[string][]string{ 72 "a": sl("b", "c", "d", "e"), 73 }, 74 wantWorld: sl("a", "b", "c", "d", "e"), 75 }, 76 77 { 78 name: "c dies, two roots", 79 world: sl("a", "b", "c", "d", "e"), 80 roots: sl("a", "d"), 81 graph: map[string][]string{ 82 "a": sl("b"), 83 "d": sl("e"), 84 }, 85 wantWorld: sl("a", "b", "d", "e"), 86 }, 87 } 88 89 type worldSet map[string]bool 90 91 func newWorldSet(start []string) worldSet { 92 s := make(worldSet) 93 for _, v := range start { 94 s[v] = true 95 } 96 return s 97 } 98 99 func (s worldSet) Delete(it Item) error { 100 delete(s, it.(string)) 101 return nil 102 } 103 104 func (s worldSet) items() []string { 105 if len(s) == 0 { 106 return nil 107 } 108 ret := make([]string, 0, len(s)) 109 for it := range s { 110 ret = append(ret, it) 111 } 112 sort.Strings(ret) 113 return ret 114 } 115 116 func TestCollector(t *testing.T) { 117 for _, tt := range collectTests { 118 if tt.name == "" { 119 panic("no name in test") 120 } 121 w := newWorldSet(tt.world) 122 c := &Collector{ 123 World: testWorld{}, 124 Marker: testMarker(map[Item]bool{}), 125 Roots: testEnum(tt.roots), 126 Sweeper: testEnum(tt.world), 127 ItemEnumerator: testItemEnum(tt.graph), 128 Deleter: w, 129 } 130 if err := c.Collect(context.New()); err != nil { 131 t.Errorf("%s: Collect = %v", tt.name, err) 132 } 133 got := w.items() 134 if !reflect.DeepEqual(tt.wantWorld, got) { 135 t.Errorf("%s: world = %q; want %q", tt.name, got, tt.wantWorld) 136 } 137 } 138 } 139 140 type testEnum []string 141 142 func (s testEnum) Enumerate(ctx *context.Context, dest chan<- Item) error { 143 defer close(dest) 144 for _, v := range s { 145 select { 146 case dest <- v: 147 case <-ctx.Done(): 148 return context.ErrCanceled 149 } 150 } 151 return nil 152 } 153 154 type testItemEnum map[string][]string 155 156 func (m testItemEnum) EnumerateItem(ctx *context.Context, it Item, dest chan<- Item) error { 157 defer close(dest) 158 for _, v := range m[it.(string)] { 159 select { 160 case dest <- v: 161 case <-ctx.Done(): 162 return context.ErrCanceled 163 } 164 } 165 return nil 166 } 167 168 type testMarker map[Item]bool 169 170 func (m testMarker) Mark(it Item) error { 171 m[it] = true 172 return nil 173 } 174 175 func (m testMarker) IsMarked(it Item) (v bool, err error) { 176 v = m[it] 177 return 178 } 179 180 type testWorld struct{} 181 182 func (testWorld) Start() error { return nil } 183 func (testWorld) Stop() error { return nil }