OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2014, 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 library test.physical_file_system; |
| 6 |
| 7 import 'dart:async'; |
| 8 import 'dart:core' hide Resource; |
| 9 import 'dart:io' as io; |
| 10 |
| 11 import 'package:analyzer/file_system/file_system.dart'; |
| 12 import 'package:analyzer/file_system/physical_file_system.dart'; |
| 13 import 'package:analyzer/src/generated/source_io.dart'; |
| 14 import 'package:path/path.dart'; |
| 15 import 'package:unittest/unittest.dart'; |
| 16 import 'package:watcher/watcher.dart'; |
| 17 |
| 18 import '../reflective_tests.dart'; |
| 19 import '../utils.dart'; |
| 20 |
| 21 main() { |
| 22 initializeTestEnvironment(); |
| 23 runReflectiveTests(PhysicalResourceProviderTest); |
| 24 runReflectiveTests(FileTest); |
| 25 runReflectiveTests(FolderTest); |
| 26 } |
| 27 |
| 28 var _isFile = new isInstanceOf<File>(); |
| 29 var _isFileSystemException = new isInstanceOf<FileSystemException>(); |
| 30 var _isFolder = new isInstanceOf<Folder>(); |
| 31 |
| 32 @reflectiveTest |
| 33 class FileTest extends _BaseTest { |
| 34 String path; |
| 35 File file; |
| 36 |
| 37 setUp() { |
| 38 super.setUp(); |
| 39 path = join(tempPath, 'file.txt'); |
| 40 file = PhysicalResourceProvider.INSTANCE.getResource(path); |
| 41 } |
| 42 |
| 43 void test_createSource() { |
| 44 new io.File(path).writeAsStringSync('contents'); |
| 45 Source source = file.createSource(); |
| 46 expect(source.uriKind, UriKind.FILE_URI); |
| 47 expect(source.exists(), isTrue); |
| 48 expect(source.contents.data, 'contents'); |
| 49 } |
| 50 |
| 51 void test_equals_differentPaths() { |
| 52 String path2 = join(tempPath, 'file2.txt'); |
| 53 File file2 = PhysicalResourceProvider.INSTANCE.getResource(path2); |
| 54 expect(file == file2, isFalse); |
| 55 } |
| 56 |
| 57 void test_equals_samePath() { |
| 58 new io.File(path).writeAsStringSync('contents'); |
| 59 File file2 = PhysicalResourceProvider.INSTANCE.getResource(path); |
| 60 expect(file == file2, isTrue); |
| 61 } |
| 62 |
| 63 void test_exists_false() { |
| 64 expect(file.exists, isFalse); |
| 65 } |
| 66 |
| 67 void test_exists_true() { |
| 68 new io.File(path).writeAsStringSync('contents'); |
| 69 expect(file.exists, isTrue); |
| 70 } |
| 71 |
| 72 void test_fullName() { |
| 73 expect(file.path, path); |
| 74 } |
| 75 |
| 76 void test_hashCode() { |
| 77 new io.File(path).writeAsStringSync('contents'); |
| 78 File file2 = PhysicalResourceProvider.INSTANCE.getResource(path); |
| 79 expect(file.hashCode, equals(file2.hashCode)); |
| 80 } |
| 81 |
| 82 void test_isOrContains() { |
| 83 File file = PhysicalResourceProvider.INSTANCE.getResource(path); |
| 84 expect(file.isOrContains(path), isTrue); |
| 85 expect(file.isOrContains('foo'), isFalse); |
| 86 } |
| 87 |
| 88 void test_modificationStamp_doesNotExist() { |
| 89 File file = PhysicalResourceProvider.INSTANCE.getResource(path); |
| 90 expect(() { |
| 91 file.modificationStamp; |
| 92 }, throwsA(_isFileSystemException)); |
| 93 } |
| 94 |
| 95 void test_modificationStamp_exists() { |
| 96 new io.File(path).writeAsStringSync('contents'); |
| 97 File file = PhysicalResourceProvider.INSTANCE.getResource(path); |
| 98 expect(file.modificationStamp, isNonNegative); |
| 99 } |
| 100 |
| 101 void test_parent() { |
| 102 Resource parent = file.parent; |
| 103 expect(parent, new isInstanceOf<Folder>()); |
| 104 expect(parent.path, equals(tempPath)); |
| 105 } |
| 106 |
| 107 void test_readAsStringSync_doesNotExist() { |
| 108 File file = PhysicalResourceProvider.INSTANCE.getResource(path); |
| 109 expect(() { |
| 110 file.readAsStringSync(); |
| 111 }, throwsA(_isFileSystemException)); |
| 112 } |
| 113 |
| 114 void test_readAsStringSync_exists() { |
| 115 new io.File(path).writeAsStringSync('abc'); |
| 116 File file = PhysicalResourceProvider.INSTANCE.getResource(path); |
| 117 expect(file.readAsStringSync(), 'abc'); |
| 118 } |
| 119 |
| 120 void test_shortName() { |
| 121 expect(file.shortName, 'file.txt'); |
| 122 } |
| 123 |
| 124 void test_toString() { |
| 125 expect(file.toString(), path); |
| 126 } |
| 127 } |
| 128 |
| 129 @reflectiveTest |
| 130 class FolderTest extends _BaseTest { |
| 131 String path; |
| 132 Folder folder; |
| 133 |
| 134 setUp() { |
| 135 super.setUp(); |
| 136 path = join(tempPath, 'folder'); |
| 137 new io.Directory(path).createSync(); |
| 138 folder = PhysicalResourceProvider.INSTANCE.getResource(path); |
| 139 } |
| 140 |
| 141 void test_canonicalizePath() { |
| 142 String path2 = join(tempPath, 'folder2'); |
| 143 String path3 = join(tempPath, 'folder3'); |
| 144 expect(folder.canonicalizePath('baz'), equals(join(path, 'baz'))); |
| 145 expect(folder.canonicalizePath(path2), equals(path2)); |
| 146 expect(folder.canonicalizePath(join('..', 'folder2')), equals(path2)); |
| 147 expect( |
| 148 folder.canonicalizePath(join(path2, '..', 'folder3')), equals(path3)); |
| 149 expect( |
| 150 folder.canonicalizePath(join('.', 'baz')), equals(join(path, 'baz'))); |
| 151 expect(folder.canonicalizePath(join(path2, '.', 'baz')), |
| 152 equals(join(path2, 'baz'))); |
| 153 } |
| 154 |
| 155 void test_contains() { |
| 156 expect(folder.contains(join(path, 'aaa.txt')), isTrue); |
| 157 expect(folder.contains(join(path, 'aaa', 'bbb.txt')), isTrue); |
| 158 expect(folder.contains(join(tempPath, 'baz.txt')), isFalse); |
| 159 expect(folder.contains(path), isFalse); |
| 160 } |
| 161 |
| 162 void test_equals_differentPaths() { |
| 163 String path2 = join(tempPath, 'folder2'); |
| 164 new io.Directory(path2).createSync(); |
| 165 Folder folder2 = PhysicalResourceProvider.INSTANCE.getResource(path2); |
| 166 expect(folder == folder2, isFalse); |
| 167 } |
| 168 |
| 169 void test_equals_samePath() { |
| 170 Folder folder2 = PhysicalResourceProvider.INSTANCE.getResource(path); |
| 171 expect(folder == folder2, isTrue); |
| 172 } |
| 173 |
| 174 void test_getChild_doesNotExist() { |
| 175 var child = folder.getChild('no-such-resource'); |
| 176 expect(child, isNotNull); |
| 177 expect(child.exists, isFalse); |
| 178 } |
| 179 |
| 180 void test_getChild_file() { |
| 181 new io.File(join(path, 'myFile')).createSync(); |
| 182 var child = folder.getChild('myFile'); |
| 183 expect(child, _isFile); |
| 184 expect(child.exists, isTrue); |
| 185 } |
| 186 |
| 187 void test_getChild_folder() { |
| 188 new io.Directory(join(path, 'myFolder')).createSync(); |
| 189 var child = folder.getChild('myFolder'); |
| 190 expect(child, _isFolder); |
| 191 expect(child.exists, isTrue); |
| 192 } |
| 193 |
| 194 void test_getChildAssumingFolder_doesNotExist() { |
| 195 Folder child = folder.getChildAssumingFolder('no-such-resource'); |
| 196 expect(child, isNotNull); |
| 197 expect(child.exists, isFalse); |
| 198 } |
| 199 |
| 200 void test_getChildAssumingFolder_file() { |
| 201 new io.File(join(path, 'myFile')).createSync(); |
| 202 Folder child = folder.getChildAssumingFolder('myFile'); |
| 203 expect(child, isNotNull); |
| 204 expect(child.exists, isFalse); |
| 205 } |
| 206 |
| 207 void test_getChildAssumingFolder_folder() { |
| 208 new io.Directory(join(path, 'myFolder')).createSync(); |
| 209 Folder child = folder.getChildAssumingFolder('myFolder'); |
| 210 expect(child, isNotNull); |
| 211 expect(child.exists, isTrue); |
| 212 } |
| 213 |
| 214 void test_getChildren_doesNotExist() { |
| 215 folder = folder.getChildAssumingFolder('no-such-folder'); |
| 216 expect(() { |
| 217 folder.getChildren(); |
| 218 }, throwsA(_isFileSystemException)); |
| 219 } |
| 220 |
| 221 void test_getChildren_exists() { |
| 222 // create 2 files and 1 folder |
| 223 new io.File(join(path, 'a.txt')).createSync(); |
| 224 new io.Directory(join(path, 'bFolder')).createSync(); |
| 225 new io.File(join(path, 'c.txt')).createSync(); |
| 226 // prepare 3 children |
| 227 List<Resource> children = folder.getChildren(); |
| 228 expect(children, hasLength(3)); |
| 229 children.sort((a, b) => a.shortName.compareTo(b.shortName)); |
| 230 // check that each child exists |
| 231 children.forEach((child) { |
| 232 expect(child.exists, true); |
| 233 }); |
| 234 // check names |
| 235 expect(children[0].shortName, 'a.txt'); |
| 236 expect(children[1].shortName, 'bFolder'); |
| 237 expect(children[2].shortName, 'c.txt'); |
| 238 // check types |
| 239 expect(children[0], _isFile); |
| 240 expect(children[1], _isFolder); |
| 241 expect(children[2], _isFile); |
| 242 } |
| 243 |
| 244 void test_hashCode() { |
| 245 Folder folder2 = PhysicalResourceProvider.INSTANCE.getResource(path); |
| 246 expect(folder.hashCode, equals(folder2.hashCode)); |
| 247 } |
| 248 |
| 249 void test_isOrContains() { |
| 250 expect(folder.isOrContains(path), isTrue); |
| 251 expect(folder.isOrContains(join(path, 'aaa.txt')), isTrue); |
| 252 expect(folder.isOrContains(join(path, 'aaa', 'bbb.txt')), isTrue); |
| 253 expect(folder.isOrContains(join(tempPath, 'baz.txt')), isFalse); |
| 254 } |
| 255 |
| 256 void test_parent() { |
| 257 Resource parent = folder.parent; |
| 258 expect(parent, new isInstanceOf<Folder>()); |
| 259 expect(parent.path, equals(tempPath)); |
| 260 |
| 261 // Since the OS is in control of where tempPath is, we don't know how |
| 262 // far it should be from the root. So just verify that each call to |
| 263 // parent results in a a folder with a shorter path, and that we |
| 264 // reach the root eventually. |
| 265 while (true) { |
| 266 Resource grandParent = parent.parent; |
| 267 if (grandParent == null) { |
| 268 break; |
| 269 } |
| 270 expect(grandParent, new isInstanceOf<Folder>()); |
| 271 expect(grandParent.path.length, lessThan(parent.path.length)); |
| 272 parent = grandParent; |
| 273 } |
| 274 } |
| 275 } |
| 276 |
| 277 @reflectiveTest |
| 278 class PhysicalResourceProviderTest extends _BaseTest { |
| 279 void test_getStateLocation_uniqueness() { |
| 280 PhysicalResourceProvider provider = PhysicalResourceProvider.INSTANCE; |
| 281 String idOne = 'one'; |
| 282 Folder folderOne = provider.getStateLocation(idOne); |
| 283 expect(folderOne, isNotNull); |
| 284 String idTwo = 'two'; |
| 285 Folder folderTwo = provider.getStateLocation(idTwo); |
| 286 expect(folderTwo, isNotNull); |
| 287 expect(folderTwo, isNot(equals(folderOne))); |
| 288 expect(provider.getStateLocation(idOne), equals(folderOne)); |
| 289 } |
| 290 |
| 291 test_watchFile_delete() { |
| 292 var path = join(tempPath, 'foo'); |
| 293 var file = new io.File(path); |
| 294 file.writeAsStringSync('contents 1'); |
| 295 return _watchingFile(path, (changesReceived) { |
| 296 expect(changesReceived, hasLength(0)); |
| 297 file.deleteSync(); |
| 298 return _delayed(() { |
| 299 expect(changesReceived, hasLength(1)); |
| 300 if (io.Platform.isWindows) { |
| 301 // See https://github.com/dart-lang/sdk/issues/23762 |
| 302 // Not sure why this breaks under Windows, but testing to see whether |
| 303 // we are running Windows causes the type to change. For now we print |
| 304 // the type out of curriosity. |
| 305 print( |
| 306 'PhysicalResourceProviderTest:test_watchFile_delete received an ev
ent with type = ${changesReceived[0].type}'); |
| 307 } else { |
| 308 expect(changesReceived[0].type, equals(ChangeType.REMOVE)); |
| 309 } |
| 310 expect(changesReceived[0].path, equals(path)); |
| 311 }); |
| 312 }); |
| 313 } |
| 314 |
| 315 test_watchFile_modify() { |
| 316 var path = join(tempPath, 'foo'); |
| 317 var file = new io.File(path); |
| 318 file.writeAsStringSync('contents 1'); |
| 319 return _watchingFile(path, (changesReceived) { |
| 320 expect(changesReceived, hasLength(0)); |
| 321 file.writeAsStringSync('contents 2'); |
| 322 return _delayed(() { |
| 323 expect(changesReceived, hasLength(1)); |
| 324 expect(changesReceived[0].type, equals(ChangeType.MODIFY)); |
| 325 expect(changesReceived[0].path, equals(path)); |
| 326 }); |
| 327 }); |
| 328 } |
| 329 |
| 330 test_watchFolder_createFile() { |
| 331 return _watchingFolder(tempPath, (changesReceived) { |
| 332 expect(changesReceived, hasLength(0)); |
| 333 var path = join(tempPath, 'foo'); |
| 334 new io.File(path).writeAsStringSync('contents'); |
| 335 return _delayed(() { |
| 336 // There should be an "add" event indicating that the file was added. |
| 337 // Depending on how long it took to write the contents, it may be |
| 338 // followed by "modify" events. |
| 339 expect(changesReceived, isNotEmpty); |
| 340 expect(changesReceived[0].type, equals(ChangeType.ADD)); |
| 341 expect(changesReceived[0].path, equals(path)); |
| 342 for (int i = 1; i < changesReceived.length; i++) { |
| 343 expect(changesReceived[i].type, equals(ChangeType.MODIFY)); |
| 344 expect(changesReceived[i].path, equals(path)); |
| 345 } |
| 346 }); |
| 347 }); |
| 348 } |
| 349 |
| 350 test_watchFolder_deleteFile() { |
| 351 var path = join(tempPath, 'foo'); |
| 352 var file = new io.File(path); |
| 353 file.writeAsStringSync('contents 1'); |
| 354 return _watchingFolder(tempPath, (changesReceived) { |
| 355 expect(changesReceived, hasLength(0)); |
| 356 file.deleteSync(); |
| 357 return _delayed(() { |
| 358 expect(changesReceived, hasLength(1)); |
| 359 expect(changesReceived[0].type, equals(ChangeType.REMOVE)); |
| 360 expect(changesReceived[0].path, equals(path)); |
| 361 }); |
| 362 }); |
| 363 } |
| 364 |
| 365 test_watchFolder_modifyFile() { |
| 366 var path = join(tempPath, 'foo'); |
| 367 var file = new io.File(path); |
| 368 file.writeAsStringSync('contents 1'); |
| 369 return _watchingFolder(tempPath, (changesReceived) { |
| 370 expect(changesReceived, hasLength(0)); |
| 371 file.writeAsStringSync('contents 2'); |
| 372 return _delayed(() { |
| 373 expect(changesReceived, hasLength(1)); |
| 374 expect(changesReceived[0].type, equals(ChangeType.MODIFY)); |
| 375 expect(changesReceived[0].path, equals(path)); |
| 376 }); |
| 377 }); |
| 378 } |
| 379 |
| 380 test_watchFolder_modifyFile_inSubDir() { |
| 381 var subdirPath = join(tempPath, 'foo'); |
| 382 new io.Directory(subdirPath).createSync(); |
| 383 var path = join(tempPath, 'bar'); |
| 384 var file = new io.File(path); |
| 385 file.writeAsStringSync('contents 1'); |
| 386 return _watchingFolder(tempPath, (changesReceived) { |
| 387 expect(changesReceived, hasLength(0)); |
| 388 file.writeAsStringSync('contents 2'); |
| 389 return _delayed(() { |
| 390 expect(changesReceived, hasLength(1)); |
| 391 expect(changesReceived[0].type, equals(ChangeType.MODIFY)); |
| 392 expect(changesReceived[0].path, equals(path)); |
| 393 }); |
| 394 }); |
| 395 } |
| 396 |
| 397 Future _delayed(computation()) { |
| 398 // Give the tests 1 second to detect the changes. While it may only |
| 399 // take up to a few hundred ms, a whole second gives a good margin |
| 400 // for when running tests. |
| 401 return new Future.delayed(new Duration(seconds: 1), computation); |
| 402 } |
| 403 |
| 404 _watchingFile(String path, test(List<WatchEvent> changesReceived)) { |
| 405 // Delay before we start watching the file. This is necessary |
| 406 // because on MacOS, file modifications that occur just before we |
| 407 // start watching are sometimes misclassified as happening just after |
| 408 // we start watching. |
| 409 return _delayed(() { |
| 410 File file = PhysicalResourceProvider.INSTANCE.getResource(path); |
| 411 var changesReceived = <WatchEvent>[]; |
| 412 var subscription = file.changes.listen(changesReceived.add); |
| 413 // Delay running the rest of the test to allow file.changes propogate. |
| 414 return _delayed(() => test(changesReceived)).whenComplete(() { |
| 415 subscription.cancel(); |
| 416 }); |
| 417 }); |
| 418 } |
| 419 |
| 420 _watchingFolder(String path, test(List<WatchEvent> changesReceived)) { |
| 421 // Delay before we start watching the folder. This is necessary |
| 422 // because on MacOS, file modifications that occur just before we |
| 423 // start watching are sometimes misclassified as happening just after |
| 424 // we start watching. |
| 425 return _delayed(() { |
| 426 Folder folder = PhysicalResourceProvider.INSTANCE.getResource(path); |
| 427 var changesReceived = <WatchEvent>[]; |
| 428 var subscription = folder.changes.listen(changesReceived.add); |
| 429 // Delay running the rest of the test to allow folder.changes to |
| 430 // take a snapshot of the current directory state. Otherwise it |
| 431 // won't be able to reliably distinguish new files from modified |
| 432 // ones. |
| 433 return _delayed(() => test(changesReceived)).whenComplete(() { |
| 434 subscription.cancel(); |
| 435 }); |
| 436 }); |
| 437 } |
| 438 } |
| 439 |
| 440 class _BaseTest { |
| 441 io.Directory tempDirectory; |
| 442 String tempPath; |
| 443 |
| 444 setUp() { |
| 445 tempDirectory = io.Directory.systemTemp.createTempSync('test_resource'); |
| 446 tempPath = tempDirectory.absolute.path; |
| 447 } |
| 448 |
| 449 tearDown() { |
| 450 tempDirectory.deleteSync(recursive: true); |
| 451 } |
| 452 } |
OLD | NEW |