Chromium Code Reviews| 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 |
| 11 import 'package:barback/barback.dart'; | 11 import 'package:barback/barback.dart'; |
| 12 import 'package:barback/src/asset_graph.dart'; | 12 import 'package:barback/src/asset_graph.dart'; |
| 13 import 'package:barback/src/asset_graph_manager.dart'; | |
| 14 import 'package:barback/src/utils.dart'; | |
| 13 import 'package:pathos/path.dart' as pathos; | 15 import 'package:pathos/path.dart' as pathos; |
| 14 import 'package:scheduled_test/scheduled_test.dart'; | 16 import 'package:scheduled_test/scheduled_test.dart'; |
| 17 import 'package:stack_trace/stack_trace.dart'; | |
| 15 | 18 |
| 16 // TODO(rnystrom): Get rid of this or find a better path for it. | 19 // TODO(rnystrom): Get rid of this or find a better path for it. |
| 17 import '../../../sdk/lib/_internal/pub/test/command_line_config.dart'; | 20 import '../../../sdk/lib/_internal/pub/test/command_line_config.dart'; |
| 18 | 21 |
| 19 var _configured = false; | 22 var _configured = false; |
| 20 | 23 |
| 21 MockProvider _provider; | 24 MockProvider _provider; |
| 22 AssetGraph _graph; | 25 AssetGraphManager _graphManager; |
| 23 | 26 |
| 24 /// Calls to [buildShouldSucceed] and [buildShouldFail] set expectations on | 27 /// Calls to [buildShouldSucceed] and [buildShouldFail] set expectations on |
| 25 /// successive [BuildResult]s from [_graph]. This keeps track of how many calls | 28 /// successive [BuildResult]s from [_graph]. This keeps track of how many calls |
| 26 /// have already been made so later calls know which result to look for. | 29 /// have already been made so later calls know which result to look for. |
| 27 int _nextBuildResult; | 30 int _nextBuildResult; |
| 28 | 31 |
| 29 void initConfig() { | 32 void initConfig() { |
| 30 if (_configured) return; | 33 if (_configured) return; |
| 31 _configured = true; | 34 _configured = true; |
| 32 unittestConfiguration = new CommandLineConfiguration(); | 35 unittestConfiguration = new CommandLineConfiguration(); |
| 33 } | 36 } |
| 34 | 37 |
| 35 /// Creates a new [AssetProvider] and [AssetGraph] with the given [assets] and | 38 /// Creates a new [AssetProvider] and [AssetGraph] with the given [assets] and |
| 36 /// [transformers]. | 39 /// [transformers]. |
| 37 /// | 40 /// |
| 38 /// This graph is used internally by most of the other functions in this | 41 /// This graph is used internally by most of the other functions in this |
| 39 /// library so you must call it in the test before calling any of the other | 42 /// library so you must call it in the test before calling any of the other |
| 40 /// functions. | 43 /// functions. |
| 41 /// | 44 /// |
| 42 /// [assets] may either be an [Iterable] or a [Map]. If it's an [Iterable], | 45 /// [assets] may either be an [Iterable] or a [Map]. If it's an [Iterable], |
| 43 /// each element may either be an [AssetId] or a string that can be parsed to | 46 /// each element may either be an [AssetId] or a string that can be parsed to |
| 44 /// one. If it's a [Map], each key should be a string that can be parsed to an | 47 /// one. If it's a [Map], each key should be a string that can be parsed to an |
| 45 /// [AssetId] and the value should be a string defining the contents of that | 48 /// [AssetId] and the value should be a string defining the contents of that |
| 46 /// asset. | 49 /// asset. |
| 47 void initGraph([assets, Iterable<Iterable<Transformer>> transformers]) { | 50 /// |
| 51 /// [transformers] is a map from package names to the transformers for each | |
| 52 /// package. | |
| 53 void initGraph([assets, | |
| 54 Map<String, Iterable<Iterable<Transformer>>> transformers]) { | |
| 48 if (assets == null) assets = []; | 55 if (assets == null) assets = []; |
| 49 if (transformers == null) transformers = []; | 56 if (transformers == null) transformers = {}; |
| 50 | 57 |
| 51 _provider = new MockProvider(assets); | 58 _provider = new MockProvider(assets, transformers); |
| 52 _graph = new AssetGraph(_provider, transformers); | 59 _graphManager = new AssetGraphManager(_provider); |
| 53 _nextBuildResult = 0; | 60 _nextBuildResult = 0; |
| 54 } | 61 } |
| 55 | 62 |
| 56 /// Updates [assets] in the current [AssetProvider]. | 63 /// Updates [assets] in the current [AssetProvider]. |
| 57 /// | 64 /// |
| 58 /// Each item in the list may either be an [AssetId] or a string that can be | 65 /// Each item in the list may either be an [AssetId] or a string that can be |
| 59 /// parsed as one. Note that this method is not automatically scheduled. | 66 /// parsed as one. Note that this method is not automatically scheduled. |
| 60 void updateSources(Iterable assets) { | 67 void updateSources(Iterable assets) { |
| 61 // Allow strings as asset IDs. | 68 // Allow strings as asset IDs. |
| 62 assets = assets.map((asset) { | 69 assets = assets.map((asset) { |
| 63 if (asset is String) return new AssetId.parse(asset); | 70 if (asset is String) return new AssetId.parse(asset); |
| 64 return asset; | 71 return asset; |
| 65 }); | 72 }); |
| 66 | 73 |
| 67 _graph.updateSources(assets); | 74 _graphManager.updateSources(assets); |
| 68 } | 75 } |
| 69 | 76 |
| 70 /// Removes [assets] from the current [AssetProvider]. | 77 /// Removes [assets] from the current [AssetProvider]. |
| 71 /// | 78 /// |
| 72 /// Each item in the list may either be an [AssetId] or a string that can be | 79 /// Each item in the list may either be an [AssetId] or a string that can be |
| 73 /// parsed as one. Note that this method is not automatically scheduled. | 80 /// parsed as one. Note that this method is not automatically scheduled. |
| 74 void removeSources(Iterable assets) { | 81 void removeSources(Iterable assets) { |
| 75 // Allow strings as asset IDs. | 82 // Allow strings as asset IDs. |
| 76 assets = assets.map((asset) { | 83 assets = assets.map((asset) { |
| 77 if (asset is String) return new AssetId.parse(asset); | 84 if (asset is String) return new AssetId.parse(asset); |
| 78 return asset; | 85 return asset; |
| 79 }); | 86 }); |
| 80 | 87 |
| 81 _graph.removeSources(assets); | 88 _graphManager.removeSources(assets); |
| 82 } | 89 } |
| 83 | 90 |
| 84 /// Schedules a change to the contents of an asset identified by [name] to | 91 /// Schedules a change to the contents of an asset identified by [name] to |
| 85 /// [contents]. | 92 /// [contents]. |
| 86 /// | 93 /// |
| 87 /// Does not update it in the graph. | 94 /// Does not update it in the graph. |
| 88 void modifyAsset(String name, String contents) { | 95 void modifyAsset(String name, String contents) { |
| 89 schedule(() { | 96 schedule(() { |
| 90 _provider._modifyAsset(name, contents); | 97 _provider._modifyAsset(name, contents); |
| 91 }, "modify asset $name"); | 98 }, "modify asset $name"); |
| 92 } | 99 } |
| 93 | 100 |
| 94 /// Schedules a pause of the internally created [AssetProvider]. | 101 /// Schedules a pause of the internally created [AssetProvider]. |
| 95 /// | 102 /// |
| 96 /// All asset requests that the [AssetGraph] makes to the provider after this | 103 /// All asset requests that the [AssetGraph] makes to the provider after this |
| 97 /// will not complete until [resumeProvider] is called. | 104 /// will not complete until [resumeProvider] is called. |
| 98 void pauseProvider() { | 105 void pauseProvider() { |
| 99 schedule(() =>_provider._pause(), "pause provider"); | 106 schedule(() => _provider._pause(), "pause provider"); |
| 100 } | 107 } |
| 101 | 108 |
| 102 /// Schedules an unpause of the provider after a call to [pauseProvider] and | 109 /// Schedules an unpause of the provider after a call to [pauseProvider] and |
| 103 /// allows all pending asset loads to finish. | 110 /// allows all pending asset loads to finish. |
| 104 void resumeProvider() { | 111 void resumeProvider() { |
| 105 schedule(() => _provider._resume(), "resume provider"); | 112 schedule(() => _provider._resume(), "resume provider"); |
| 106 } | 113 } |
| 107 | 114 |
| 115 /// Asserts that the build should not terminate at this point in the schedule. | |
|
Bob Nystrom
2013/07/11 23:03:40
"should not terminate at this point" is unclear. D
nweiz
2013/07/15 22:11:44
Clarified.
| |
| 116 /// | |
| 117 /// This uses the same build counter as [buildShouldSucceed] and | |
| 118 /// [buildShouldFail], so those can be used to validate build results before and | |
| 119 /// after this. | |
| 120 void buildShouldNotBeDone() { | |
| 121 var resultAllowed = false; | |
| 122 var trace = new Trace.current(); | |
| 123 _graphManager.results.elementAt(_nextBuildResult).then((result) { | |
| 124 if (resultAllowed) return; | |
| 125 | |
| 126 currentSchedule.signalError( | |
| 127 new Exception("Expected build not to terminate " | |
| 128 "here, but it terminated with result: $result"), trace); | |
| 129 }).catchError((error) { | |
| 130 if (resultAllowed) return; | |
| 131 currentSchedule.signalError(error); | |
| 132 }); | |
| 133 | |
| 134 schedule(() { | |
| 135 return pumpEventQueue().then((_) { | |
|
Bob Nystrom
2013/07/11 23:03:40
Explain/document this.
nweiz
2013/07/15 22:11:44
Done.
| |
| 136 resultAllowed = true; | |
| 137 }); | |
| 138 }, "ensuring build doesn't terminate"); | |
| 139 } | |
| 140 | |
| 108 /// Expects that the next [BuildResult] is a build success. | 141 /// Expects that the next [BuildResult] is a build success. |
| 109 void buildShouldSucceed() { | 142 void buildShouldSucceed() { |
| 110 expect(_graph.results.elementAt(_nextBuildResult++).then((result) { | 143 expect(_getNextBuildResult().then((result) { |
| 111 expect(result.succeeded, isTrue); | 144 expect(result.succeeded, isTrue); |
| 112 }), completes); | 145 }), completes); |
| 113 } | 146 } |
| 114 | 147 |
| 115 /// Expects that the next [BuildResult] emitted is a failure. | 148 /// Expects that the next [BuildResult] emitted is a failure. |
| 116 /// | 149 /// |
| 117 /// [matchers] is a list of matchers to match against the errors that caused the | 150 /// [matchers] is a list of matchers to match against the errors that caused the |
| 118 /// build to fail. Every matcher is expected to match an error, but the order of | 151 /// build to fail. Every matcher is expected to match an error, but the order of |
| 119 /// matchers is unimportant. | 152 /// matchers is unimportant. |
| 120 void buildShouldFail(List matchers) { | 153 void buildShouldFail(List matchers) { |
| 121 expect(_graph.results.elementAt(_nextBuildResult++).then((result) { | 154 expect(_getNextBuildResult().then((result) { |
| 122 expect(result.succeeded, isFalse); | 155 expect(result.succeeded, isFalse); |
| 123 expect(result.errors.length, equals(matchers.length)); | 156 expect(result.errors.length, equals(matchers.length)); |
| 124 for (var matcher in matchers) { | 157 for (var matcher in matchers) { |
| 125 expect(result.errors, contains(matcher)); | 158 expect(result.errors, contains(matcher)); |
| 126 } | 159 } |
| 127 }), completes); | 160 }), completes); |
| 128 } | 161 } |
| 129 | 162 |
| 163 Future<BuildResult> _getNextBuildResult() => | |
| 164 _graphManager.results.elementAt(_nextBuildResult++); | |
| 165 | |
| 130 /// Pauses the schedule until the currently running build completes. | 166 /// Pauses the schedule until the currently running build completes. |
| 131 /// | 167 /// |
| 132 /// Validates that the build completed successfully. | 168 /// Validates that the build completed successfully. |
| 133 void waitForBuild() { | 169 void waitForBuild() { |
| 134 schedule(() { | 170 schedule(() { |
| 135 return _graph.results.first.then((result) { | 171 return _graphManager.results.first.then((result) { |
| 136 expect(result.succeeded, isTrue); | 172 expect(result.succeeded, isTrue); |
| 137 }); | 173 }); |
| 138 }, "wait for build"); | 174 }, "wait for build"); |
| 139 } | 175 } |
| 140 | 176 |
| 141 /// Schedules an expectation that the graph will deliver an asset matching | 177 /// Schedules an expectation that the graph will deliver an asset matching |
| 142 /// [name] and [contents]. | 178 /// [name] and [contents]. |
| 143 /// | 179 /// |
| 144 /// If [contents] is omitted, defaults to the asset's filename without an | 180 /// If [contents] is omitted, defaults to the asset's filename without an |
| 145 /// extension (which is the same default that [initGraph] uses). | 181 /// extension (which is the same default that [initGraph] uses). |
| 146 void expectAsset(String name, [String contents]) { | 182 void expectAsset(String name, [String contents]) { |
| 147 var id = new AssetId.parse(name); | 183 var id = new AssetId.parse(name); |
| 148 | 184 |
| 149 if (contents == null) { | 185 if (contents == null) { |
| 150 contents = pathos.basenameWithoutExtension(id.path); | 186 contents = pathos.basenameWithoutExtension(id.path); |
| 151 } | 187 } |
| 152 | 188 |
| 153 schedule(() { | 189 schedule(() { |
| 154 return _graph.getAssetById(id).then((asset) { | 190 return _graphManager.getAssetById(id).then((asset) { |
| 155 // TODO(rnystrom): Make an actual Matcher class for this. | 191 // TODO(rnystrom): Make an actual Matcher class for this. |
| 156 expect(asset, new isInstanceOf<MockAsset>()); | 192 expect(asset, new isInstanceOf<MockAsset>()); |
| 157 expect(asset.id, equals(id)); | 193 expect(asset.id, equals(id)); |
| 158 expect(asset.contents, equals(contents)); | 194 expect(asset.contents, equals(contents)); |
| 159 }); | 195 }); |
| 160 }, "get asset $name"); | 196 }, "get asset $name"); |
| 161 } | 197 } |
| 162 | 198 |
| 163 /// Schedules an expectation that the graph will not find an asset matching | 199 /// Schedules an expectation that the graph will not find an asset matching |
| 164 /// [name]. | 200 /// [name]. |
| 165 void expectNoAsset(String name) { | 201 void expectNoAsset(String name) { |
| 166 var id = new AssetId.parse(name); | 202 var id = new AssetId.parse(name); |
| 167 | 203 |
| 168 // Make sure the future gets the error. | 204 // Make sure the future gets the error. |
| 169 schedule(() { | 205 schedule(() { |
| 170 return _graph.getAssetById(id).then((asset) { | 206 return _graphManager.getAssetById(id).then((asset) { |
| 171 fail("Should have thrown error but got $asset."); | 207 fail("Should have thrown error but got $asset."); |
| 172 }).catchError((error) { | 208 }).catchError((error) { |
| 173 expect(error, new isInstanceOf<AssetNotFoundException>()); | 209 expect(error, new isInstanceOf<AssetNotFoundException>()); |
| 174 expect(error.id, equals(id)); | 210 expect(error.id, equals(id)); |
| 175 }); | 211 }); |
| 176 }, "get asset $name"); | 212 }, "get asset $name"); |
| 177 } | 213 } |
| 178 | 214 |
| 179 /// Schedules an expectation that [graph] will have an error on an asset | |
| 180 /// matching [name] for missing [input]. | |
| 181 Future expectMissingInput(AssetGraph graph, String name, String input) { | |
| 182 var missing = new AssetId.parse(input); | |
| 183 | |
| 184 // Make sure the future gets the error. | |
| 185 schedule(() { | |
| 186 return graph.getAssetById(new AssetId.parse(name)).then((asset) { | |
| 187 fail("Should have thrown error but got $asset."); | |
| 188 }).catchError((error) { | |
| 189 expect(error, new isInstanceOf<MissingInputException>()); | |
| 190 expect(error.id, equals(missing)); | |
| 191 }); | |
| 192 }, "get missing input on $name"); | |
| 193 } | |
| 194 | |
| 195 /// Returns a matcher for an [AssetNotFoundException] with the given [id]. | 215 /// Returns a matcher for an [AssetNotFoundException] with the given [id]. |
| 196 Matcher isAssetNotFoundException(String name) { | 216 Matcher isAssetNotFoundException(String name) { |
| 197 var id = new AssetId.parse(name); | 217 var id = new AssetId.parse(name); |
| 198 return allOf( | 218 return allOf( |
| 199 new isInstanceOf<AssetNotFoundException>(), | 219 new isInstanceOf<AssetNotFoundException>(), |
| 200 predicate((error) => error.id == id, 'id is $name')); | 220 predicate((error) => error.id == id, 'id is $name')); |
| 201 } | 221 } |
| 202 | 222 |
| 203 /// Returns a matcher for an [AssetCollisionException] with the given [id]. | 223 /// Returns a matcher for an [AssetCollisionException] with the given [id]. |
| 204 Matcher isAssetCollisionException(String name) { | 224 Matcher isAssetCollisionException(String name) { |
| 205 var id = new AssetId.parse(name); | 225 var id = new AssetId.parse(name); |
| 206 return allOf( | 226 return allOf( |
| 207 new isInstanceOf<AssetCollisionException>(), | 227 new isInstanceOf<AssetCollisionException>(), |
| 208 predicate((error) => error.id == id, 'id is $name')); | 228 predicate((error) => error.id == id, 'id is $name')); |
| 209 } | 229 } |
| 210 | 230 |
| 211 /// Returns a matcher for a [MissingInputException] with the given [id]. | 231 /// Returns a matcher for a [MissingInputException] with the given [id]. |
| 212 Matcher isMissingInputException(String name) { | 232 Matcher isMissingInputException(String name) { |
| 213 var id = new AssetId.parse(name); | 233 var id = new AssetId.parse(name); |
| 214 return allOf( | 234 return allOf( |
| 215 new isInstanceOf<MissingInputException>(), | 235 new isInstanceOf<MissingInputException>(), |
| 216 predicate((error) => error.id == id, 'id is $name')); | 236 predicate((error) => error.id == id, 'id is $name')); |
| 217 } | 237 } |
| 218 | 238 |
| 219 /// An [AssetProvider] that provides the given set of assets. | 239 /// An [AssetProvider] that provides the given set of assets. |
| 220 class MockProvider implements AssetProvider { | 240 class MockProvider implements AssetProvider { |
| 221 Iterable<String> get packages => _packages.keys; | 241 Iterable<String> get packages => _packages.keys; |
| 222 | 242 |
| 223 final _packages = new Map<String, List<MockAsset>>(); | 243 Map<String, _MockPackage> _packages; |
| 224 | 244 |
| 225 /// The completer that [getAsset()] is waiting on to complete when paused. | 245 /// The completer that [getAsset()] is waiting on to complete when paused. |
| 226 /// | 246 /// |
| 227 /// If `null` it will return the asset immediately. | 247 /// If `null` it will return the asset immediately. |
| 228 Completer _pauseCompleter; | 248 Completer _pauseCompleter; |
| 229 | 249 |
| 230 /// Tells the provider to wait during [getAsset] until [complete()] | 250 /// Tells the provider to wait during [getAsset] until [complete()] |
| 231 /// is called. | 251 /// is called. |
| 232 /// | 252 /// |
| 233 /// Lets you test the asynchronous behavior of loading. | 253 /// Lets you test the asynchronous behavior of loading. |
| 234 void _pause() { | 254 void _pause() { |
| 235 _pauseCompleter = new Completer(); | 255 _pauseCompleter = new Completer(); |
| 236 } | 256 } |
| 237 | 257 |
| 238 void _resume() { | 258 void _resume() { |
| 239 _pauseCompleter.complete(); | 259 _pauseCompleter.complete(); |
| 240 _pauseCompleter = null; | 260 _pauseCompleter = null; |
| 241 } | 261 } |
| 242 | 262 |
| 243 MockProvider(assets) { | 263 MockProvider(assets, |
| 264 Map<String, Iterable<Iterable<Transformer>>> transformers) { | |
|
Bob Nystrom
2013/07/11 23:03:40
How about also allowing this to just be a nested l
nweiz
2013/07/15 22:11:44
I thought about that, but it seemed weird to assum
Bob Nystrom
2013/07/16 17:36:01
Yeah, I was actually thinking about doing the form
nweiz
2013/07/16 19:39:39
I'll leave it for now, but let's keep the idea in
| |
| 265 var assetList; | |
| 244 if (assets is Map) { | 266 if (assets is Map) { |
| 245 assets.forEach((asset, contents) { | 267 assetList = assets.keys.map((asset) { |
| 246 var id = new AssetId.parse(asset); | 268 var id = new AssetId.parse(asset); |
| 247 var package = _packages.putIfAbsent(id.package, () => []); | 269 return new MockAsset(id, assets[asset]); |
| 248 package.add(new MockAsset(id, contents)); | |
| 249 }); | 270 }); |
| 250 } else if (assets is Iterable) { | 271 } else if (assets is Iterable) { |
| 251 for (var asset in assets) { | 272 assetList = assets.map((asset) { |
| 252 var id = new AssetId.parse(asset); | 273 var id = new AssetId.parse(asset); |
| 253 var package = _packages.putIfAbsent(id.package, () => []); | |
| 254 var contents = pathos.basenameWithoutExtension(id.path); | 274 var contents = pathos.basenameWithoutExtension(id.path); |
| 255 package.add(new MockAsset(id, contents)); | 275 return new MockAsset(id, contents); |
| 256 } | 276 }); |
| 257 } | 277 } |
| 278 | |
| 279 _packages = mapMapValues(groupBy(assetList, (asset) => asset.id.package), | |
| 280 (package, assets) { | |
| 281 var packageTransformers = transformers[package]; | |
| 282 if (packageTransformers == null) packageTransformers = []; | |
| 283 return new _MockPackage(assets, packageTransformers.toList()); | |
| 284 }); | |
| 285 | |
| 286 // If there are no assets or transformers, add a dummy package. This better | |
| 287 // simulates the real world, where there'll always be at least the | |
| 288 // entrypoint package. | |
| 289 if (_packages.isEmpty) _packages = {"app": new _MockPackage([], [])}; | |
| 258 } | 290 } |
| 259 | 291 |
| 260 void _modifyAsset(String name, String contents) { | 292 void _modifyAsset(String name, String contents) { |
| 261 var id = new AssetId.parse(name); | 293 var id = new AssetId.parse(name); |
| 262 var asset = _packages[id.package].firstWhere((a) => a.id == id); | 294 var asset = _packages[id.package].assets.firstWhere((a) => a.id == id); |
| 263 asset.contents = contents; | 295 asset.contents = contents; |
| 264 } | 296 } |
| 265 | 297 |
| 266 List<AssetId> listAssets(String package, {String within}) { | 298 List<AssetId> listAssets(String package, {String within}) { |
| 267 if (within != null) { | 299 if (within != null) { |
| 268 throw new UnimplementedError("Doesn't handle 'within' yet."); | 300 throw new UnimplementedError("Doesn't handle 'within' yet."); |
| 269 } | 301 } |
| 270 | 302 |
| 271 return _packages[package].map((asset) => asset.id); | 303 return _packages[package].assets.map((asset) => asset.id); |
| 304 } | |
| 305 | |
| 306 Iterable<Iterable<Transformer>> getTransformers(String package) { | |
| 307 var mockPackage = _packages[package]; | |
| 308 if (mockPackage == null) { | |
| 309 throw new ArgumentError("No package named $package."); | |
| 310 } | |
| 311 return mockPackage.transformers; | |
| 272 } | 312 } |
| 273 | 313 |
| 274 Future<Asset> getAsset(AssetId id) { | 314 Future<Asset> getAsset(AssetId id) { |
| 275 var future; | 315 var future; |
| 276 if (_pauseCompleter != null) { | 316 if (_pauseCompleter != null) { |
| 277 future = _pauseCompleter.future; | 317 future = _pauseCompleter.future; |
| 278 } else { | 318 } else { |
| 279 future = new Future.value(); | 319 future = new Future.value(); |
| 280 } | 320 } |
| 281 | 321 |
| 282 return future.then((_) { | 322 return future.then((_) { |
| 283 var package = _packages[id.package]; | 323 var package = _packages[id.package]; |
| 284 if (package == null) throw new AssetNotFoundException(id); | 324 if (package == null) throw new AssetNotFoundException(id); |
| 285 | 325 |
| 286 return package.firstWhere((asset) => asset.id == id, | 326 return package.assets.firstWhere((asset) => asset.id == id, |
| 287 orElse: () => throw new AssetNotFoundException(id)); | 327 orElse: () => throw new AssetNotFoundException(id)); |
| 288 }); | 328 }); |
| 289 } | 329 } |
| 290 } | 330 } |
| 291 | 331 |
| 332 class _MockPackage { | |
|
Bob Nystrom
2013/07/11 23:03:40
Document.
nweiz
2013/07/15 22:11:44
Done.
| |
| 333 final List<MockAsset> assets; | |
| 334 final List<List<Transformer>> transformers; | |
| 335 | |
| 336 _MockPackage(this.assets, Iterable<Iterable<Transformer>> transformers) | |
| 337 : transformers = transformers.map((phase) => phase.toList()).toList(); | |
| 338 } | |
| 339 | |
| 292 /// A [Transformer] that takes assets ending with one extension and generates | 340 /// A [Transformer] that takes assets ending with one extension and generates |
| 293 /// assets with a given extension. | 341 /// assets with a given extension. |
| 294 /// | 342 /// |
| 295 /// Appends the output extension to the contents of the input file. | 343 /// Appends the output extension to the contents of the input file. |
| 296 class RewriteTransformer extends Transformer { | 344 class RewriteTransformer extends Transformer { |
| 297 final String from; | 345 final String from; |
| 298 final String to; | 346 final String to; |
| 299 | 347 |
| 300 /// The number of times the transformer has been applied. | 348 /// The number of times the transformer has been applied. |
| 301 int numRuns = 0; | 349 int numRuns = 0; |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 475 | 523 |
| 476 MockAsset(this.id, this.contents); | 524 MockAsset(this.id, this.contents); |
| 477 | 525 |
| 478 Future<String> readAsString({Encoding encoding}) => | 526 Future<String> readAsString({Encoding encoding}) => |
| 479 new Future.value(contents); | 527 new Future.value(contents); |
| 480 | 528 |
| 481 Stream<List<int>> read() => throw new UnimplementedError(); | 529 Stream<List<int>> read() => throw new UnimplementedError(); |
| 482 | 530 |
| 483 String toString() => "MockAsset $id $contents"; | 531 String toString() => "MockAsset $id $contents"; |
| 484 } | 532 } |
| OLD | NEW |