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