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..67762e51bb0653980dd85cb7b9dd0e8ec1914e6c 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,141 @@ import '../../../sdk/lib/_internal/pub/test/command_line_config.dart'; |
| var _configured = false; |
| +MockProvider _provider; |
| +AssetGraph _graph; |
| + |
| +/// [BuildResult]s that have been output by the graph before an expectation has |
| +/// consumed them. |
| +/// |
| +/// Since [AssetGraph] starts building immediately in the background, results |
| +/// may start streaming before we've set an explicit expectation. When that |
| +/// occurs, we just queue them up here. |
| +final _buildResults = new Queue<BuildResult>(); |
| + |
| +/// The expectations we have on upcoming [BuildResult]s. |
| +final _buildExpectations = new Queue<Completer<BuildResult>>(); |
|
nweiz
2013/06/25 22:37:56
I really don't like this [_buildResults]/[_buildEx
Bob Nystrom
2013/06/26 20:44:45
Maybe the results stream shouldn't be broadcast by
nweiz
2013/06/27 00:19:25
You're being fuzzy about what "in the background"
Bob Nystrom
2013/06/27 17:55:14
That's correct. It always pumps the event loop. Ac
nweiz
2013/06/27 21:08:46
I don't understand why they're blocked on one anot
Bob Nystrom
2013/06/27 22:23:07
Done!
|
| + |
| 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. |
|
nweiz
2013/06/25 22:37:56
Mention that all operations on the graph are sched
Bob Nystrom
2013/06/26 20:44:45
Done.
|
| +AssetGraph initGraph([assets, Iterable<Iterable<Transformer>> transformers]) { |
|
nweiz
2013/06/25 22:37:56
Since [assets] isn't type-annotated, the documenta
Bob Nystrom
2013/06/26 20:44:45
Done.
|
| + if (assets == null) assets = []; |
| + if (transformers == null) transformers = []; |
| + |
| + _provider = new MockProvider(assets); |
| + _graph = new AssetGraph(_provider, transformers); |
| + |
| + _graph.results.listen(wrapAsync((result) { |
| + if (_buildExpectations.isEmpty) { |
| + // We aren't waiting for a result yet, so just queue it up for later. |
| + _buildResults.add(result); |
| + } else { |
| + // See if it meets the expectation. |
| + _buildExpectations.removeFirst().complete(result); |
| + } |
| + })); |
| + |
| + // Discard any previous builds from earlier tests. It's OK for a test to not |
| + // care about some build results. |
| + _buildResults.clear(); |
|
nweiz
2013/06/25 22:37:56
Earlier tests should clean up their own mess. This
Bob Nystrom
2013/06/26 20:44:45
Done.
|
| + |
| + // This library should ensure that you can't move to the next test until all |
| + // build expectations are processed. |
| + assert(_buildExpectations.isEmpty); |
| + |
| + // TODO(bob): Temp! |
|
nweiz
2013/06/25 22:37:56
*cough cough*
Bob Nystrom
2013/06/26 20:44:45
Oops! Done.
|
| + return _graph; |
| +} |
| + |
| +/// 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. |
|
nweiz
2013/06/25 22:37:56
Style nit: the second sentence here should be in a
Bob Nystrom
2013/06/26 20:44:45
Done.
|
| +void updateSources(List 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. |
| +void removeSources(assets) { |
| + // Allow strings as asset IDs. |
| + assets = assets.map((asset) { |
| + if (asset is String) return new AssetId.parse(asset); |
| + return asset; |
| + }); |
| + |
| + _graph.removeSources(assets); |
| +} |
| + |
| +/// Changes the contents of an asset identified by [name] to [contents]. Does |
| +/// not update it in the graph. |
| +void modifyAsset(String name, String contents) { |
| + _provider._modifyAsset(name, contents); |
|
nweiz
2013/06/25 22:37:56
This seems like it should be scheduled.
Bob Nystrom
2013/06/26 20:44:45
Done.
|
| +} |
| + |
| +/// Pauses the internally created [AssetProvider]. All asset requests that come |
| +/// in after this will wait until the provider is unpaused. |
|
nweiz
2013/06/25 22:37:56
"that come in" -> "that the [AssetGraph] makes to
Bob Nystrom
2013/06/26 20:44:45
Done.
|
| +void pauseProvider() { |
| + schedule(() { |
|
nweiz
2013/06/25 22:37:56
Style nit: =>. Also below.
All [schedule] calls i
Bob Nystrom
2013/06/26 20:44:45
Done.
|
| + _provider._wait(); |
|
nweiz
2013/06/25 22:37:56
It's weird that the public methods are named "paus
Bob Nystrom
2013/06/26 20:44:45
Done.
|
| + }); |
| +} |
| + |
| +/// Unpauses the provider and allows all pending asset loads to finish. |
|
nweiz
2013/06/25 22:37:56
This should refer explicitly to [pauseProvider].
Bob Nystrom
2013/06/26 20:44:45
Done.
|
| +void resumeProvider() { |
| + schedule(() { |
| + _provider._complete(); |
| + }); |
| +} |
| + |
| +/// Waits for the next [BuildResult] to be emitted and asserts that it is a |
| +/// build success. |
| +Future buildShouldSucceed() { |
|
nweiz
2013/06/25 22:37:56
This doesn't return a Future.
Bob Nystrom
2013/06/26 20:44:45
Done.
|
| + schedule(() { |
| + return _getNextBuildResult().then((result) { |
| + expect(result.succeeded, isTrue); |
| + }); |
| + }); |
| +} |
| + |
| +/// Waits for the next [BuildResult] to be emitted and asserts that it is a |
| +/// build failure. Invokes [callback] with the error (not the result) so that |
| +/// it can provide more precise expectations. |
| +Future buildShouldFail(void callback(error)) { |
|
nweiz
2013/06/25 22:37:56
This doesn't return a Future either, although it's
Bob Nystrom
2013/06/26 20:44:45
Done.
|
| + schedule(() { |
| + return _getNextBuildResult().then((result) { |
| + expect(result.succeeded, isFalse); |
| + callback(result.error); |
| + }); |
| + }); |
| +} |
| + |
| +Future<BuildResult> _getNextBuildResult() { |
| + if (_buildResults.isNotEmpty) { |
| + return new Future.value(_buildResults.removeFirst()); |
| + } |
| + |
| + // We don't have any results yet, so enqueue the expectation. |
| + var completer = new Completer<BuildResult>(); |
| + _buildExpectations.add(completer); |
| + return completer.future; |
| +} |
| + |
| +/// Expects that the graph will return an asset matching [name] and [contents]. |
|
nweiz
2013/06/25 22:37:56
This comment is confusing. "return" implies that s
Bob Nystrom
2013/06/26 20:44:45
Changed to "deliver".
|
| +void expectAsset(String name, [String contents]) { |
| var id = new AssetId.parse(name); |
| if (contents == null) { |
| @@ -31,7 +159,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 +169,13 @@ 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) { |
| +/// Expects 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."); |
|
nweiz
2013/06/25 22:37:56
Manually failing feels unnecessary when we have li
Bob Nystrom
2013/06/26 20:44:45
The body of that predicate gets kind of nasty. Thi
nweiz
2013/06/27 00:19:25
I thought you could just use [expect] in [predicat
|
| }).catchError((error) { |
| expect(error, new isInstanceOf<AssetNotFoundException>()); |
| @@ -56,12 +184,12 @@ void expectNoAsset(AssetGraph graph, String name) { |
| }, "get asset $name"); |
| } |
| -/// Expects that [graph] will have an output file collision error on an asset |
| +/// Expects that the graph will have an output file collision error on an asset |
| /// matching [name]. |
| -Future expectCollision(AssetGraph graph, String name) { |
| +Future expectCollision(String name) { |
| var id = new AssetId.parse(name); |
| return schedule(() { |
| - return graph.results.first.then((result) { |
| + return _graph.results.first.then((result) { |
| expect(result.error, new isInstanceOf<AssetCollisionException>()); |
| expect(result.error.id, equals(id)); |
| }); |
| @@ -93,19 +221,19 @@ class MockProvider implements AssetProvider { |
| /// The completer that [getAsset()] is waiting on to complete. |
| /// |
| /// If `null` it will return the asset immediately. |
| - Completer _wait; |
| + Completer _waitCompleter; |
| /// 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 _wait() { |
| + _waitCompleter = new Completer(); |
| } |
| - void complete() { |
| - _wait.complete(); |
| - _wait = null; |
| + void _complete() { |
| + _waitCompleter.complete(); |
| + _waitCompleter = null; |
| } |
| MockProvider(assets) { |
| @@ -125,7 +253,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 +269,8 @@ class MockProvider implements AssetProvider { |
| Future<Asset> getAsset(AssetId id) { |
| var future; |
| - if (_wait != null) { |
| - future = _wait.future; |
| + if (_waitCompleter != null) { |
| + future = _waitCompleter.future; |
| } else { |
| future = new Future.value(); |
| } |