Chromium Code Reviews| Index: pkg/barback/test/utils.dart |
| diff --git a/pkg/barback/test/utils.dart b/pkg/barback/test/utils.dart |
| index 23f8e2a1267320b4297299264186dd5f615bde8f..be11ef63f0e947ac16dd3d4f7b85c6c1cd7cab5f 100644 |
| --- a/pkg/barback/test/utils.dart |
| +++ b/pkg/barback/test/utils.dart |
| @@ -5,6 +5,7 @@ |
| library barback.test.utils; |
| import 'dart:async'; |
| +import 'dart:collection'; |
| import 'package:barback/barback.dart'; |
| import 'package:barback/src/asset_graph.dart'; |
| @@ -16,14 +17,125 @@ import '../../../sdk/lib/_internal/pub/test/command_line_config.dart'; |
| var _configured = false; |
| +MockProvider _provider; |
| +AssetGraph _graph; |
| + |
| +/// Calls to [buildShouldSucceed] and [buildShouldFail] set expectations on |
| +/// successive [BuildResult]s from [_graph]. This keeps track of how many calls |
| +/// have already been made so later calls know which result to look for. |
| +int _nextBuildResult; |
|
nweiz
2013/06/27 23:12:20
Apparently we have a StreamIterator class, which s
Bob Nystrom
2013/07/02 21:41:28
I tried that, but it doesn't allow queueing up mul
nweiz
2013/07/03 00:40:35
Gross. File a bug?
Bob Nystrom
2013/07/03 17:12:16
It's the documented behavior. :-/
nweiz
2013/07/03 18:17:15
Then file a feature request? It's good to have the
|
| + |
| void initConfig() { |
| if (_configured) return; |
| _configured = true; |
| unittestConfiguration = new CommandLineConfiguration(); |
| } |
| -/// Expects that [graph] will return an asset matching [name] and [contents]. |
| -void expectAsset(AssetGraph graph, String name, [String contents]) { |
| +/// Creates a new [AssetProvider] and [AssetGraph] with the given [assets] and |
| +/// [transformers]. |
| +/// |
| +/// This graph is used internally by most of the other functions in this |
| +/// library so you must call it in the test before calling any of the other |
| +/// functions. |
| +/// |
| +/// [assets] may either be an [Iterable] or a [Map]. If it's an [Iterable], |
| +/// each element may either be an [AssetId] or a string that can be parsed to |
| +/// one. If it's a [Map], each key should be a string that can be parsed to an |
| +/// [AssetId] and the value should be a string defining the contents of that |
| +/// asset. |
| +void initGraph([assets, Iterable<Iterable<Transformer>> transformers]) { |
| + if (assets == null) assets = []; |
| + if (transformers == null) transformers = []; |
| + |
| + _provider = new MockProvider(assets); |
| + _graph = new AssetGraph(_provider, transformers); |
| + _nextBuildResult = 0; |
| +} |
| + |
| +/// Updates [assets] in the current [AssetProvider]. |
| +/// |
| +/// Each item in the list may either be an [AssetId] or a string that can be |
| +/// parsed as one. Note that this method is not automatically scheduled. |
| +void updateSources(Iterable assets) { |
| + // Allow strings as asset IDs. |
| + assets = assets.map((asset) { |
| + if (asset is String) return new AssetId.parse(asset); |
| + return asset; |
| + }); |
| + |
| + _graph.updateSources(assets); |
| +} |
| + |
| +/// Removes [assets] from the current [AssetProvider]. |
| +/// |
| +/// Each item in the list may either be an [AssetId] or a string that can be |
| +/// parsed as one. Note that this method is not automatically scheduled. |
| +void removeSources(Iterable assets) { |
| + // Allow strings as asset IDs. |
| + assets = assets.map((asset) { |
| + if (asset is String) return new AssetId.parse(asset); |
| + return asset; |
| + }); |
| + |
| + _graph.removeSources(assets); |
| +} |
| + |
| +/// Schedules a change to the contents of an asset identified by [name] to |
| +/// [contents]. |
| +/// |
| +/// Does not update it in the graph. |
| +void modifyAsset(String name, String contents) { |
| + schedule(() { |
| + _provider._modifyAsset(name, contents); |
| + }, "modify asset $name"); |
| +} |
| + |
| +/// Schedules a pause of the internally created [AssetProvider]. |
| +/// |
| +/// All asset requests that the [AssetGraph] makes to the provider after this |
| +/// will not complete until [resumeProvider] is called. |
| +void pauseProvider() { |
| + schedule(() =>_provider._pause(), "pause provider"); |
| +} |
| + |
| +/// Schedules an unpause of the provider after a call to [pauseProvider] and |
| +/// allows all pending asset loads to finish. |
| +void resumeProvider() { |
| + schedule(() => _provider._resume(), "resume provider"); |
| +} |
| + |
| +/// Expects that the next [BuildResult] is a build success. |
| +void buildShouldSucceed([void callback()]) { |
| + _graph.results.elementAt(_nextBuildResult++).then(wrapAsync((result) { |
|
nweiz
2013/06/27 23:12:20
I strongly prefer expect(..., completes) to [wrapA
Bob Nystrom
2013/07/02 21:41:28
Done.
|
| + expect(result.succeeded, isTrue); |
| + if (callback != null) callback(); |
| + })); |
| +} |
| + |
| +/// Expects that the next [BuildResult] emitted is a failure. |
| +/// |
| +/// Invokes [callback] with the error (not the result) so that it can provide |
| +/// more precise expectations. |
| +void buildShouldFail(void callback(error)) { |
| + _graph.results.elementAt(_nextBuildResult++).then(wrapAsync((result) { |
| + expect(result.succeeded, isFalse); |
| + callback(result.error); |
| + })); |
| +} |
| + |
| +/// Pauses the schedule until the currently running build completes. |
| +void waitForBuild() { |
|
nweiz
2013/06/27 23:12:20
Isn't it possible that a build emits an error befo
Bob Nystrom
2013/07/02 21:41:28
Yup. Modified this to check that the result is act
|
| + schedule(() { |
| + return _graph.results.first; |
|
nweiz
2013/06/27 23:12:20
Style nit: =>
Bob Nystrom
2013/07/02 21:41:28
Invalidated by above change.
|
| + }); |
| +} |
| + |
| +/// Schedules an expectation that the graph will deliver an asset matching |
| +/// [name] and [contents]. |
| +/// |
| +/// If [contents] is omitted, defaults to the asset's filename without an |
| +/// extension (which is the same default that [initGraph] uses). |
| +void expectAsset(String name, [String contents]) { |
| var id = new AssetId.parse(name); |
| if (contents == null) { |
| @@ -31,7 +143,7 @@ void expectAsset(AssetGraph graph, String name, [String contents]) { |
| } |
| schedule(() { |
| - return graph.getAssetById(id).then((asset) { |
| + return _graph.getAssetById(id).then((asset) { |
| // TODO(rnystrom): Make an actual Matcher class for this. |
| expect(asset, new isInstanceOf<MockAsset>()); |
| expect(asset._id.package, equals(id.package)); |
| @@ -41,13 +153,14 @@ void expectAsset(AssetGraph graph, String name, [String contents]) { |
| }, "get asset $name"); |
| } |
| -/// Expects that [graph] will not find an asset matching [name]. |
| -void expectNoAsset(AssetGraph graph, String name) { |
| +/// Schedules an expectation that the graph will not find an asset matching |
| +/// [name]. |
| +void expectNoAsset(String name) { |
| var id = new AssetId.parse(name); |
| // Make sure the future gets the error. |
| schedule(() { |
| - return graph.getAssetById(id).then((asset) { |
| + return _graph.getAssetById(id).then((asset) { |
| fail("Should have thrown error but got $asset."); |
| }).catchError((error) { |
| expect(error, new isInstanceOf<AssetNotFoundException>()); |
| @@ -56,20 +169,18 @@ void expectNoAsset(AssetGraph graph, String name) { |
| }, "get asset $name"); |
| } |
| -/// Expects that [graph] will have an output file collision error on an asset |
| -/// matching [name]. |
| -Future expectCollision(AssetGraph graph, String name) { |
| +/// Expects that the next [BuildResult] is an output file collision error on an |
| +/// asset matching [name]. |
| +Future expectCollision(String name) { |
| var id = new AssetId.parse(name); |
| - return schedule(() { |
| - return graph.results.first.then((result) { |
| - expect(result.error, new isInstanceOf<AssetCollisionException>()); |
| - expect(result.error.id, equals(id)); |
| - }); |
| - }, "get collision on $name"); |
| + _graph.results.first.then(wrapAsync((result) { |
| + expect(result.error, new isInstanceOf<AssetCollisionException>()); |
| + expect(result.error.id, equals(id)); |
| + })); |
| } |
| -/// Expects that [graph] will have an error on an asset matching [name] for |
| -/// missing [input]. |
| +/// Schedules an expectation that [graph] will have an error on an asset |
| +/// matching [name] for missing [input]. |
| Future expectMissingInput(AssetGraph graph, String name, String input) { |
| var missing = new AssetId.parse(input); |
| @@ -90,22 +201,22 @@ class MockProvider implements AssetProvider { |
| final _packages = new Map<String, List<MockAsset>>(); |
| - /// The completer that [getAsset()] is waiting on to complete. |
| + /// The completer that [getAsset()] is waiting on to complete when paused. |
| /// |
| /// If `null` it will return the asset immediately. |
| - Completer _wait; |
| + Completer _pauseCompleter; |
| /// Tells the provider to wait during [getAsset] until [complete()] |
| /// is called. |
| /// |
| /// Lets you test the asynchronous behavior of loading. |
| - void wait() { |
| - _wait = new Completer(); |
| + void _pause() { |
| + _pauseCompleter = new Completer(); |
| } |
| - void complete() { |
| - _wait.complete(); |
| - _wait = null; |
| + void _resume() { |
| + _pauseCompleter.complete(); |
| + _pauseCompleter = null; |
| } |
| MockProvider(assets) { |
| @@ -125,7 +236,7 @@ class MockProvider implements AssetProvider { |
| } |
| } |
| - void modifyAsset(String name, String contents) { |
| + void _modifyAsset(String name, String contents) { |
| var id = new AssetId.parse(name); |
| var asset = _packages[id.package].firstWhere((a) => a._id == id); |
| asset._contents = contents; |
| @@ -141,8 +252,8 @@ class MockProvider implements AssetProvider { |
| Future<Asset> getAsset(AssetId id) { |
| var future; |
| - if (_wait != null) { |
| - future = _wait.future; |
| + if (_pauseCompleter != null) { |
| + future = _pauseCompleter.future; |
| } else { |
| future = new Future.value(); |
| } |