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 current build step shouldn't have finished by this point in | |
| 116 /// the schedule. | |
| 117 /// | |
| 118 /// This uses the same build counter as [buildShouldSucceed] and | |
| 119 /// [buildShouldFail], so those can be used to validate build results before and | |
| 120 /// after this. | |
| 121 void buildShouldNotBeDone() { | |
| 122 var resultAllowed = false; | |
| 123 var trace = new Trace.current(); | |
| 124 _graphManager.results.elementAt(_nextBuildResult).then((result) { | |
| 125 if (resultAllowed) return; | |
| 126 | |
| 127 currentSchedule.signalError( | |
| 128 new Exception("Expected build not to terminate " | |
| 129 "here, but it terminated with result: $result"), trace); | |
| 130 }).catchError((error) { | |
| 131 if (resultAllowed) return; | |
| 132 currentSchedule.signalError(error); | |
| 133 }); | |
| 134 | |
| 135 schedule(() { | |
| 136 // Pump the event queue in case the build completes out-of-band after we get | |
| 137 // here. If it does, we want to signal an error. | |
| 138 return pumpEventQueue().then((_) { | |
| 139 resultAllowed = true; | |
| 140 }); | |
| 141 }, "ensuring build doesn't terminate"); | |
| 142 } | |
| 143 | |
| 108 /// Expects that the next [BuildResult] is a build success. | 144 /// Expects that the next [BuildResult] is a build success. |
| 109 void buildShouldSucceed() { | 145 void buildShouldSucceed() { |
| 110 expect(_graph.results.elementAt(_nextBuildResult++).then((result) { | 146 expect(_getNextBuildResult().then((result) { |
| 111 expect(result.succeeded, isTrue); | 147 expect(result.succeeded, isTrue); |
| 112 }), completes); | 148 }), completes); |
| 113 } | 149 } |
| 114 | 150 |
| 115 /// Expects that the next [BuildResult] emitted is a failure. | 151 /// Expects that the next [BuildResult] emitted is a failure. |
| 116 /// | 152 /// |
| 117 /// [matchers] is a list of matchers to match against the errors that caused the | 153 /// [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 | 154 /// build to fail. Every matcher is expected to match an error, but the order of |
| 119 /// matchers is unimportant. | 155 /// matchers is unimportant. |
| 120 void buildShouldFail(List matchers) { | 156 void buildShouldFail(List matchers) { |
| 121 expect(_graph.results.elementAt(_nextBuildResult++).then((result) { | 157 expect(_getNextBuildResult().then((result) { |
| 122 expect(result.succeeded, isFalse); | 158 expect(result.succeeded, isFalse); |
| 123 expect(result.errors.length, equals(matchers.length)); | 159 expect(result.errors.length, equals(matchers.length)); |
| 124 for (var matcher in matchers) { | 160 for (var matcher in matchers) { |
| 125 expect(result.errors, contains(matcher)); | 161 expect(result.errors, contains(matcher)); |
| 126 } | 162 } |
| 127 }), completes); | 163 }), completes); |
| 128 } | 164 } |
| 129 | 165 |
| 166 Future<BuildResult> _getNextBuildResult() => | |
| 167 _graphManager.results.elementAt(_nextBuildResult++); | |
| 168 | |
| 130 /// Pauses the schedule until the currently running build completes. | 169 /// Pauses the schedule until the currently running build completes. |
| 131 /// | 170 /// |
| 132 /// Validates that the build completed successfully. | 171 /// Validates that the build completed successfully. |
| 133 void waitForBuild() { | 172 void waitForBuild() { |
| 134 schedule(() { | 173 schedule(() { |
| 135 return _graph.results.first.then((result) { | 174 return _graphManager.results.first.then((result) { |
| 136 expect(result.succeeded, isTrue); | 175 expect(result.succeeded, isTrue); |
| 137 }); | 176 }); |
| 138 }, "wait for build"); | 177 }, "wait for build"); |
| 139 } | 178 } |
| 140 | 179 |
| 141 /// Schedules an expectation that the graph will deliver an asset matching | 180 /// Schedules an expectation that the graph will deliver an asset matching |
| 142 /// [name] and [contents]. | 181 /// [name] and [contents]. |
| 143 /// | 182 /// |
| 144 /// If [contents] is omitted, defaults to the asset's filename without an | 183 /// If [contents] is omitted, defaults to the asset's filename without an |
| 145 /// extension (which is the same default that [initGraph] uses). | 184 /// extension (which is the same default that [initGraph] uses). |
| 146 void expectAsset(String name, [String contents]) { | 185 void expectAsset(String name, [String contents]) { |
| 147 var id = new AssetId.parse(name); | 186 var id = new AssetId.parse(name); |
| 148 | 187 |
| 149 if (contents == null) { | 188 if (contents == null) { |
| 150 contents = pathos.basenameWithoutExtension(id.path); | 189 contents = pathos.basenameWithoutExtension(id.path); |
| 151 } | 190 } |
| 152 | 191 |
| 153 schedule(() { | 192 schedule(() { |
| 154 return _graph.getAssetById(id).then((asset) { | 193 return _graphManager.getAssetById(id).then((asset) { |
| 155 // TODO(rnystrom): Make an actual Matcher class for this. | 194 // TODO(rnystrom): Make an actual Matcher class for this. |
| 156 expect(asset, new isInstanceOf<MockAsset>()); | 195 expect(asset, new isInstanceOf<MockAsset>()); |
| 157 expect(asset.id, equals(id)); | 196 expect(asset.id, equals(id)); |
| 158 expect(asset.contents, equals(contents)); | 197 expect(asset.contents, equals(contents)); |
| 159 }); | 198 }); |
| 160 }, "get asset $name"); | 199 }, "get asset $name"); |
| 161 } | 200 } |
| 162 | 201 |
| 163 /// Schedules an expectation that the graph will not find an asset matching | 202 /// Schedules an expectation that the graph will not find an asset matching |
| 164 /// [name]. | 203 /// [name]. |
| 165 void expectNoAsset(String name) { | 204 void expectNoAsset(String name) { |
| 166 var id = new AssetId.parse(name); | 205 var id = new AssetId.parse(name); |
| 167 | 206 |
| 168 // Make sure the future gets the error. | 207 // Make sure the future gets the error. |
| 169 schedule(() { | 208 schedule(() { |
| 170 return _graph.getAssetById(id).then((asset) { | 209 return _graphManager.getAssetById(id).then((asset) { |
| 171 fail("Should have thrown error but got $asset."); | 210 fail("Should have thrown error but got $asset."); |
| 172 }).catchError((error) { | 211 }).catchError((error) { |
| 173 expect(error, new isInstanceOf<AssetNotFoundException>()); | 212 expect(error, new isInstanceOf<AssetNotFoundException>()); |
| 174 expect(error.id, equals(id)); | 213 expect(error.id, equals(id)); |
| 175 }); | 214 }); |
| 176 }, "get asset $name"); | 215 }, "get asset $name"); |
| 177 } | 216 } |
| 178 | 217 |
| 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]. | 218 /// Returns a matcher for an [AssetNotFoundException] with the given [id]. |
| 196 Matcher isAssetNotFoundException(String name) { | 219 Matcher isAssetNotFoundException(String name) { |
| 197 var id = new AssetId.parse(name); | 220 var id = new AssetId.parse(name); |
| 198 return allOf( | 221 return allOf( |
| 199 new isInstanceOf<AssetNotFoundException>(), | 222 new isInstanceOf<AssetNotFoundException>(), |
| 200 predicate((error) => error.id == id, 'id is $name')); | 223 predicate((error) => error.id == id, 'id is $name')); |
| 201 } | 224 } |
| 202 | 225 |
| 203 /// Returns a matcher for an [AssetCollisionException] with the given [id]. | 226 /// Returns a matcher for an [AssetCollisionException] with the given [id]. |
| 204 Matcher isAssetCollisionException(String name) { | 227 Matcher isAssetCollisionException(String name) { |
| 205 var id = new AssetId.parse(name); | 228 var id = new AssetId.parse(name); |
| 206 return allOf( | 229 return allOf( |
| 207 new isInstanceOf<AssetCollisionException>(), | 230 new isInstanceOf<AssetCollisionException>(), |
| 208 predicate((error) => error.id == id, 'id is $name')); | 231 predicate((error) => error.id == id, 'id is $name')); |
| 209 } | 232 } |
| 210 | 233 |
| 211 /// Returns a matcher for a [MissingInputException] with the given [id]. | 234 /// Returns a matcher for a [MissingInputException] with the given [id]. |
| 212 Matcher isMissingInputException(String name) { | 235 Matcher isMissingInputException(String name) { |
| 213 var id = new AssetId.parse(name); | 236 var id = new AssetId.parse(name); |
| 214 return allOf( | 237 return allOf( |
| 215 new isInstanceOf<MissingInputException>(), | 238 new isInstanceOf<MissingInputException>(), |
| 216 predicate((error) => error.id == id, 'id is $name')); | 239 predicate((error) => error.id == id, 'id is $name')); |
| 217 } | 240 } |
| 218 | 241 |
| 242 /// Returns a matcher for an [InvalidOutputException] with the given id and | |
| 243 /// package name. | |
| 244 Matcher isInvalidOutputException(String package, String name) { | |
| 245 var id = new AssetId.parse(name); | |
| 246 return allOf( | |
| 247 new isInstanceOf<InvalidOutputException>(), | |
| 248 predicate((error) => error.package == package, 'package is $package'), | |
| 249 predicate((error) => error.id == id, 'id is $name')); | |
| 250 } | |
| 251 | |
| 219 /// An [AssetProvider] that provides the given set of assets. | 252 /// An [AssetProvider] that provides the given set of assets. |
| 220 class MockProvider implements AssetProvider { | 253 class MockProvider implements AssetProvider { |
| 221 Iterable<String> get packages => _packages.keys; | 254 Iterable<String> get packages => _packages.keys; |
| 222 | 255 |
| 223 final _packages = new Map<String, List<MockAsset>>(); | 256 Map<String, _MockPackage> _packages; |
| 224 | 257 |
| 225 /// The completer that [getAsset()] is waiting on to complete when paused. | 258 /// The completer that [getAsset()] is waiting on to complete when paused. |
| 226 /// | 259 /// |
| 227 /// If `null` it will return the asset immediately. | 260 /// If `null` it will return the asset immediately. |
| 228 Completer _pauseCompleter; | 261 Completer _pauseCompleter; |
| 229 | 262 |
| 230 /// Tells the provider to wait during [getAsset] until [complete()] | 263 /// Tells the provider to wait during [getAsset] until [complete()] |
| 231 /// is called. | 264 /// is called. |
| 232 /// | 265 /// |
| 233 /// Lets you test the asynchronous behavior of loading. | 266 /// Lets you test the asynchronous behavior of loading. |
| 234 void _pause() { | 267 void _pause() { |
| 235 _pauseCompleter = new Completer(); | 268 _pauseCompleter = new Completer(); |
| 236 } | 269 } |
| 237 | 270 |
| 238 void _resume() { | 271 void _resume() { |
| 239 _pauseCompleter.complete(); | 272 _pauseCompleter.complete(); |
| 240 _pauseCompleter = null; | 273 _pauseCompleter = null; |
| 241 } | 274 } |
| 242 | 275 |
| 243 MockProvider(assets) { | 276 MockProvider(assets, |
| 277 Map<String, Iterable<Iterable<Transformer>>> transformers) { | |
| 278 var assetList; | |
| 244 if (assets is Map) { | 279 if (assets is Map) { |
| 245 assets.forEach((asset, contents) { | 280 assetList = assets.keys.map((asset) { |
| 246 var id = new AssetId.parse(asset); | 281 var id = new AssetId.parse(asset); |
| 247 var package = _packages.putIfAbsent(id.package, () => []); | 282 return new MockAsset(id, assets[asset]); |
| 248 package.add(new MockAsset(id, contents)); | |
| 249 }); | 283 }); |
| 250 } else if (assets is Iterable) { | 284 } else if (assets is Iterable) { |
| 251 for (var asset in assets) { | 285 assetList = assets.map((asset) { |
| 252 var id = new AssetId.parse(asset); | 286 var id = new AssetId.parse(asset); |
| 253 var package = _packages.putIfAbsent(id.package, () => []); | |
| 254 var contents = pathos.basenameWithoutExtension(id.path); | 287 var contents = pathos.basenameWithoutExtension(id.path); |
| 255 package.add(new MockAsset(id, contents)); | 288 return new MockAsset(id, contents); |
| 256 } | 289 }); |
| 257 } | 290 } |
| 291 | |
| 292 _packages = mapMapValues(groupBy(assetList, (asset) => asset.id.package), | |
| 293 (package, assets) { | |
| 294 var packageTransformers = transformers[package]; | |
| 295 if (packageTransformers == null) packageTransformers = []; | |
| 296 return new _MockPackage(assets, packageTransformers.toList()); | |
| 297 }); | |
| 298 | |
| 299 // If there are no assets or transformers, add a dummy package. This better | |
| 300 // simulates the real world, where there'll always be at least the | |
| 301 // entrypoint package. | |
| 302 if (_packages.isEmpty) _packages = {"app": new _MockPackage([], [])}; | |
| 258 } | 303 } |
| 259 | 304 |
| 260 void _modifyAsset(String name, String contents) { | 305 void _modifyAsset(String name, String contents) { |
| 261 var id = new AssetId.parse(name); | 306 var id = new AssetId.parse(name); |
| 262 var asset = _packages[id.package].firstWhere((a) => a.id == id); | 307 var asset = _packages[id.package].assets.firstWhere((a) => a.id == id); |
| 263 asset.contents = contents; | 308 asset.contents = contents; |
| 264 } | 309 } |
| 265 | 310 |
| 266 List<AssetId> listAssets(String package, {String within}) { | 311 List<AssetId> listAssets(String package, {String within}) { |
| 267 if (within != null) { | 312 if (within != null) { |
| 268 throw new UnimplementedError("Doesn't handle 'within' yet."); | 313 throw new UnimplementedError("Doesn't handle 'within' yet."); |
| 269 } | 314 } |
| 270 | 315 |
| 271 return _packages[package].map((asset) => asset.id); | 316 return _packages[package].assets.map((asset) => asset.id); |
| 317 } | |
| 318 | |
| 319 Iterable<Iterable<Transformer>> getTransformers(String package) { | |
| 320 var mockPackage = _packages[package]; | |
| 321 if (mockPackage == null) { | |
| 322 throw new ArgumentError("No package named $package."); | |
| 323 } | |
| 324 return mockPackage.transformers; | |
| 272 } | 325 } |
| 273 | 326 |
| 274 Future<Asset> getAsset(AssetId id) { | 327 Future<Asset> getAsset(AssetId id) { |
| 275 var future; | 328 var future; |
| 276 if (_pauseCompleter != null) { | 329 if (_pauseCompleter != null) { |
| 277 future = _pauseCompleter.future; | 330 future = _pauseCompleter.future; |
| 278 } else { | 331 } else { |
| 279 future = new Future.value(); | 332 future = new Future.value(); |
| 280 } | 333 } |
| 281 | 334 |
| 282 return future.then((_) { | 335 return future.then((_) { |
| 283 var package = _packages[id.package]; | 336 var package = _packages[id.package]; |
| 284 if (package == null) throw new AssetNotFoundException(id); | 337 if (package == null) throw new AssetNotFoundException(id); |
| 285 | 338 |
| 286 return package.firstWhere((asset) => asset.id == id, | 339 return package.assets.firstWhere((asset) => asset.id == id, |
| 287 orElse: () => throw new AssetNotFoundException(id)); | 340 orElse: () => throw new AssetNotFoundException(id)); |
| 288 }); | 341 }); |
| 289 } | 342 } |
| 290 } | 343 } |
| 291 | 344 |
| 345 /// A struct used by [MockProvider] to keep track of which assets and | |
|
Bob Nystrom
2013/07/16 17:36:01
"struct" is out of place here. How about just "Use
nweiz
2013/07/16 19:39:39
Done.
| |
| 346 /// transformers exist for each package. | |
| 347 class _MockPackage { | |
| 348 final List<MockAsset> assets; | |
| 349 final List<List<Transformer>> transformers; | |
| 350 | |
| 351 _MockPackage(this.assets, Iterable<Iterable<Transformer>> transformers) | |
| 352 : transformers = transformers.map((phase) => phase.toList()).toList(); | |
| 353 } | |
| 354 | |
| 292 /// A [Transformer] that takes assets ending with one extension and generates | 355 /// A [Transformer] that takes assets ending with one extension and generates |
| 293 /// assets with a given extension. | 356 /// assets with a given extension. |
| 294 /// | 357 /// |
| 295 /// Appends the output extension to the contents of the input file. | 358 /// Appends the output extension to the contents of the input file. |
| 296 class RewriteTransformer extends Transformer { | 359 class RewriteTransformer extends Transformer { |
| 297 final String from; | 360 final String from; |
| 298 final String to; | 361 final String to; |
| 299 | 362 |
| 300 /// The number of times the transformer has been applied. | 363 /// The number of times the transformer has been applied. |
| 301 int numRuns = 0; | 364 int numRuns = 0; |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 461 var id = new AssetId.parse(output); | 524 var id = new AssetId.parse(output); |
| 462 transform.addOutput(new MockAsset(id, output)); | 525 transform.addOutput(new MockAsset(id, output)); |
| 463 } | 526 } |
| 464 | 527 |
| 465 // Then fail. | 528 // Then fail. |
| 466 throw ERROR; | 529 throw ERROR; |
| 467 }); | 530 }); |
| 468 } | 531 } |
| 469 } | 532 } |
| 470 | 533 |
| 534 /// A transformer that outputs an asset with the wrong package name. | |
|
Bob Nystrom
2013/07/16 17:36:01
That may be how it's used, but it isn't what it do
nweiz
2013/07/16 19:39:39
Done.
| |
| 535 class WrongPackageTransformer extends Transformer { | |
| 536 final String output; | |
| 537 | |
| 538 WrongPackageTransformer(this.output); | |
| 539 | |
| 540 Future<bool> isPrimary(Asset asset) => new Future.value(true); | |
| 541 | |
| 542 Future apply(Transform transform) { | |
| 543 return new Future(() { | |
| 544 transform.addOutput(new MockAsset(new AssetId.parse(output), output)); | |
| 545 }); | |
| 546 } | |
| 547 } | |
| 548 | |
| 471 /// An implementation of [Asset] that never hits the file system. | 549 /// An implementation of [Asset] that never hits the file system. |
| 472 class MockAsset implements Asset { | 550 class MockAsset implements Asset { |
| 473 final AssetId id; | 551 final AssetId id; |
| 474 String contents; | 552 String contents; |
| 475 | 553 |
| 476 MockAsset(this.id, this.contents); | 554 MockAsset(this.id, this.contents); |
| 477 | 555 |
| 478 Future<String> readAsString({Encoding encoding}) => | 556 Future<String> readAsString({Encoding encoding}) => |
| 479 new Future.value(contents); | 557 new Future.value(contents); |
| 480 | 558 |
| 481 Stream<List<int>> read() => throw new UnimplementedError(); | 559 Stream<List<int>> read() => throw new UnimplementedError(); |
| 482 | 560 |
| 483 String toString() => "MockAsset $id $contents"; | 561 String toString() => "MockAsset $id $contents"; |
| 484 } | 562 } |
| OLD | NEW |