OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 import 'package:scheduled_test/scheduled_test.dart'; |
| 6 import 'package:watcher/src/utils.dart'; |
| 7 |
| 8 import '../utils.dart'; |
| 9 |
| 10 void sharedTests() { |
| 11 test('does not notify for files that already exist when started', () { |
| 12 // Make some pre-existing files. |
| 13 writeFile("a.txt"); |
| 14 writeFile("b.txt"); |
| 15 |
| 16 startWatcher(); |
| 17 |
| 18 // Change one after the watcher is running. |
| 19 writeFile("b.txt", contents: "modified"); |
| 20 |
| 21 // We should get a modify event for the changed file, but no add events |
| 22 // for them before this. |
| 23 expectModifyEvent("b.txt"); |
| 24 }); |
| 25 |
| 26 test('notifies when a file is added', () { |
| 27 startWatcher(); |
| 28 writeFile("file.txt"); |
| 29 expectAddEvent("file.txt"); |
| 30 }); |
| 31 |
| 32 test('notifies when a file is modified', () { |
| 33 writeFile("file.txt"); |
| 34 startWatcher(); |
| 35 writeFile("file.txt", contents: "modified"); |
| 36 expectModifyEvent("file.txt"); |
| 37 }); |
| 38 |
| 39 test('notifies when a file is removed', () { |
| 40 writeFile("file.txt"); |
| 41 startWatcher(); |
| 42 deleteFile("file.txt"); |
| 43 expectRemoveEvent("file.txt"); |
| 44 }); |
| 45 |
| 46 test('notifies when a file is modified multiple times', () { |
| 47 writeFile("file.txt"); |
| 48 startWatcher(); |
| 49 writeFile("file.txt", contents: "modified"); |
| 50 expectModifyEvent("file.txt"); |
| 51 writeFile("file.txt", contents: "modified again"); |
| 52 expectModifyEvent("file.txt"); |
| 53 }); |
| 54 |
| 55 test('notifies even if the file contents are unchanged', () { |
| 56 writeFile("a.txt", contents: "same"); |
| 57 writeFile("b.txt", contents: "before"); |
| 58 startWatcher(); |
| 59 |
| 60 writeFile("a.txt", contents: "same"); |
| 61 writeFile("b.txt", contents: "after"); |
| 62 inAnyOrder([ |
| 63 isModifyEvent("a.txt"), |
| 64 isModifyEvent("b.txt") |
| 65 ]); |
| 66 }); |
| 67 |
| 68 test('when the watched directory is deleted, removes all files', () { |
| 69 writeFile("dir/a.txt"); |
| 70 writeFile("dir/b.txt"); |
| 71 |
| 72 startWatcher(path: "dir"); |
| 73 |
| 74 deleteDir("dir"); |
| 75 inAnyOrder([ |
| 76 isRemoveEvent("dir/a.txt"), |
| 77 isRemoveEvent("dir/b.txt") |
| 78 ]); |
| 79 }); |
| 80 |
| 81 test('when the watched directory is moved, removes all files', () { |
| 82 writeFile("dir/a.txt"); |
| 83 writeFile("dir/b.txt"); |
| 84 |
| 85 startWatcher(path: "dir"); |
| 86 |
| 87 renameDir("dir", "moved_dir"); |
| 88 createDir("dir"); |
| 89 inAnyOrder([ |
| 90 isRemoveEvent("dir/a.txt"), |
| 91 isRemoveEvent("dir/b.txt") |
| 92 ]); |
| 93 }); |
| 94 |
| 95 group("moves", () { |
| 96 test('notifies when a file is moved within the watched directory', () { |
| 97 writeFile("old.txt"); |
| 98 startWatcher(); |
| 99 renameFile("old.txt", "new.txt"); |
| 100 |
| 101 inAnyOrder([ |
| 102 isAddEvent("new.txt"), |
| 103 isRemoveEvent("old.txt") |
| 104 ]); |
| 105 }); |
| 106 |
| 107 test('notifies when a file is moved from outside the watched directory', |
| 108 () { |
| 109 writeFile("old.txt"); |
| 110 createDir("dir"); |
| 111 startWatcher(path: "dir"); |
| 112 |
| 113 renameFile("old.txt", "dir/new.txt"); |
| 114 expectAddEvent("dir/new.txt"); |
| 115 }); |
| 116 |
| 117 test('notifies when a file is moved outside the watched directory', () { |
| 118 writeFile("dir/old.txt"); |
| 119 startWatcher(path: "dir"); |
| 120 |
| 121 renameFile("dir/old.txt", "new.txt"); |
| 122 expectRemoveEvent("dir/old.txt"); |
| 123 }); |
| 124 |
| 125 test('notifies when a file is moved onto an existing one', () { |
| 126 writeFile("from.txt"); |
| 127 writeFile("to.txt"); |
| 128 startWatcher(); |
| 129 |
| 130 renameFile("from.txt", "to.txt"); |
| 131 inAnyOrder([ |
| 132 isRemoveEvent("from.txt"), |
| 133 isModifyEvent("to.txt") |
| 134 ]); |
| 135 }); |
| 136 }); |
| 137 |
| 138 // Most of the time, when multiple filesystem actions happen in sequence, |
| 139 // they'll be batched together and the watcher will see them all at once. |
| 140 // These tests verify that the watcher normalizes and combine these events |
| 141 // properly. However, very occasionally the events will be reported in |
| 142 // separate batches, and the watcher will report them as though they occurred |
| 143 // far apart in time, so each of these tests has a "backup case" to allow for |
| 144 // that as well. |
| 145 group("clustered changes", () { |
| 146 test("doesn't notify when a file is created and then immediately removed", |
| 147 () { |
| 148 startWatcher(); |
| 149 writeFile("file.txt"); |
| 150 deleteFile("file.txt"); |
| 151 |
| 152 // Backup case. |
| 153 startClosingEventStream(); |
| 154 allowEvents(() { |
| 155 expectAddEvent("file.txt"); |
| 156 expectRemoveEvent("file.txt"); |
| 157 }); |
| 158 }); |
| 159 |
| 160 test("reports a modification when a file is deleted and then immediately " |
| 161 "recreated", () { |
| 162 writeFile("file.txt"); |
| 163 startWatcher(); |
| 164 |
| 165 deleteFile("file.txt"); |
| 166 writeFile("file.txt", contents: "re-created"); |
| 167 |
| 168 allowEither(() { |
| 169 expectModifyEvent("file.txt"); |
| 170 }, () { |
| 171 // Backup case. |
| 172 expectRemoveEvent("file.txt"); |
| 173 expectAddEvent("file.txt"); |
| 174 }); |
| 175 }); |
| 176 |
| 177 test("reports a modification when a file is moved and then immediately " |
| 178 "recreated", () { |
| 179 writeFile("old.txt"); |
| 180 startWatcher(); |
| 181 |
| 182 renameFile("old.txt", "new.txt"); |
| 183 writeFile("old.txt", contents: "re-created"); |
| 184 |
| 185 allowEither(() { |
| 186 inAnyOrder([ |
| 187 isModifyEvent("old.txt"), |
| 188 isAddEvent("new.txt") |
| 189 ]); |
| 190 }, () { |
| 191 // Backup case. |
| 192 expectRemoveEvent("old.txt"); |
| 193 expectAddEvent("new.txt"); |
| 194 expectAddEvent("old.txt"); |
| 195 }); |
| 196 }); |
| 197 |
| 198 test("reports a removal when a file is modified and then immediately " |
| 199 "removed", () { |
| 200 writeFile("file.txt"); |
| 201 startWatcher(); |
| 202 |
| 203 writeFile("file.txt", contents: "modified"); |
| 204 deleteFile("file.txt"); |
| 205 |
| 206 // Backup case. |
| 207 allowModifyEvent("file.txt"); |
| 208 |
| 209 expectRemoveEvent("file.txt"); |
| 210 }); |
| 211 |
| 212 test("reports an add when a file is added and then immediately modified", |
| 213 () { |
| 214 startWatcher(); |
| 215 |
| 216 writeFile("file.txt"); |
| 217 writeFile("file.txt", contents: "modified"); |
| 218 |
| 219 expectAddEvent("file.txt"); |
| 220 |
| 221 // Backup case. |
| 222 startClosingEventStream(); |
| 223 allowModifyEvent("file.txt"); |
| 224 }); |
| 225 }); |
| 226 |
| 227 group("subdirectories", () { |
| 228 test('watches files in subdirectories', () { |
| 229 startWatcher(); |
| 230 writeFile("a/b/c/d/file.txt"); |
| 231 expectAddEvent("a/b/c/d/file.txt"); |
| 232 }); |
| 233 |
| 234 test('notifies when a subdirectory is moved within the watched directory ' |
| 235 'and then its contents are modified', () { |
| 236 writeFile("old/file.txt"); |
| 237 startWatcher(); |
| 238 |
| 239 renameDir("old", "new"); |
| 240 inAnyOrder([ |
| 241 isRemoveEvent("old/file.txt"), |
| 242 isAddEvent("new/file.txt") |
| 243 ]); |
| 244 |
| 245 writeFile("new/file.txt", contents: "modified"); |
| 246 expectModifyEvent("new/file.txt"); |
| 247 }); |
| 248 |
| 249 test('emits events for many nested files added at once', () { |
| 250 withPermutations((i, j, k) => |
| 251 writeFile("sub/sub-$i/sub-$j/file-$k.txt")); |
| 252 |
| 253 createDir("dir"); |
| 254 startWatcher(path: "dir"); |
| 255 renameDir("sub", "dir/sub"); |
| 256 |
| 257 inAnyOrder(withPermutations((i, j, k) => |
| 258 isAddEvent("dir/sub/sub-$i/sub-$j/file-$k.txt"))); |
| 259 }); |
| 260 |
| 261 test('emits events for many nested files removed at once', () { |
| 262 withPermutations((i, j, k) => |
| 263 writeFile("dir/sub/sub-$i/sub-$j/file-$k.txt")); |
| 264 |
| 265 createDir("dir"); |
| 266 startWatcher(path: "dir"); |
| 267 |
| 268 // Rename the directory rather than deleting it because native watchers |
| 269 // report a rename as a single DELETE event for the directory, whereas |
| 270 // they report recursive deletion with DELETE events for every file in the |
| 271 // directory. |
| 272 renameDir("dir/sub", "sub"); |
| 273 |
| 274 inAnyOrder(withPermutations((i, j, k) => |
| 275 isRemoveEvent("dir/sub/sub-$i/sub-$j/file-$k.txt"))); |
| 276 }); |
| 277 |
| 278 test('emits events for many nested files moved at once', () { |
| 279 withPermutations((i, j, k) => |
| 280 writeFile("dir/old/sub-$i/sub-$j/file-$k.txt")); |
| 281 |
| 282 createDir("dir"); |
| 283 startWatcher(path: "dir"); |
| 284 renameDir("dir/old", "dir/new"); |
| 285 |
| 286 inAnyOrder(unionAll(withPermutations((i, j, k) { |
| 287 return new Set.from([ |
| 288 isRemoveEvent("dir/old/sub-$i/sub-$j/file-$k.txt"), |
| 289 isAddEvent("dir/new/sub-$i/sub-$j/file-$k.txt") |
| 290 ]); |
| 291 }))); |
| 292 }); |
| 293 |
| 294 test("emits events for many files added at once in a subdirectory with the " |
| 295 "same name as a removed file", () { |
| 296 writeFile("dir/sub"); |
| 297 withPermutations((i, j, k) => |
| 298 writeFile("old/sub-$i/sub-$j/file-$k.txt")); |
| 299 startWatcher(path: "dir"); |
| 300 |
| 301 deleteFile("dir/sub"); |
| 302 renameDir("old", "dir/sub"); |
| 303 |
| 304 var events = withPermutations((i, j, k) => |
| 305 isAddEvent("dir/sub/sub-$i/sub-$j/file-$k.txt")); |
| 306 events.add(isRemoveEvent("dir/sub")); |
| 307 inAnyOrder(events); |
| 308 }); |
| 309 }); |
| 310 } |
OLD | NEW |