github.com/bazelbuild/bazel-watcher@v0.25.2/internal/ibazel/fswatcher/fsnotify/fsnotify_test.go (about) 1 // Copyright 2017 The Bazel Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package fsnotify 16 17 import ( 18 "errors" 19 "runtime/debug" 20 "testing" 21 22 "github.com/fsnotify/fsnotify" 23 ) 24 25 type mockFSNotifyWatcher struct { 26 recentlyAddedFiles map[string]struct{} 27 recentlyRemovedFiles map[string]struct{} 28 closed bool 29 } 30 31 func (w *mockFSNotifyWatcher) Add(name string) error { 32 if _, ok := w.recentlyAddedFiles[name]; ok { 33 return errors.New("Already added file " + name) 34 } 35 w.recentlyAddedFiles[name] = struct{}{} 36 return nil 37 } 38 func (w *mockFSNotifyWatcher) Remove(name string) error { 39 if _, ok := w.recentlyRemovedFiles[name]; ok { 40 return errors.New("Already removed file " + name) 41 } 42 w.recentlyRemovedFiles[name] = struct{}{} 43 return nil 44 } 45 func (w *mockFSNotifyWatcher) Close() error { 46 if w.closed { 47 return errors.New("Already closed") 48 } 49 w.closed = true 50 return nil 51 } 52 func (w *mockFSNotifyWatcher) Events() chan fsnotify.Event { 53 return nil 54 } 55 56 func (w *mockFSNotifyWatcher) Reset() { 57 w.recentlyAddedFiles = make(map[string]struct{}, 0) 58 w.recentlyRemovedFiles = make(map[string]struct{}, 0) 59 w.closed = false 60 } 61 62 func (w *mockFSNotifyWatcher) assertRecentlyAdded(t *testing.T, added []string) { 63 k := keys(w.recentlyAddedFiles) 64 if val, ok := containsAll(k, added); !ok { 65 t.Errorf("Expected Add(\"%s\") not to have been called", val) 66 debug.PrintStack() 67 } 68 if val, ok := containsAll(added, k); !ok { 69 t.Errorf("Expected Add(\"%s\") to have been called", val) 70 debug.PrintStack() 71 } 72 } 73 74 func (w *mockFSNotifyWatcher) assertRecentlyRemoved(t *testing.T, removed []string) { 75 k := keys(w.recentlyRemovedFiles) 76 if val, ok := containsAll(k, removed); !ok { 77 t.Errorf("Expected Remove(\"%s\") not to have been called", val) 78 debug.PrintStack() 79 } 80 if val, ok := containsAll(removed, k); !ok { 81 t.Errorf("Expected Remove(\"%s\") to have been called", val) 82 debug.PrintStack() 83 } 84 } 85 86 func (w *mockFSNotifyWatcher) assertClosed(t *testing.T, closed bool) { 87 if w.closed != closed { 88 assertion := "to" 89 if !closed { 90 assertion = "not to" 91 } 92 t.Errorf("Expected Close() %s have been called", assertion) 93 debug.PrintStack() 94 } 95 } 96 97 func newWatcher() (*realFSNotifyWatcher, *mockFSNotifyWatcher) { 98 mock := &mockFSNotifyWatcher{} 99 mock.Reset() 100 watcher := &realFSNotifyWatcher{wrapper: mock} 101 return watcher, mock 102 } 103 104 func TestWatchedFilesState(t *testing.T) { 105 watcher, mock := newWatcher() 106 107 mock.Reset() 108 watcher.UpdateAll([]string{ 109 "/path/a", 110 "/path/b", 111 "/path/c", 112 }) 113 mock.assertRecentlyAdded(t, []string{ 114 "/path/a", 115 "/path/b", 116 "/path/c", 117 }) 118 mock.assertRecentlyRemoved(t, []string{}) 119 120 mock.Reset() 121 watcher.UpdateAll([]string{ 122 "/path/a", 123 "/path/b", 124 }) 125 mock.assertRecentlyAdded(t, []string{}) 126 mock.assertRecentlyRemoved(t, []string{ 127 "/path/c", 128 }) 129 130 mock.Reset() 131 watcher.UpdateAll([]string{ 132 "/path/a", 133 "/path/d", 134 }) 135 mock.assertRecentlyAdded(t, []string{ 136 "/path/d", 137 }) 138 mock.assertRecentlyRemoved(t, []string{ 139 "/path/b", 140 }) 141 142 mock.Reset() 143 watcher.UpdateAll([]string{}) 144 mock.assertRecentlyAdded(t, []string{}) 145 mock.assertRecentlyRemoved(t, []string{ 146 "/path/a", 147 "/path/d", 148 }) 149 150 mock.Reset() 151 watcher.UpdateAll([]string{ 152 "/other/1", 153 "/other/2", 154 "/other/4", 155 }) 156 mock.assertRecentlyAdded(t, []string{ 157 "/other/1", 158 "/other/2", 159 "/other/4", 160 }) 161 mock.assertRecentlyRemoved(t, []string{}) 162 163 mock.assertClosed(t, false) 164 watcher.Close() 165 mock.assertClosed(t, true) 166 } 167 168 // Equal tells whether a and b contain the same elements, regardless of order 169 func containsAll(a, b []string) (string, bool) { 170 OUTER: 171 for _, v1 := range a { 172 for _, v2 := range b { 173 if v1 == v2 { 174 continue OUTER 175 } 176 } 177 return v1, false 178 } 179 return "", true 180 } 181 182 func keys(m map[string]struct{}) []string { 183 keys := make([]string, len(m)) 184 i := 0 185 for k := range m { 186 keys[i] = k 187 i++ 188 } 189 return keys 190 }