| 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_cascade.dart'; |
| 13 import 'package:barback/src/asset_graph_manager.dart'; | 13 import 'package:barback/src/package_graph.dart'; |
| 14 import 'package:barback/src/utils.dart'; | 14 import 'package:barback/src/utils.dart'; |
| 15 import 'package:path/path.dart' as pathos; | 15 import 'package:path/path.dart' as pathos; |
| 16 import 'package:scheduled_test/scheduled_test.dart'; | 16 import 'package:scheduled_test/scheduled_test.dart'; |
| 17 import 'package:stack_trace/stack_trace.dart'; | 17 import 'package:stack_trace/stack_trace.dart'; |
| 18 import 'package:unittest/compact_vm_config.dart'; | 18 import 'package:unittest/compact_vm_config.dart'; |
| 19 | 19 |
| 20 var _configured = false; | 20 var _configured = false; |
| 21 | 21 |
| 22 MockProvider _provider; | 22 MockProvider _provider; |
| 23 AssetGraphManager _graphManager; | 23 PackageGraph _graph; |
| 24 | 24 |
| 25 /// Calls to [buildShouldSucceed] and [buildShouldFail] set expectations on | 25 /// Calls to [buildShouldSucceed] and [buildShouldFail] set expectations on |
| 26 /// successive [BuildResult]s from [_graph]. This keeps track of how many calls | 26 /// successive [BuildResult]s from [_graph]. This keeps track of how many calls |
| 27 /// have already been made so later calls know which result to look for. | 27 /// have already been made so later calls know which result to look for. |
| 28 int _nextBuildResult; | 28 int _nextBuildResult; |
| 29 | 29 |
| 30 void initConfig() { | 30 void initConfig() { |
| 31 if (_configured) return; | 31 if (_configured) return; |
| 32 _configured = true; | 32 _configured = true; |
| 33 useCompactVMConfiguration(); | 33 useCompactVMConfiguration(); |
| 34 } | 34 } |
| 35 | 35 |
| 36 /// Creates a new [AssetProvider] and [AssetGraph] with the given [assets] and | 36 /// Creates a new [PackageProvider] and [PackageGraph] with the given [assets] |
| 37 /// [transformers]. | 37 /// and [transformers]. |
| 38 /// | 38 /// |
| 39 /// This graph is used internally by most of the other functions in this | 39 /// This graph is used internally by most of the other functions in this |
| 40 /// library so you must call it in the test before calling any of the other | 40 /// library so you must call it in the test before calling any of the other |
| 41 /// functions. | 41 /// functions. |
| 42 /// | 42 /// |
| 43 /// [assets] may either be an [Iterable] or a [Map]. If it's an [Iterable], | 43 /// [assets] may either be an [Iterable] or a [Map]. If it's an [Iterable], |
| 44 /// each element may either be an [AssetId] or a string that can be parsed to | 44 /// each element may either be an [AssetId] or a string that can be parsed to |
| 45 /// one. If it's a [Map], each key should be a string that can be parsed to an | 45 /// one. If it's a [Map], each key should be a string that can be parsed to an |
| 46 /// [AssetId] and the value should be a string defining the contents of that | 46 /// [AssetId] and the value should be a string defining the contents of that |
| 47 /// asset. | 47 /// asset. |
| 48 /// | 48 /// |
| 49 /// [transformers] is a map from package names to the transformers for each | 49 /// [transformers] is a map from package names to the transformers for each |
| 50 /// package. | 50 /// package. |
| 51 void initGraph([assets, | 51 void initGraph([assets, |
| 52 Map<String, Iterable<Iterable<Transformer>>> transformers]) { | 52 Map<String, Iterable<Iterable<Transformer>>> transformers]) { |
| 53 if (assets == null) assets = []; | 53 if (assets == null) assets = []; |
| 54 if (transformers == null) transformers = {}; | 54 if (transformers == null) transformers = {}; |
| 55 | 55 |
| 56 _provider = new MockProvider(assets, transformers); | 56 _provider = new MockProvider(assets, transformers); |
| 57 _graphManager = new AssetGraphManager(_provider); | 57 _graph = new PackageGraph(_provider); |
| 58 _nextBuildResult = 0; | 58 _nextBuildResult = 0; |
| 59 } | 59 } |
| 60 | 60 |
| 61 /// Updates [assets] in the current [AssetProvider]. | 61 /// Updates [assets] in the current [PackageProvider]. |
| 62 /// | 62 /// |
| 63 /// Each item in the list may either be an [AssetId] or a string that can be | 63 /// Each item in the list may either be an [AssetId] or a string that can be |
| 64 /// parsed as one. Note that this method is not automatically scheduled. | 64 /// parsed as one. Note that this method is not automatically scheduled. |
| 65 void updateSources(Iterable assets) { | 65 void updateSources(Iterable assets) { |
| 66 // Allow strings as asset IDs. | 66 // Allow strings as asset IDs. |
| 67 assets = assets.map((asset) { | 67 assets = assets.map((asset) { |
| 68 if (asset is String) return new AssetId.parse(asset); | 68 if (asset is String) return new AssetId.parse(asset); |
| 69 return asset; | 69 return asset; |
| 70 }); | 70 }); |
| 71 | 71 |
| 72 _graphManager.updateSources(assets); | 72 _graph.updateSources(assets); |
| 73 } | 73 } |
| 74 | 74 |
| 75 /// Removes [assets] from the current [AssetProvider]. | 75 /// Removes [assets] from the current [PackageProvider]. |
| 76 /// | 76 /// |
| 77 /// Each item in the list may either be an [AssetId] or a string that can be | 77 /// Each item in the list may either be an [AssetId] or a string that can be |
| 78 /// parsed as one. Note that this method is not automatically scheduled. | 78 /// parsed as one. Note that this method is not automatically scheduled. |
| 79 void removeSources(Iterable assets) { | 79 void removeSources(Iterable assets) { |
| 80 // Allow strings as asset IDs. | 80 // Allow strings as asset IDs. |
| 81 assets = assets.map((asset) { | 81 assets = assets.map((asset) { |
| 82 if (asset is String) return new AssetId.parse(asset); | 82 if (asset is String) return new AssetId.parse(asset); |
| 83 return asset; | 83 return asset; |
| 84 }); | 84 }); |
| 85 | 85 |
| 86 _graphManager.removeSources(assets); | 86 _graph.removeSources(assets); |
| 87 } | 87 } |
| 88 | 88 |
| 89 /// Schedules a change to the contents of an asset identified by [name] to | 89 /// Schedules a change to the contents of an asset identified by [name] to |
| 90 /// [contents]. | 90 /// [contents]. |
| 91 /// | 91 /// |
| 92 /// Does not update it in the graph. | 92 /// Does not update it in the graph. |
| 93 void modifyAsset(String name, String contents) { | 93 void modifyAsset(String name, String contents) { |
| 94 schedule(() { | 94 schedule(() { |
| 95 _provider._modifyAsset(name, contents); | 95 _provider._modifyAsset(name, contents); |
| 96 }, "modify asset $name"); | 96 }, "modify asset $name"); |
| 97 } | 97 } |
| 98 | 98 |
| 99 /// Schedules a pause of the internally created [AssetProvider]. | 99 /// Schedules a pause of the internally created [PackageProvider]. |
| 100 /// | 100 /// |
| 101 /// All asset requests that the [AssetGraph] makes to the provider after this | 101 /// All asset requests that the [PackageGraph] makes to the provider after this |
| 102 /// will not complete until [resumeProvider] is called. | 102 /// will not complete until [resumeProvider] is called. |
| 103 void pauseProvider() { | 103 void pauseProvider() { |
| 104 schedule(() => _provider._pause(), "pause provider"); | 104 schedule(() => _provider._pause(), "pause provider"); |
| 105 } | 105 } |
| 106 | 106 |
| 107 /// Schedules an unpause of the provider after a call to [pauseProvider] and | 107 /// Schedules an unpause of the provider after a call to [pauseProvider] and |
| 108 /// allows all pending asset loads to finish. | 108 /// allows all pending asset loads to finish. |
| 109 void resumeProvider() { | 109 void resumeProvider() { |
| 110 schedule(() => _provider._resume(), "resume provider"); | 110 schedule(() => _provider._resume(), "resume provider"); |
| 111 } | 111 } |
| 112 | 112 |
| 113 /// Asserts that the current build step shouldn't have finished by this point in | 113 /// Asserts that the current build step shouldn't have finished by this point in |
| 114 /// the schedule. | 114 /// the schedule. |
| 115 /// | 115 /// |
| 116 /// This uses the same build counter as [buildShouldSucceed] and | 116 /// This uses the same build counter as [buildShouldSucceed] and |
| 117 /// [buildShouldFail], so those can be used to validate build results before and | 117 /// [buildShouldFail], so those can be used to validate build results before and |
| 118 /// after this. | 118 /// after this. |
| 119 void buildShouldNotBeDone() { | 119 void buildShouldNotBeDone() { |
| 120 var resultAllowed = false; | 120 var resultAllowed = false; |
| 121 var trace = new Trace.current(); | 121 var trace = new Trace.current(); |
| 122 _graphManager.results.elementAt(_nextBuildResult).then((result) { | 122 _graph.results.elementAt(_nextBuildResult).then((result) { |
| 123 if (resultAllowed) return; | 123 if (resultAllowed) return; |
| 124 | 124 |
| 125 currentSchedule.signalError( | 125 currentSchedule.signalError( |
| 126 new Exception("Expected build not to terminate " | 126 new Exception("Expected build not to terminate " |
| 127 "here, but it terminated with result: $result"), trace); | 127 "here, but it terminated with result: $result"), trace); |
| 128 }).catchError((error) { | 128 }).catchError((error) { |
| 129 if (resultAllowed) return; | 129 if (resultAllowed) return; |
| 130 currentSchedule.signalError(error); | 130 currentSchedule.signalError(error); |
| 131 }); | 131 }); |
| 132 | 132 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 155 expect(_getNextBuildResult().then((result) { | 155 expect(_getNextBuildResult().then((result) { |
| 156 expect(result.succeeded, isFalse); | 156 expect(result.succeeded, isFalse); |
| 157 expect(result.errors.length, equals(matchers.length)); | 157 expect(result.errors.length, equals(matchers.length)); |
| 158 for (var matcher in matchers) { | 158 for (var matcher in matchers) { |
| 159 expect(result.errors, contains(matcher)); | 159 expect(result.errors, contains(matcher)); |
| 160 } | 160 } |
| 161 }), completes); | 161 }), completes); |
| 162 } | 162 } |
| 163 | 163 |
| 164 Future<BuildResult> _getNextBuildResult() => | 164 Future<BuildResult> _getNextBuildResult() => |
| 165 _graphManager.results.elementAt(_nextBuildResult++); | 165 _graph.results.elementAt(_nextBuildResult++); |
| 166 | 166 |
| 167 /// Pauses the schedule until the currently running build completes. | 167 /// Pauses the schedule until the currently running build completes. |
| 168 /// | 168 /// |
| 169 /// Validates that the build completed successfully. | 169 /// Validates that the build completed successfully. |
| 170 void waitForBuild() { | 170 void waitForBuild() { |
| 171 schedule(() { | 171 schedule(() { |
| 172 return _graphManager.results.first.then((result) { | 172 return _graph.results.first.then((result) { |
| 173 expect(result.succeeded, isTrue); | 173 expect(result.succeeded, isTrue); |
| 174 }); | 174 }); |
| 175 }, "wait for build"); | 175 }, "wait for build"); |
| 176 } | 176 } |
| 177 | 177 |
| 178 /// Schedules an expectation that the graph will deliver an asset matching | 178 /// Schedules an expectation that the graph will deliver an asset matching |
| 179 /// [name] and [contents]. | 179 /// [name] and [contents]. |
| 180 /// | 180 /// |
| 181 /// If [contents] is omitted, defaults to the asset's filename without an | 181 /// If [contents] is omitted, defaults to the asset's filename without an |
| 182 /// extension (which is the same default that [initGraph] uses). | 182 /// extension (which is the same default that [initGraph] uses). |
| 183 void expectAsset(String name, [String contents]) { | 183 void expectAsset(String name, [String contents]) { |
| 184 var id = new AssetId.parse(name); | 184 var id = new AssetId.parse(name); |
| 185 | 185 |
| 186 if (contents == null) { | 186 if (contents == null) { |
| 187 contents = pathos.basenameWithoutExtension(id.path); | 187 contents = pathos.basenameWithoutExtension(id.path); |
| 188 } | 188 } |
| 189 | 189 |
| 190 schedule(() { | 190 schedule(() { |
| 191 return _graphManager.getAssetById(id).then((asset) { | 191 return _graph.getAssetById(id).then((asset) { |
| 192 // TODO(rnystrom): Make an actual Matcher class for this. | 192 // TODO(rnystrom): Make an actual Matcher class for this. |
| 193 expect(asset, new isInstanceOf<MockAsset>()); | 193 expect(asset, new isInstanceOf<MockAsset>()); |
| 194 expect(asset.id, equals(id)); | 194 expect(asset.id, equals(id)); |
| 195 expect(asset.contents, equals(contents)); | 195 expect(asset.contents, equals(contents)); |
| 196 }); | 196 }); |
| 197 }, "get asset $name"); | 197 }, "get asset $name"); |
| 198 } | 198 } |
| 199 | 199 |
| 200 /// Schedules an expectation that the graph will not find an asset matching | 200 /// Schedules an expectation that the graph will not find an asset matching |
| 201 /// [name]. | 201 /// [name]. |
| 202 void expectNoAsset(String name) { | 202 void expectNoAsset(String name) { |
| 203 var id = new AssetId.parse(name); | 203 var id = new AssetId.parse(name); |
| 204 | 204 |
| 205 // Make sure the future gets the error. | 205 // Make sure the future gets the error. |
| 206 schedule(() { | 206 schedule(() { |
| 207 return _graphManager.getAssetById(id).then((asset) { | 207 return _graph.getAssetById(id).then((asset) { |
| 208 fail("Should have thrown error but got $asset."); | 208 fail("Should have thrown error but got $asset."); |
| 209 }).catchError((error) { | 209 }).catchError((error) { |
| 210 expect(error, new isInstanceOf<AssetNotFoundException>()); | 210 expect(error, new isInstanceOf<AssetNotFoundException>()); |
| 211 expect(error.id, equals(id)); | 211 expect(error.id, equals(id)); |
| 212 }); | 212 }); |
| 213 }, "get asset $name"); | 213 }, "get asset $name"); |
| 214 } | 214 } |
| 215 | 215 |
| 216 /// Returns a matcher for an [AssetNotFoundException] with the given [id]. | 216 /// Returns a matcher for an [AssetNotFoundException] with the given [id]. |
| 217 Matcher isAssetNotFoundException(String name) { | 217 Matcher isAssetNotFoundException(String name) { |
| (...skipping 23 matching lines...) Expand all Loading... |
| 241 /// package name. | 241 /// package name. |
| 242 Matcher isInvalidOutputException(String package, String name) { | 242 Matcher isInvalidOutputException(String package, String name) { |
| 243 var id = new AssetId.parse(name); | 243 var id = new AssetId.parse(name); |
| 244 return allOf( | 244 return allOf( |
| 245 new isInstanceOf<InvalidOutputException>(), | 245 new isInstanceOf<InvalidOutputException>(), |
| 246 predicate((error) => error.package == package, 'package is $package'), | 246 predicate((error) => error.package == package, 'package is $package'), |
| 247 predicate((error) => error.id == id, 'id is $name')); | 247 predicate((error) => error.id == id, 'id is $name')); |
| 248 } | 248 } |
| 249 | 249 |
| 250 /// An [AssetProvider] that provides the given set of assets. | 250 /// An [AssetProvider] that provides the given set of assets. |
| 251 class MockProvider implements AssetProvider { | 251 class MockProvider implements PackageProvider { |
| 252 Iterable<String> get packages => _packages.keys; | 252 Iterable<String> get packages => _packages.keys; |
| 253 | 253 |
| 254 Map<String, _MockPackage> _packages; | 254 Map<String, _MockPackage> _packages; |
| 255 | 255 |
| 256 /// The completer that [getAsset()] is waiting on to complete when paused. | 256 /// The completer that [getAsset()] is waiting on to complete when paused. |
| 257 /// | 257 /// |
| 258 /// If `null` it will return the asset immediately. | 258 /// If `null` it will return the asset immediately. |
| 259 Completer _pauseCompleter; | 259 Completer _pauseCompleter; |
| 260 | 260 |
| 261 /// Tells the provider to wait during [getAsset] until [complete()] | 261 /// Tells the provider to wait during [getAsset] until [complete()] |
| (...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 551 | 551 |
| 552 MockAsset(this.id, this.contents); | 552 MockAsset(this.id, this.contents); |
| 553 | 553 |
| 554 Future<String> readAsString({Encoding encoding}) => | 554 Future<String> readAsString({Encoding encoding}) => |
| 555 new Future.value(contents); | 555 new Future.value(contents); |
| 556 | 556 |
| 557 Stream<List<int>> read() => throw new UnimplementedError(); | 557 Stream<List<int>> read() => throw new UnimplementedError(); |
| 558 | 558 |
| 559 String toString() => "MockAsset $id $contents"; | 559 String toString() => "MockAsset $id $contents"; |
| 560 } | 560 } |
| OLD | NEW |