Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(877)

Side by Side Diff: pkg/barback/test/utils.dart

Issue 17507003: Clean up barback tests. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 9
9 import 'package:barback/barback.dart'; 10 import 'package:barback/barback.dart';
10 import 'package:barback/src/asset_graph.dart'; 11 import 'package:barback/src/asset_graph.dart';
11 import 'package:pathos/path.dart' as pathos; 12 import 'package:pathos/path.dart' as pathos;
12 import 'package:scheduled_test/scheduled_test.dart'; 13 import 'package:scheduled_test/scheduled_test.dart';
13 14
14 // TODO(rnystrom): Get rid of this or find a better path for it. 15 // TODO(rnystrom): Get rid of this or find a better path for it.
15 import '../../../sdk/lib/_internal/pub/test/command_line_config.dart'; 16 import '../../../sdk/lib/_internal/pub/test/command_line_config.dart';
16 17
17 var _configured = false; 18 var _configured = false;
18 19
20 MockProvider _provider;
21 AssetGraph _graph;
22
23 /// [BuildResult]s that have been output by the graph before an expectation has
24 /// consumed them.
25 ///
26 /// Since [AssetGraph] starts building immediately in the background, results
27 /// may start streaming before we've set an explicit expectation. When that
28 /// occurs, we just queue them up here.
29 final _buildResults = new Queue<BuildResult>();
30
31 /// The expectations we have on upcoming [BuildResult]s.
32 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!
33
19 void initConfig() { 34 void initConfig() {
20 if (_configured) return; 35 if (_configured) return;
21 _configured = true; 36 _configured = true;
22 unittestConfiguration = new CommandLineConfiguration(); 37 unittestConfiguration = new CommandLineConfiguration();
23 } 38 }
24 39
25 /// Expects that [graph] will return an asset matching [name] and [contents]. 40 /// Creates a new [AssetProvider] and [AssetGraph] with the given [assets] and
26 void expectAsset(AssetGraph graph, String name, [String contents]) { 41 /// [transformers].
42 ///
43 /// This graph is used internally by most of the other functions in this
44 /// library so you must call it in the test before calling any of the other
45 /// 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.
46 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.
47 if (assets == null) assets = [];
48 if (transformers == null) transformers = [];
49
50 _provider = new MockProvider(assets);
51 _graph = new AssetGraph(_provider, transformers);
52
53 _graph.results.listen(wrapAsync((result) {
54 if (_buildExpectations.isEmpty) {
55 // We aren't waiting for a result yet, so just queue it up for later.
56 _buildResults.add(result);
57 } else {
58 // See if it meets the expectation.
59 _buildExpectations.removeFirst().complete(result);
60 }
61 }));
62
63 // Discard any previous builds from earlier tests. It's OK for a test to not
64 // care about some build results.
65 _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.
66
67 // This library should ensure that you can't move to the next test until all
68 // build expectations are processed.
69 assert(_buildExpectations.isEmpty);
70
71 // TODO(bob): Temp!
nweiz 2013/06/25 22:37:56 *cough cough*
Bob Nystrom 2013/06/26 20:44:45 Oops! Done.
72 return _graph;
73 }
74
75 /// Updates [assets] in the current [AssetProvider]. Each item in the list may
76 /// 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.
77 void updateSources(List assets) {
78 // Allow strings as asset IDs.
79 assets = assets.map((asset) {
80 if (asset is String) return new AssetId.parse(asset);
81 return asset;
82 });
83
84 _graph.updateSources(assets);
85 }
86
87 /// Removes [assets] from the current [AssetProvider]. Each item in the list
88 /// may either be an [AssetId] or a string that can be parsed as one.
89 void removeSources(assets) {
90 // Allow strings as asset IDs.
91 assets = assets.map((asset) {
92 if (asset is String) return new AssetId.parse(asset);
93 return asset;
94 });
95
96 _graph.removeSources(assets);
97 }
98
99 /// Changes the contents of an asset identified by [name] to [contents]. Does
100 /// not update it in the graph.
101 void modifyAsset(String name, String contents) {
102 _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.
103 }
104
105 /// Pauses the internally created [AssetProvider]. All asset requests that come
106 /// 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.
107 void pauseProvider() {
108 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.
109 _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.
110 });
111 }
112
113 /// 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.
114 void resumeProvider() {
115 schedule(() {
116 _provider._complete();
117 });
118 }
119
120 /// Waits for the next [BuildResult] to be emitted and asserts that it is a
121 /// build success.
122 Future buildShouldSucceed() {
nweiz 2013/06/25 22:37:56 This doesn't return a Future.
Bob Nystrom 2013/06/26 20:44:45 Done.
123 schedule(() {
124 return _getNextBuildResult().then((result) {
125 expect(result.succeeded, isTrue);
126 });
127 });
128 }
129
130 /// Waits for the next [BuildResult] to be emitted and asserts that it is a
131 /// build failure. Invokes [callback] with the error (not the result) so that
132 /// it can provide more precise expectations.
133 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.
134 schedule(() {
135 return _getNextBuildResult().then((result) {
136 expect(result.succeeded, isFalse);
137 callback(result.error);
138 });
139 });
140 }
141
142 Future<BuildResult> _getNextBuildResult() {
143 if (_buildResults.isNotEmpty) {
144 return new Future.value(_buildResults.removeFirst());
145 }
146
147 // We don't have any results yet, so enqueue the expectation.
148 var completer = new Completer<BuildResult>();
149 _buildExpectations.add(completer);
150 return completer.future;
151 }
152
153 /// 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".
154 void expectAsset(String name, [String contents]) {
27 var id = new AssetId.parse(name); 155 var id = new AssetId.parse(name);
28 156
29 if (contents == null) { 157 if (contents == null) {
30 contents = pathos.basenameWithoutExtension(id.path); 158 contents = pathos.basenameWithoutExtension(id.path);
31 } 159 }
32 160
33 schedule(() { 161 schedule(() {
34 return graph.getAssetById(id).then((asset) { 162 return _graph.getAssetById(id).then((asset) {
35 // TODO(rnystrom): Make an actual Matcher class for this. 163 // TODO(rnystrom): Make an actual Matcher class for this.
36 expect(asset, new isInstanceOf<MockAsset>()); 164 expect(asset, new isInstanceOf<MockAsset>());
37 expect(asset._id.package, equals(id.package)); 165 expect(asset._id.package, equals(id.package));
38 expect(asset._id.path, equals(id.path)); 166 expect(asset._id.path, equals(id.path));
39 expect(asset._contents, equals(contents)); 167 expect(asset._contents, equals(contents));
40 }); 168 });
41 }, "get asset $name"); 169 }, "get asset $name");
42 } 170 }
43 171
44 /// Expects that [graph] will not find an asset matching [name]. 172 /// Expects that the graph will not find an asset matching [name].
45 void expectNoAsset(AssetGraph graph, String name) { 173 void expectNoAsset(String name) {
46 var id = new AssetId.parse(name); 174 var id = new AssetId.parse(name);
47 175
48 // Make sure the future gets the error. 176 // Make sure the future gets the error.
49 schedule(() { 177 schedule(() {
50 return graph.getAssetById(id).then((asset) { 178 return _graph.getAssetById(id).then((asset) {
51 fail("Should have thrown error but got $asset."); 179 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
52 }).catchError((error) { 180 }).catchError((error) {
53 expect(error, new isInstanceOf<AssetNotFoundException>()); 181 expect(error, new isInstanceOf<AssetNotFoundException>());
54 expect(error.id, equals(id)); 182 expect(error.id, equals(id));
55 }); 183 });
56 }, "get asset $name"); 184 }, "get asset $name");
57 } 185 }
58 186
59 /// Expects that [graph] will have an output file collision error on an asset 187 /// Expects that the graph will have an output file collision error on an asset
60 /// matching [name]. 188 /// matching [name].
61 Future expectCollision(AssetGraph graph, String name) { 189 Future expectCollision(String name) {
62 var id = new AssetId.parse(name); 190 var id = new AssetId.parse(name);
63 return schedule(() { 191 return schedule(() {
64 return graph.results.first.then((result) { 192 return _graph.results.first.then((result) {
65 expect(result.error, new isInstanceOf<AssetCollisionException>()); 193 expect(result.error, new isInstanceOf<AssetCollisionException>());
66 expect(result.error.id, equals(id)); 194 expect(result.error.id, equals(id));
67 }); 195 });
68 }, "get collision on $name"); 196 }, "get collision on $name");
69 } 197 }
70 198
71 /// Expects that [graph] will have an error on an asset matching [name] for 199 /// Expects that [graph] will have an error on an asset matching [name] for
72 /// missing [input]. 200 /// missing [input].
73 Future expectMissingInput(AssetGraph graph, String name, String input) { 201 Future expectMissingInput(AssetGraph graph, String name, String input) {
74 var missing = new AssetId.parse(input); 202 var missing = new AssetId.parse(input);
(...skipping 11 matching lines...) Expand all
86 214
87 /// An [AssetProvider] that provides the given set of assets. 215 /// An [AssetProvider] that provides the given set of assets.
88 class MockProvider implements AssetProvider { 216 class MockProvider implements AssetProvider {
89 Iterable<String> get packages => _packages.keys; 217 Iterable<String> get packages => _packages.keys;
90 218
91 final _packages = new Map<String, List<MockAsset>>(); 219 final _packages = new Map<String, List<MockAsset>>();
92 220
93 /// The completer that [getAsset()] is waiting on to complete. 221 /// The completer that [getAsset()] is waiting on to complete.
94 /// 222 ///
95 /// If `null` it will return the asset immediately. 223 /// If `null` it will return the asset immediately.
96 Completer _wait; 224 Completer _waitCompleter;
97 225
98 /// Tells the provider to wait during [getAsset] until [complete()] 226 /// Tells the provider to wait during [getAsset] until [complete()]
99 /// is called. 227 /// is called.
100 /// 228 ///
101 /// Lets you test the asynchronous behavior of loading. 229 /// Lets you test the asynchronous behavior of loading.
102 void wait() { 230 void _wait() {
103 _wait = new Completer(); 231 _waitCompleter = new Completer();
104 } 232 }
105 233
106 void complete() { 234 void _complete() {
107 _wait.complete(); 235 _waitCompleter.complete();
108 _wait = null; 236 _waitCompleter = null;
109 } 237 }
110 238
111 MockProvider(assets) { 239 MockProvider(assets) {
112 if (assets is Map) { 240 if (assets is Map) {
113 assets.forEach((asset, contents) { 241 assets.forEach((asset, contents) {
114 var id = new AssetId.parse(asset); 242 var id = new AssetId.parse(asset);
115 var package = _packages.putIfAbsent(id.package, () => []); 243 var package = _packages.putIfAbsent(id.package, () => []);
116 package.add(new MockAsset(id, contents)); 244 package.add(new MockAsset(id, contents));
117 }); 245 });
118 } else if (assets is Iterable) { 246 } else if (assets is Iterable) {
119 for (var asset in assets) { 247 for (var asset in assets) {
120 var id = new AssetId.parse(asset); 248 var id = new AssetId.parse(asset);
121 var package = _packages.putIfAbsent(id.package, () => []); 249 var package = _packages.putIfAbsent(id.package, () => []);
122 var contents = pathos.basenameWithoutExtension(id.path); 250 var contents = pathos.basenameWithoutExtension(id.path);
123 package.add(new MockAsset(id, contents)); 251 package.add(new MockAsset(id, contents));
124 } 252 }
125 } 253 }
126 } 254 }
127 255
128 void modifyAsset(String name, String contents) { 256 void _modifyAsset(String name, String contents) {
129 var id = new AssetId.parse(name); 257 var id = new AssetId.parse(name);
130 var asset = _packages[id.package].firstWhere((a) => a._id == id); 258 var asset = _packages[id.package].firstWhere((a) => a._id == id);
131 asset._contents = contents; 259 asset._contents = contents;
132 } 260 }
133 261
134 List<AssetId> listAssets(String package, {String within}) { 262 List<AssetId> listAssets(String package, {String within}) {
135 if (within != null) { 263 if (within != null) {
136 throw new UnimplementedError("Doesn't handle 'within' yet."); 264 throw new UnimplementedError("Doesn't handle 'within' yet.");
137 } 265 }
138 266
139 return _packages[package].map((asset) => asset.id); 267 return _packages[package].map((asset) => asset.id);
140 } 268 }
141 269
142 Future<Asset> getAsset(AssetId id) { 270 Future<Asset> getAsset(AssetId id) {
143 var future; 271 var future;
144 if (_wait != null) { 272 if (_waitCompleter != null) {
145 future = _wait.future; 273 future = _waitCompleter.future;
146 } else { 274 } else {
147 future = new Future.value(); 275 future = new Future.value();
148 } 276 }
149 277
150 return future.then((_) { 278 return future.then((_) {
151 var package = _packages[id.package]; 279 var package = _packages[id.package];
152 if (package == null) throw new AssetNotFoundException(id); 280 if (package == null) throw new AssetNotFoundException(id);
153 281
154 return package.firstWhere((asset) => asset._id == id, 282 return package.firstWhere((asset) => asset._id == id,
155 orElse: () => throw new AssetNotFoundException(id)); 283 orElse: () => throw new AssetNotFoundException(id));
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after
333 461
334 MockAsset(this._id, this._contents); 462 MockAsset(this._id, this._contents);
335 463
336 String readAsString() => _contents; 464 String readAsString() => _contents;
337 Stream<List<int>> read() => throw new UnimplementedError(); 465 Stream<List<int>> read() => throw new UnimplementedError();
338 466
339 serialize() => throw new UnimplementedError(); 467 serialize() => throw new UnimplementedError();
340 468
341 String toString() => "MockAsset $_id $_contents"; 469 String toString() => "MockAsset $_id $_contents";
342 } 470 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698