| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 library barback.test.utils; | 5 library barback.test.utils; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:collection'; | 8 import 'dart:collection'; |
| 9 import 'dart:io'; | 9 import 'dart:io'; |
| 10 | 10 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 54 /// [AssetId] and the value should be a string defining the contents of that | 54 /// [AssetId] and the value should be a string defining the contents of that |
| 55 /// asset. | 55 /// asset. |
| 56 /// | 56 /// |
| 57 /// [transformers] is a map from package names to the transformers for each | 57 /// [transformers] is a map from package names to the transformers for each |
| 58 /// package. | 58 /// package. |
| 59 void initGraph([assets, | 59 void initGraph([assets, |
| 60 Map<String, Iterable<Iterable<Transformer>>> transformers]) { | 60 Map<String, Iterable<Iterable<Transformer>>> transformers]) { |
| 61 if (assets == null) assets = []; | 61 if (assets == null) assets = []; |
| 62 if (transformers == null) transformers = {}; | 62 if (transformers == null) transformers = {}; |
| 63 | 63 |
| 64 _provider = new MockProvider(assets, transformers); | 64 var assetList; |
| 65 if (assets is Map) { |
| 66 assetList = assets.keys.map((asset) { |
| 67 var id = new AssetId.parse(asset); |
| 68 return new _MockAsset(id, assets[asset]); |
| 69 }); |
| 70 } else if (assets is Iterable) { |
| 71 assetList = assets.map((asset) { |
| 72 var id = new AssetId.parse(asset); |
| 73 var contents = pathos.basenameWithoutExtension(id.path); |
| 74 return new _MockAsset(id, contents); |
| 75 }); |
| 76 } |
| 77 |
| 78 var assetMap = mapMapValues(groupBy(assetList, (asset) => asset.id.package), |
| 79 (package, assets) => new AssetSet.from(assets)); |
| 80 |
| 81 // Make sure that packages that have transformers but no assets are considered |
| 82 // by MockProvider to exist. |
| 83 for (var package in transformers.keys) { |
| 84 assetMap.putIfAbsent(package, () => new AssetSet()); |
| 85 } |
| 86 |
| 87 _provider = new MockProvider(assetMap); |
| 65 _barback = new Barback(_provider); | 88 _barback = new Barback(_provider); |
| 66 _nextBuildResult = 0; | 89 _nextBuildResult = 0; |
| 90 |
| 91 transformers.forEach(_barback.updateTransformers); |
| 92 |
| 93 // There should be one successful build after adding all the transformers but |
| 94 // before adding any sources. |
| 95 if (!transformers.isEmpty) buildShouldSucceed(); |
| 67 } | 96 } |
| 68 | 97 |
| 69 /// Updates [assets] in the current [PackageProvider]. | 98 /// Updates [assets] in the current [PackageProvider]. |
| 70 /// | 99 /// |
| 71 /// Each item in the list may either be an [AssetId] or a string that can be | 100 /// Each item in the list may either be an [AssetId] or a string that can be |
| 72 /// parsed as one. | 101 /// parsed as one. |
| 73 void updateSources(Iterable assets) { | 102 void updateSources(Iterable assets) { |
| 74 assets = _parseAssets(assets); | 103 assets = _parseAssets(assets); |
| 75 schedule(() => _barback.updateSources(assets), | 104 schedule(() => _barback.updateSources(assets), |
| 76 "updating ${assets.join(', ')}"); | 105 "updating ${assets.join(', ')}"); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 95 } | 124 } |
| 96 | 125 |
| 97 /// Removes [assets] from the current [PackageProvider]. | 126 /// Removes [assets] from the current [PackageProvider]. |
| 98 /// | 127 /// |
| 99 /// Each item in the list may either be an [AssetId] or a string that can be | 128 /// Each item in the list may either be an [AssetId] or a string that can be |
| 100 /// parsed as one. Unlike [removeSources], this is not automatically scheduled | 129 /// parsed as one. Unlike [removeSources], this is not automatically scheduled |
| 101 /// and will be run synchronously when called. | 130 /// and will be run synchronously when called. |
| 102 void removeSourcesSync(Iterable assets) => | 131 void removeSourcesSync(Iterable assets) => |
| 103 _barback.removeSources(_parseAssets(assets)); | 132 _barback.removeSources(_parseAssets(assets)); |
| 104 | 133 |
| 134 /// Sets the transformers for [package] to [transformers]. |
| 135 void updateTransformers(String package, |
| 136 Iterable<Iterable<Transformers>> transformers) { |
| 137 schedule(() => _barback.updateTransformers(package, transformers), |
| 138 "updating transformers for $package"); |
| 139 } |
| 140 |
| 105 /// Parse a list of strings or [AssetId]s into a list of [AssetId]s. | 141 /// Parse a list of strings or [AssetId]s into a list of [AssetId]s. |
| 106 List<AssetId> _parseAssets(Iterable assets) { | 142 List<AssetId> _parseAssets(Iterable assets) { |
| 107 return assets.map((asset) { | 143 return assets.map((asset) { |
| 108 if (asset is String) return new AssetId.parse(asset); | 144 if (asset is String) return new AssetId.parse(asset); |
| 109 return asset; | 145 return asset; |
| 110 }).toList(); | 146 }).toList(); |
| 111 } | 147 } |
| 112 | 148 |
| 113 /// Schedules a change to the contents of an asset identified by [name] to | 149 /// Schedules a change to the contents of an asset identified by [name] to |
| 114 /// [contents]. | 150 /// [contents]. |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 333 trace); | 369 trace); |
| 334 }).catchError((error) { | 370 }).catchError((error) { |
| 335 currentSchedule.signalError(error); | 371 currentSchedule.signalError(error); |
| 336 }); | 372 }); |
| 337 | 373 |
| 338 return delay.then((_) => cancelable.cancel()); | 374 return delay.then((_) => cancelable.cancel()); |
| 339 } | 375 } |
| 340 | 376 |
| 341 /// An [AssetProvider] that provides the given set of assets. | 377 /// An [AssetProvider] that provides the given set of assets. |
| 342 class MockProvider implements PackageProvider { | 378 class MockProvider implements PackageProvider { |
| 343 Iterable<String> get packages => _packages.keys; | 379 Iterable<String> get packages => _assets.keys; |
| 344 | 380 |
| 345 Map<String, _MockPackage> _packages; | 381 Map<String, AssetSet> _assets; |
| 346 | 382 |
| 347 /// The set of assets for which [MockLoadException]s should be emitted if | 383 /// The set of assets for which [MockLoadException]s should be emitted if |
| 348 /// they're loaded. | 384 /// they're loaded. |
| 349 final _errors = new Set<AssetId>(); | 385 final _errors = new Set<AssetId>(); |
| 350 | 386 |
| 351 /// The completer that [getAsset()] is waiting on to complete when paused. | 387 /// The completer that [getAsset()] is waiting on to complete when paused. |
| 352 /// | 388 /// |
| 353 /// If `null` it will return the asset immediately. | 389 /// If `null` it will return the asset immediately. |
| 354 Completer _pauseCompleter; | 390 Completer _pauseCompleter; |
| 355 | 391 |
| 356 /// Tells the provider to wait during [getAsset] until [complete()] | 392 /// Tells the provider to wait during [getAsset] until [complete()] |
| 357 /// is called. | 393 /// is called. |
| 358 /// | 394 /// |
| 359 /// Lets you test the asynchronous behavior of loading. | 395 /// Lets you test the asynchronous behavior of loading. |
| 360 void _pause() { | 396 void _pause() { |
| 361 _pauseCompleter = new Completer(); | 397 _pauseCompleter = new Completer(); |
| 362 } | 398 } |
| 363 | 399 |
| 364 void _resume() { | 400 void _resume() { |
| 365 _pauseCompleter.complete(); | 401 _pauseCompleter.complete(); |
| 366 _pauseCompleter = null; | 402 _pauseCompleter = null; |
| 367 } | 403 } |
| 368 | 404 |
| 369 MockProvider(assets, | 405 MockProvider(this._assets) { |
| 370 Map<String, Iterable<Iterable<Transformer>>> transformers) { | |
| 371 var assetList; | |
| 372 if (assets is Map) { | |
| 373 assetList = assets.keys.map((asset) { | |
| 374 var id = new AssetId.parse(asset); | |
| 375 return new _MockAsset(id, assets[asset]); | |
| 376 }); | |
| 377 } else if (assets is Iterable) { | |
| 378 assetList = assets.map((asset) { | |
| 379 var id = new AssetId.parse(asset); | |
| 380 var contents = pathos.basenameWithoutExtension(id.path); | |
| 381 return new _MockAsset(id, contents); | |
| 382 }); | |
| 383 } | |
| 384 | |
| 385 _packages = mapMapValues(groupBy(assetList, (asset) => asset.id.package), | |
| 386 (package, assets) { | |
| 387 var packageTransformers = transformers[package]; | |
| 388 if (packageTransformers == null) packageTransformers = []; | |
| 389 return new _MockPackage( | |
| 390 new AssetSet.from(assets), packageTransformers.toList()); | |
| 391 }); | |
| 392 | |
| 393 // If there are no assets or transformers, add a dummy package. This better | 406 // If there are no assets or transformers, add a dummy package. This better |
| 394 // simulates the real world, where there'll always be at least the | 407 // simulates the real world, where there'll always be at least the |
| 395 // entrypoint package. | 408 // entrypoint package. |
| 396 if (_packages.isEmpty) { | 409 if (_assets.isEmpty) { |
| 397 _packages = {"app": new _MockPackage(new AssetSet(), [])}; | 410 _assets = {"app": new AssetSet()}; |
| 398 } | 411 } |
| 399 } | 412 } |
| 400 | 413 |
| 401 void _modifyAsset(String name, String contents) { | 414 void _modifyAsset(String name, String contents) { |
| 402 var id = new AssetId.parse(name); | 415 var id = new AssetId.parse(name); |
| 403 _errors.remove(id); | 416 _errors.remove(id); |
| 404 _packages[id.package].assets[id].contents = contents; | 417 _assets[id.package][id].contents = contents; |
| 405 } | 418 } |
| 406 | 419 |
| 407 void _setAssetError(String name) => _errors.add(new AssetId.parse(name)); | 420 void _setAssetError(String name) => _errors.add(new AssetId.parse(name)); |
| 408 | 421 |
| 409 List<AssetId> listAssets(String package, {String within}) { | 422 List<AssetId> listAssets(String package, {String within}) { |
| 410 if (within != null) { | 423 if (within != null) { |
| 411 throw new UnimplementedError("Doesn't handle 'within' yet."); | 424 throw new UnimplementedError("Doesn't handle 'within' yet."); |
| 412 } | 425 } |
| 413 | 426 |
| 414 return _packages[package].assets.map((asset) => asset.id); | 427 return _assets[package].map((asset) => asset.id); |
| 415 } | |
| 416 | |
| 417 Iterable<Iterable<Transformer>> getTransformers(String package) { | |
| 418 var mockPackage = _packages[package]; | |
| 419 if (mockPackage == null) { | |
| 420 throw new ArgumentError("No package named $package."); | |
| 421 } | |
| 422 return mockPackage.transformers; | |
| 423 } | 428 } |
| 424 | 429 |
| 425 Future<Asset> getAsset(AssetId id) { | 430 Future<Asset> getAsset(AssetId id) { |
| 426 // Eagerly load the asset so we can test an asset's value changing between | 431 // Eagerly load the asset so we can test an asset's value changing between |
| 427 // when a load starts and when it finishes. | 432 // when a load starts and when it finishes. |
| 428 var package = _packages[id.package]; | 433 var assets = _assets[id.package]; |
| 429 var asset; | 434 var asset; |
| 430 if (package != null) asset = package.assets[id]; | 435 if (assets != null) asset = assets[id]; |
| 431 | 436 |
| 432 var hasError = _errors.contains(id); | 437 var hasError = _errors.contains(id); |
| 433 | 438 |
| 434 var future; | 439 var future; |
| 435 if (_pauseCompleter != null) { | 440 if (_pauseCompleter != null) { |
| 436 future = _pauseCompleter.future; | 441 future = _pauseCompleter.future; |
| 437 } else { | 442 } else { |
| 438 future = new Future.value(); | 443 future = new Future.value(); |
| 439 } | 444 } |
| 440 | 445 |
| 441 return future.then((_) { | 446 return future.then((_) { |
| 442 if (hasError) throw new MockLoadException(id); | 447 if (hasError) throw new MockLoadException(id); |
| 443 if (asset == null) throw new AssetNotFoundException(id); | 448 if (asset == null) throw new AssetNotFoundException(id); |
| 444 return asset; | 449 return asset; |
| 445 }); | 450 }); |
| 446 } | 451 } |
| 447 } | 452 } |
| 448 | 453 |
| 449 /// Error thrown for assets with [setAssetError] set. | 454 /// Error thrown for assets with [setAssetError] set. |
| 450 class MockLoadException implements Exception { | 455 class MockLoadException implements Exception { |
| 451 final AssetId id; | 456 final AssetId id; |
| 452 | 457 |
| 453 MockLoadException(this.id); | 458 MockLoadException(this.id); |
| 454 | 459 |
| 455 String toString() => "Error loading $id."; | 460 String toString() => "Error loading $id."; |
| 456 } | 461 } |
| 457 | 462 |
| 458 /// Used by [MockProvider] to keep track of which assets and transformers exist | |
| 459 /// for each package. | |
| 460 class _MockPackage { | |
| 461 final AssetSet assets; | |
| 462 final List<List<Transformer>> transformers; | |
| 463 | |
| 464 _MockPackage(this.assets, Iterable<Iterable<Transformer>> transformers) | |
| 465 : transformers = transformers.map((phase) => phase.toList()).toList(); | |
| 466 } | |
| 467 | |
| 468 /// An implementation of [Asset] that never hits the file system. | 463 /// An implementation of [Asset] that never hits the file system. |
| 469 class _MockAsset implements Asset { | 464 class _MockAsset implements Asset { |
| 470 final AssetId id; | 465 final AssetId id; |
| 471 String contents; | 466 String contents; |
| 472 | 467 |
| 473 _MockAsset(this.id, this.contents); | 468 _MockAsset(this.id, this.contents); |
| 474 | 469 |
| 475 Future<String> readAsString({Encoding encoding}) => | 470 Future<String> readAsString({Encoding encoding}) => |
| 476 new Future.value(contents); | 471 new Future.value(contents); |
| 477 | 472 |
| 478 Stream<List<int>> read() => throw new UnimplementedError(); | 473 Stream<List<int>> read() => throw new UnimplementedError(); |
| 479 | 474 |
| 480 String toString() => "MockAsset $id $contents"; | 475 String toString() => "MockAsset $id $contents"; |
| 481 } | 476 } |
| OLD | NEW |