Index: observatory_pub_packages/code_transformers/src/test_harness.dart |
=================================================================== |
--- observatory_pub_packages/code_transformers/src/test_harness.dart (revision 0) |
+++ observatory_pub_packages/code_transformers/src/test_harness.dart (working copy) |
@@ -0,0 +1,124 @@ |
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+/// Utilities for creating unit tests of Barback transformers. |
+library code_transformers.src.test_harness; |
+ |
+import 'dart:async'; |
+ |
+import 'package:barback/barback.dart'; |
+import 'package:stack_trace/stack_trace.dart'; |
+import 'package:unittest/unittest.dart'; |
+ |
+String idToString(AssetId id) => '${id.package}|${id.path}'; |
+AssetId idFromString(String s) { |
+ int index = s.indexOf('|'); |
+ return new AssetId(s.substring(0, index), s.substring(index + 1)); |
+} |
+ |
+String _removeTrailingWhitespace(String str) => |
+ str.splitMapJoin('\n', |
+ onNonMatch: (s) => s.replaceAll(new RegExp(r'\s+$'), '')); |
+ |
+/// A helper package provider that has files stored in memory, also wraps |
+/// [Barback] to simply our tests. |
+class TestHelper implements PackageProvider { |
+ |
+ /// Maps from an asset string identifier of the form 'package|path' to the |
+ /// file contents. |
+ final Map<String, String> files; |
+ final Iterable<String> packages; |
+ final List<String> messages; |
+ int messagesSeen = 0; |
+ bool errorSeen = false; |
+ |
+ Barback barback; |
+ var errorSubscription; |
+ var resultSubscription; |
+ var logSubscription; |
+ |
+ Future<Asset> getAsset(AssetId id) => |
+ new Future.value(new Asset.fromString(id, files[idToString(id)])); |
+ |
+ TestHelper(List<List<Transformer>> transformers, Map<String, String> files, |
+ this.messages) |
+ : files = files, |
+ packages = files.keys.map((s) => idFromString(s).package) { |
+ barback = new Barback(this); |
+ for (var p in packages) { |
+ barback.updateTransformers(p, transformers); |
+ } |
+ |
+ errorSubscription = barback.errors.listen((e) { |
+ var trace = null; |
+ if (e is Error) trace = e.stackTrace; |
+ if (trace != null) { |
+ print(Trace.format(trace)); |
+ } |
+ fail('error running barback: $e'); |
+ }); |
+ |
+ resultSubscription = barback.results.listen((result) { |
+ expect(result.succeeded, !errorSeen, reason: "${result.errors}"); |
+ }); |
+ |
+ logSubscription = barback.log.listen((entry) { |
+ // Ignore info and fine messages. |
+ if (entry.level == LogLevel.INFO || entry.level == LogLevel.FINE) return; |
+ if (entry.level == LogLevel.ERROR) errorSeen = true; |
+ // We only check messages when an expectation is provided. |
+ if (messages == null) return; |
+ |
+ var msg = '${entry.level.name.toLowerCase()}: ${entry.message}'; |
+ var span = entry.span; |
+ var spanInfo = span == null ? '' : |
+ ' (${span.sourceUrl} ${span.start.line} ${span.start.column})'; |
+ expect(messagesSeen, lessThan(messages.length), |
+ reason: 'more messages than expected.\nMessage seen: $msg$spanInfo'); |
+ expect('$msg$spanInfo', messages[messagesSeen++]); |
+ }); |
+ } |
+ |
+ void tearDown() { |
+ errorSubscription.cancel(); |
+ resultSubscription.cancel(); |
+ logSubscription.cancel(); |
+ } |
+ |
+ /// Tells barback which files have changed, and thus anything that depends on |
+ /// it on should be computed. By default mark all the input files. |
+ void run([Iterable<String> paths]) { |
+ if (paths == null) paths = files.keys; |
+ barback.updateSources(paths.map(idFromString)); |
+ } |
+ |
+ Future<String> operator [](String assetString){ |
+ return barback.getAssetById(idFromString(assetString)) |
+ .then((asset) => asset.readAsString()); |
+ } |
+ |
+ Future check(String assetIdString, String content) { |
+ return this[assetIdString].then((value) { |
+ value = _removeTrailingWhitespace(value); |
+ content = _removeTrailingWhitespace(content); |
+ expect(value, content, reason: 'Final output of $assetIdString differs.'); |
+ }); |
+ } |
+ |
+ Future checkAll(Map<String, String> files) { |
+ return barback.results.first.then((_) { |
+ if (files == null) return null; |
+ var futures = []; |
+ files.forEach((k, v) { |
+ futures.add(check(k, v)); |
+ }); |
+ return Future.wait(futures); |
+ }).then((_) { |
+ // We only check messages when an expectation is provided. |
+ if (messages == null) return; |
+ expect(messagesSeen, messages.length, |
+ reason: 'less messages than expected'); |
+ }); |
+ } |
+} |