Version 0.6.21.0
svn merge -r 26492:26574 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
git-svn-id: http://dart.googlecode.com/svn/trunk@26575 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkg/barback/lib/src/asset_cascade.dart b/pkg/barback/lib/src/asset_cascade.dart
index e8e9355..078c510 100644
--- a/pkg/barback/lib/src/asset_cascade.dart
+++ b/pkg/barback/lib/src/asset_cascade.dart
@@ -186,12 +186,11 @@
_addPhase(_phases.last.addPhase(transformers[i]));
}
- if (transformers.length < _phases.length) {
- for (var i = transformers.length; i < _phases.length; i++) {
- // TODO(nweiz): actually remove phases rather than emptying them of
- // transformers.
- _phases[i].updateTransformers([]);
- }
+ if (transformers.length == 0) {
+ _phases.last.updateTransformers([]);
+ } else if (transformers.length < _phases.length) {
+ _phases[transformers.length - 1].removeFollowing();
+ _phases.removeRange(transformers.length, _phases.length);
}
}
diff --git a/pkg/barback/lib/src/asset_forwarder.dart b/pkg/barback/lib/src/asset_forwarder.dart
index 7dc74dc..a2440e0 100644
--- a/pkg/barback/lib/src/asset_forwarder.dart
+++ b/pkg/barback/lib/src/asset_forwarder.dart
@@ -25,7 +25,9 @@
AssetNode get node => _controller.node;
AssetForwarder(AssetNode node)
- : _controller = new AssetNodeController(node.id, node.transform) {
+ : _controller = new AssetNodeController.from(node) {
+ if (node.state.isRemoved) return;
+
_subscription = node.onStateChange.listen((state) {
if (state.isAvailable) {
_controller.setAvailable(node.asset);
@@ -36,12 +38,6 @@
close();
}
});
-
- if (node.state.isAvailable) {
- _controller.setAvailable(node.asset);
- } else if (node.state.isRemoved) {
- close();
- }
}
/// Closes the forwarder and marks [node] as removed.
diff --git a/pkg/barback/lib/src/asset_id.dart b/pkg/barback/lib/src/asset_id.dart
index c4ed1d8..e091264 100644
--- a/pkg/barback/lib/src/asset_id.dart
+++ b/pkg/barback/lib/src/asset_id.dart
@@ -6,9 +6,6 @@
import 'package:path/path.dart' as pathos;
-/// AssetIDs always use POSIX style paths regardless of the host platform.
-final _posix = new pathos.Builder(style: pathos.Style.posix);
-
/// Identifies an asset within a package.
class AssetId implements Comparable<AssetId> {
/// The name of the package containing this asset.
@@ -29,10 +26,18 @@
String get extension => pathos.extension(path);
/// Creates a new AssetId at [path] within [package].
+ ///
+ /// The [path] will be normalized: any backslashes will be replaced with
+ /// forward slashes (regardless of host OS) and "." and ".." will be removed
+ /// where possible.
AssetId(this.package, String path)
- : path = _posix.normalize(path);
+ : path = _normalizePath(path);
/// Parses an [AssetId] string of the form "package|path/to/asset.txt".
+ ///
+ /// The [path] will be normalized: any backslashes will be replaced with
+ /// forward slashes (regardless of host OS) and "." and ".." will be removed
+ /// where possible.
factory AssetId.parse(String description) {
var parts = description.split("|");
if (parts.length != 2) {
@@ -92,3 +97,15 @@
/// and passed to [deserialize].
serialize() => [package, path];
}
+
+String _normalizePath(String path) {
+ if (pathos.isAbsolute(path)) {
+ throw new ArgumentError('Asset paths must be relative, but got "$path".');
+ }
+
+ // Normalize path separators so that they are always "/" in the AssetID.
+ path = path.replaceAll(r"\", "/");
+
+ // Collapse "." and "..".
+ return pathos.posix.normalize(path);
+}
\ No newline at end of file
diff --git a/pkg/barback/lib/src/asset_node.dart b/pkg/barback/lib/src/asset_node.dart
index edc7408..db80a9f 100644
--- a/pkg/barback/lib/src/asset_node.dart
+++ b/pkg/barback/lib/src/asset_node.dart
@@ -23,8 +23,11 @@
/// The transform that created this asset node.
///
- /// This is `null` for source assets.
- final TransformNode transform;
+ /// This is `null` for source assets. It can change if the upstream transform
+ /// that created this asset changes; this change will *not* cause an
+ /// [onStateChange] event.
+ TransformNode get transform => _transform;
+ TransformNode _transform;
/// The current state of the asset node.
AssetState get state => _state;
@@ -110,10 +113,10 @@
return onStateChange.firstWhere(test);
}
- AssetNode._(this.id, this.transform)
+ AssetNode._(this.id, this._transform)
: _state = AssetState.DIRTY;
- AssetNode._available(Asset asset, this.transform)
+ AssetNode._available(Asset asset, this._transform)
: id = asset.id,
_asset = asset,
_state = AssetState.AVAILABLE;
@@ -134,6 +137,17 @@
AssetNodeController.available(Asset asset, [TransformNode transform])
: node = new AssetNode._available(asset, transform);
+ /// Creates a controller for a node whose initial state matches the current
+ /// state of [node].
+ AssetNodeController.from(AssetNode node)
+ : node = new AssetNode._(node.id, node.transform) {
+ if (node.state.isAvailable) {
+ setAvailable(node.asset);
+ } else if (node.state.isRemoved) {
+ setRemoved();
+ }
+ }
+
/// Marks the node as [AssetState.DIRTY].
void setDirty() {
assert(node._state != AssetState.REMOVED);
@@ -165,6 +179,14 @@
node._asset = asset;
node._stateChangeController.add(AssetState.AVAILABLE);
}
+
+ /// Sets the node's [AssetNode.transform] property.
+ ///
+ /// This is used when resolving collisions, where a node will stick around but
+ /// a different transform will have created it.
+ void setTransform(TransformNode transform) {
+ node._transform = transform;
+ }
}
// TODO(nweiz): add an error state.
diff --git a/pkg/barback/lib/src/phase.dart b/pkg/barback/lib/src/phase.dart
index 690126a..a73ee00 100644
--- a/pkg/barback/lib/src/phase.dart
+++ b/pkg/barback/lib/src/phase.dart
@@ -13,6 +13,7 @@
import 'asset_set.dart';
import 'errors.dart';
import 'phase_input.dart';
+import 'phase_output.dart';
import 'stream_pool.dart';
import 'transformer.dart';
import 'utils.dart';
@@ -44,15 +45,8 @@
/// phases, they will be the outputs from the previous phase.
final _inputs = new Map<AssetId, PhaseInput>();
- /// A map of output ids to the asset node outputs for those ids and the
- /// transforms that produced those asset nodes.
- ///
- /// Usually there's only one node for a given output id. However, it's
- /// possible for multiple transformers to output an asset with the same id. In
- /// that case, the chronologically first output emitted is passed forward. We
- /// keep track of the other nodes so that if that output is removed, we know
- /// which asset to replace it with.
- final _outputs = new Map<AssetId, Queue<AssetNode>>();
+ /// The outputs for this phase.
+ final _outputs = new Map<AssetId, PhaseOutput>();
/// A stream that emits an event whenever this phase becomes dirty and needs
/// to be run.
@@ -77,7 +71,7 @@
/// Returns all currently-available output assets for this phase.
AssetSet get availableOutputs {
return new AssetSet.from(_outputs.values
- .map((queue) => queue.first)
+ .map((output) => output.output)
.where((node) => node.state.isAvailable)
.map((node) => node.asset));
}
@@ -125,7 +119,7 @@
return newFuture(() {
if (id.package != cascade.package) return cascade.graph.getAssetNode(id);
if (!_outputs.containsKey(id)) return null;
- return _outputs[id].first;
+ return _outputs[id].output;
});
}
@@ -145,12 +139,38 @@
Phase addPhase(Iterable<Transformer> transformers) {
assert(_next == null);
_next = new Phase(cascade, transformers);
- for (var outputs in _outputs.values) {
- _next.addInput(outputs.first);
+ for (var output in _outputs.values.toList()) {
+ // Remove [output]'s listeners because now they should get the asset from
+ // [_next], rather than this phase. Any transforms consuming [output] will
+ // be re-run and will consume the output from the new final phase.
+ output.removeListeners();
+
+ // Removing [output]'s listeners will cause it to be removed from
+ // [_outputs], so we have to put it back.
+ _outputs[output.output.id] = output;
+ _next.addInput(output.output);
}
return _next;
}
+ /// Mark this phase as removed.
+ ///
+ /// This will remove all the phase's outputs and all following phases.
+ void remove() {
+ removeFollowing();
+ for (var input in _inputs.values.toList()) {
+ input.remove();
+ }
+ _onDirtyPool.close();
+ }
+
+ /// Remove all phases after this one.
+ Phase removeFollowing() {
+ if (_next == null) return;
+ _next.remove();
+ _next = null;
+ }
+
/// Processes this phase.
///
/// Returns a future that completes when processing is done. If there is
@@ -158,76 +178,32 @@
Future process() {
if (!_inputs.values.any((input) => input.isDirty)) return null;
+ var outputIds = new Set<AssetId>();
return Future.wait(_inputs.values.map((input) {
if (!input.isDirty) return new Future.value(new Set());
return input.process().then((outputs) {
- return outputs.where(_addOutput).map((output) => output.id).toSet();
+ for (var asset in outputs) {
+ outputIds.add(asset.id);
+ if (_outputs.containsKey(asset.id)) {
+ _outputs[asset.id].add(asset);
+ } else {
+ _outputs[asset.id] = new PhaseOutput(this, asset);
+ _outputs[asset.id].output.whenRemoved
+ .then((_) => _outputs.remove(asset.id));
+ if (_next != null) _next.addInput(_outputs[asset.id].output);
+ }
+ }
});
- })).then((collisionsList) {
+ })).then((_) {
// Report collisions in a deterministic order.
- var collisions = unionAll(collisionsList).toList();
- collisions.sort((a, b) => a.compareTo(b));
- for (var collision in collisions) {
- // Ensure that there's still a collision. It's possible it was resolved
- // while another transform was running.
- if (_outputs[collision].length <= 1) continue;
- cascade.reportError(new AssetCollisionException(
- _outputs[collision].where((asset) => asset.transform != null)
- .map((asset) => asset.transform.info),
- collision));
- }
- });
- }
-
- /// Add [output] as an output of this phase, forwarding it to the next phase
- /// if necessary.
- ///
- /// Returns whether or not [output] collides with another pre-existing output.
- bool _addOutput(AssetNode output) {
- _handleOutputRemoval(output);
-
- if (_outputs.containsKey(output.id)) {
- _outputs[output.id].add(output);
- return true;
- }
-
- _outputs[output.id] = new Queue<AssetNode>.from([output]);
- if (_next != null) _next.addInput(output);
- return false;
- }
-
- /// Properly resolve collisions when [output] is removed.
- void _handleOutputRemoval(AssetNode output) {
- output.whenRemoved.then((_) {
- var assets = _outputs[output.id];
- if (assets.length == 1) {
- assert(assets.single == output);
- _outputs.remove(output.id);
- return;
- }
-
- // If there was more than one asset, we're resolving a collision --
- // possibly partially.
- var wasFirst = assets.first == output;
- assets.remove(output);
-
- // If this was the first asset, we need to pass the next asset
- // (chronologically) to the next phase. Pump the event queue first to give
- // [_next] a chance to handle the removal of its input before getting a
- // new input.
- if (wasFirst && _next != null) {
- newFuture(() => _next.addInput(assets.first));
- }
-
- // If there's still a collision, report it. This lets the user know
- // if they've successfully resolved the collision or not.
- if (assets.length > 1) {
- // Pump the event queue to ensure that the removal of the input triggers
- // a new build to which we can attach the error.
- newFuture(() => cascade.reportError(new AssetCollisionException(
- assets.where((asset) => asset.transform != null)
- .map((asset) => asset.transform.info),
- output.id)));
+ outputIds = outputIds.toList();
+ outputIds.sort((a, b) => a.compareTo(b));
+ for (var id in outputIds) {
+ // It's possible the output was removed before other transforms in this
+ // phase finished.
+ if (!_outputs.containsKey(id)) continue;
+ var exception = _outputs[id].collisionException;
+ if (exception != null) cascade.reportError(exception);
}
});
}
diff --git a/pkg/barback/lib/src/phase_output.dart b/pkg/barback/lib/src/phase_output.dart
new file mode 100644
index 0000000..8082e54
--- /dev/null
+++ b/pkg/barback/lib/src/phase_output.dart
@@ -0,0 +1,129 @@
+// Copyright (c) 2013, 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.
+
+library barback.phase_output;
+
+import 'dart:async';
+import 'dart:collection';
+
+import 'asset_cascade.dart';
+import 'asset_id.dart';
+import 'asset_node.dart';
+import 'errors.dart';
+import 'phase_input.dart';
+import 'stream_pool.dart';
+import 'transformer.dart';
+import 'utils.dart';
+
+/// A class that handles a single output of a phase.
+///
+/// Normally there's only a single [AssetNode] for a phase's output, but it's
+/// possible that multiple transformers in the same phase emit assets with the
+/// same id, causing collisions. This handles those collisions by forwarding the
+/// chronologically first asset.
+class PhaseOutput {
+ /// The phase for which this is an output.
+ final Phase _phase;
+
+ /// The asset node for this output.
+ AssetNode get output => _outputController.node;
+ AssetNodeController _outputController;
+
+ /// The assets for this output.
+ ///
+ /// If there's no collision, this will only have one element. Otherwise, it
+ /// will be ordered by which asset was added first.
+ final _assets = new Queue<AssetNode>();
+
+ /// The [AssetCollisionException] for this output, or null if there is no
+ /// collision currently.
+ AssetCollisionException get collisionException {
+ if (_assets.length == 1) return null;
+ return new AssetCollisionException(
+ _assets.where((asset) => asset.transform != null)
+ .map((asset) => asset.transform.info),
+ output.id);
+ }
+
+ PhaseOutput(this._phase, AssetNode output)
+ : _outputController = new AssetNodeController.from(output) {
+ assert(!output.state.isRemoved);
+ add(output);
+ }
+
+ /// Adds an asset node as an output with this id.
+ void add(AssetNode node) {
+ assert(node.id == output.id);
+ _assets.add(node);
+ _watchAsset(node);
+ }
+
+ /// Removes all existing listeners on [output] without actually closing
+ /// [this].
+ ///
+ /// This marks [output] as removed, but immediately replaces it with a new
+ /// [AssetNode] in the same state as the old output. This is used when adding
+ /// a new [Phase] to cause consumers of the prior phase's outputs to be to
+ /// start consuming the new phase's outputs instead.
+ void removeListeners() {
+ _outputController.setRemoved();
+ _outputController = new AssetNodeController.from(_assets.first);
+ }
+
+ /// Watches [node] for state changes and adjusts [_assets] and [output]
+ /// appropriately when they occur.
+ void _watchAsset(AssetNode node) {
+ node.onStateChange.listen((state) {
+ if (state.isRemoved) {
+ _removeAsset(node);
+ return;
+ }
+ if (_assets.first != node) return;
+
+ if (state.isAvailable) {
+ _outputController.setAvailable(node.asset);
+ } else {
+ assert(state.isDirty);
+ _outputController.setDirty();
+ }
+ });
+ }
+
+ /// Removes [node] as an output.
+ void _removeAsset(AssetNode node) {
+ if (_assets.length == 1) {
+ assert(_assets.single == node);
+ _outputController.setRemoved();
+ return;
+ }
+
+ // If there was more than one asset, we're resolving a collision --
+ // possibly partially.
+ var wasFirst = _assets.first == node;
+ _assets.remove(node);
+
+ // If this was the first asset, we replace it with the next asset
+ // (chronologically).
+ if (wasFirst) {
+ var newOutput = _assets.first;
+ _outputController.setTransform(newOutput.transform);
+ if (newOutput.state.isAvailable) {
+ if (output.state.isAvailable) _outputController.setDirty();
+ _outputController.setAvailable(newOutput.asset);
+ } else {
+ assert(newOutput.isDirty);
+ if (!output.isDirty) _outputController.setDirty();
+ }
+ }
+
+ // If there's still a collision, report it. This lets the user know
+ // if they've successfully resolved the collision or not.
+ if (_assets.length > 1) {
+ // Pump the event queue to ensure that the removal of the input triggers
+ // a new build to which we can attach the error.
+ // TODO(nweiz): report this through the output asset.
+ newFuture(() => _phase.cascade.reportError(collisionException));
+ }
+ }
+}
diff --git a/pkg/barback/test/asset_id_test.dart b/pkg/barback/test/asset_id_test.dart
index a55bb18..16d29ae 100644
--- a/pkg/barback/test/asset_id_test.dart
+++ b/pkg/barback/test/asset_id_test.dart
@@ -11,6 +11,18 @@
main() {
initConfig();
+ group("constructor", () {
+ test("normalizes the path", () {
+ var id = new AssetId("app", r"path/././/to/drop/..//asset.txt");
+ expect(id.path, equals("path/to/asset.txt"));
+ });
+
+ test("normalizes backslashes to slashes in the path", () {
+ var id = new AssetId("app", r"path\to/asset.txt");
+ expect(id.path, equals("path/to/asset.txt"));
+ });
+ });
+
group("parse", () {
test("parses the package and path", () {
var id = new AssetId.parse("package|path/to/asset.txt");
@@ -29,6 +41,16 @@
test("throws if the path is empty '|'", () {
expect(() => new AssetId.parse("app|"), throwsFormatException);
});
+
+ test("normalizes the path", () {
+ var id = new AssetId.parse(r"app|path/././/to/drop/..//asset.txt");
+ expect(id.path, equals("path/to/asset.txt"));
+ });
+
+ test("normalizes backslashes to slashes in the path", () {
+ var id = new AssetId.parse(r"app|path\to/asset.txt");
+ expect(id.path, equals("path/to/asset.txt"));
+ });
});
test("equals another ID with the same package and path", () {
diff --git a/pkg/barback/test/package_graph/add_remove_transform_test.dart b/pkg/barback/test/package_graph/add_remove_transform_test.dart
index b79c69a..bd68f68 100644
--- a/pkg/barback/test/package_graph/add_remove_transform_test.dart
+++ b/pkg/barback/test/package_graph/add_remove_transform_test.dart
@@ -191,9 +191,6 @@
});
test("a cross-package transform sees a new transformer in a new phase", () {
- // TODO(nweiz): make this work.
- return;
-
var rewrite = new RewriteTransformer("inc", "inc");
initGraph({
"pkg1|foo.txt": "pkg2|foo.inc",
@@ -204,7 +201,7 @@
});
updateSources(["pkg1|foo.txt", "pkg2|foo.inc"]);
- expectAsset("pkg1|foo.out", "foo");
+ expectAsset("pkg1|foo.out", "foo.inc");
buildShouldSucceed();
updateTransformers("pkg2", [
diff --git a/pkg/fixnum/lib/fixnum.dart b/pkg/fixnum/lib/fixnum.dart
index 1f89dd4..fe21c47 100644
--- a/pkg/fixnum/lib/fixnum.dart
+++ b/pkg/fixnum/lib/fixnum.dart
@@ -8,7 +8,7 @@
* The integer implementations in this library are designed to work
* identically whether executed on the Dart VM or compiled to JavaScript.
*
- * For information on getting this library, see the
+ * For information on installing and importing this library, see the
* [fixnum package on pub.dartlang.org]
* (http://pub.dartlang.org/packages/fixnum).
*/
diff --git a/pkg/intl/lib/generate_localized.dart b/pkg/intl/lib/generate_localized.dart
index 6477023..5f9639f 100644
--- a/pkg/intl/lib/generate_localized.dart
+++ b/pkg/intl/lib/generate_localized.dart
@@ -159,7 +159,7 @@
for (var locale in allLocales) {
var baseFile = '${generatedFilePrefix}messages_$locale.dart';
var file = importForGeneratedFile(baseFile);
- output.write("@${_deferredName(locale)} ");
+ output.write("@${_deferredName(locale)}\n");
output.write("import '$file' as ${_libraryName(locale)};\n");
}
output.write("\n");
diff --git a/pkg/intl/lib/intl.dart b/pkg/intl/lib/intl.dart
index a15abed..4f17a82 100644
--- a/pkg/intl/lib/intl.dart
+++ b/pkg/intl/lib/intl.dart
@@ -81,6 +81,11 @@
* produce "I see 2 other people in Athens." as output in the default locale.
*
* To use a locale other than the default, use the `withLocale` function.
+ * You can set the default locale.
+ * Intl.defaultLocale = "pt_BR";
+ *
+ * To temporarily use a locale other than the default, use the `withLocale`
+ * function.
* var todayString = new DateFormat("pt_BR").format(new DateTime.now());
* print(withLocale("pt_BR", () => today(todayString));
*
@@ -99,7 +104,7 @@
* can also be set explicitly, and will then apply to any new instances where
* the locale isn't specified.
*/
- static String _defaultLocale;
+ static String defaultLocale;
/**
* The system's locale, as obtained from the window.navigator.language
@@ -345,9 +350,9 @@
// but must be a static variable in order to be visible to the Intl.message
// invocation.
var oldLocale = getCurrentLocale();
- _defaultLocale = locale;
+ defaultLocale = locale;
var result = message_function();
- _defaultLocale = oldLocale;
+ defaultLocale = oldLocale;
return result;
}
@@ -357,8 +362,8 @@
* locale.
*/
static String getCurrentLocale() {
- if (_defaultLocale == null) _defaultLocale = systemLocale;
- return _defaultLocale;
+ if (defaultLocale == null) defaultLocale = systemLocale;
+ return defaultLocale;
}
toString() => "Intl($locale)";
diff --git a/pkg/intl/lib/message_lookup_by_library.dart b/pkg/intl/lib/message_lookup_by_library.dart
index 2e92dbd..c4107dc 100644
--- a/pkg/intl/lib/message_lookup_by_library.dart
+++ b/pkg/intl/lib/message_lookup_by_library.dart
@@ -97,23 +97,9 @@
String lookupMessage(String message_str, [final String desc='',
final Map examples=const {}, String locale,
String name, List<String> args]) {
- // If we don't have a name, return the original, and if we have
- // been recursively invoked, also just return message_str. This
- // happens because the replacement functions also call Intl.message,
- // so we assume that when _lookupInProgress is true that we're
- // already translated.
- if (name == null || _lookupInProgress) return message_str;
- _lookupInProgress = true;
- // Try to apply the function holding the translated version. If there
- // is an exception, use the original [message_str] as the result.
- var result = message_str;
- try {
- var function = this[name];
- if (function != null) result = Function.apply(function, args);
- } finally {
- _lookupInProgress = false;
- }
- return result;
+ if (name == null) return message_str;
+ var function = this[name];
+ return function == null ? message_str : Function.apply(function, args);
}
/** Return our message with the given name */
diff --git a/pkg/intl/lib/src/intl_message.dart b/pkg/intl/lib/src/intl_message.dart
index 886c82d..ad88395 100644
--- a/pkg/intl/lib/src/intl_message.dart
+++ b/pkg/intl/lib/src/intl_message.dart
@@ -350,9 +350,9 @@
var out = new StringBuffer()
..write('static $name(')
..write(arguments.join(", "))
- ..write(') => Intl.$dartMessageName("')
+ ..write(') => "')
..write(translations[locale])
- ..write('");');
+ ..write('";');
return out.toString();
}
diff --git a/pkg/logging/lib/logging.dart b/pkg/logging/lib/logging.dart
index 28fbc2f..1eae910 100644
--- a/pkg/logging/lib/logging.dart
+++ b/pkg/logging/lib/logging.dart
@@ -3,25 +3,15 @@
// BSD-style license that can be found in the LICENSE file.
/**
- * Provides APIs for debugging and error logging. This library introduces
- * abstractions similar to those used in other languages, such as the Closure JS
+ * Support for debugging and error logging.
+ *
+ * This library introduces abstractions similar to
+ * those used in other languages, such as the Closure JS
* Logger and java.util.logging.Logger.
*
- * ## Installing ##
- *
- * Use [pub][] to install this package. Add the following to your `pubspec.yaml`
- * file.
- *
- * dependencies:
- * logging: any
- *
- * Then run `pub install`.
- *
- * For more information, see the
- * [logging package on pub.dartlang.org][pkg].
- *
- * [pub]: http://pub.dartlang.org
- * [pkg]: http://pub.dartlang.org/packages/logging
+ * For information on installing and importing this library, see the
+ * [logging package on pub.dartlang.org]
+ * (http://pub.dartlang.org/packages/logging).
*/
library logging;
diff --git a/pkg/meta/lib/meta.dart b/pkg/meta/lib/meta.dart
index 9960d59..e3e4a25 100644
--- a/pkg/meta/lib/meta.dart
+++ b/pkg/meta/lib/meta.dart
@@ -3,24 +3,21 @@
// BSD-style license that can be found in the LICENSE file.
/**
- * This library contains the definitions of annotations that provide additional
- * semantic information about the program being annotated. These annotations are
- * intended to be used by tools to provide a better user experience.
+ * Constants for use in metadata annotations such as
+ * `@deprecated`, `@override`, and `@proxy`.
+ *
+ * Annotations provide semantic information
+ * that tools can use to provide a better user experience.
+ * For example, an IDE might not autocomplete
+ * the name of a function that's been marked `@deprecated`,
+ * or it might display the function's name differently.
*
- * ## Installing ##
- *
- * Use [pub][] to install this package. Add the following to your `pubspec.yaml`
- * file.
- *
- * dependencies:
- * meta: any
- *
- * Then run `pub install`.
- *
- * For more information, see the
- * [meta package on pub.dartlang.org](http://pub.dartlang.org/packages/meta).
- *
- * [pub]: http://pub.dartlang.org
+ * For information on installing and importing this library, see the
+ * [meta package on pub.dartlang.org]
+ * (http://pub.dartlang.org/packages/meta).
+ * For examples of using annotations, see
+ * [Metadata](https://www.dartlang.org/docs/dart-up-and-running/contents/ch02.html#ch02-metadata)
+ * in the language tour.
*/
library meta;
diff --git a/pkg/pkg.status b/pkg/pkg.status
index f41776a..4acfd1b 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -59,7 +59,7 @@
[ $runtime == safari ]
fixnum/test/int_64_test: Pass, Fail # Bug in JSC.
-crypto/test/hmac_sha1_test: Fail # Issue 11407.
+crypto/test/hmac_sha1_test: Pass, Fail # Issue 11407.
crypto/test/sha1_test: Fail # Issue 11407.
stack_trace/test/trace_test: Fail # http://dartbug.com/12380
crypto/test/sha256_test: Pass, Fail # Issue 12502
diff --git a/pkg/polymer/lib/src/emitters.dart b/pkg/polymer/lib/src/emitters.dart
index dbd6816..c5da7ba 100644
--- a/pkg/polymer/lib/src/emitters.dart
+++ b/pkg/polymer/lib/src/emitters.dart
@@ -79,11 +79,8 @@
return printer
..indent -= 1
..addLine('],')
- ..addLine(
- "currentMirrorSystem().findLibrary(const Symbol('app_bootstrap'))")
- ..indent += 2
- ..addLine(".first.uri.toString());")
- ..indent -= 4
+ ..addLine("currentMirrorSystem().isolate.rootLibrary.uri.toString());")
+ ..indent -= 2
..addLine('}');
}
diff --git a/pkg/polymer/lib/src/transform.dart b/pkg/polymer/lib/src/transform.dart
new file mode 100644
index 0000000..ff5de2b
--- /dev/null
+++ b/pkg/polymer/lib/src/transform.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2013, 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.
+
+/** Transfomers used for pub-serve and pub-deploy. */
+// TODO(sigmund): move into a plugin directory when pub supports it.
+library polymer.src.transform;
+
+import 'package:observe/transform.dart';
+import 'transform/code_extractor.dart';
+import 'transform/import_inliner.dart';
+import 'transform/script_compactor.dart';
+
+export 'transform/code_extractor.dart';
+export 'transform/import_inliner.dart';
+export 'transform/script_compactor.dart';
+
+/** Phases to deploy a polymer application. */
+var phases = [
+ [new InlineCodeExtractor()],
+ [new ObservableTransformer()],
+ [new ImportedElementInliner()],
+ [new ScriptCompactor()]
+];
diff --git a/pkg/polymer/lib/src/transform/code_extractor.dart b/pkg/polymer/lib/src/transform/code_extractor.dart
new file mode 100644
index 0000000..0e6d4d5
--- /dev/null
+++ b/pkg/polymer/lib/src/transform/code_extractor.dart
@@ -0,0 +1,58 @@
+// Copyright (c) 2013, 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.
+
+/** Transfomer that extracts inlined script code into separate assets. */
+library polymer.src.transformers;
+
+import 'dart:async';
+
+import 'package:barback/barback.dart';
+import 'package:path/path.dart' as path;
+
+import 'common.dart';
+
+/**
+ * Transformer that extracts Dart code inlined in HTML script tags and outputs a
+ * separate file for each.
+ */
+class InlineCodeExtractor extends Transformer {
+ Future<bool> isPrimary(Asset input) =>
+ new Future.value(input.id.extension == ".html");
+
+ Future apply(Transform transform) {
+ var inputId = transform.primaryId;
+ return getPrimaryContent(transform).then((content) {
+ var document = parseHtml(content, inputId.path, transform.logger);
+ int count = 0;
+ bool htmlChanged = false;
+ for (var tag in document.queryAll('script')) {
+ // Only process tags that have inline Dart code
+ if (tag.attributes['type'] != 'application/dart' ||
+ tag.attributes.containsKey('src')) {
+ continue;
+ }
+ htmlChanged = true;
+
+ // Remove empty tags
+ if (tag.nodes.length == 0) {
+ tag.remove();
+ continue;
+ }
+
+ // TODO(sigmund): should we automatically include a library directive
+ // if it doesn't have one?
+ var filename = path.url.basename(inputId.path);
+ // TODO(sigmund): ensure this filename is unique (dartbug.com/12618).
+ tag.attributes['src'] = '$filename.$count.dart';
+ var textContent = tag.nodes.first;
+ var id = inputId.addExtension('.$count.dart');
+ transform.addOutput(new Asset.fromString(id, textContent.value));
+ textContent.remove();
+ count++;
+ }
+ transform.addOutput(new Asset.fromString(inputId,
+ htmlChanged ? document.outerHtml : content));
+ });
+ }
+}
diff --git a/pkg/polymer/lib/src/transform/common.dart b/pkg/polymer/lib/src/transform/common.dart
new file mode 100644
index 0000000..c72e8b1
--- /dev/null
+++ b/pkg/polymer/lib/src/transform/common.dart
@@ -0,0 +1,83 @@
+// Copyright (c) 2013, 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.
+
+/** Common methods used by transfomers. */
+library polymer.src.transform.common;
+
+import 'dart:async';
+
+import 'package:barback/barback.dart';
+import 'package:html5lib/dom.dart' show Document;
+import 'package:html5lib/parser.dart' show HtmlParser;
+import 'package:path/path.dart' as path;
+import 'package:source_maps/span.dart' show Span;
+
+// TODO(sigmund): delete this function (see dartbug.com/12515 and
+// dartbug.com/12516)
+Future<String> getPrimaryContent(Transform transform) =>
+ transform.primaryInput.then((asset) => asset.readAsString());
+
+// TODO(sigmund): delete this function (see dartbug.com/12515)
+Future<String> getContent(Transform transform, AssetId id) =>
+ transform.getInput(id).then((asset) => asset.readAsString());
+
+/**
+ * Parses an HTML file [contents] and returns a DOM-like tree. Adds emitted
+ * error/warning to [logger].
+ */
+Document parseHtml(String contents, String sourcePath, TransformLogger logger,
+ {bool checkDocType: true}) {
+ // TODO(jmesserly): make HTTP encoding configurable
+ var parser = new HtmlParser(contents, encoding: 'utf8', generateSpans: true,
+ sourceUrl: sourcePath);
+ var document = parser.parse();
+
+ // Note: errors aren't fatal in HTML (unless strict mode is on).
+ // So just print them as warnings.
+ for (var e in parser.errors) {
+ if (checkDocType || e.errorCode != 'expected-doctype-but-got-start-tag') {
+ logger.warning(e.message, e.span);
+ }
+ }
+ return document;
+}
+
+/** Create an [AssetId] for a [url] seen in the [source] asset. */
+// TODO(sigmund): delete once this is part of barback (dartbug.com/12610)
+AssetId resolve(AssetId source, String url, TransformLogger logger, Span span) {
+ if (url == null || url == '') return null;
+ var uri = Uri.parse(url);
+ var urlBuilder = path.url;
+ if (uri.host != '' || uri.scheme != '' || urlBuilder.isAbsolute(url)) {
+ logger.error('absolute paths not allowed: "$url"', span);
+ return null;
+ }
+
+ var package;
+ var targetPath;
+ var segments = urlBuilder.split(url);
+ if (segments[0] == 'packages') {
+ if (segments.length < 3) {
+ logger.error("incomplete packages/ path. It should have at least 3 "
+ "segments packages/name/path-from-name's-lib-dir", span);
+ return null;
+ }
+ package = segments[1];
+ targetPath = urlBuilder.join('lib',
+ urlBuilder.joinAll(segments.sublist(2)));
+ } else if (segments[0] == 'assets') {
+ if (segments.length < 3) {
+ logger.error("incomplete assets/ path. It should have at least 3 "
+ "segments assets/name/path-from-name's-asset-dir", span);
+ }
+ package = segments[1];
+ targetPath = urlBuilder.join('asset',
+ urlBuilder.joinAll(segments.sublist(2)));
+ } else {
+ package = source.package;
+ targetPath = urlBuilder.normalize(
+ urlBuilder.join(urlBuilder.dirname(source.path), url));
+ }
+ return new AssetId(package, targetPath);
+}
diff --git a/pkg/polymer/lib/src/transform/import_inliner.dart b/pkg/polymer/lib/src/transform/import_inliner.dart
new file mode 100644
index 0000000..ac8ab7e
--- /dev/null
+++ b/pkg/polymer/lib/src/transform/import_inliner.dart
@@ -0,0 +1,91 @@
+// Copyright (c) 2013, 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.
+
+/** Transfomer that inlines polymer-element definitions from html imports. */
+library polymer.src.transform.import_inliner;
+
+import 'dart:async';
+
+import 'package:barback/barback.dart';
+import 'package:html5lib/dom.dart' show Document, Node, DocumentFragment;
+import 'common.dart';
+
+/** Recursively inlines polymer-element definitions from html imports. */
+// TODO(sigmund): make sure we match semantics of html-imports for tags other
+// than polymer-element (see dartbug.com/12613).
+class ImportedElementInliner extends Transformer {
+ Future<bool> isPrimary(Asset input) =>
+ new Future.value(input.id.extension == ".html");
+
+ Future apply(Transform transform) {
+ var seen = new Set<AssetId>();
+ var elements = [];
+ var id = transform.primaryId;
+ seen.add(id);
+ return getPrimaryContent(transform).then((content) {
+ var document = parseHtml(content, id.path, transform.logger);
+ var future = _visitImports(document, id, transform, seen, elements);
+ return future.then((importsFound) {
+ if (!importsFound) {
+ transform.addOutput(new Asset.fromString(id, content));
+ return;
+ }
+
+ for (var tag in document.queryAll('link')) {
+ if (tag.attributes['rel'] == 'import') {
+ tag.remove();
+ }
+ }
+ var fragment = new DocumentFragment()..nodes.addAll(elements);
+ document.body.insertBefore(fragment,
+ //TODO(jmesserly): add Node.firstChild to html5lib
+ document.body.nodes.length == 0 ? null : document.body.nodes[0]);
+ transform.addOutput(new Asset.fromString(id, document.outerHtml));
+ });
+ });
+ }
+
+ /**
+ * Visits imports in [document] and add their polymer-element definitions to
+ * [elements], unless they have already been [seen]. Elements are added in the
+ * order they appear, transitive imports are added first.
+ */
+ Future<bool> _visitImports(Document document, AssetId sourceId,
+ Transform transform, Set<AssetId> seen, List<Node> elements) {
+ var importIds = [];
+ bool hasImports = false;
+ for (var tag in document.queryAll('link')) {
+ if (tag.attributes['rel'] != 'import') continue;
+ var href = tag.attributes['href'];
+ var id = resolve(sourceId, href, transform.logger, tag.sourceSpan);
+ hasImports = true;
+ if (id == null || seen.contains(id)) continue;
+ importIds.add(id);
+ }
+
+ if (importIds.isEmpty) return new Future.value(hasImports);
+
+ // Note: we need to preserve the import order in the generated output.
+ return Future.forEach(importIds, (id) {
+ if (seen.contains(id)) return new Future.value(null);
+ seen.add(id);
+ return _collectPolymerElements(id, transform, seen, elements);
+ }).then((_) => true);
+ }
+
+ /**
+ * Loads an asset identified by [id], visits its imports and collects it's
+ * polymer-element definitions.
+ */
+ Future _collectPolymerElements(
+ AssetId id, Transform transform, Set<AssetId> seen, List elements) {
+ return getContent(transform, id)
+ .then((content) => parseHtml(
+ content, id.path, transform.logger, checkDocType: false))
+ .then((document) {
+ return _visitImports(document, id, transform, seen, elements)
+ .then((_) => elements.addAll(document.queryAll('polymer-element')));
+ });
+ }
+}
diff --git a/pkg/polymer/lib/src/transform/script_compactor.dart b/pkg/polymer/lib/src/transform/script_compactor.dart
new file mode 100644
index 0000000..9c2550a
--- /dev/null
+++ b/pkg/polymer/lib/src/transform/script_compactor.dart
@@ -0,0 +1,145 @@
+// Copyright (c) 2013, 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.
+
+/** Transfomer that combines multiple dart script tags into a single one. */
+library polymer.src.transform.script_compactor;
+
+import 'dart:async';
+
+import 'package:barback/barback.dart';
+import 'package:html5lib/parser.dart' show parseFragment;
+import 'package:path/path.dart' as path;
+
+import 'code_extractor.dart'; // import just for documentation.
+import 'common.dart';
+
+/**
+ * Combines Dart script tags into a single script tag, and creates a new Dart
+ * file that calls the main function of each of the original script tags.
+ *
+ * This transformer assumes that all script tags point to external files. To
+ * support script tags with inlined code, use this transformer after running
+ * [InlineCodeExtractor] on an earlier phase.
+ *
+ * Internally, this transformer will convert each script tag into an import
+ * statement to a library, and then uses `initPolymer` (see polymer.dart) to
+ * invoke the main method on each of these libraries and register any polymer
+ * elements annotated with `@CustomTag`.
+ */
+class ScriptCompactor extends Transformer {
+ Future<bool> isPrimary(Asset input) =>
+ new Future.value(input.id.extension == ".html");
+
+ Future apply(Transform transform) {
+ var id = transform.primaryId;
+ var logger = transform.logger;
+ return getPrimaryContent(transform).then((content) {
+ var document = parseHtml(content, id.path, logger);
+ var libraries = [];
+ bool changed = false;
+ var dartLoaderTag = null;
+ for (var tag in document.queryAll('script')) {
+ var src = tag.attributes['src'];
+ if (src != null) {
+ if (src == 'packages/polymer/boot.js') {
+ tag.remove();
+ continue;
+ }
+ var last = src.split('/').last;
+ if (last == 'dart.js' || last == 'testing.js') {
+ dartLoaderTag = tag;
+ }
+ }
+ if (tag.attributes['type'] != 'application/dart') continue;
+ tag.remove();
+ changed = true;
+ if (src == null) {
+ logger.warning('unexpected script without a src url. The '
+ 'ScriptCompactor transformer should run after running the '
+ 'InlineCodeExtractor', tag.sourceSpan);
+ continue;
+ }
+ var libraryId = resolve(id, src, logger, tag.sourceSpan);
+
+ // TODO(sigmund): should we detect/remove duplicates?
+ if (libraryId == null) continue;
+ libraries.add(libraryId);
+ }
+
+ if (!changed) {
+ transform.addOutput(new Asset.fromString(id, content));
+ return;
+ }
+
+ var bootstrapId = id.addExtension('_bootstrap.dart');
+ var filename = path.url.basename(bootstrapId.path);
+
+ var bootstrapScript = parseFragment(
+ '<script type="application/dart" src="$filename"></script>');
+ if (dartLoaderTag == null) {
+ document.body.nodes.add(bootstrapScript);
+ document.body.nodes.add(parseFragment('<script type="text/javascript" '
+ 'src="packages/browser/dart.js"></script>'));
+ } else if (dartLoaderTag.parent != document.body) {
+ document.body.nodes.add(bootstrapScript);
+ } else {
+ document.body.insertBefore(bootstrapScript, dartLoaderTag);
+ }
+
+ var urls = libraries.map((id) => importUrlFor(id, bootstrapId, logger))
+ .where((url) => url != null).toList();
+ var buffer = new StringBuffer()..write(_header);
+ for (int i = 0; i < urls.length; i++) {
+ buffer.writeln("import '${urls[i]}' as i$i;");
+ }
+ buffer..write(_mainPrefix)
+ ..writeAll(urls.map((url) => " '$url',\n"))
+ ..write(_mainSuffix);
+
+ transform.addOutput(new Asset.fromString(bootstrapId, buffer.toString()));
+ transform.addOutput(new Asset.fromString(id, document.outerHtml));
+ });
+ }
+
+ /**
+ * Generate the import url for a file described by [id], referenced by a file
+ * with [sourceId].
+ */
+ String importUrlFor(AssetId id, AssetId sourceId, TransformLogger logger) {
+ // use package: urls if possible
+ if (id.path.startsWith('lib/')) {
+ return 'package:${id.package}/${id.path.substring(4)}';
+ }
+
+ // Use relative urls only if it's possible.
+ if (id.package != sourceId.package) {
+ logger.error("don't know how to import $id from $sourceId");
+ return null;
+ }
+
+ var builder = path.url;
+ return builder.relative(builder.join('/', id.path),
+ from: builder.join('/', builder.dirname(sourceId.path)));
+ }
+}
+
+const _header = """
+library app_bootstrap;
+
+import 'package:polymer/polymer.dart';
+import 'dart:mirrors' show currentMirrorSystem;
+
+""";
+
+const _mainPrefix = """
+
+void main() {
+ initPolymer([
+""";
+
+// TODO(sigmund): investigate alternative to get the baseUri (dartbug.com/12612)
+const _mainSuffix = """
+ ], currentMirrorSystem().isolate.rootLibrary.uri.toString());
+}
+""";
diff --git a/pkg/polymer/test/run_all.dart b/pkg/polymer/test/run_all.dart
index b149502..cc666ed 100644
--- a/pkg/polymer/test/run_all.dart
+++ b/pkg/polymer/test/run_all.dart
@@ -17,6 +17,10 @@
import 'compiler_test.dart' as compiler_test;
import 'paths_test.dart' as paths_test;
import 'utils_test.dart' as utils_test;
+import 'transform/code_extractor_test.dart' as code_extractor_test;
+import 'transform/import_inliner_test.dart' as import_inliner_test;
+import 'transform/script_compactor_test.dart' as script_compactor_test;
+import 'transform/all_phases_test.dart' as all_phases_test;
main() {
var args = new Options().arguments;
@@ -34,6 +38,10 @@
addGroup('css_test.dart', css_test.main);
addGroup('paths_test.dart', paths_test.main);
addGroup('utils_test.dart', utils_test.main);
+ addGroup('transform/code_extractor_test.dart', code_extractor_test.main);
+ addGroup('transform/import_inliner_test.dart', import_inliner_test.main);
+ addGroup('transform/script_compactor_test.dart', script_compactor_test.main);
+ addGroup('transform/all_phases_test.dart', all_phases_test.main);
endToEndTests('data/unit/', 'data/out');
diff --git a/pkg/polymer/test/transform/all_phases_test.dart b/pkg/polymer/test/transform/all_phases_test.dart
new file mode 100644
index 0000000..a644fe5
--- /dev/null
+++ b/pkg/polymer/test/transform/all_phases_test.dart
@@ -0,0 +1,206 @@
+// Copyright (c) 2013, 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.
+
+library polymer.test.transform.script_compactor_test;
+
+import 'package:polymer/src/transform.dart';
+import 'package:unittest/compact_vm_config.dart';
+
+import 'common.dart';
+
+void main() {
+ useCompactVMConfiguration();
+
+ testPhases('no changes', phases, {
+ 'a|web/test.html': '<!DOCTYPE html><html></html>',
+ }, {
+ 'a|web/test.html': '<!DOCTYPE html><html></html>',
+ });
+
+ testPhases('observable changes', phases, {
+ 'a|web/test.dart': _sampleObservable('A', 'foo'),
+ 'a|web/test2.dart': _sampleObservableOutput('B', 'bar'),
+ }, {
+ 'a|web/test.dart': _sampleObservableOutput('A', 'foo'),
+ 'a|web/test2.dart': _sampleObservableOutput('B', 'bar'),
+ });
+
+ testPhases('single script', phases, {
+ 'a|web/test.html':
+ '<!DOCTYPE html><html><head>'
+ '<script type="application/dart" src="a.dart"></script>',
+ 'a|web/test.dart': _sampleObservable('A', 'foo'),
+ }, {
+ 'a|web/test.html':
+ '<!DOCTYPE html><html><head></head><body>'
+ '<script type="application/dart" '
+ 'src="test.html_bootstrap.dart"></script>'
+ '<script type="text/javascript" '
+ 'src="packages/browser/dart.js"></script>'
+ '</body></html>',
+
+ 'a|web/test.html_bootstrap.dart':
+ '''library app_bootstrap;
+
+ import 'package:polymer/polymer.dart';
+ import 'dart:mirrors' show currentMirrorSystem;
+
+ import 'a.dart' as i0;
+
+ void main() {
+ initPolymer([
+ 'a.dart',
+ ], currentMirrorSystem().isolate.rootLibrary.uri.toString());
+ }
+ '''.replaceAll('\n ', '\n'),
+ 'a|web/test.dart': _sampleObservableOutput('A', 'foo'),
+ });
+
+ testPhases('single inline script', phases, {
+ 'a|web/test.html':
+ '<!DOCTYPE html><html><head>'
+ '<script type="application/dart">'
+ '${_sampleObservable("B", "bar")}</script>',
+ }, {
+ 'a|web/test.html':
+ '<!DOCTYPE html><html><head></head><body>'
+ '<script type="application/dart" '
+ 'src="test.html_bootstrap.dart"></script>'
+ '<script type="text/javascript" '
+ 'src="packages/browser/dart.js"></script>'
+ '</body></html>',
+
+ 'a|web/test.html_bootstrap.dart':
+ '''library app_bootstrap;
+
+ import 'package:polymer/polymer.dart';
+ import 'dart:mirrors' show currentMirrorSystem;
+
+ import 'test.html.0.dart' as i0;
+
+ void main() {
+ initPolymer([
+ 'test.html.0.dart',
+ ], currentMirrorSystem().isolate.rootLibrary.uri.toString());
+ }
+ '''.replaceAll('\n ', '\n'),
+ 'a|web/test.html.0.dart': _sampleObservableOutput("B", "bar"),
+ });
+
+ testPhases('several scripts', phases, {
+ 'a|web/test.html':
+ '<!DOCTYPE html><html><head>'
+ '<script type="application/dart" src="a.dart"></script>'
+ '<script type="application/dart">'
+ '${_sampleObservable("B", "bar")}</script>'
+ '</head><body><div>'
+ '<script type="application/dart">'
+ '${_sampleObservable("C", "car")}</script>'
+ '</div>'
+ '<script type="application/dart" src="d.dart"></script>',
+ 'a|web/a.dart': _sampleObservable('A', 'foo'),
+ }, {
+ 'a|web/test.html':
+ '<!DOCTYPE html><html><head></head><body><div></div>'
+ '<script type="application/dart" '
+ 'src="test.html_bootstrap.dart"></script>'
+ '<script type="text/javascript" '
+ 'src="packages/browser/dart.js"></script>'
+ '</body></html>',
+
+ 'a|web/test.html_bootstrap.dart':
+ '''library app_bootstrap;
+
+ import 'package:polymer/polymer.dart';
+ import 'dart:mirrors' show currentMirrorSystem;
+
+ import 'a.dart' as i0;
+ import 'test.html.0.dart' as i1;
+ import 'test.html.1.dart' as i2;
+ import 'd.dart' as i3;
+
+ void main() {
+ initPolymer([
+ 'a.dart',
+ 'test.html.0.dart',
+ 'test.html.1.dart',
+ 'd.dart',
+ ], currentMirrorSystem().isolate.rootLibrary.uri.toString());
+ }
+ '''.replaceAll('\n ', '\n'),
+ 'a|web/a.dart': _sampleObservableOutput('A', 'foo'),
+ 'a|web/test.html.0.dart': _sampleObservableOutput("B", "bar"),
+ 'a|web/test.html.1.dart': _sampleObservableOutput("C", "car"),
+ });
+
+ testPhases('with imports', phases, {
+ 'a|web/index.html':
+ '<!DOCTYPE html><html><head>'
+ '<link rel="import" href="test2.html">'
+ '</head><body>'
+ '<script type="application/dart" src="b.dart"></script>'
+ '<script type="application/dart">'
+ '${_sampleObservable("C", "car")}</script>',
+ 'a|web/b.dart': _sampleObservable('B', 'bar'),
+ 'a|web/test2.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body><polymer-element>1'
+ '<script type="application/dart">'
+ '${_sampleObservable("A", "foo")}</script>'
+ '</polymer-element></html>',
+ }, {
+ 'a|web/index.html':
+ '<!DOCTYPE html><html><head></head><body>'
+ '<polymer-element>1</polymer-element>'
+ '<script type="application/dart" '
+ 'src="index.html_bootstrap.dart"></script>'
+ '<script type="text/javascript" '
+ 'src="packages/browser/dart.js"></script>'
+ '</body></html>',
+ 'a|web/index.html_bootstrap.dart':
+ '''library app_bootstrap;
+
+ import 'package:polymer/polymer.dart';
+ import 'dart:mirrors' show currentMirrorSystem;
+
+ import 'test2.html.0.dart' as i0;
+ import 'b.dart' as i1;
+ import 'index.html.0.dart' as i2;
+
+ void main() {
+ initPolymer([
+ 'test2.html.0.dart',
+ 'b.dart',
+ 'index.html.0.dart',
+ ], currentMirrorSystem().isolate.rootLibrary.uri.toString());
+ }
+ '''.replaceAll('\n ', '\n'),
+ 'a|web/test2.html.0.dart': _sampleObservableOutput("A", "foo"),
+ 'a|web/b.dart': _sampleObservableOutput('B', 'bar'),
+ 'a|web/index.html.0.dart': _sampleObservableOutput("C", "car"),
+ });
+}
+
+String _sampleObservable(String className, String fieldName) => '''
+import 'package:observe/observe.dart';
+
+class $className extends ObservableBase {
+ @observable int $fieldName;
+ $className(this.$fieldName);
+}
+''';
+
+String _sampleObservableOutput(String className, String fieldName) => '''
+import 'package:observe/observe.dart';
+
+class $className extends ChangeNotifierBase {
+ int __\$$fieldName;
+ int get $fieldName => __\$$fieldName;
+ set $fieldName(int value) {
+ __\$$fieldName = notifyPropertyChange(const Symbol('$fieldName'), __\$$fieldName, value);
+ }
+
+ $className($fieldName) : __\$$fieldName = $fieldName;
+}
+''';
diff --git a/pkg/polymer/test/transform/code_extractor_test.dart b/pkg/polymer/test/transform/code_extractor_test.dart
new file mode 100644
index 0000000..e62ec96
--- /dev/null
+++ b/pkg/polymer/test/transform/code_extractor_test.dart
@@ -0,0 +1,82 @@
+// Copyright (c) 2013, 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.
+
+library polymer.test.transform.code_extractor_test;
+
+import 'package:polymer/src/transform/code_extractor.dart';
+import 'package:unittest/compact_vm_config.dart';
+
+import 'common.dart';
+
+void main() {
+ useCompactVMConfiguration();
+
+ testPhases('no changes', [[new InlineCodeExtractor()]], {
+ 'a|test.html': '<!DOCTYPE html><html></html>',
+ }, {
+ 'a|test.html': '<!DOCTYPE html><html></html>',
+ });
+
+ testPhases('single script', [[new InlineCodeExtractor()]], {
+ 'a|test.html':
+ '<!DOCTYPE html><html><head>'
+ '<script type="application/dart">main() { }</script>',
+ }, {
+ 'a|test.html':
+ '<!DOCTYPE html><html><head>'
+ '<script type="application/dart" src="test.html.0.dart"></script>'
+ '</head><body></body></html>',
+
+ 'a|test.html.0.dart':
+ 'main() { }',
+ });
+
+ testPhases('multiple scripts', [[new InlineCodeExtractor()]], {
+ 'a|test.html':
+ '<!DOCTYPE html><html><head>'
+ '<script type="application/dart">main1() { }</script>'
+ '<script type="application/dart">main2() { }</script>',
+ }, {
+ 'a|test.html':
+ '<!DOCTYPE html><html><head>'
+ '<script type="application/dart" src="test.html.0.dart"></script>'
+ '<script type="application/dart" src="test.html.1.dart"></script>'
+ '</head><body></body></html>',
+
+ 'a|test.html.0.dart':
+ 'main1() { }',
+
+ 'a|test.html.1.dart':
+ 'main2() { }',
+ });
+
+ testPhases('multiple deeper scripts', [[new InlineCodeExtractor()]], {
+ 'a|test.html':
+ '<!DOCTYPE html><html><head>'
+ '<script type="application/dart">main1() { }</script>'
+ '</head><body><div>'
+ '<script type="application/dart">main2() { }</script>'
+ '</div><div><div>'
+ '<script type="application/dart">main3() { }</script>'
+ '</div></div>'
+ }, {
+ 'a|test.html':
+ '<!DOCTYPE html><html><head>'
+ '<script type="application/dart" src="test.html.0.dart"></script>'
+ '</head><body><div>'
+ '<script type="application/dart" src="test.html.1.dart"></script>'
+ '</div><div><div>'
+ '<script type="application/dart" src="test.html.2.dart"></script>'
+ '</div></div></body></html>',
+
+ 'a|test.html.0.dart':
+ 'main1() { }',
+
+ 'a|test.html.1.dart':
+ 'main2() { }',
+
+ 'a|test.html.2.dart':
+ 'main3() { }',
+ });
+}
diff --git a/pkg/polymer/test/transform/common.dart b/pkg/polymer/test/transform/common.dart
new file mode 100644
index 0000000..c0fd47e
--- /dev/null
+++ b/pkg/polymer/test/transform/common.dart
@@ -0,0 +1,97 @@
+// Copyright (c) 2013, 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.
+
+library polymer.test.transfom.common;
+
+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));
+}
+
+/**
+ * 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;
+
+ Barback barback;
+ var errorSubscription;
+ var resultSubscription;
+
+ Future<Asset> getAsset(AssetId id) =>
+ new Future.value(new Asset.fromString(id, files[idToString(id)]));
+ TestHelper(List<List<Transformer>> transformers, Map<String, String> files)
+ : 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 = getAttachedStackTrace(e);
+ if (trace != null) {
+ print(Trace.format(trace));
+ }
+ fail('error running barback: $e');
+ });
+ resultSubscription = barback.results.listen((result) {
+ expect(result.succeeded, isTrue, reason: "${result.errors}");
+ });
+ }
+
+ void tearDown() {
+ errorSubscription.cancel();
+ resultSubscription.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) {
+ expect(value, content, reason: 'Final output of $assetIdString differs.');
+ });
+ }
+
+ Future checkAll(Map<String, String> files) {
+ var futures = [];
+ files.forEach((k, v) {
+ futures.add(check(k, v));
+ });
+ return Future.wait(futures);
+ }
+}
+
+testPhases(String testName, List<List<Transformer>> phases,
+ Map<String, String> inputFiles, Map<String, String> expectedFiles) {
+ test(testName, () {
+ var helper = new TestHelper(phases, inputFiles)..run();
+ return helper.checkAll(expectedFiles).then((_) => helper.tearDown());
+ });
+}
+
diff --git a/pkg/polymer/test/transform/import_inliner_test.dart b/pkg/polymer/test/transform/import_inliner_test.dart
new file mode 100644
index 0000000..7776bbd
--- /dev/null
+++ b/pkg/polymer/test/transform/import_inliner_test.dart
@@ -0,0 +1,352 @@
+// Copyright (c) 2013, 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.
+
+library polymer.test.transform.import_inliner_test;
+
+import 'package:polymer/src/transform/import_inliner.dart';
+import 'package:unittest/compact_vm_config.dart';
+import 'package:unittest/unittest.dart';
+
+import 'common.dart';
+
+void main() {
+ useCompactVMConfiguration();
+ testPhases('no changes', [[new ImportedElementInliner()]], {
+ 'a|test.html': '<!DOCTYPE html><html></html>',
+ }, {
+ 'a|test.html': '<!DOCTYPE html><html></html>',
+ });
+
+ testPhases('empty import', [[new ImportedElementInliner()]], {
+ 'a|test.html':
+ '<!DOCTYPE html><html><head>'
+ '<link rel="import" href="">' // empty href
+ '</head></html>',
+ 'a|test2.html':
+ '<!DOCTYPE html><html><head>'
+ '<link rel="import">' // no href
+ '</head></html>',
+ }, {
+ 'a|test.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body></body></html>',
+ 'a|test2.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body></body></html>',
+ });
+
+ testPhases('shallow, no elements', [[new ImportedElementInliner()]], {
+ 'a|test.html':
+ '<!DOCTYPE html><html><head>'
+ '<link rel="import" href="test2.html">'
+ '</head></html>',
+ 'a|test2.html':
+ '<!DOCTYPE html><html><head>'
+ '</head></html>',
+ }, {
+ 'a|test.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body></body></html>',
+ 'a|test2.html':
+ '<!DOCTYPE html><html><head>'
+ '</head></html>',
+ });
+
+ testPhases('shallow, elements, one import', [[new ImportedElementInliner()]],
+ {
+ 'a|test.html':
+ '<!DOCTYPE html><html><head>'
+ '<link rel="import" href="test2.html">'
+ '</head></html>',
+ 'a|test2.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body><polymer-element>2</polymer-element></html>',
+ }, {
+ 'a|test.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body>'
+ '<polymer-element>2</polymer-element>'
+ '</body></html>',
+ 'a|test2.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body><polymer-element>2</polymer-element></html>',
+ });
+
+ testPhases('shallow, elements, many', [[new ImportedElementInliner()]],
+ {
+ 'a|test.html':
+ '<!DOCTYPE html><html><head>'
+ '<link rel="import" href="test2.html">'
+ '<link rel="import" href="test3.html">'
+ '</head></html>',
+ 'a|test2.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body><polymer-element>2</polymer-element></html>',
+ 'a|test3.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body><polymer-element>3</polymer-element></html>',
+ }, {
+ 'a|test.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body>'
+ '<polymer-element>2</polymer-element>'
+ '<polymer-element>3</polymer-element>'
+ '</body></html>',
+ 'a|test2.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body><polymer-element>2</polymer-element></html>',
+ 'a|test3.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body><polymer-element>3</polymer-element></html>',
+ });
+
+ testPhases('deep, elements, one per file', [[new ImportedElementInliner()]], {
+ 'a|test.html':
+ '<!DOCTYPE html><html><head>'
+ '<link rel="import" href="test2.html">'
+ '</head></html>',
+ 'a|test2.html':
+ '<!DOCTYPE html><html><head>'
+ '<link rel="import" href="assets/b/test3.html">'
+ '</head><body><polymer-element>2</polymer-element></html>',
+ 'b|asset/test3.html':
+ '<!DOCTYPE html><html><head>'
+ '<link rel="import" href="packages/c/test4.html">'
+ '</head><body><polymer-element>3</polymer-element></html>',
+ 'c|lib/test4.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body><polymer-element>4</polymer-element></html>',
+ }, {
+ 'a|test.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body>'
+ '<polymer-element>4</polymer-element>'
+ '<polymer-element>3</polymer-element>'
+ '<polymer-element>2</polymer-element></body></html>',
+ 'a|test2.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body>'
+ '<polymer-element>4</polymer-element>'
+ '<polymer-element>3</polymer-element>'
+ '<polymer-element>2</polymer-element></body></html>',
+ 'b|asset/test3.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body>'
+ '<polymer-element>4</polymer-element>'
+ '<polymer-element>3</polymer-element></body></html>',
+ 'c|lib/test4.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body><polymer-element>4</polymer-element></html>',
+ });
+
+ testPhases('deep, elements, many imports', [[new ImportedElementInliner()]], {
+ 'a|test.html':
+ '<!DOCTYPE html><html><head>'
+ '<link rel="import" href="test2a.html">'
+ '<link rel="import" href="test2b.html">'
+ '</head></html>',
+ 'a|test2a.html':
+ '<!DOCTYPE html><html><head>'
+ '<link rel="import" href="test3a.html">'
+ '<link rel="import" href="test3b.html">'
+ '</head><body><polymer-element>2a</polymer-element></body></html>',
+ 'a|test2b.html':
+ '<!DOCTYPE html><html><head>'
+ '<link rel="import" href="test4a.html">'
+ '<link rel="import" href="test4b.html">'
+ '</head><body><polymer-element>2b</polymer-element></body></html>',
+ 'a|test3a.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body><polymer-element>3a</polymer-element></body></html>',
+ 'a|test3b.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body><polymer-element>3b</polymer-element></body></html>',
+ 'a|test4a.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body><polymer-element>4a</polymer-element></body></html>',
+ 'a|test4b.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body><polymer-element>4b</polymer-element></body></html>',
+ }, {
+ 'a|test.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body>'
+ '<polymer-element>3a</polymer-element>'
+ '<polymer-element>3b</polymer-element>'
+ '<polymer-element>2a</polymer-element>'
+ '<polymer-element>4a</polymer-element>'
+ '<polymer-element>4b</polymer-element>'
+ '<polymer-element>2b</polymer-element>'
+ '</body></html>',
+ 'a|test2a.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body>'
+ '<polymer-element>3a</polymer-element>'
+ '<polymer-element>3b</polymer-element>'
+ '<polymer-element>2a</polymer-element>'
+ '</body></html>',
+ 'a|test2b.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body>'
+ '<polymer-element>4a</polymer-element>'
+ '<polymer-element>4b</polymer-element>'
+ '<polymer-element>2b</polymer-element>'
+ '</body></html>',
+ 'a|test3a.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body>'
+ '<polymer-element>3a</polymer-element>'
+ '</body></html>',
+ 'a|test3b.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body>'
+ '<polymer-element>3b</polymer-element>'
+ '</body></html>',
+ 'a|test4a.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body>'
+ '<polymer-element>4a</polymer-element>'
+ '</body></html>',
+ 'a|test4b.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body>'
+ '<polymer-element>4b</polymer-element>'
+ '</body></html>',
+ });
+
+ testPhases('imports cycle, 1-step lasso', [[new ImportedElementInliner()]], {
+ 'a|test.html':
+ '<!DOCTYPE html><html><head>'
+ '<link rel="import" href="test_1.html">'
+ '</head></html>',
+ 'a|test_1.html':
+ '<!DOCTYPE html><html><head>'
+ '<link rel="import" href="test_2.html">'
+ '</head><body><polymer-element>1</polymer-element></html>',
+ 'a|test_2.html':
+ '<!DOCTYPE html><html><head>'
+ '<link rel="import" href="test_1.html">'
+ '</head><body><polymer-element>2</polymer-element></html>',
+ }, {
+ 'a|test.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body>'
+ '<polymer-element>2</polymer-element>'
+ '<polymer-element>1</polymer-element></body></html>',
+ 'a|test_1.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body>'
+ '<polymer-element>2</polymer-element>'
+ '<polymer-element>1</polymer-element></body></html>',
+ 'a|test_2.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body>'
+ '<polymer-element>1</polymer-element>'
+ '<polymer-element>2</polymer-element></body></html>',
+ });
+
+ testPhases('imports cycle, 2-step lasso', [[new ImportedElementInliner()]], {
+ 'a|test.html':
+ '<!DOCTYPE html><html><head>'
+ '<link rel="import" href="test_1.html">'
+ '</head></html>',
+ 'a|test_1.html':
+ '<!DOCTYPE html><html><head>'
+ '<link rel="import" href="test_2.html">'
+ '</head><body><polymer-element>1</polymer-element></html>',
+ 'a|test_2.html':
+ '<!DOCTYPE html><html><head>'
+ '<link rel="import" href="test_3.html">'
+ '</head><body><polymer-element>2</polymer-element></html>',
+ 'a|test_3.html':
+ '<!DOCTYPE html><html><head>'
+ '<link rel="import" href="test_1.html">'
+ '</head><body><polymer-element>3</polymer-element></html>',
+ }, {
+ 'a|test.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body>'
+ '<polymer-element>3</polymer-element>'
+ '<polymer-element>2</polymer-element>'
+ '<polymer-element>1</polymer-element></body></html>',
+ 'a|test_1.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body>'
+ '<polymer-element>3</polymer-element>'
+ '<polymer-element>2</polymer-element>'
+ '<polymer-element>1</polymer-element></body></html>',
+ 'a|test_2.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body>'
+ '<polymer-element>1</polymer-element>'
+ '<polymer-element>3</polymer-element>'
+ '<polymer-element>2</polymer-element></body></html>',
+ 'a|test_3.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body>'
+ '<polymer-element>2</polymer-element>'
+ '<polymer-element>1</polymer-element>'
+ '<polymer-element>3</polymer-element></body></html>',
+ });
+
+ testPhases('imports cycle, self cycle', [[new ImportedElementInliner()]], {
+ 'a|test.html':
+ '<!DOCTYPE html><html><head>'
+ '<link rel="import" href="test_1.html">'
+ '</head></html>',
+ 'a|test_1.html':
+ '<!DOCTYPE html><html><head>'
+ '<link rel="import" href="test_1.html">'
+ '</head><body><polymer-element>1</polymer-element></html>',
+ }, {
+ 'a|test.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body>'
+ '<polymer-element>1</polymer-element></body></html>',
+ 'a|test_1.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body>'
+ '<polymer-element>1</polymer-element></body></html>',
+ });
+
+ testPhases('imports DAG', [[new ImportedElementInliner()]], {
+ 'a|test.html':
+ '<!DOCTYPE html><html><head>'
+ '<link rel="import" href="test_1.html">'
+ '<link rel="import" href="test_2.html">'
+ '</head></html>',
+ 'a|test_1.html':
+ '<!DOCTYPE html><html><head>'
+ '<link rel="import" href="test_3.html">'
+ '</head><body><polymer-element>1</polymer-element></body></html>',
+ 'a|test_2.html':
+ '<!DOCTYPE html><html><head>'
+ '<link rel="import" href="test_3.html">'
+ '</head><body><polymer-element>2</polymer-element></body></html>',
+ 'a|test_3.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body><polymer-element>3</polymer-element></body></html>',
+ }, {
+ 'a|test.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body>'
+ '<polymer-element>3</polymer-element>'
+ '<polymer-element>1</polymer-element>'
+ '<polymer-element>2</polymer-element></body></html>',
+ 'a|test_1.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body>'
+ '<polymer-element>3</polymer-element>'
+ '<polymer-element>1</polymer-element></body></html>',
+ 'a|test_2.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body>'
+ '<polymer-element>3</polymer-element>'
+ '<polymer-element>2</polymer-element></body></html>',
+ 'a|test_3.html':
+ '<!DOCTYPE html><html><head>'
+ '</head><body>'
+ '<polymer-element>3</polymer-element></body></html>',
+ });
+}
diff --git a/pkg/polymer/test/transform/script_compactor_test.dart b/pkg/polymer/test/transform/script_compactor_test.dart
new file mode 100644
index 0000000..b271e3c
--- /dev/null
+++ b/pkg/polymer/test/transform/script_compactor_test.dart
@@ -0,0 +1,89 @@
+// Copyright (c) 2013, 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.
+
+library polymer.test.transform.script_compactor_test;
+
+import 'package:polymer/src/transform/script_compactor.dart';
+import 'package:unittest/compact_vm_config.dart';
+
+import 'common.dart';
+
+void main() {
+ useCompactVMConfiguration();
+
+ testPhases('no changes', [[new ScriptCompactor()]], {
+ 'a|test.html': '<!DOCTYPE html><html></html>',
+ }, {
+ 'a|test.html': '<!DOCTYPE html><html></html>',
+ });
+
+ testPhases('single script', [[new ScriptCompactor()]], {
+ 'a|test.html':
+ '<!DOCTYPE html><html><head>'
+ '<script type="application/dart" src="a.dart"></script>',
+ }, {
+ 'a|test.html':
+ '<!DOCTYPE html><html><head></head><body>'
+ '<script type="application/dart" '
+ 'src="test.html_bootstrap.dart"></script>'
+ '<script type="text/javascript" '
+ 'src="packages/browser/dart.js"></script>'
+ '</body></html>',
+
+ 'a|test.html_bootstrap.dart':
+ '''library app_bootstrap;
+
+ import 'package:polymer/polymer.dart';
+ import 'dart:mirrors' show currentMirrorSystem;
+
+ import 'a.dart' as i0;
+
+ void main() {
+ initPolymer([
+ 'a.dart',
+ ], currentMirrorSystem().isolate.rootLibrary.uri.toString());
+ }
+ '''.replaceAll('\n ', '\n'),
+ });
+
+ testPhases('several scripts', [[new ScriptCompactor()]], {
+ 'a|test.html':
+ '<!DOCTYPE html><html><head>'
+ '<script type="application/dart" src="a.dart"></script>'
+ '<script type="application/dart" src="b.dart"></script>'
+ '</head><body><div>'
+ '<script type="application/dart" src="c.dart"></script>'
+ '</div>'
+ '<script type="application/dart" src="d.dart"></script>',
+ }, {
+ 'a|test.html':
+ '<!DOCTYPE html><html><head></head><body><div></div>'
+ '<script type="application/dart" '
+ 'src="test.html_bootstrap.dart"></script>'
+ '<script type="text/javascript" '
+ 'src="packages/browser/dart.js"></script>'
+ '</body></html>',
+
+ 'a|test.html_bootstrap.dart':
+ '''library app_bootstrap;
+
+ import 'package:polymer/polymer.dart';
+ import 'dart:mirrors' show currentMirrorSystem;
+
+ import 'a.dart' as i0;
+ import 'b.dart' as i1;
+ import 'c.dart' as i2;
+ import 'd.dart' as i3;
+
+ void main() {
+ initPolymer([
+ 'a.dart',
+ 'b.dart',
+ 'c.dart',
+ 'd.dart',
+ ], currentMirrorSystem().isolate.rootLibrary.uri.toString());
+ }
+ '''.replaceAll('\n ', '\n'),
+ });
+}
diff --git a/pkg/unittest/lib/html_config.dart b/pkg/unittest/lib/html_config.dart
index 2dde44b..b86b3fc 100644
--- a/pkg/unittest/lib/html_config.dart
+++ b/pkg/unittest/lib/html_config.dart
@@ -132,6 +132,11 @@
}
void onInit() {
+ // For Dart internal tests, we want to turn off stack frame
+ // filtering, which we do with this meta-header.
+ var meta = query('meta[name="dart.unittest"]');
+ filterStacks = meta == null ? true :
+ !meta.content.contains('full-stack-traces');
_installHandlers();
window.postMessage('unittest-suite-wait-for-done', '*');
}
diff --git a/pkg/unittest/lib/src/simple_configuration.dart b/pkg/unittest/lib/src/simple_configuration.dart
index d4a0f6e..1056ad3 100644
--- a/pkg/unittest/lib/src/simple_configuration.dart
+++ b/pkg/unittest/lib/src/simple_configuration.dart
@@ -50,7 +50,7 @@
// If stopTestOnExpectFailure is false, we need to capture failures, which
// we do with this List.
- final _testLogBuffer = <Pair<String, Trace>>[];
+ final _testLogBuffer = <Pair<String, StackTrace>>[];
/**
* The constructor sets up a failure handler for [expect] that redirects
@@ -61,6 +61,10 @@
}
void onInit() {
+ // For Dart internal tests, we don't want stack frame filtering.
+ // We turn it off here in the default config, but by default turn
+ // it back on in the vm and html configs.
+ filterStacks = false;
_receivePort = new ReceivePort();
_postMessage('unittest-suite-wait-for-done');
}
@@ -135,8 +139,9 @@
try {
throw '';
} catch (_, stack) {
- _testLogBuffer.add(
- new Pair<String, Trace>(reason, new Trace.from(stack)));
+ var trace = _getTrace(stack);
+ if (trace == null) trace = stack;
+ _testLogBuffer.add(new Pair<String, StackTrace>(reason, trace));
}
}
}
diff --git a/pkg/unittest/lib/src/test_case.dart b/pkg/unittest/lib/src/test_case.dart
index d965082..c37b8a5 100644
--- a/pkg/unittest/lib/src/test_case.dart
+++ b/pkg/unittest/lib/src/test_case.dart
@@ -41,9 +41,9 @@
*/
String get result => _result;
- Trace _stackTrace;
+ StackTrace _stackTrace;
/** Stack trace associated with this test, or [null] if it succeeded. */
- Trace get stackTrace => _stackTrace;
+ StackTrace get stackTrace => _stackTrace;
/** The group (or groups) under which this test is running. */
final String currentGroup;
@@ -130,9 +130,10 @@
// Set the results, notify the config, and return true if this
// is the first time the result is being set.
- void _setResult(String testResult, String messageText, stack) {
+ void _setResult(String testResult, String messageText, StackTrace stack) {
_message = messageText;
_stackTrace = _getTrace(stack);
+ if (_stackTrace == null) _stackTrace = stack;
if (result == null) {
_result = testResult;
_config.onTestResult(this);
@@ -142,7 +143,8 @@
}
}
- void _complete(String testResult, [String messageText = '', stack]) {
+ void _complete(String testResult, [String messageText = '',
+ StackTrace stack]) {
if (runningTime == null) {
// The startTime can be `null` if an error happened during setup. In this
// case we simply report a running time of 0.
@@ -164,7 +166,7 @@
_complete(PASS);
}
- void fail(String messageText, [stack]) {
+ void fail(String messageText, [StackTrace stack]) {
if (result != null) {
String newMessage = (result == PASS)
? 'Test failed after initially passing: $messageText'
@@ -176,7 +178,7 @@
}
}
- void error(String messageText, [stack]) {
+ void error(String messageText, [StackTrace stack]) {
_complete(ERROR, messageText, stack);
}
diff --git a/pkg/unittest/lib/unittest.dart b/pkg/unittest/lib/unittest.dart
index eb186bd..f6e83c2 100644
--- a/pkg/unittest/lib/unittest.dart
+++ b/pkg/unittest/lib/unittest.dart
@@ -852,10 +852,19 @@
*/
bool formatStacks = true;
-/** Returns a Trace object from a StackTrace object or a String. */
+/**
+ * A flag that controls whether we try to filter out irrelevant frames from
+ * the stack trace. Requires formatStacks to be set.
+ */
+bool filterStacks = true;
+
+/**
+ * Returns a Trace object from a StackTrace object or a String, or the
+ * unchanged input if formatStacks is false;
+ */
Trace _getTrace(stack) {
Trace trace;
- if (stack == null) return null;
+ if (stack == null || !formatStacks) return null;
if (stack is String) {
trace = new Trace.parse(stack);
} else if (stack is StackTrace) {
@@ -864,7 +873,7 @@
throw new Exception('Invalid stack type ${stack.runtimeType} for $stack.');
}
- if (!formatStacks) return trace;
+ if (!filterStacks) return trace;
// Format the stack trace by removing everything above TestCase._runTest,
// which is usually going to be irrelevant. Also fold together unittest and
diff --git a/pkg/unittest/lib/vm_config.dart b/pkg/unittest/lib/vm_config.dart
index 0133186..962ca97 100644
--- a/pkg/unittest/lib/vm_config.dart
+++ b/pkg/unittest/lib/vm_config.dart
@@ -38,6 +38,11 @@
return result;
}
+ void onInit() {
+ super.onInit();
+ filterStacks = formatStacks = true;
+ }
+
void onDone(bool success) {
int status;
try {
diff --git a/runtime/bin/eventhandler.cc b/runtime/bin/eventhandler.cc
index a07cf3d..c25a2fa 100644
--- a/runtime/bin/eventhandler.cc
+++ b/runtime/bin/eventhandler.cc
@@ -16,12 +16,6 @@
static const intptr_t kTimerId = -1;
static const intptr_t kInvalidId = -2;
-static EventHandler* event_handler = NULL;
-// TODO(ajohnsen): Consider removing mutex_ if we can enforce an invariant
-// that eventhandler is kept alive untill all isolates are closed.
-static dart::Mutex* mutex_ = new dart::Mutex();
-
-
void TimeoutQueue::UpdateTimeout(Dart_Port port, int64_t timeout) {
// Find port if present.
Timeout* last = NULL;
@@ -63,51 +57,40 @@
}
+static EventHandler* event_handler = NULL;
+
+
+void EventHandler::Start() {
+ ASSERT(event_handler == NULL);
+ event_handler = new EventHandler();
+ event_handler->delegate_.Start(event_handler);
+}
+
+
void EventHandler::Stop() {
- MutexLocker locker(mutex_);
if (event_handler == NULL) return;
- event_handler->Shutdown();
+ event_handler->delegate_.Shutdown();
event_handler = NULL;
}
/*
- * Starts the EventHandler thread and stores its reference in the dart
- * EventHandler object. args[0] holds the reference to the dart EventHandler
- * object.
- */
-void FUNCTION_NAME(EventHandler_Start)(Dart_NativeArguments args) {
- MutexLocker locker(mutex_);
- if (event_handler != NULL) return;
- event_handler = EventHandler::Start();
-}
-
-
-/*
* Send data to the EventHandler thread to register for a given instance
- * args[1] a ReceivePort args[2] with a notification event args[3]. args[0]
- * holds the reference to the dart EventHandler object.
+ * args[0] a ReceivePort args[1] with a notification event args[2].
*/
void FUNCTION_NAME(EventHandler_SendData)(Dart_NativeArguments args) {
- Dart_Handle sender = Dart_GetNativeArgument(args, 1);
+ Dart_Handle sender = Dart_GetNativeArgument(args, 0);
intptr_t id = kInvalidId;
if (Dart_IsNull(sender)) {
id = kTimerId;
} else {
Socket::GetSocketIdNativeField(sender, &id);
}
- Dart_Handle handle = Dart_GetNativeArgument(args, 2);
+ Dart_Handle handle = Dart_GetNativeArgument(args, 1);
Dart_Port dart_port =
DartUtils::GetIntegerField(handle, DartUtils::kIdFieldName);
- int64_t data = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 3));
- {
- MutexLocker locker(mutex_);
- // Only send if the event_handler is not NULL. This means that the handler
- // shut down, and a message is send later on.
- if (event_handler != NULL) {
- event_handler->SendData(id, dart_port, data);
- }
- }
+ int64_t data = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 2));
+ event_handler->SendData(id, dart_port, data);
}
} // namespace bin
diff --git a/runtime/bin/eventhandler.h b/runtime/bin/eventhandler.h
index 8a26043..a9b0bcd 100644
--- a/runtime/bin/eventhandler.h
+++ b/runtime/bin/eventhandler.h
@@ -108,16 +108,15 @@
delegate_.SendData(id, dart_port, data);
}
- void Shutdown() {
- delegate_.Shutdown();
- }
+ /**
+ * Start the event-handler.
+ */
+ static void Start();
- static EventHandler* Start() {
- EventHandler* handler = new EventHandler();
- handler->delegate_.Start(handler);
- return handler;
- }
-
+ /**
+ * Stop the event-handler. It's expected that there will be no further calls
+ * to SendData after a call to Stop.
+ */
static void Stop();
private:
diff --git a/runtime/bin/eventhandler_android.cc b/runtime/bin/eventhandler_android.cc
index 90f94b4..975a6d1 100644
--- a/runtime/bin/eventhandler_android.cc
+++ b/runtime/bin/eventhandler_android.cc
@@ -160,6 +160,9 @@
msg.id = id;
msg.dart_port = dart_port;
msg.data = data;
+ // WriteToBlocking will write up to 512 bytes atomically, and since our msg
+ // is smaller than 512, we don't need a thread lock.
+ // See: http://linux.die.net/man/7/pipe, section 'Pipe_buf'.
intptr_t result =
FDUtils::WriteToBlocking(interrupt_fds_[1], &msg, kInterruptMessageSize);
if (result != kInterruptMessageSize) {
diff --git a/runtime/bin/eventhandler_linux.cc b/runtime/bin/eventhandler_linux.cc
index 6d15c9e..e95def6 100644
--- a/runtime/bin/eventhandler_linux.cc
+++ b/runtime/bin/eventhandler_linux.cc
@@ -165,6 +165,9 @@
msg.id = id;
msg.dart_port = dart_port;
msg.data = data;
+ // WriteToBlocking will write up to 512 bytes atomically, and since our msg
+ // is smaller than 512, we don't need a thread lock.
+ // See: http://linux.die.net/man/7/pipe, section 'Pipe_buf'.
intptr_t result =
FDUtils::WriteToBlocking(interrupt_fds_[1], &msg, kInterruptMessageSize);
if (result != kInterruptMessageSize) {
diff --git a/runtime/bin/eventhandler_macos.cc b/runtime/bin/eventhandler_macos.cc
index 419c93e..20c6b61 100644
--- a/runtime/bin/eventhandler_macos.cc
+++ b/runtime/bin/eventhandler_macos.cc
@@ -184,6 +184,9 @@
msg.id = id;
msg.dart_port = dart_port;
msg.data = data;
+ // WriteToBlocking will write up to 512 bytes atomically, and since our msg
+ // is smaller than 512, we don't need a thread lock.
+ // See: http://linux.die.net/man/7/pipe, section 'Pipe_buf'.
intptr_t result =
FDUtils::WriteToBlocking(interrupt_fds_[1], &msg, kInterruptMessageSize);
if (result != kInterruptMessageSize) {
diff --git a/runtime/bin/eventhandler_patch.dart b/runtime/bin/eventhandler_patch.dart
index 46c1e3d..2038a57 100644
--- a/runtime/bin/eventhandler_patch.dart
+++ b/runtime/bin/eventhandler_patch.dart
@@ -5,28 +5,9 @@
import 'dart:nativewrappers';
patch class _EventHandler {
- /* patch */ static void _start() {
- if (_eventHandler == null) {
- _eventHandler = new _EventHandlerImpl();
- _eventHandler._start();
- }
- }
-
- /* patch */ static _sendData(Object sender,
- ReceivePort receivePort,
- int data) {
- if (_eventHandler != null) {
- _eventHandler._sendData(sender, receivePort, data);
- }
- }
-
- static _EventHandlerImpl _eventHandler;
-}
-
-
-class _EventHandlerImpl {
- _EventHandlerImpl() { }
- void _start() native "EventHandler_Start";
- void _sendData(Object sender, ReceivePort receivePort, int data)
+ /* patch */ static void _sendData(Object sender,
+ ReceivePort receivePort,
+ int data)
native "EventHandler_SendData";
}
+
diff --git a/runtime/bin/io_natives.cc b/runtime/bin/io_natives.cc
index 2948ce8..eb5b444 100644
--- a/runtime/bin/io_natives.cc
+++ b/runtime/bin/io_natives.cc
@@ -21,8 +21,7 @@
// builtin_natives.cc instead.
#define IO_NATIVE_LIST(V) \
V(Crypto_GetRandomBytes, 1) \
- V(EventHandler_Start, 1) \
- V(EventHandler_SendData, 4) \
+ V(EventHandler_SendData, 3) \
V(Filter_CreateZLibDeflate, 3) \
V(Filter_CreateZLibInflate, 1) \
V(Filter_End, 1) \
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 7e5138e..0e813eb 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -744,6 +744,9 @@
}
}
+ // Start event handler.
+ EventHandler::Start();
+
// Start the VM service isolate, if necessary.
if (start_vm_service) {
ASSERT(vm_service_server_port >= 0);
@@ -860,7 +863,6 @@
Dart_ShutdownIsolate();
// Terminate process exit-code handler.
Process::TerminateExitCodeHandler();
- EventHandler::Stop();
// Free copied argument strings if converted.
if (argv_converted) {
diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart
index 55f9224e..512cdbe 100644
--- a/runtime/bin/socket_patch.dart
+++ b/runtime/bin/socket_patch.dart
@@ -358,17 +358,14 @@
_NativeSocket.normal() : typeFlags = TYPE_NORMAL_SOCKET {
eventHandlers = new List(EVENT_COUNT + 1);
- _EventHandler._start();
}
_NativeSocket.listen() : typeFlags = TYPE_LISTENING_SOCKET {
eventHandlers = new List(EVENT_COUNT + 1);
- _EventHandler._start();
}
_NativeSocket.pipe() : typeFlags = TYPE_PIPE {
eventHandlers = new List(EVENT_COUNT + 1);
- _EventHandler._start();
}
int available() {
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 4f35fab..80fc69b 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -1410,12 +1410,6 @@
intptr_t length);
/**
- * Retrieves the peer pointer associated with an external String.
- */
-DART_EXPORT Dart_Handle Dart_ExternalStringGetPeer(Dart_Handle object,
- void** peer);
-
-/**
* Returns a String which references an external array of
* Latin-1 (ISO-8859-1) encoded characters.
*
@@ -1536,8 +1530,9 @@
* \return the converted ExternalString object if no error occurs.
* Otherwise returns an error handle.
* If the object is a valid string but if it cannot be externalized
- * then Dart_Null() is returned and the string data is copied into
- * the external space specified.
+ * the string data is copied into the external space specified
+ * and the passed in peer is setup as a peer for this string object.
+ * In this case the function returns the original String object as is.
*
* For example:
* intptr_t size;
@@ -1562,7 +1557,8 @@
* \param str A String.
* \param char_size Returns the character size of the String.
* \param str_len Returns the length of the String.
- * \param peer Returns the peer pointer if the String is an external String.
+ * \param peer Returns the peer pointer associated with the String or 0 if
+ * there is no peer pointer for it.
* \return Success if no error occurs. Otherwise returns
* an error handle.
*/
@@ -2001,9 +1997,10 @@
* Gets a string native argument at some index.
* \param args Native arguments structure.
* \param arg_index Index of the desired argument in the structure above.
- * \param peer Returns the peer pointer if the String is an external String.
- * \return the String object if no error occurs. Otherwise returns
- * an error handle.
+ * \param peer Returns the peer pointer if the string argument has one.
+ * \return Success if the string argument has a peer, if it does not
+ * have a peer then the String object is returned. Otherwise returns
+ * an error handle (argument is not a String object).
*/
DART_EXPORT Dart_Handle Dart_GetNativeStringArgument(Dart_NativeArguments args,
int arg_index,
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index e0c8b23..ed78b7b 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -187,6 +187,8 @@
static RawInstance* CreateClassMirror(const Class& cls,
const AbstractType& type,
const Instance& owner_mirror) {
+ ASSERT(!cls.IsDynamicClass() && !cls.IsVoidClass());
+
if (cls.IsSignatureClass()) {
if (cls.IsCanonicalSignatureClass()) {
// We represent function types as canonical signature classes.
@@ -305,6 +307,12 @@
GET_NON_NULL_NATIVE_ARGUMENT(Type, type, arguments->NativeArgAt(0));
const Class& cls = Class::Handle(type.type_class());
ASSERT(!cls.IsNull());
+ if (cls.IsDynamicClass() || cls.IsVoidClass()) {
+ const Array& args = Array::Handle(Array::New(1));
+ args.SetAt(0, type);
+ Exceptions::ThrowByType(Exceptions::kArgument, args);
+ UNREACHABLE();
+ }
// Strip the type for generics only.
if (cls.NumTypeParameters() == 0) {
return CreateClassMirror(cls,
@@ -561,15 +569,15 @@
entry = entries.GetNext();
if (entry.IsClass()) {
const Class& klass = Class::Cast(entry);
- if (!klass.IsCanonicalSignatureClass()) {
- // The various implementations of public classes don't always have the
- // expected superinterfaces or other properties, so we filter them out.
- if (!RawObject::IsImplementationClassId(klass.id())) {
- member_mirror = CreateClassMirror(klass,
- AbstractType::Handle(),
- owner_mirror);
- member_mirrors.Add(member_mirror);
- }
+ // We filter out implementation classes like Smi, Mint, Bignum,
+ // OneByteString; function signature classes; and dynamic.
+ if (!klass.IsCanonicalSignatureClass() &&
+ !klass.IsDynamicClass() &&
+ !RawObject::IsImplementationClassId(klass.id())) {
+ member_mirror = CreateClassMirror(klass,
+ AbstractType::Handle(),
+ owner_mirror);
+ member_mirrors.Add(member_mirror);
}
} else if (entry.IsField()) {
const Field& field = Field::Cast(entry);
diff --git a/runtime/vm/benchmark_test.cc b/runtime/vm/benchmark_test.cc
index 2ca11fe..4cb8158 100644
--- a/runtime/vm/benchmark_test.cc
+++ b/runtime/vm/benchmark_test.cc
@@ -198,6 +198,8 @@
// Create strings.
uint8_t data8[] = { 'o', 'n', 'e', 0xFF };
int external_peer_data = 123;
+ intptr_t char_size;
+ intptr_t str_len;
Dart_Handle external_string = Dart_NewExternalLatin1String(
data8, ARRAY_SIZE(data8), &external_peer_data, NULL);
Dart_Handle internal_string = NewString("two");
@@ -209,7 +211,12 @@
EXPECT_VALID(external_string);
EXPECT(Dart_IsExternalString(external_string));
void* external_peer = NULL;
- EXPECT_VALID(Dart_ExternalStringGetPeer(external_string, &external_peer));
+ EXPECT_VALID(Dart_StringGetProperties(external_string,
+ &char_size,
+ &str_len,
+ &external_peer));
+ EXPECT_EQ(1, char_size);
+ EXPECT_EQ(4, str_len);
EXPECT_EQ(&external_peer_data, external_peer);
}
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 4c082e8..b55b5b2 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -240,44 +240,33 @@
}
-#define GET_PEER(type, ctype, raw_obj, peer) \
-
-
-#define EXTERNAL_PEER_HELPER(cid, raw_obj, peer) \
- switch (cid) { \
- case kExternalOneByteStringCid: { \
- RawExternalOneByteString* raw_string = \
- reinterpret_cast<RawExternalOneByteString*>(raw_obj)->ptr(); \
- ExternalStringData<uint8_t>* data = raw_string->external_data_; \
- *peer = data->peer(); \
- return true; \
- } \
- case kExternalTwoByteStringCid: { \
- RawExternalTwoByteString* raw_string = \
- reinterpret_cast<RawExternalTwoByteString*>(raw_obj)->ptr(); \
- ExternalStringData<uint16_t>* data = raw_string->external_data_; \
- *peer = data->peer(); \
- return true; \
- } \
- } \
- return false; \
-
-
-bool Api::ExternalStringGetPeerHelper(Dart_NativeArguments args,
- int arg_index,
- void** peer) {
+bool Api::StringGetPeerHelper(Dart_NativeArguments args,
+ int arg_index,
+ void** peer) {
NoGCScope no_gc_scope;
NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
RawObject* raw_obj = arguments->NativeArgAt(arg_index);
intptr_t cid = raw_obj->GetClassId();
- EXTERNAL_PEER_HELPER(cid, raw_obj, peer);
-}
-
-
-bool Api::ExternalStringGetPeerHelper(Dart_Handle object, void** peer) {
- NoGCScope no_gc_scope;
- RawObject* raw_obj = Api::UnwrapHandle(object);
- EXTERNAL_PEER_HELPER(Api::ClassId(object), raw_obj, peer);
+ if (cid == kExternalOneByteStringCid) {
+ RawExternalOneByteString* raw_string =
+ reinterpret_cast<RawExternalOneByteString*>(raw_obj)->ptr();
+ ExternalStringData<uint8_t>* data = raw_string->external_data_;
+ *peer = data->peer();
+ return true;
+ }
+ if (cid == kOneByteStringCid || cid == kTwoByteStringCid) {
+ Isolate* isolate = arguments->isolate();
+ *peer = isolate->heap()->GetPeer(raw_obj);
+ return (*peer != 0);
+ }
+ if (cid == kExternalTwoByteStringCid) {
+ RawExternalTwoByteString* raw_string =
+ reinterpret_cast<RawExternalTwoByteString*>(raw_obj)->ptr();
+ ExternalStringData<uint16_t>* data = raw_string->external_data_;
+ *peer = data->peer();
+ return true;
+ }
+ return false;
}
@@ -1647,28 +1636,6 @@
}
-DART_EXPORT Dart_Handle Dart_ExternalStringGetPeer(Dart_Handle object,
- void** peer) {
- if (peer == NULL) {
- RETURN_NULL_ERROR(peer);
- }
-
- if (Api::ExternalStringGetPeerHelper(object, peer)) {
- return Api::Success();
- }
-
- // It's not an external string, return appropriate error.
- if (!RawObject::IsStringClassId(Api::ClassId(object))) {
- RETURN_TYPE_ERROR(Isolate::Current(), object, String);
- } else {
- return
- Api::NewError(
- "%s expects argument 'object' to be an external String.",
- CURRENT_FUNC);
- }
-}
-
-
DART_EXPORT Dart_Handle Dart_NewExternalLatin1String(
const uint8_t* latin1_array,
intptr_t length,
@@ -1842,9 +1809,9 @@
if (str_obj.InVMHeap()) {
// Since the string object is read only we do not externalize
// the string but instead copy the contents of the string into the
- // specified buffer and return a Null object.
- // This ensures that the embedder does not have to call again
- // to get at the contents.
+ // specified buffer add the specified peer/cback as a Peer object
+ // to this string. The Api::StringGetPeerHelper function picks up
+ // the peer from the Peer table.
intptr_t copy_len = str_obj.Length();
if (str_obj.IsOneByteString()) {
ASSERT(length >= copy_len);
@@ -1852,6 +1819,7 @@
for (intptr_t i = 0; i < copy_len; i++) {
latin1_array[i] = static_cast<uint8_t>(str_obj.CharAt(i));
}
+ OneByteString::SetPeer(str_obj, peer, cback);
} else {
ASSERT(str_obj.IsTwoByteString());
ASSERT(length >= (copy_len * str_obj.CharSize()));
@@ -1859,8 +1827,9 @@
for (intptr_t i = 0; i < copy_len; i++) {
utf16_array[i] = static_cast<uint16_t>(str_obj.CharAt(i));
}
+ TwoByteString::SetPeer(str_obj, peer, cback);
}
- return Api::Null();
+ return str;
}
return Api::NewHandle(isolate,
str_obj.MakeExternal(array, length, peer, cback));
@@ -1881,7 +1850,8 @@
*peer = str.GetPeer();
ASSERT(*peer != NULL);
} else {
- *peer = NULL;
+ NoGCScope no_gc_scope;
+ *peer = isolate->heap()->GetPeer(str.raw());
}
*char_size = str.CharSize();
*str_len = str.Length();
@@ -3704,7 +3674,7 @@
NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
Isolate* isolate = arguments->isolate();
CHECK_ISOLATE(isolate);
- if (Api::ExternalStringGetPeerHelper(args, arg_index, peer)) {
+ if (Api::StringGetPeerHelper(args, arg_index, peer)) {
return Api::Success();
}
*peer = NULL;
diff --git a/runtime/vm/dart_api_impl.h b/runtime/vm/dart_api_impl.h
index 322a265..6c05c98 100644
--- a/runtime/vm/dart_api_impl.h
+++ b/runtime/vm/dart_api_impl.h
@@ -191,10 +191,9 @@
static void InitHandles();
// Helper function to get the peer value of an external string object.
- static bool ExternalStringGetPeerHelper(Dart_NativeArguments args,
- int arg_index,
- void** peer);
- static bool ExternalStringGetPeerHelper(Dart_Handle object, void** peer);
+ static bool StringGetPeerHelper(Dart_NativeArguments args,
+ int arg_index,
+ void** peer);
// Helper function to set the return value of native functions.
static void SetReturnValue(NativeArguments* args, Dart_Handle retval) {
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index f92f29c..a9def3f 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -643,49 +643,6 @@
}
-TEST_CASE(ExternalStringGetPeer) {
- Dart_Handle result;
-
- uint8_t data8[] = { 'o', 'n', 'e', 0xFF };
- int peer_data = 123;
- void* peer = NULL;
-
- // Success.
- Dart_Handle ext8 = Dart_NewExternalLatin1String(data8, ARRAY_SIZE(data8),
- &peer_data, NULL);
- EXPECT_VALID(ext8);
-
- result = Dart_ExternalStringGetPeer(ext8, &peer);
- EXPECT_VALID(result);
- EXPECT_EQ(&peer_data, peer);
-
- // NULL peer.
- result = Dart_ExternalStringGetPeer(ext8, NULL);
- EXPECT(Dart_IsError(result));
- EXPECT_STREQ("Dart_ExternalStringGetPeer expects argument 'peer' to be "
- "non-null.", Dart_GetError(result));
-
- // String is not external.
- peer = NULL;
- uint8_t utf8_data8[] = { 'o', 'n', 'e', 0x7F };
- Dart_Handle str8 = Dart_NewStringFromUTF8(utf8_data8, ARRAY_SIZE(data8));
- EXPECT_VALID(str8);
- result = Dart_ExternalStringGetPeer(str8, &peer);
- EXPECT(Dart_IsError(result));
- EXPECT_STREQ("Dart_ExternalStringGetPeer expects argument 'object' to be "
- "an external String.", Dart_GetError(result));
- EXPECT(peer == NULL);
-
- // Not a String.
- peer = NULL;
- result = Dart_ExternalStringGetPeer(Dart_True(), &peer);
- EXPECT(Dart_IsError(result));
- EXPECT_STREQ("Dart_ExternalStringGetPeer expects argument 'object' to be "
- "of type String.", Dart_GetError(result));
- EXPECT(peer == NULL);
-}
-
-
static void ExternalStringCallbackFinalizer(void* peer) {
*static_cast<int*>(peer) *= 2;
}
@@ -705,9 +662,6 @@
&peer8,
ExternalStringCallbackFinalizer);
EXPECT_VALID(obj8);
- void* api_peer8 = NULL;
- EXPECT_VALID(Dart_ExternalStringGetPeer(obj8, &api_peer8));
- EXPECT_EQ(api_peer8, &peer8);
uint16_t data16[] = { 'h', 'e', 'l', 'l', 'o' };
Dart_Handle obj16 = Dart_NewExternalUTF16String(
@@ -716,9 +670,6 @@
&peer16,
ExternalStringCallbackFinalizer);
EXPECT_VALID(obj16);
- void* api_peer16 = NULL;
- EXPECT_VALID(Dart_ExternalStringGetPeer(obj16, &api_peer16));
- EXPECT_EQ(api_peer16, &peer16);
Dart_ExitScope();
}
@@ -6940,6 +6891,7 @@
TEST_CASE(MakeExternalString) {
int peer8 = 40;
int peer16 = 41;
+ int canonical_str_peer = 42;
intptr_t length = 0;
intptr_t expected_length = 0;
{
@@ -7001,6 +6953,29 @@
EXPECT_VALID(Dart_StringLength(str, &length));
EXPECT_EQ(0, length);
+ // Test with single character canonical string, it should not become
+ // external string but the peer should be setup for it.
+ Isolate* isolate = Isolate::Current();
+ Dart_Handle canonical_str = Api::NewHandle(isolate, Symbols::New("*"));
+ EXPECT(Dart_IsString(canonical_str));
+ EXPECT(!Dart_IsExternalString(canonical_str));
+ uint8_t ext_canonical_str[kLength];
+ str = Dart_MakeExternalString(canonical_str,
+ ext_canonical_str,
+ kLength,
+ &canonical_str_peer,
+ MakeExternalCback);
+ EXPECT(Dart_IsString(str));
+ EXPECT(!Dart_IsExternalString(canonical_str));
+ EXPECT_EQ(canonical_str, str);
+ EXPECT(Dart_IsString(canonical_str));
+ EXPECT(!Dart_IsExternalString(canonical_str));
+ void* peer;
+ EXPECT_VALID(Dart_StringGetProperties(str, &size, &length, &peer));
+ EXPECT_EQ(1, size);
+ EXPECT_EQ(1, length);
+ EXPECT_EQ(reinterpret_cast<void*>(&canonical_str_peer), peer);
+
// Test with a one byte ascii string.
const char* ascii = "string";
expected_length = strlen(ascii);
@@ -7071,9 +7046,11 @@
}
EXPECT_EQ(40, peer8);
EXPECT_EQ(41, peer16);
+ EXPECT_EQ(42, canonical_str_peer);
Isolate::Current()->heap()->CollectGarbage(Heap::kNew);
EXPECT_EQ(80, peer8);
EXPECT_EQ(82, peer16);
+ EXPECT_EQ(42, canonical_str_peer); // "*" Symbol is not removed on GC.
}
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index 8affac2..ba9a4d9 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -408,31 +408,21 @@
deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId;
ASSERT(from != kTagged);
ASSERT(to != kTagged);
- Value* to_value = NULL;
+ Definition* boxed = NULL;
if (from == kUnboxedDouble) {
- BoxDoubleInstr* boxed = new BoxDoubleInstr(use->CopyWithType());
- use->BindTo(boxed);
- InsertBefore(insert_before, boxed, NULL, Definition::kValue);
- to_value = new Value(boxed);
+ boxed = new BoxDoubleInstr(use->CopyWithType());
} else if (from == kUnboxedUint32x4) {
- BoxUint32x4Instr* boxed = new BoxUint32x4Instr(use->CopyWithType());
- use->BindTo(boxed);
- InsertBefore(insert_before, boxed, NULL, Definition::kValue);
- to_value = new Value(boxed);
+ boxed = new BoxUint32x4Instr(use->CopyWithType());
} else if (from == kUnboxedFloat32x4) {
- BoxFloat32x4Instr* boxed = new BoxFloat32x4Instr(use->CopyWithType());
- use->BindTo(boxed);
- InsertBefore(insert_before, boxed, NULL, Definition::kValue);
- to_value = new Value(boxed);
+ boxed = new BoxFloat32x4Instr(use->CopyWithType());
} else if (from == kUnboxedMint) {
- BoxIntegerInstr* boxed = new BoxIntegerInstr(use->CopyWithType());
- use->BindTo(boxed);
- InsertBefore(insert_before, boxed, NULL, Definition::kValue);
- to_value = new Value(boxed);
+ boxed = new BoxIntegerInstr(use->CopyWithType());
} else {
UNIMPLEMENTED();
}
- ASSERT(to_value != NULL);
+ use->BindTo(boxed);
+ InsertBefore(insert_before, boxed, NULL, Definition::kValue);
+ Value* to_value = new Value(boxed);
if (to == kUnboxedDouble) {
converted = new UnboxDoubleInstr(to_value, deopt_id);
} else if (to == kUnboxedUint32x4) {
@@ -6979,6 +6969,7 @@
right,
Object::null_array());
new_equality_compare->set_ic_data(equality_compare->ic_data());
+ new_equality_compare->set_operation_cid(equality_compare->operation_cid());
new_comparison = new_equality_compare;
} else {
ASSERT(comparison->IsRelationalOp());
@@ -6990,6 +6981,7 @@
right,
Object::null_array());
new_relational_op->set_ic_data(relational_op->ic_data());
+ new_relational_op->set_operation_cid(relational_op->operation_cid());
new_comparison = new_relational_op;
}
return new BranchInstr(new_comparison, branch->is_checked());
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index 88ebbab..830ade1 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -3818,10 +3818,10 @@
break;
}
case Token::kADD:
- UNIMPLEMENTED();
+ __ vaddqi(kWord, result, left, right);
break;
case Token::kSUB:
- UNIMPLEMENTED();
+ __ vsubqi(kWord, result, left, right);
break;
default: UNREACHABLE();
}
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index af1c5e6..6fcb9fa 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -13427,6 +13427,24 @@
}
+void OneByteString::SetPeer(const String& str,
+ void* peer,
+ Dart_PeerFinalizer cback) {
+ ASSERT(!str.IsNull() && str.IsOneByteString());
+ ASSERT(peer != NULL);
+ ExternalStringData<uint8_t>* ext_data =
+ new ExternalStringData<uint8_t>(NULL, peer, cback);
+ AddFinalizer(str, ext_data, OneByteString::Finalize);
+ Isolate::Current()->heap()->SetPeer(str.raw(), peer);
+}
+
+
+void OneByteString::Finalize(Dart_WeakPersistentHandle handle, void* peer) {
+ delete reinterpret_cast<ExternalStringData<uint8_t>*>(peer);
+ DeleteWeakPersistentHandle(handle);
+}
+
+
RawTwoByteString* TwoByteString::EscapeSpecialCharacters(const String& str) {
intptr_t len = str.Length();
if (len > 0) {
@@ -13579,6 +13597,24 @@
}
+void TwoByteString::SetPeer(const String& str,
+ void* peer,
+ Dart_PeerFinalizer cback) {
+ ASSERT(!str.IsNull() && str.IsTwoByteString());
+ ASSERT(peer != NULL);
+ ExternalStringData<uint16_t>* ext_data =
+ new ExternalStringData<uint16_t>(NULL, peer, cback);
+ AddFinalizer(str, ext_data, TwoByteString::Finalize);
+ Isolate::Current()->heap()->SetPeer(str.raw(), peer);
+}
+
+
+void TwoByteString::Finalize(Dart_WeakPersistentHandle handle, void* peer) {
+ delete reinterpret_cast<ExternalStringData<uint16_t>*>(peer);
+ DeleteWeakPersistentHandle(handle);
+}
+
+
RawExternalOneByteString* ExternalOneByteString::New(
const uint8_t* data,
intptr_t len,
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 20c508b..d591d4e 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -4608,7 +4608,6 @@
void* peer,
Dart_PeerFinalizer cback) const;
-
// Creates a new String object from a C string that is assumed to contain
// UTF-8 encoded characters and '\0' is considered a termination character.
// TODO(7123) - Rename this to FromCString(....).
@@ -4808,6 +4807,12 @@
intptr_t length,
Heap::Space space);
+ static void SetPeer(const String& str,
+ void* peer,
+ Dart_PeerFinalizer cback);
+
+ static void Finalize(Dart_WeakPersistentHandle handle, void* peer);
+
static const ClassId kClassId = kOneByteStringCid;
static RawOneByteString* null() {
@@ -4890,6 +4895,12 @@
const String& str,
Heap::Space space);
+ static void SetPeer(const String& str,
+ void* peer,
+ Dart_PeerFinalizer cback);
+
+ static void Finalize(Dart_WeakPersistentHandle handle, void* peer);
+
static RawTwoByteString* null() {
return reinterpret_cast<RawTwoByteString*>(Object::null());
}
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 1e96917..36e3deb 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -9287,10 +9287,11 @@
ASSERT(key->IsLiteralNode());
const Instance& new_key = key->AsLiteralNode()->literal();
for (int i = 0; i < pairs->length(); i += 2) {
- const Instance& key_i =
- (*pairs)[i]->AsLiteralNode()->literal();
- ASSERT(key_i.IsString());
- if (new_key.Equals(key_i)) {
+ const Instance& key_i = (*pairs)[i]->AsLiteralNode()->literal();
+ // The keys of a compile time constant map are compile time
+ // constants, i.e. canonicalized values. Thus, we can compare
+ // raw pointers to check for equality.
+ if (new_key.raw() == key_i.raw()) {
// Duplicate key found. The new value replaces the previously
// defined value.
(*pairs)[i + 1] = value;
diff --git a/sdk/lib/_internal/lib/io_patch.dart b/sdk/lib/_internal/lib/io_patch.dart
index 4216317..80725b8 100644
--- a/sdk/lib/_internal/lib/io_patch.dart
+++ b/sdk/lib/_internal/lib/io_patch.dart
@@ -33,13 +33,9 @@
}
patch class _EventHandler {
- patch static void _start() {
- throw new UnsupportedError("EventHandler._start");
- }
-
- patch static _sendData(Object sender,
- ReceivePort receivePort,
- int data) {
+ patch static void _sendData(Object sender,
+ ReceivePort receivePort,
+ int data) {
throw new UnsupportedError("EventHandler._sendData");
}
}
diff --git a/sdk/lib/_internal/pub/lib/src/command/serve.dart b/sdk/lib/_internal/pub/lib/src/command/serve.dart
index ad891dc..6393428 100644
--- a/sdk/lib/_internal/pub/lib/src/command/serve.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/serve.dart
@@ -226,7 +226,8 @@
var subdirectory = path.join(packageDir, name);
var watcher = new DirectoryWatcher(subdirectory);
watcher.events.listen((event) {
- var id = pathToAssetId(package, packageDir, event.path);
+ var id = new AssetId(package,
+ path.relative(event.path, from: packageDir));
if (event.type == ChangeType.REMOVE) {
_barback.removeSources([id]);
} else {
@@ -256,7 +257,8 @@
// Skip directories.
if (!fileExists(entry)) continue;
- files.add(pathToAssetId(package, packageDir, entry));
+ var id = new AssetId(package, path.relative(entry, from: packageDir));
+ files.add(id);
}
}
@@ -270,14 +272,4 @@
if (package == entrypoint.root.name) directories.add("web");
return directories;
}
-
- /// Converts a local file path to an [AssetId].
- AssetId pathToAssetId(String package, String packageDir, String filePath) {
- var relative = path.relative(filePath, from: packageDir);
-
- // AssetId paths use "/" on all platforms.
- relative = path.toUri(relative).path;
-
- return new AssetId(package, relative);
- }
}
diff --git a/sdk/lib/_internal/pub/lib/src/pubspec.dart b/sdk/lib/_internal/pub/lib/src/pubspec.dart
index 6da96ba..56b012b 100644
--- a/sdk/lib/_internal/pub/lib/src/pubspec.dart
+++ b/sdk/lib/_internal/pub/lib/src/pubspec.dart
@@ -121,7 +121,6 @@
Pubspec _parseMap(String filePath, Map map, SourceRegistry sources) {
var name = null;
- var version = Version.none;
if (map.containsKey('name')) {
name = map['name'];
@@ -131,14 +130,14 @@
}
}
- if (map.containsKey('version')) {
- version = new Version.parse(map['version']);
- }
+ var version = _parseVersion(map['version'], (v) =>
+ 'The pubspec "version" field should be a semantic version number, '
+ 'but was "$v".');
- var dependencies = _parseDependencies(filePath, sources,
+ var dependencies = _parseDependencies(name, filePath, sources,
map['dependencies']);
- var devDependencies = _parseDependencies(filePath, sources,
+ var devDependencies = _parseDependencies(name, filePath, sources,
map['dev_dependencies']);
// Make sure the same package doesn't appear as both a regular and dev
@@ -183,14 +182,9 @@
'"$environmentYaml".');
}
- var sdkYaml = environmentYaml['sdk'];
- if (sdkYaml is! String) {
- throw new FormatException(
- 'The "sdk" field of "environment" should be a string, but was '
- '"$sdkYaml".');
- }
-
- sdkConstraint = new VersionConstraint.parse(sdkYaml);
+ sdkConstraint = _parseVersionConstraint(environmentYaml['sdk'], (v) =>
+ 'The "sdk" field of "environment" should be a semantic version '
+ 'constraint, but was "$v".');
}
var environment = new PubspecEnvironment(sdkConstraint);
@@ -241,8 +235,38 @@
environment, map);
}
-List<PackageDep> _parseDependencies(String pubspecPath, SourceRegistry sources,
- yaml) {
+/// Parses [yaml] to a [Version] or throws a [FormatException] with the result
+/// of calling [message] if it isn't valid.
+///
+/// If [yaml] is `null`, returns [Version.none].
+Version _parseVersion(yaml, String message(yaml)) {
+ if (yaml == null) return Version.none;
+ if (yaml is! String) throw new FormatException(message(yaml));
+
+ try {
+ return new Version.parse(yaml);
+ } on FormatException catch(_) {
+ throw new FormatException(message(yaml));
+ }
+}
+
+/// Parses [yaml] to a [VersionConstraint] or throws a [FormatException] with
+/// the result of calling [message] if it isn't valid.
+///
+/// If [yaml] is `null`, returns [VersionConstraint.any].
+VersionConstraint _parseVersionConstraint(yaml, String getMessage(yaml)) {
+ if (yaml == null) return VersionConstraint.any;
+ if (yaml is! String) throw new FormatException(getMessage(yaml));
+
+ try {
+ return new VersionConstraint.parse(yaml);
+ } on FormatException catch(_) {
+ throw new FormatException(getMessage(yaml));
+ }
+}
+
+List<PackageDep> _parseDependencies(String packageName, String pubspecPath,
+ SourceRegistry sources, yaml) {
var dependencies = <PackageDep>[];
// Allow an empty dependencies key.
@@ -255,6 +279,10 @@
}
yaml.forEach((name, spec) {
+ if (name == packageName) {
+ throw new FormatException("Package '$name' cannot depend on itself.");
+ }
+
var description;
var sourceName;
@@ -268,7 +296,9 @@
versionConstraint = new VersionConstraint.parse(spec);
} else if (spec is Map) {
if (spec.containsKey('version')) {
- versionConstraint = new VersionConstraint.parse(spec.remove('version'));
+ versionConstraint = _parseVersionConstraint(spec.remove('version'),
+ (v) => 'The "version" field for $name should be a semantic '
+ 'version constraint, but was "$v".');
}
var sourceNames = spec.keys.toList();
diff --git a/sdk/lib/_internal/pub/lib/src/validator/dependency.dart b/sdk/lib/_internal/pub/lib/src/validator/dependency.dart
index 46e0015..1715240 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/dependency.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/dependency.dart
@@ -22,14 +22,6 @@
return _warnAboutSource(dependency);
}
- if (dependency.name == entrypoint.root.name) {
- warnings.add('You don\'t need to explicitly depend on your own '
- 'package.\n'
- 'Pub enables "package:${entrypoint.root.name}" imports '
- 'implicitly.');
- return new Future.value();
- }
-
if (dependency.constraint.isAny) _warnAboutConstraint(dependency);
return new Future.value();
diff --git a/sdk/lib/_internal/pub/pub.status b/sdk/lib/_internal/pub/pub.status
index 951e99a..56f997a 100644
--- a/sdk/lib/_internal/pub/pub.status
+++ b/sdk/lib/_internal/pub/pub.status
@@ -6,6 +6,12 @@
test/oauth2/with_an_expired_credentials_refreshes_and_saves_test: Pass, Fail # 12581
test/hosted/remove_removed_dependency_test: Pass, Fail # 12582
test/hosted/remove_removed_transitive_dependency_test: Pass, Fail # 12582
+test/install/hosted/cached_pubspec_test: Pass, Fail # 12678
+test/install/hosted/do_not_update_on_removed_constraints_test: Pass, Fail # 12680
+test/install/hosted/install_test: Pass, Fail # 12682
+test/install/hosted/install_transitive_test: Pass, Fail # 12683
+test/install/hosted/repair_cache_test: Pass, Fail # 12684
+pub/test/serve/serve_from_dependency_asset_test: Pass, Fail # 12686
# Pub only runs on the VM, so just rule out all compilers.
[ $compiler == dart2js || $compiler == dart2dart ]
diff --git a/sdk/lib/_internal/pub/test/pub_install_and_update_test.dart b/sdk/lib/_internal/pub/test/pub_install_and_update_test.dart
index f269126..06da50a 100644
--- a/sdk/lib/_internal/pub/test/pub_install_and_update_test.dart
+++ b/sdk/lib/_internal/pub/test/pub_install_and_update_test.dart
@@ -113,5 +113,30 @@
pubCommand(command,
error: new RegExp("^Incompatible dependencies on 'baz':\n"));
});
+
+ integration('does not allow a dependency on itself', () {
+ d.dir(appPath, [
+ d.appPubspec({
+ "myapp": {"path": "."}
+ })
+ ]).create();
+
+ pubCommand(command,
+ error: new RegExp("Package 'myapp' cannot depend on itself."));
+ });
+
+ integration('does not allow a dev dependency on itself', () {
+ d.dir(appPath, [
+ d.pubspec({
+ "name": "myapp",
+ "dev_dependencies": {
+ "myapp": {"path": "."}
+ }
+ })
+ ]).create();
+
+ pubCommand(command,
+ error: new RegExp("Package 'myapp' cannot depend on itself."));
+ });
});
}
diff --git a/sdk/lib/_internal/pub/test/pubspec_test.dart b/sdk/lib/_internal/pub/test/pubspec_test.dart
index 47f838a..092611d 100644
--- a/sdk/lib/_internal/pub/test/pubspec_test.dart
+++ b/sdk/lib/_internal/pub/test/pubspec_test.dart
@@ -103,6 +103,24 @@
''');
});
+ test("throws if it dependes on itself", () {
+ expectFormatError('''
+name: myapp
+dependencies:
+ myapp:
+ mock: ok
+''');
+ });
+
+ test("throws if it has a dev dependency on itself", () {
+ expectFormatError('''
+name: myapp
+dev_dependencies:
+ myapp:
+ mock: ok
+''');
+ });
+
test("throws if the description isn't valid", () {
expectFormatError('''
dependencies:
@@ -111,10 +129,40 @@
''');
});
+ test("throws if dependency version is not a string", () {
+ expectFormatError('''
+dependencies:
+ foo:
+ mock: ok
+ version: 1.2
+''');
+ });
+
+ test("throws if version is not a version constraint", () {
+ expectFormatError('''
+dependencies:
+ foo:
+ mock: ok
+ version: not constraint
+''');
+ });
+
test("throws if 'name' is not a string", () {
expectFormatError('name: [not, a, string]');
});
+ test("throws if version is not a string", () {
+ expectFormatError('''
+version: 1.0
+''');
+ });
+
+ test("throws if version is not a version", () {
+ expectFormatError('''
+version: not version
+''');
+ });
+
test("throws if 'homepage' is not a string", () {
expectFormatError('homepage:');
expectFormatError('homepage: [not, a, string]');
@@ -212,6 +260,13 @@
''');
});
+ test("throws if the sdk is not a string", () {
+ expectFormatError('''
+environment:
+ sdk: 1.0
+''');
+ });
+
test("throws if the sdk isn't a valid version constraint", () {
expectFormatError('''
environment:
diff --git a/sdk/lib/_internal/pub/test/validator/dependency_test.dart b/sdk/lib/_internal/pub/test/validator/dependency_test.dart
index ee38ee8..ba29373 100644
--- a/sdk/lib/_internal/pub/test/validator/dependency_test.dart
+++ b/sdk/lib/_internal/pub/test/validator/dependency_test.dart
@@ -237,15 +237,5 @@
});
});
});
-
- integration('has a hosted dependency on itself', () {
- d.dir(appPath, [
- d.libPubspec("test_pkg", "1.0.0", deps: {
- "test_pkg": ">=1.0.0"
- })
- ]).create();
-
- expectValidationWarning(dependency);
- });
});
}
diff --git a/sdk/lib/async/timer.dart b/sdk/lib/async/timer.dart
index ed8103f..6c15c4b 100644
--- a/sdk/lib/async/timer.dart
+++ b/sdk/lib/async/timer.dart
@@ -25,7 +25,8 @@
* var duration = milliseconds == null ? TIMEOUT : ms * milliseconds;
* return new Timer(duration, handleTimeout);
* }
- * void handleTimeout(Timer _) { // callback function
+ * ...
+ * void handleTimeout() { // callback function
* ...
* }
*
diff --git a/sdk/lib/convert/ascii.dart b/sdk/lib/convert/ascii.dart
new file mode 100644
index 0000000..bea9680
--- /dev/null
+++ b/sdk/lib/convert/ascii.dart
@@ -0,0 +1,285 @@
+// Copyright (c) 2013, 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.
+
+part of dart.convert;
+
+/**
+ * An instance of the default implementation of the [AsciiCodec].
+ *
+ * This instance provides a convenient access to the most common ASCII
+ * use cases.
+ *
+ * Examples:
+ *
+ * var encoded = ASCII.encode("This is ASCII!");
+ * var decoded = ASCII.decode([0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73,
+ * 0x20, 0x41, 0x53, 0x43, 0x49, 0x49, 0x21]);
+ */
+const ASCII = const AsciiCodec();
+
+const int _ASCII_MASK = 0x7F;
+
+/**
+ * An [AsciiCodec] allows encoding strings as ASCII bytes
+ * and decoding ASCII bytes to strings.
+ */
+class AsciiCodec extends _Encoding {
+ final bool _allowInvalid;
+ /**
+ * Instantiates a new [AsciiCodec].
+ *
+ * If [allowInvalid] is true, the [decode] method and the converter
+ * returned by [decoder] will default to allowing invalid values.
+ * If allowing invalid values, the values will be decoded into the Unicode
+ * Replacement character (U+FFFD). If not, an exception will be thrown.
+ * Calls to the [decode] method can choose to override this default.
+ *
+ * Encoders will not accept invalid (non Latin-1) characters.
+ */
+ const AsciiCodec({bool allowInvalid: false}) : _allowInvalid = allowInvalid;
+
+ /**
+ * Decodes the ASCII [bytes] (a list of unsigned 7-bit integers) to the
+ * corresponding string.
+ *
+ * If [bytes] contains values that are not in the range 0 .. 127, the decoder
+ * will eventually throw a [FormatException].
+ *
+ * If [allowInvalid] is not provided, it defaults to the value used to create
+ * this [AsciiCodec].
+ */
+ String decode(List<int> bytes, { bool allowInvalid }) {
+ if (allowInvalid == null) allowInvalid = _allowInvalid;
+ if (allowInvalid) {
+ return const AsciiDecoder(allowInvalid: true).convert(bytes);
+ } else {
+ return const AsciiDecoder(allowInvalid: false).convert(bytes);
+ }
+ }
+
+ Converter<String, List<int>> get encoder => const AsciiEncoder();
+
+ Converter<List<int>, String> get decoder =>
+ _allowInvalid ? const AsciiDecoder(allowInvalid: true)
+ : const AsciiDecoder(allowInvalid: false);
+}
+
+// Superclass for [AsciiEncoder] and [Latin1Encoder].
+// Generalizes common operations that only differ by a mask;
+class _UnicodeSubsetEncoder extends Converter<String, List<int>> {
+ final int _subsetMask;
+
+ const _UnicodeSubsetEncoder(this._subsetMask);
+
+ List<int> convert(String string) {
+ // TODO(11971): Use Uint8List when possible.
+ List result = new List<int>(string.length);
+ for (int i = 0; i < string.length; i++) {
+ var codeUnit = string.codeUnitAt(i);
+ if ((codeUnit & ~_subsetMask) != 0) {
+ throw new ArgumentError("String contains invalid characters.");
+ }
+ result[i] = codeUnit;
+ }
+ return result;
+ }
+
+ /**
+ * Starts a chunked conversion.
+ *
+ * The converter works more efficiently if the given [sink] is a
+ * [ByteConversionSink].
+ */
+ StringConversionSink startChunkedConversion(
+ ChunkedConversionSink<List<int>> sink) {
+ if (sink is! ByteConversionSink) {
+ sink = new ByteConversionSink.from(sink);
+ }
+ return new _UnicodeSubsetEncoderSink(_subsetMask, sink);
+ }
+
+ // Override the base-class' bind, to provide a better type.
+ Stream<List<int>> bind(Stream<String> stream) => super.bind(stream);
+}
+
+/**
+ * This class converts strings of only ASCII characters to bytes.
+ */
+class AsciiEncoder extends _UnicodeSubsetEncoder {
+ const AsciiEncoder() : super(_ASCII_MASK);
+}
+
+/**
+ * This class encodes chunked strings to bytes (unsigned 8-bit
+ * integers).
+ */
+class _UnicodeSubsetEncoderSink extends StringConversionSinkBase {
+ final ByteConversionSink _sink;
+ final int _subsetMask;
+
+ _UnicodeSubsetEncoderSink(this._subsetMask, this._sink);
+
+ void close() {
+ _sink.close();
+ }
+
+ void addSlice(String source, int start, int end, bool isLast) {
+ if (start < 0 || start > source.length) {
+ throw new RangeError.range(start, 0, source.length);
+ }
+ if (end < start || end > source.length) {
+ throw new RangeError.range(end, start, source.length);
+ }
+ for (int i = start; i < end; i++) {
+ int codeUnit = source.codeUnitAt(i);
+ if ((codeUnit & ~_subsetMask) != 0) {
+ throw new ArgumentError(
+ "Source contains invalid character with code point: $codeUnit.");
+ }
+ }
+ _sink.add(source.codeUnits);
+ if (isLast) {
+ close();
+ }
+ }
+}
+
+/**
+ * This class converts Latin-1 bytes (lists of unsigned 8-bit integers)
+ * to a string.
+ */
+abstract class _UnicodeSubsetDecoder extends Converter<List<int>, String> {
+ final bool _allowInvalid;
+ final int _subsetMask;
+
+ /**
+ * Instantiates a new decoder.
+ *
+ * The [_allowInvalid] argument defines how [convert] deals
+ * with invalid bytes.
+ *
+ * The [_subsetMask] argument is a bit mask used to define the subset
+ * of Unicode being decoded. Use [_LATIN1_MASK] for Latin-1 (8-bit) or
+ * [_ASCII_MASK] for ASCII (7-bit).
+ *
+ * If [_allowInvalid] is `true`, [convert] replaces invalid bytes with the
+ * Unicode Replacement character `U+FFFD` (�).
+ * Otherwise it throws a [FormatException].
+ */
+ const _UnicodeSubsetDecoder(this._allowInvalid, this._subsetMask);
+
+ /**
+ * Converts the [bytes] (a list of unsigned 7- or 8-bit integers) to the
+ * corresponding string.
+ */
+ String convert(List<int> bytes) {
+ for (int i = 0; i < bytes.length; i++) {
+ int byte = bytes[i];
+ if ((byte & ~_subsetMask) != 0) {
+ if (!_allowInvalid) {
+ throw new FormatException("Invalid value in input: $byte");
+ }
+ return _convertInvalid(bytes);
+ }
+ }
+ return new String.fromCharCodes(bytes);
+ }
+
+ String _convertInvalid(List<int> bytes) {
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0; i < bytes.length; i++) {
+ int value = bytes[i];
+ if ((value & ~_subsetMask) != 0) value = 0xFFFD;
+ buffer.writeCharCode(value);
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Starts a chunked conversion.
+ *
+ * The converter works more efficiently if the given [sink] is a
+ * [StringConversionSink].
+ */
+ ByteConversionSink startChunkedConversion(
+ ChunkedConversionSink<String> sink) {
+ StringConversionSink stringSink;
+ if (sink is StringConversionSink) {
+ stringSink = sink;
+ } else {
+ stringSink = new StringConversionSink.from(sink);
+ }
+ // TODO(lrn): Use stringSink.asUtf16Sink() if it becomes available.
+ return new _Latin1DecoderSink(_allowInvalid, stringSink);
+ }
+
+ // Override the base-class's bind, to provide a better type.
+ Stream<String> bind(Stream<List<int>> stream) => super.bind(stream);
+}
+
+class AsciiDecoder extends _UnicodeSubsetDecoder {
+ const AsciiDecoder({bool allowInvalid: false})
+ : super(allowInvalid, _ASCII_MASK);
+
+ /**
+ * Starts a chunked conversion.
+ *
+ * The converter works more efficiently if the given [sink] is a
+ * [StringConversionSink].
+ */
+ ByteConversionSink startChunkedConversion(
+ ChunkedConversionSink<String> sink) {
+ StringConversionSink stringSink;
+ if (sink is StringConversionSink) {
+ stringSink = sink;
+ } else {
+ stringSink = new StringConversionSink.from(sink);
+ }
+ // TODO(lrn): Use asUtf16Sink when it becomes available. It
+ // works just as well, is likely to have less decoding overhead,
+ // and make adding U+FFFD easier.
+ // At that time, merge this with _Latin1DecoderSink;
+ return new _AsciiDecoderSink(_allowInvalid, stringSink.asUtf8Sink(false));
+ }
+}
+
+class _AsciiDecoderSink extends ByteConversionSinkBase {
+ final bool _allowInvalid;
+ ByteConversionSink _utf8Sink;
+ _AsciiDecoderSink(this._allowInvalid, this._utf8Sink);
+
+ void close() {
+ _utf8Sink.close();
+ }
+
+ void add(List<int> source) {
+ addSlice(source, 0, source.length, false);
+ }
+
+ void addSlice(List<int> source, int start, int end, bool isLast) {
+ if (start < 0 || start > source.length) {
+ throw new RangeError.range(start, 0, source.length);
+ }
+ if (end < start || end > source.length) {
+ throw new RangeError.range(end, start, source.length);
+ }
+ for (int i = start; i < end; i++) {
+ if ((source[i] & ~_ASCII_MASK) != 0) {
+ if (_allowInvalid) {
+ if (i > start) _utf8Sink.addSlice(source, start, i, false);
+ // Add UTF-8 encoding of U+FFFD.
+ _utf8Sink.add(const<int>[0xEF, 0xBF, 0xBD]);
+ start = i + 1;
+ } else {
+ throw new FormatException("Source contains non-ASCII bytes.");
+ }
+ }
+ }
+ if (start < end) {
+ _utf8Sink.addSlice(source, start, end, isLast);
+ } else if (isLast) {
+ close();
+ }
+ }
+}
diff --git a/sdk/lib/convert/convert.dart b/sdk/lib/convert/convert.dart
index 3e9b6f5..5cca4d4 100644
--- a/sdk/lib/convert/convert.dart
+++ b/sdk/lib/convert/convert.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
/**
- * Converters for JSON and UTF-8, as well as support for creating additional
+ * Converters for JSON and UTF-8, as well as support for creating additional
* converters.
*/
library dart.convert;
@@ -11,12 +11,14 @@
import 'dart:async';
import 'dart:json' as OLD_JSON_LIB;
+part 'ascii.dart';
part 'byte_conversion.dart';
part 'chunked_conversion.dart';
part 'codec.dart';
part 'converter.dart';
part 'encoding.dart';
part 'json.dart';
+part 'latin1.dart';
part 'line_splitter.dart';
part 'string_conversion.dart';
part 'utf.dart';
diff --git a/sdk/lib/convert/convert_sources.gypi b/sdk/lib/convert/convert_sources.gypi
index eaf9952..35a825f 100644
--- a/sdk/lib/convert/convert_sources.gypi
+++ b/sdk/lib/convert/convert_sources.gypi
@@ -7,12 +7,14 @@
'sources': [
'convert.dart',
# The above file needs to be first as it lists the parts below.
+ 'ascii.dart',
'byte_conversion.dart',
'chunked_conversion.dart',
'codec.dart',
'converter.dart',
'encoding.dart',
'json.dart',
+ 'latin1.dart',
'line_splitter.dart',
'string_conversion.dart',
'utf.dart',
diff --git a/sdk/lib/convert/latin1.dart b/sdk/lib/convert/latin1.dart
new file mode 100644
index 0000000..3e9232f
--- /dev/null
+++ b/sdk/lib/convert/latin1.dart
@@ -0,0 +1,158 @@
+// Copyright (c) 2013, 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.
+
+part of dart.convert;
+
+/**
+ * An instance of the default implementation of the [Latin1Codec].
+ *
+ * This instance provides a convenient access to the most common ISO Latin 1
+ * use cases.
+ *
+ * Examples:
+ *
+ * var encoded = LATIN1.encode("blåbærgrød");
+ * var decoded = LATIN1.decode([0x62, 0x6c, 0xe5, 0x62, 0xe6,
+ * 0x72, 0x67, 0x72, 0xf8, 0x64]);
+ */
+const LATIN1 = const Latin1Codec();
+
+const int _LATIN1_MASK = 0xFF;
+
+/**
+ * A [LatinCodec] encodes strings to ISO Latin-1 (aka ISO-8859-1) bytes
+ * and decodes Latin-1 bytes to strings.
+ */
+class Latin1Codec extends _Encoding {
+ final bool _allowInvalid;
+ /**
+ * Instantiates a new [Latin1Codec].
+ *
+ * If [allowInvalid] is true, the [decode] method and the converter
+ * returned by [decoder] will default to allowing invalid values. Invalid
+ * values are decoded into the Unicode Replacement character (U+FFFD).
+ * Calls to the [decode] method can override this default.
+ *
+ * Encoders will not accept invalid (non Latin-1) characters.
+ */
+ const Latin1Codec({bool allowInvalid: false}) : _allowInvalid = allowInvalid;
+
+ /**
+ * Decodes the Latin-1 [bytes] (a list of unsigned 8-bit integers) to the
+ * corresponding string.
+ *
+ * If [bytes] contains values that are not in the range 0 .. 255, the decoder
+ * will eventually throw a [FormatException].
+ *
+ * If [allowInvalid] is not provided, it defaults to the value used to create
+ * this [Latin1Codec].
+ */
+ String decode(List<int> bytes, { bool allowInvalid }) {
+ if (allowInvalid == null) allowInvalid = _allowInvalid;
+ if (allowInvalid) {
+ return const Latin1Decoder(allowInvalid: true).convert(bytes);
+ } else {
+ return const Latin1Decoder(allowInvalid: false).convert(bytes);
+ }
+ }
+
+ Converter<String, List<int>> get encoder => const Latin1Encoder();
+
+ Converter<List<int>, String> get decoder =>
+ _allowInvalid ? const Latin1Decoder(allowInvalid: true)
+ : const Latin1Decoder(allowInvalid: false);
+}
+
+/**
+ * This class converts strings of only ISO Latin-1 characters to bytes.
+ */
+class Latin1Encoder extends _UnicodeSubsetEncoder {
+ const Latin1Encoder() : super(_LATIN1_MASK);
+}
+
+/**
+ * This class converts Latin-1 bytes (lists of unsigned 8-bit integers)
+ * to a string.
+ */
+class Latin1Decoder extends _UnicodeSubsetDecoder {
+ /**
+ * Instantiates a new [Latin1Decoder].
+ *
+ * The optional [allowInvalid] argument defines how [convert] deals
+ * with invalid bytes.
+ *
+ * If it is `true`, [convert] replaces invalid bytes with the Unicode
+ * Replacement character `U+FFFD` (�).
+ * Otherwise it throws a [FormatException].
+ */
+ const Latin1Decoder({ bool allowInvalid: false })
+ : super(allowInvalid, _LATIN1_MASK);
+
+ /**
+ * Starts a chunked conversion.
+ *
+ * The converter works more efficiently if the given [sink] is a
+ * [StringConversionSink].
+ */
+ ByteConversionSink startChunkedConversion(
+ ChunkedConversionSink<String> sink) {
+ StringConversionSink stringSink;
+ if (sink is StringConversionSink) {
+ stringSink = sink;
+ } else {
+ stringSink = new StringConversionSink.from(sink);
+ }
+ // TODO(lrn): Use stringSink.asUtf16Sink() if it becomes available.
+ return new _Latin1DecoderSink(_allowInvalid, stringSink);
+ }
+}
+
+class _Latin1DecoderSink extends ByteConversionSinkBase {
+ final bool _allowInvalid;
+ StringConversionSink _sink;
+ _Latin1DecoderSink(this._allowInvalid, this._sink);
+
+ void close() {
+ _sink.close();
+ }
+
+ void add(List<int> source) {
+ addSlice(source, 0, source.length, false);
+ }
+
+ void _addSliceToSink(List<int> source, int start, int end, bool isLast) {
+ // If _sink was a UTF-16 conversion sink, just add the slice directly with
+ // _sink.addSlice(source, start, end, isLast).
+ // The code below is an incredibly stupid workaround until a real
+ // solution can be made.
+ _sink.add(new String.fromCharCodes(source.getRange(start, end)));
+ if (isLast) close();
+ }
+
+ void addSlice(List<int> source, int start, int end, bool isLast) {
+ if (start < 0 || start > source.length) {
+ throw new RangeError.range(start, 0, source.length);
+ }
+ if (end < start || end > source.length) {
+ throw new RangeError.range(end, start, source.length);
+ }
+ for (int i = start; i < end; i++) {
+ if ((source[i] & ~_LATIN1_MASK) != 0) {
+ if (_allowInvalid) {
+ if (i > start) _addSliceToSink(source, start, i, false);
+ // Add UTF-8 encoding of U+FFFD.
+ _addSliceToSink(const[0xFFFD], 0, 1, false);
+ start = i + 1;
+ } else {
+ throw new FormatException("Source contains non-Latin-1 characters.");
+ }
+ }
+ }
+ if (start < end) {
+ _addSliceToSink(source, start, end, isLast);
+ } else if (isLast) {
+ close();
+ }
+ }
+}
diff --git a/sdk/lib/convert/string_conversion.dart b/sdk/lib/convert/string_conversion.dart
index ee0d135..4a90cfa 100644
--- a/sdk/lib/convert/string_conversion.dart
+++ b/sdk/lib/convert/string_conversion.dart
@@ -299,7 +299,6 @@
*/
// TODO(floitsch): make this class public?
class _Utf8ConversionSink extends ByteConversionSink {
- static const _MIN_STRING_SIZE = 16;
final _Utf8Decoder _decoder;
final StringConversionSink _chunkedSink;
@@ -327,10 +326,9 @@
addSlice(chunk, 0, chunk.length, false);
}
- void addSlice(List<int> chunk, int startIndex, int endIndex,
- bool isLast) {
+ void addSlice(List<int> chunk, int startIndex, int endIndex, bool isLast) {
_decoder.convert(chunk, startIndex, endIndex);
- if (_buffer.length > _MIN_STRING_SIZE) {
+ if (_buffer.isNotEmpty) {
String accumulated = _buffer.toString();
_chunkedSink.addSlice(accumulated, 0, accumulated.length, isLast);
_buffer.clear();
diff --git a/sdk/lib/convert/utf.dart b/sdk/lib/convert/utf.dart
index 80f7a78..37f2335 100644
--- a/sdk/lib/convert/utf.dart
+++ b/sdk/lib/convert/utf.dart
@@ -455,7 +455,19 @@
while (i < endIndex) {
int unit = codeUnits[i++];
- if (unit <= _ONE_BYTE_LIMIT) {
+ // TODO(floitsch): the way we test we could potentially allow
+ // units that are too large, if they happen to have the
+ // right bit-pattern. (Same is true for the multibyte loop above).
+ // TODO(floitsch): optimize this loop. See:
+ // https://codereview.chromium.org/22929022/diff/1/sdk/lib/convert/utf.dart?column_width=80
+ if (unit < 0) {
+ // TODO(floitsch): should this be unit <= 0 ?
+ if (!_allowMalformed) {
+ throw new FormatException(
+ "Negative UTF-8 code unit: -0x${(-unit).toRadixString(16)}");
+ }
+ _stringSink.writeCharCode(_REPLACEMENT_CHARACTER);
+ } else if (unit <= _ONE_BYTE_LIMIT) {
_isFirstCharacter = false;
_stringSink.writeCharCode(unit);
} else {
diff --git a/sdk/lib/core/core.dart b/sdk/lib/core/core.dart
index 6cfe998..a902226 100644
--- a/sdk/lib/core/core.dart
+++ b/sdk/lib/core/core.dart
@@ -7,62 +7,87 @@
* Built-in types, collections,
* and other core functionality for every Dart program.
*
+ * This library is automatically imported.
+ *
* Some classes in this library,
* such as [String] and [num],
* support Dart's built-in data types.
- * Other classes provide data structures
+ * Other classes, such as [List] and [Map], provide data structures
* for managing collections of objects.
* And still other classes represent commonly used types of data
- * such as URIs, dates, and times.
+ * such as URIs, dates and times, and errors.
*
+ * ## Numbers and booleans
*
- * ## Built-in types
+ * [int] and [double] provide support for Dart's built-in numerical data types:
+ * integers and double-precision floating point numbers, respectively.
+ * An object of type [bool] is either true or false.
+ * Variables of these types can be constructed from literals:
*
- * [String], [int], [double], [bool], [List], and [Map]
- * provide support for Dart's built-in data types.
- * To declare and initialize variables of these types, write:
- * String myString = 'A sequence of characters.';
* int meaningOfLife = 42;
* double valueOfPi = 3.141592;
* bool visible = true;
- * List superHeros = [ 'Batman', 'Superman', 'Harry Potter' ];
- * Map sidekicks = { 'Batman': 'Robin',
- * 'Superman': 'Lois Lane',
- * 'Harry Potter': 'Ron and Hermione' };
*
- * ## Strings
+ * ## Strings and regular expressions
*
* A [String] is immutable and represents a sequence of characters.
- * [StringBuffer] provides a way to construct strings efficiently.
- *
- * The Dart language uses the [String] and [StringBuffer]
- * behind the scenes to implement string concatenation, interpolation,
- * and other features.
- * String myString = 'Live on ';
- * String get palindrome => myString + myString.split('').reversed.join();
*
+ * String shakespeareQuote = "All the world's a stage, ...";
+ *
+ * [StringBuffer] provides a way to construct strings efficiently.
+ *
+ * StringBuffer moreShakespeare = new StringBuffer();
+ * moreShakespeare.write('And all the men and women ');
+ * moreShakespeare.write('merely players; ...');
+ *
+ * The String and StringBuffer classes implement string concatenation,
+ * interpolation, and other string manipulation features.
+ *
+ * String philosophy = 'Live on ';
+ * String get palindrome => philosophy + philosophy.split('').reversed.join();
+ *
+ * [RegExp] implements Dart regular expressions,
+ * which provide a grammar for matching patterns within text.
+ * For example, here's a regular expression that matches
+ * a string of one or more digits:
+ *
+ * var numbers = new RegExp(r'\d+');
+ *
+ * Dart regular expressions have the same syntax and semantics as
+ * JavaScript regular expressions. See
+ * <http://ecma-international.org/ecma-262/5.1/#sec-15.10>
+ * for the specification of JavaScript regular expressions.
*
* ## Collections
*
* The dart:core library provides basic collections,
* such as [List], [Map], and [Set].
*
- * * A [List] is an ordered collection of objects, with a length.
+ * A List is an ordered collection of objects, with a length.
* Lists are sometimes called arrays.
* Use a List when you need to access objects by index.
*
- * * A [Set] is an unordered collection of unique objects.
+ * List superheroes = [ 'Batman', 'Superman', 'Harry Potter' ];
+ *
+ * A Set is an unordered collection of unique objects.
* You cannot get an item by index (position).
* Adding a duplicate item has no effect.
- * Use a [Set] when you need to guarantee object uniqueness.
*
- * * A [Map] is an unordered collection of key-value pairs.
+ * Set villians = new Set();
+ * villians.add('Joker');
+ * villians.addAll( ['Lex Luther', 'Voldemort'] );
+ *
+ * A Map is an unordered collection of key-value pairs.
* Maps are sometimes called associative arrays because
* maps associate a key to some value for easy retrieval.
* Keys are unique.
- * Use a [Map] when you need to access objects
+ * Use a Map when you need to access objects
* by a unique identifier.
*
+ * Map sidekicks = { 'Batman': 'Robin',
+ * 'Superman': 'Lois Lane',
+ * 'Harry Potter': 'Ron and Hermione' };
+ *
* In addition to these classes,
* dart:core contains [Iterable],
* an interface that defines functionality
@@ -72,30 +97,43 @@
* to apply a test to each element,
* to retrieve an object, and to determine length.
*
- * Iterable is implemented by [List] and [Set],
- * and used by [Map] for its lists of keys and values.
+ * Iterable is implemented by List and Set,
+ * and used by Map for its keys and values.
*
- * For other kinds of collections, check out the dart:collection library.
+ * For other kinds of collections, check out the
+ * [dart:collection](#dart-collection) library.
*
* ## Date and time
*
* Use [DateTime] to represent a point in time
* and [Duration] to represent a span of time.
*
- * You can create [DateTime] objects with constructors
+ * You can create DateTime objects with constructors
* or by parsing a correctly formatted string.
+ *
* DateTime now = new DateTime.now();
* DateTime berlinWallFell = new DateTime(1989, 11, 9);
* DateTime moonLanding = DateTime.parse("1969-07-20");
*
- * Create a [Duration] object specifying the individual time units.
+ * Create a Duration object specifying the individual time units.
+ *
* Duration timeRemaining = new Duration(hours:56, minutes:14);
+ *
+ * In addition to DateTime and Duration,
+ * dart:core contains the [Stopwatch] class for measuring elapsed time.
*
* ## Uri
*
* A [Uri] object represents a uniform resource identifier,
* which identifies a resource on the web.
+ *
* Uri dartlang = Uri.parse('http://dartlang.org/');
+ *
+ * ## Errors
+ *
+ * The [Error] class represents the occurrence of an error
+ * during runtime.
+ * Subclasses of this class represent specific kinds of errors.
*
* ## Other documentation
*
@@ -108,9 +146,10 @@
* [dart:core - Numbers, Collections, Strings, and More](http://www.dartlang.org/docs/dart-up-and-running/contents/ch03.html#ch03-dartcore---strings-collections-and-more)
* for more coverage of classes in this package.
*
+ * The
+ * [Dart Language Specification](https://www.dartlang.org/docs/spec/)
+ * provides technical details.
*/
-
-
library dart.core;
import "dart:collection";
diff --git a/sdk/lib/core/date_time.dart b/sdk/lib/core/date_time.dart
index 39a5f2f..0b4a63a 100644
--- a/sdk/lib/core/date_time.dart
+++ b/sdk/lib/core/date_time.dart
@@ -506,7 +506,7 @@
*
* DateTime moonLanding = DateTime.parse("1969-07-20 20:18:00");
* assert(moonLanding.month == 7);
- * assert(moonLanding.month == JULY);
+ * assert(moonLanding.month == DateTime.JULY);
*/
external int get month;
diff --git a/sdk/lib/core/map.dart b/sdk/lib/core/map.dart
index e74b936..e5ccb87 100644
--- a/sdk/lib/core/map.dart
+++ b/sdk/lib/core/map.dart
@@ -5,27 +5,32 @@
part of dart.core;
/**
- * A [Map] is an associative container, mapping a key to a value.
+ * An unordered collection of key-value pairs,
+ * from which you retrieve a value by using its associated key.
+ *
+ * Each key must be unique.
* Null values are supported, but null keys are not.
*/
abstract class Map<K, V> {
/**
- * Creates a map with the default implementation.
+ * Creates a Map instance with the default implementation.
*/
factory Map() => new HashMap<K, V>();
/**
- * Creates a [Map] that contains all key value pairs of [other].
+ * Creates a Map instance that contains all key-value pairs of [other].
*/
factory Map.from(Map<K, V> other) => new HashMap<K, V>.from(other);
/**
- * Creates a [Map] where the keys and values are computed from the [iterable].
+ * Creates a Map instance
+ * where the keys and values are computed from the [iterable].
*
- * For each element of the [iterable] this constructor computes a key/value
+ * For each element of the [iterable] this constructor computes a key-value
* pair, by applying [key] and [value] respectively.
*
- * The keys of the key/value pairs do not need to be unique. The last
+ * The keys computed by the source [iterable]
+ * do not need to be unique. The last
* occurrence of a key will simply overwrite any previous value.
*
* If no values are specified for [key] and [value] the default is the
@@ -35,7 +40,7 @@
{K key(element), V value(element)}) = HashMap<K, V>.fromIterable;
/**
- * Creates a [Map] associating the given [keys] to [values].
+ * Creates a Map instance associating the given [keys] to [values].
*
* This constructor iterates over [keys] and [values] and maps each element of
* [keys] to the corresponding element of [values].
@@ -49,19 +54,19 @@
= HashMap<K, V>.fromIterables;
/**
- * Returns whether this map contains the given [value].
+ * Returns true if this map contains the given value.
*/
bool containsValue(Object value);
/**
- * Returns whether this map contains the given [key].
+ * Returns true if this map contains the given key.
*/
bool containsKey(Object key);
/**
* Returns the value for the given [key] or null if [key] is not
* in the map. Because null values are supported, one should either
- * use containsKey to distinguish between an absent key and a null
+ * use [containsKey] to distinguish between an absent key and a null
* value, or use the [putIfAbsent] method.
*/
V operator [](Object key);
@@ -76,7 +81,7 @@
* updates the map by mapping [key] to the value returned by
* [ifAbsent]. Returns the value in the map.
*
- * It is an error to add or remove keys from map during the call to
+ * It is an error to add or remove keys from the map during the call to
* [ifAbsent].
*/
V putIfAbsent(K key, V ifAbsent());
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index b584d35..b527e44 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -7183,6 +7183,12 @@
@DocsEditable()
Event $dom_createEvent(String eventType) native;
+ @JSName('createNodeIterator')
+ @DomName('Document.createNodeIterator')
+ @DocsEditable()
+ @Unstable()
+ NodeIterator $dom_createNodeIterator(Node root, [int whatToShow, NodeFilter filter, bool expandEntityReferences]) native;
+
@JSName('createRange')
@DomName('Document.createRange')
@DocsEditable()
@@ -7216,6 +7222,11 @@
@Experimental()
TouchList $dom_createTouchList() native;
+ @JSName('createTreeWalker')
+ @DomName('Document.createTreeWalker')
+ @DocsEditable()
+ TreeWalker $dom_createTreeWalker(Node root, [int whatToShow, NodeFilter filter, bool expandEntityReferences]) native;
+
@JSName('elementFromPoint')
@DomName('Document.elementFromPoint')
@DocsEditable()
@@ -17904,6 +17915,47 @@
@DocsEditable()
static const int SHOW_TEXT = 0x00000004;
}
+// Copyright (c) 2013, 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.
+
+
+@DomName('NodeIterator')
+@Unstable()
+class NodeIterator extends Interceptor native "NodeIterator" {
+ factory NodeIterator(Node root, int whatToShow) {
+ return document.$dom_createNodeIterator(root, whatToShow, null, false);
+ }
+
+ @DomName('NodeIterator.pointerBeforeReferenceNode')
+ @DocsEditable()
+ final bool pointerBeforeReferenceNode;
+
+ @DomName('NodeIterator.referenceNode')
+ @DocsEditable()
+ final Node referenceNode;
+
+ @DomName('NodeIterator.root')
+ @DocsEditable()
+ final Node root;
+
+ @DomName('NodeIterator.whatToShow')
+ @DocsEditable()
+ final int whatToShow;
+
+ @DomName('NodeIterator.detach')
+ @DocsEditable()
+ void detach() native;
+
+ @DomName('NodeIterator.nextNode')
+ @DocsEditable()
+ Node nextNode() native;
+
+ @DomName('NodeIterator.previousNode')
+ @DocsEditable()
+ Node previousNode() native;
+
+}
// Copyright (c) 2012, 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.
@@ -23609,6 +23661,69 @@
@DocsEditable()
final String pseudoElement;
}
+// Copyright (c) 2013, 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.
+
+
+@DomName('TreeWalker')
+@Unstable()
+class TreeWalker extends Interceptor native "TreeWalker" {
+ factory TreeWalker(Node root, int whatToShow) {
+ return document.$dom_createTreeWalker(root, whatToShow, null, false);
+ }
+
+ @DomName('TreeWalker.currentNode')
+ @DocsEditable()
+ Node currentNode;
+
+ @DomName('TreeWalker.expandEntityReferences')
+ @DocsEditable()
+ // http://dom.spec.whatwg.org/#dom-traversal
+ @deprecated // deprecated
+ final bool expandEntityReferences;
+
+ @DomName('TreeWalker.filter')
+ @DocsEditable()
+ final NodeFilter filter;
+
+ @DomName('TreeWalker.root')
+ @DocsEditable()
+ final Node root;
+
+ @DomName('TreeWalker.whatToShow')
+ @DocsEditable()
+ final int whatToShow;
+
+ @DomName('TreeWalker.firstChild')
+ @DocsEditable()
+ Node firstChild() native;
+
+ @DomName('TreeWalker.lastChild')
+ @DocsEditable()
+ Node lastChild() native;
+
+ @DomName('TreeWalker.nextNode')
+ @DocsEditable()
+ Node nextNode() native;
+
+ @DomName('TreeWalker.nextSibling')
+ @DocsEditable()
+ Node nextSibling() native;
+
+ @DomName('TreeWalker.parentNode')
+ @DocsEditable()
+ Node parentNode() native;
+
+ @DomName('TreeWalker.previousNode')
+ @DocsEditable()
+ Node previousNode() native;
+
+ @DomName('TreeWalker.previousSibling')
+ @DocsEditable()
+ Node previousSibling() native;
+
+}
// Copyright (c) 2012, 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.
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index dc81135..1fe8297 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -7724,6 +7724,27 @@
@DocsEditable()
Event $dom_createEvent(String eventType) native "Document_createEvent_Callback";
+ NodeIterator $dom_createNodeIterator(Node root, [int whatToShow, NodeFilter filter, bool expandEntityReferences]) {
+ if (expandEntityReferences != null) {
+ return _createNodeIterator_1(root, whatToShow, filter, expandEntityReferences);
+ }
+ if (filter != null) {
+ return _createNodeIterator_2(root, whatToShow, filter);
+ }
+ if (whatToShow != null) {
+ return _createNodeIterator_3(root, whatToShow);
+ }
+ return _createNodeIterator_4(root);
+ }
+
+ NodeIterator _createNodeIterator_1(root, whatToShow, filter, expandEntityReferences) native "Document__createNodeIterator_1_Callback";
+
+ NodeIterator _createNodeIterator_2(root, whatToShow, filter) native "Document__createNodeIterator_2_Callback";
+
+ NodeIterator _createNodeIterator_3(root, whatToShow) native "Document__createNodeIterator_3_Callback";
+
+ NodeIterator _createNodeIterator_4(root) native "Document__createNodeIterator_4_Callback";
+
@DomName('Document.createRange')
@DocsEditable()
Range $dom_createRange() native "Document_createRange_Callback";
@@ -7745,6 +7766,27 @@
@Experimental()
TouchList $dom_createTouchList() native "Document_createTouchList_Callback";
+ TreeWalker $dom_createTreeWalker(Node root, [int whatToShow, NodeFilter filter, bool expandEntityReferences]) {
+ if (expandEntityReferences != null) {
+ return _createTreeWalker_1(root, whatToShow, filter, expandEntityReferences);
+ }
+ if (filter != null) {
+ return _createTreeWalker_2(root, whatToShow, filter);
+ }
+ if (whatToShow != null) {
+ return _createTreeWalker_3(root, whatToShow);
+ }
+ return _createTreeWalker_4(root);
+ }
+
+ TreeWalker _createTreeWalker_1(root, whatToShow, filter, expandEntityReferences) native "Document__createTreeWalker_1_Callback";
+
+ TreeWalker _createTreeWalker_2(root, whatToShow, filter) native "Document__createTreeWalker_2_Callback";
+
+ TreeWalker _createTreeWalker_3(root, whatToShow) native "Document__createTreeWalker_3_Callback";
+
+ TreeWalker _createTreeWalker_4(root) native "Document__createTreeWalker_4_Callback";
+
@DomName('Document.elementFromPoint')
@DocsEditable()
Element $dom_elementFromPoint(int x, int y) native "Document_elementFromPoint_Callback";
@@ -19285,6 +19327,47 @@
static const int SHOW_TEXT = 0x00000004;
}
+// Copyright (c) 2013, 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.
+
+
+@DomName('NodeIterator')
+@Unstable()
+class NodeIterator extends NativeFieldWrapperClass1 {
+ factory NodeIterator(Node root, int whatToShow) {
+ return document.$dom_createNodeIterator(root, whatToShow, null, false);
+ }
+
+ @DomName('NodeIterator.pointerBeforeReferenceNode')
+ @DocsEditable()
+ bool get pointerBeforeReferenceNode native "NodeIterator_pointerBeforeReferenceNode_Getter";
+
+ @DomName('NodeIterator.referenceNode')
+ @DocsEditable()
+ Node get referenceNode native "NodeIterator_referenceNode_Getter";
+
+ @DomName('NodeIterator.root')
+ @DocsEditable()
+ Node get root native "NodeIterator_root_Getter";
+
+ @DomName('NodeIterator.whatToShow')
+ @DocsEditable()
+ int get whatToShow native "NodeIterator_whatToShow_Getter";
+
+ @DomName('NodeIterator.detach')
+ @DocsEditable()
+ void detach() native "NodeIterator_detach_Callback";
+
+ @DomName('NodeIterator.nextNode')
+ @DocsEditable()
+ Node nextNode() native "NodeIterator_nextNode_Callback";
+
+ @DomName('NodeIterator.previousNode')
+ @DocsEditable()
+ Node previousNode() native "NodeIterator_previousNode_Callback";
+
+}
// Copyright (c) 2012, 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.
@@ -25765,6 +25848,73 @@
String get pseudoElement native "TransitionEvent_pseudoElement_Getter";
}
+// Copyright (c) 2013, 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.
+
+
+@DomName('TreeWalker')
+@Unstable()
+class TreeWalker extends NativeFieldWrapperClass1 {
+ factory TreeWalker(Node root, int whatToShow) {
+ return document.$dom_createTreeWalker(root, whatToShow, null, false);
+ }
+
+ @DomName('TreeWalker.currentNode')
+ @DocsEditable()
+ Node get currentNode native "TreeWalker_currentNode_Getter";
+
+ @DomName('TreeWalker.currentNode')
+ @DocsEditable()
+ void set currentNode(Node value) native "TreeWalker_currentNode_Setter";
+
+ @DomName('TreeWalker.expandEntityReferences')
+ @DocsEditable()
+ // http://dom.spec.whatwg.org/#dom-traversal
+ @deprecated // deprecated
+ bool get expandEntityReferences native "TreeWalker_expandEntityReferences_Getter";
+
+ @DomName('TreeWalker.filter')
+ @DocsEditable()
+ NodeFilter get filter native "TreeWalker_filter_Getter";
+
+ @DomName('TreeWalker.root')
+ @DocsEditable()
+ Node get root native "TreeWalker_root_Getter";
+
+ @DomName('TreeWalker.whatToShow')
+ @DocsEditable()
+ int get whatToShow native "TreeWalker_whatToShow_Getter";
+
+ @DomName('TreeWalker.firstChild')
+ @DocsEditable()
+ Node firstChild() native "TreeWalker_firstChild_Callback";
+
+ @DomName('TreeWalker.lastChild')
+ @DocsEditable()
+ Node lastChild() native "TreeWalker_lastChild_Callback";
+
+ @DomName('TreeWalker.nextNode')
+ @DocsEditable()
+ Node nextNode() native "TreeWalker_nextNode_Callback";
+
+ @DomName('TreeWalker.nextSibling')
+ @DocsEditable()
+ Node nextSibling() native "TreeWalker_nextSibling_Callback";
+
+ @DomName('TreeWalker.parentNode')
+ @DocsEditable()
+ Node parentNode() native "TreeWalker_parentNode_Callback";
+
+ @DomName('TreeWalker.previousNode')
+ @DocsEditable()
+ Node previousNode() native "TreeWalker_previousNode_Callback";
+
+ @DomName('TreeWalker.previousSibling')
+ @DocsEditable()
+ Node previousSibling() native "TreeWalker_previousSibling_Callback";
+
+}
// Copyright (c) 2012, 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.
diff --git a/sdk/lib/io/eventhandler.dart b/sdk/lib/io/eventhandler.dart
index 003c3ed..376b799 100644
--- a/sdk/lib/io/eventhandler.dart
+++ b/sdk/lib/io/eventhandler.dart
@@ -5,6 +5,7 @@
part of dart.io;
class _EventHandler {
- external static void _start();
- external static _sendData(Object sender, ReceivePort receivePort, int data);
+ external static void _sendData(Object sender,
+ ReceivePort receivePort,
+ int data);
}
diff --git a/sdk/lib/io/timer_impl.dart b/sdk/lib/io/timer_impl.dart
index 6e56e3e..4939a629b 100644
--- a/sdk/lib/io/timer_impl.dart
+++ b/sdk/lib/io/timer_impl.dart
@@ -21,7 +21,6 @@
static Timer _createTimer(void callback(Timer timer),
int milliSeconds,
bool repeating) {
- _EventHandler._start();
_Timer timer = new _Timer._internal();
timer._callback = callback;
timer._wakeupTime =
diff --git a/sdk/lib/isolate/isolate.dart b/sdk/lib/isolate/isolate.dart
index 49c0eb8..3cfc4fc 100644
--- a/sdk/lib/isolate/isolate.dart
+++ b/sdk/lib/isolate/isolate.dart
@@ -2,6 +2,16 @@
// 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.
+/**
+ * Concurrent programming using _isolates_:
+ * independent workers that are similar to threads
+ * but don't share memory,
+ * communicating only via messages.
+ *
+ * See also:
+ * [dart:isolate - Concurrency with Isolates](https://www.dartlang.org/docs/dart-up-and-running/contents/ch03.html#ch03-dartisolate---concurrency-with-isolates)
+ * in the library tour.
+ */
library dart.isolate;
import "dart:async";
@@ -15,43 +25,53 @@
}
/**
- * The initial [ReceivePort] available by default for this isolate. This
- * [ReceivePort] is created automatically and it is commonly used to establish
- * the first communication between isolates (see [spawnFunction] and
- * [spawnUri]).
+ * The initial ReceivePort available by default for this isolate.
+ *
+ * This ReceivePort is created automatically
+ * and is commonly used to establish
+ * the first communication between isolates.
+ * (See [spawnFunction] and [spawnUri].)
*/
ReceivePort get port => _Isolate.port;
/**
- * Creates and spawns an isolate that shares the same code as the current
- * isolate, but that starts from [topLevelFunction]. The [topLevelFunction]
- * argument must be a static top-level function or a static method that takes no
+ * Creates and spawns an isolate
+ * that shares the same code as the current isolate,
+ * but that starts from the specified function.
+ *
+ * The [topLevelFunction] argument must be
+ * a static top-level function or a static method that takes no
* arguments. It is illegal to pass a function closure.
*
* When any isolate starts (even the main script of the application), a default
* [ReceivePort] is created for it. This port is available from the top-level
* getter [port] defined in this library.
*
- * [spawnFunction] returns a [SendPort] derived from the child isolate's default
- * port.
+ * This function returns a [SendPort] derived from
+ * the child isolate's default port.
*
* The optional [unhandledExceptionCallback] argument is invoked whenever an
* exception inside the isolate is unhandled. It can be seen as a big
* `try/catch` around everything that is executed inside the isolate. The
- * callback should return `true` when it was able to handled the exception.
+ * callback should return `true` if it was able to handle the exception.
*/
SendPort spawnFunction(void topLevelFunction(),
[bool unhandledExceptionCallback(IsolateUnhandledException e)])
=> _Isolate.spawnFunction(topLevelFunction, unhandledExceptionCallback);
/**
- * Creates and spawns an isolate whose code is available at [uri]. Like with
- * [spawnFunction], the child isolate will have a default [ReceivePort], and a
- * this function returns a [SendPort] derived from it.
+ * Creates and spawns an isolate that runs the code from the specified URI.
+ *
+ * As with [spawnFunction],
+ * the child isolate has a default [ReceivePort],
+ * and this function returns a [SendPort] derived from it.
*/
SendPort spawnUri(String uri) => _Isolate.spawnUri(uri);
/**
+ * Together with [ReceivePort],
+ * the only means of communication between isolates.
+ *
* [SendPort]s are created from [ReceivePort]s. Any message sent through
* a [SendPort] is delivered to its respective [ReceivePort]. There might be
* many [SendPort]s for the same [ReceivePort].
@@ -105,8 +125,10 @@
}
/**
- * [ReceivePort]s, together with [SendPort]s, are the only means of
- * communication between isolates. [ReceivePort]s have a [:toSendPort:] method
+ * Together with [SendPort], the only means of
+ * communication between isolates.
+ *
+ * [ReceivePort]s have a [:toSendPort:] method
* which returns a [SendPort]. Any message that is sent through this [SendPort]
* is delivered to the [ReceivePort] it has been created from. There, they are
* dispatched to the callback that has been registered on the receive port.
diff --git a/sdk/lib/isolate/isolate_stream.dart b/sdk/lib/isolate/isolate_stream.dart
index f16271e..922f6f9 100644
--- a/sdk/lib/isolate/isolate_stream.dart
+++ b/sdk/lib/isolate/isolate_stream.dart
@@ -5,16 +5,17 @@
part of dart.isolate;
/**
- * The initial [IsolateStream] available by default for this isolate. This
- * [IsolateStream] is created automatically and it is commonly used to establish
- * the first communication between isolates (see [streamSpawnFunction] and
- * [streamSpawnUri]).
+ * The initial IsolateStream available by default for this isolate.
+ *
+ * This IsolateStream is created automatically and is commonly used
+ * to establish the first communication between isolates.
+ * (See [streamSpawnFunction].)
*/
final IsolateStream stream = new IsolateStream._fromOriginalReceivePort(port);
/**
- * A [MessageBox] creates an [IsolateStream], [stream], and an [IsolateSink],
- * [sink].
+ * The creator of the [IsolateStream] and [IsolateSink]
+ * that allow an isolate to exchange messages with other isolates.
*
* Any message that is written into the [sink] (independent of the isolate) is
* sent to the [stream] where its subscribers can react to the messages.
@@ -30,8 +31,10 @@
external bool _isCloseToken(var object);
/**
- * [IsolateStream]s, together with [IsolateSink]s, are the only means of
- * communication between isolates. Each IsolateStream has a corresponding
+ * Together with [IsolateSink], the only means of
+ * communication between isolates.
+ *
+ * Each IsolateStream has a corresponding
* [IsolateSink]. Any message written into that sink will be delivered to
* the stream and then dispatched to the stream's subscribers.
*/
@@ -64,7 +67,7 @@
}
/**
- * Close the stream from the receiving end.
+ * Closes the stream from the receiving end.
*
* Closing an already closed port has no effect.
*/
@@ -88,9 +91,11 @@
}
/**
- * [IsolateSink]s represent the feed for [IsolateStream]s. Any message written
- * to [this] is delivered to its respective [IsolateStream]. [IsolateSink]s are
- * created by [MessageBox]es.
+ * The feed for an [IsolateStream].
+ *
+ * Any message written to [this] is delivered
+ * to its respective [IsolateStream].
+ * [IsolateSink]s are created by [MessageBox]es.
*
* [IsolateSink]s can be transmitted to other isolates.
*/
@@ -99,8 +104,8 @@
// control).
/**
- * Sends an asynchronous [message] to the linked [IsolateStream]. The message
- * is copied to the receiving isolate.
+ * Sends an asynchronous [message] to the linked [IsolateStream];
+ * the message is copied to the receiving isolate.
*
* The content of [message] can be: primitive values (null, num, bool, double,
* String), instances of [IsolateSink]s, and lists and maps whose elements are
@@ -129,9 +134,10 @@
/**
* Creates and spawns an isolate that shares the same code as the current
- * isolate, but that starts from [topLevelFunction]. The [topLevelFunction]
- * argument must be a static top-level function or a static method that takes no
- * arguments.
+ * isolate, but that starts from the specified function.
+ *
+ * The [topLevelFunction] argument must be
+ * a static top-level function or a static method that takes no arguments.
*
* When any isolate starts (even the main script of the application), a default
* [IsolateStream] is created for it. This sink is available from the top-level
@@ -143,7 +149,7 @@
* The optional [unhandledExceptionCallback] argument is invoked whenever an
* exception inside the isolate is unhandled. It can be seen as a big
* `try/catch` around everything that is executed inside the isolate. The
- * callback should return `true` when it was able to handled the exception.
+ * callback should return `true` if it was able to handle the exception.
*/
external IsolateSink streamSpawnFunction(
void topLevelFunction(),
diff --git a/sdk/lib/mirrors/mirrors.dart b/sdk/lib/mirrors/mirrors.dart
index c22d3c3..66b9abd 100644
--- a/sdk/lib/mirrors/mirrors.dart
+++ b/sdk/lib/mirrors/mirrors.dart
@@ -135,7 +135,8 @@
* This function returns a [ClassMirror] reflecting *C*.
*
* If [key] is not an instance of [Type] then this function
- * throws an [ArgumentError].
+ * throws an [ArgumentError]. If [key] is the Type dynamic,
+ * throws an [ArgumentError] because dynamic is not a class.
*
* Note that since one cannot obtain a [Type] object from
* another isolate, this function can only be used to
diff --git a/tests/co19/co19-analyzer.status b/tests/co19/co19-analyzer.status
index 4d9ef03..843ace1 100644
--- a/tests/co19/co19-analyzer.status
+++ b/tests/co19/co19-analyzer.status
@@ -227,6 +227,10 @@
# co19 issue #531, void f(void f()) {f();} is error. Gilad: The formal parameter conflicts with the name of the function.
Language/13_Statements/04_Local_Function_Declaration_A01_t01: fail, OK
+# co19 issue #541: tests contain unqualified reference to static members defined in superclass
+Language/12_Expressions/14_Function_Invocation/3_Unqualified_Invocation_A01_t07: fail, OK
+Language/12_Expressions/30_Identifier_Reference_A14_t03: fail, OK
+
# co19-roll r546 (11.08.2013) caused these failures
Language/13_Statements/11_Return_A07_t01: fail # co19-roll r546: Please triage this failure
diff --git a/tests/co19/co19-co19.status b/tests/co19/co19-co19.status
index 97bece2..3d31a9d 100644
--- a/tests/co19/co19-co19.status
+++ b/tests/co19/co19-co19.status
@@ -64,8 +64,11 @@
Utils/tests/Expect/listEquals_A03_t01: FAIL, OK # co19 issue 500
Utils/tests/Expect/setEquals_A02_t01: FAIL, OK # co19 issue 499
-LibTest/isolate_api/streamSpawnFunction_A02_t02: Pass, Fail # co19 issue 540
-LibTest/isolate_api/streamSpawnFunction_A02_t03: Pass, Fail # co19 issue 540
+LibTest/isolate_api/streamSpawnFunction_A02_t02: PASS, FAIL, OK # co19 issue 540
+LibTest/isolate_api/streamSpawnFunction_A02_t03: PASS, FAIL, OK # co19 issue 540
+LibTest/isolate/IsolateStream/contains_A02_t01: PASS, FAIL, OK # co19 issue 540
+
+LibTest/async/EventTransformStream/listen_A04_t01: Pass, Timeout # co19 issue 542
### CHECKED MODE FAILURES ###
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index e373794..82ddff6 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -200,7 +200,6 @@
[ $compiler == dart2js && $runtime == ie9 ]
LibTest/math/cos_A01_t01: Fail # co19 issue 44
-LibTest/async/EventTransformStream/listen_A04_t01: Pass, Timeout # Issue 12595
#
# The following tests are failing. Please add the error message
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index c52aec6..3e06a4b 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -104,7 +104,6 @@
[ $compiler == none && $runtime == vm && $mode == debug ]
LibTest/isolate/isolate_api/spawnFunction_A02_t01: Crash
-Language/12_Expressions/00_Object_Identity/1_Object_Identity_A04_t02: Crash # co19-roll r546: Please triage this failure
LibTest/async/Stream/Stream.periodic_A03_t01: Fail # co19-roll r546: Please triage this failure
LibTest/isolate/IsolateStream/contains_A02_t01: Fail # co19-roll r546: Please triage this failure
diff --git a/tests/compiler/dart2js_extra/dart2js_extra.status b/tests/compiler/dart2js_extra/dart2js_extra.status
index 4e70d58..3e81bd4 100644
--- a/tests/compiler/dart2js_extra/dart2js_extra.status
+++ b/tests/compiler/dart2js_extra/dart2js_extra.status
@@ -24,6 +24,7 @@
[ $compiler == dart2js && $runtime == ie9 ]
class_test: Fail
+deferred/deferred_function_test: Pass, Fail, Timeout # Issue 12635
[ $compiler == dart2js && $runtime == none ]
*: Fail, Pass # TODO(ahe): Triage these tests.
diff --git a/tests/html/html.status b/tests/html/html.status
index 7c00a70..b3c80c6 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -2,10 +2,6 @@
# 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.
-# Skipped for in-progress Dartium rull on 8-16-2013
-node_test/iterating: Fail
-websocket_test: skip
-
async_window_test: Skip #TODO(gram): investigating
event_test: Skip # Issue 1996
interactive_test: Skip # Must be run manually.
@@ -23,10 +19,10 @@
[ $compiler == none && ($runtime == drt || $runtime == dartium) ]
# postMessage in dartium always transfers the typed array buffer, never a view
postmessage_structured_test/typed_arrays: Fail
-custom_elements_test/lifecycle: Fail # Issue 9326 - Implement "extends Element" in dartium
-# Issue 9326 failures
-custom/attribute_changed_callback_test: Fail
-custom/created_callback_test: Fail
+xhr_test: Pass, Fail # Issue 12648
+custom_elements_test/lifecycle: Fail # Issue 12642
+custom/attribute_changed_callback_test: Fail # 12643
+custom/created_callback_test: Fail # Issue 12642
[ $compiler == none && $runtime == drt && $system == windows ]
worker_test/functional: Pass, Crash # Issue 9929.
diff --git a/tests/html/websocket_test.dart b/tests/html/websocket_test.dart
index 752856c..2e02761 100644
--- a/tests/html/websocket_test.dart
+++ b/tests/html/websocket_test.dart
@@ -19,7 +19,7 @@
test('constructorTest', () {
expect(() {
- var socket = new WebSocket('ws://localhost');
+ var socket = new WebSocket('ws://localhost/ws', 'chat');
expect(socket, isNotNull);
expect(socket, isWebSocket);
}, expectation);
@@ -27,7 +27,8 @@
if (WebSocket.supported) {
test('echo', () {
- var socket = new WebSocket('ws://${window.location.host}/ws', 'chat');
+ var socket = new WebSocket('ws://${window.location.host}/ws');
+
socket.onOpen.first.then((_) {
socket.send('hello!');
});
diff --git a/tests/html/xhr_test.dart b/tests/html/xhr_test.dart
index d47707f..1d53209 100644
--- a/tests/html/xhr_test.dart
+++ b/tests/html/xhr_test.dart
@@ -201,7 +201,7 @@
for (var i = 0; i < data.length; ++i) {
data[i] = i & 0xFF;
}
- xhr.send(data);
+ xhr.send(new Uint8List.view(data.buffer));
return xhr.onLoad.first.then((_) {
expect(progressCalled, isTrue);
diff --git a/tests/isolate/compute_this_script_browser_stream_test.dart b/tests/isolate/browser/compute_this_script_browser_stream_test.dart
similarity index 90%
rename from tests/isolate/compute_this_script_browser_stream_test.dart
rename to tests/isolate/browser/compute_this_script_browser_stream_test.dart
index a6f5173..509614e 100644
--- a/tests/isolate/compute_this_script_browser_stream_test.dart
+++ b/tests/isolate/browser/compute_this_script_browser_stream_test.dart
@@ -9,8 +9,8 @@
import 'dart:html';
import 'dart:isolate';
-import '../../pkg/unittest/lib/unittest.dart';
-import '../../pkg/unittest/lib/html_config.dart';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
child() {
var sink;
diff --git a/tests/isolate/compute_this_script_browser_test.dart b/tests/isolate/browser/compute_this_script_browser_test.dart
similarity index 90%
rename from tests/isolate/compute_this_script_browser_test.dart
rename to tests/isolate/browser/compute_this_script_browser_test.dart
index e91d4a9..74cd118 100644
--- a/tests/isolate/compute_this_script_browser_test.dart
+++ b/tests/isolate/browser/compute_this_script_browser_test.dart
@@ -9,8 +9,8 @@
import 'dart:html';
import 'dart:isolate';
-import '../../pkg/unittest/lib/unittest.dart';
-import '../../pkg/unittest/lib/html_config.dart';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
child() {
port.receive((msg, reply) {
diff --git a/tests/isolate/ports_compilation_browser_test.dart b/tests/isolate/browser/ports_compilation_browser_test.dart
similarity index 91%
rename from tests/isolate/ports_compilation_browser_test.dart
rename to tests/isolate/browser/ports_compilation_browser_test.dart
index 5ab16ab..5eb76d7 100644
--- a/tests/isolate/ports_compilation_browser_test.dart
+++ b/tests/isolate/browser/ports_compilation_browser_test.dart
@@ -8,19 +8,19 @@
library ports_compilation;
import 'dart:html';
import 'dart:isolate';
-import '../../pkg/unittest/lib/unittest.dart';
-import '../../pkg/unittest/lib/html_config.dart';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
void foo() {
// Create a "SendPortSync" object and access one of its members.
SendPortSync s_port;
s_port.callSync;
-
+
// Create a "ReceivePortSync" object (with the constructor) and
// access one of its members.
var r_port = new ReceivePortSync();
r_port.receive;
-
+
// Call getComputedStyle() from the HTML library.
query("").getComputedStyle("");
}
diff --git a/tests/isolate/typed_data_message_test.dart b/tests/isolate/browser/typed_data_message_test.dart
similarity index 97%
rename from tests/isolate/typed_data_message_test.dart
rename to tests/isolate/browser/typed_data_message_test.dart
index b725b1c..38e7815 100644
--- a/tests/isolate/typed_data_message_test.dart
+++ b/tests/isolate/browser/typed_data_message_test.dart
@@ -8,7 +8,7 @@
library TypedDataMessageTest;
import 'dart:isolate';
import 'dart:typed_data';
-import '../../pkg/unittest/lib/unittest.dart';
+import 'package:unittest/unittest.dart';
// ---------------------------------------------------------------------------
// Message passing test.
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status
index 3655cf9..df59051 100644
--- a/tests/isolate/isolate.status
+++ b/tests/isolate/isolate.status
@@ -3,43 +3,31 @@
# BSD-style license that can be found in the LICENSE file.
[ $runtime == vm ]
-isolate2_negative_test: Skip # Need to resolve correct behaviour.
-isolate3_negative_test: Skip # test depends on isolate error exiting process.
-serialization_test: Skip # tests dart2js-specific serialization code
-spawn_uri_test: Fail, OK # test uses a ".js" suffix that is bogus on vm.
-compute_this_script_browser_test: Skip # browser specific test
-compute_this_script_browser_stream_test: Skip # browser specific test
-ports_compilation_browser_test: Skip # browser specific test
-unresolved_ports_negative_test: Skip # See Issue 6839
-isolate_stress_test: Fail # TODO(ahe): This should be able to pass when we have wrapper-less tests.
+browser/*: SkipByDesign # Browser specific tests
+unresolved_ports_negative_test: Skip # Issue 6839
+isolate_stress_test: Fail # Issue 12588: This should be able to pass when we have wrapper-less tests.
-[ $compiler == none && $runtime == drt ]
-isolate2_negative_test: Skip # Inherited from VM.
-isolate3_negative_test: Skip # Inherited from VM.
-serialization_test: Skip # tests dart2js-specific serialization code
-spawn_uri_test: Skip # uses a .js extension (not for dartium)
-spawn_uri_negative_test: Skip # ditto
+[ $compiler == none ]
+serialization_test: SkipByDesign # Tests dart2js-specific serialization code
+spawn_uri_test: SkipByDesign # Test uses a ".js" URI.
+spawn_uri_negative_test: SkipByDesign # Test uses a ".js" URI.
+isolate2_negative_test: Skip # Issue 12587.
+isolate3_negative_test: Skip # Issue 12587.
-[ $compiler == dartanalyzer ]
-isolate2_negative_test: fail
-isolate_negative_test: fail
-spawn_function_negative_test: fail
-spawn_uri_negative_test: fail
-spawn_uri_vm_negative_test: fail
-unresolved_ports_negative_test: fail
+[ $analyzer ]
+isolate2_negative_test: Fail
+isolate_negative_test: Fail
+spawn_function_negative_test: Fail
+spawn_uri_negative_test: Fail
+spawn_uri_vm_negative_test: Fail
+unresolved_ports_negative_test: Fail
[ $compiler == dart2analyzer ]
-isolate2_negative_test: fail
-isolate_import_negative_test: fail
-isolate_negative_test: fail
-spawn_function_negative_test: fail
-spawn_uri_negative_test: fail
-spawn_uri_vm_negative_test: fail
-unresolved_ports_negative_test: fail
+isolate_import_negative_test: Fail
-[ $compiler == dart2js && ($runtime == d8 || $jscl) ]
+[ $compiler == dart2js && $jscl ]
+browser/*: SkipByDesign # Browser specific tests
illegal_msg_stream_test: Fail # Issue 6750
-typed_data_message_test: Fail, OK # DataView only supported in browsers.
[ $compiler == dart2js && $browser ]
illegal_msg_stream_test: Fail, Pass # Issue 6750
@@ -48,50 +36,54 @@
unresolved_ports_negative_test: Pass, Crash # Issue 10613
[ $compiler == dart2js ]
-serialization_test: Fail # Tries to access class TestingOnly declared in isolate_patch.dart
+serialization_test: Fail # Issue 1882, tries to access class TestingOnly declared in isolate_patch.dart
illegal_msg_test: Fail # Issue 6750
stream_mangling_test: Fail # Issue 9245
-global_error_handler_test: Pass, Fail # http://dartbug.com/9012 and http://dartbug.com/9024
-global_error_handler_stream_test: Pass, Fail # http://dartbug.com/9012 and http://dartbug.com/9024
-global_error_handler2_test: Pass, Fail # http://dartbug.com/9012 and http://dartbug.com/9024
-global_error_handler_stream2_test: Pass, Fail # http://dartbug.com/9012 and http://dartbug.com/9024
+global_error_handler_test: Pass, Fail # Issue 9012, Issue 9024
+global_error_handler_stream_test: Pass, Fail # Issue 9012, Issue 9024
+global_error_handler2_test: Pass, Fail # Issue 9012, Issue 9024
+global_error_handler_stream2_test: Pass, Fail # Issue 9012, Issue 9024
[ $compiler == dart2js && ($runtime == drt || $runtime == ff || $runtime == chrome || $runtime == chromeOnAndroid || $runtime == ie9 || $runtime == ie10 || $runtime == safari) ]
-typed_data_message_test: Fail
+browser/typed_data_message_test: Fail # Issue 12624
-[ $runtime == safari ]
-cross_isolate_message_test: Skip # Depends on 32/64 bit Safari. See Issue 1120
-message_test: Skip
+[ $compiler == dart2js && $runtime == safari ]
+cross_isolate_message_test: Skip # Issue 12627
+message_test: Skip # Issue 12627
-[ $runtime == opera ]
-isolate2_negative_test: Skip # Timeout.
-unresolved_ports_negative_test: Skip # See Issue 6839
+[ $compiler == dart2js && $runtime == opera ]
+isolate2_negative_test: Skip # Issue 12625
+unresolved_ports_negative_test: Skip # Issue 12626
+
+[ $compiler == dart2js ]
+spawn_uri_vm_test: SkipByDesign # Test uses a ".dart" URI.
+spawn_uri_nested_vm_test: SkipByDesign # Test uses a ".dart" URI.
+spawn_uri_vm_negative_test: SkipByDesign # Test uses a ".dart" URI.
[ $compiler == dart2js && $browser ]
-spawn_uri_vm_test: Skip # test uses a ".dart" suffix that only works in vm.
-spawn_uri_nested_vm_test: Skip # test uses a ".dart" suffix that only works in vm.
-spawn_uri_vm_negative_test: Skip # ditto above.
isolate2_negative_test: Fail, Pass # Issue 7769
[ $compiler == dart2js && $jscl ]
-spawn_uri_negative_test: Pass # for the wrong reasons (not supported in d8)
-spawn_uri_test: Fail, OK # loading another file is not supported in d8
-spawn_uri_vm_negative_test: Skip # ditto above.
-spawn_uri_vm_test: Skip # test uses a ".dart" suffix that only works in vm.
-spawn_uri_nested_vm_test: Skip # test uses a ".dart" suffix that only works in vm.
+spawn_uri_test: SkipByDesign # Loading another file is not supported in JS shell
[ $compiler == dart2js && $runtime == ie9 ]
-spawn_uri_test: Fail
+spawn_uri_test: Fail # Issue 12630
[ $compiler == dart2js && $runtime == none ]
-*: Fail, Pass # TODO(ahe): Triage these tests.
+spawn_function_negative_test: Fail # Issue 12628
+spawn_uri_negative_test: Fail # Issue 12628
+unresolved_ports_negative_test: Fail # Issue 12628
+stream_mangling_test: Pass # Issue 12628
+isolate_negative_test: Fail # Issue 12628
+serialization_test: Pass # Issue 12628
+isolate_import_negative_test: Fail # Issue 12628
+isolate2_negative_test: Fail # Issue 12628
+illegal_msg_test: Pass # Issue 12628
[ $compiler == dart2dart ]
-# Skip until we stabilize language tests.
-*: Skip
+*: Skip # Issue 12629
-# TODO(ajohnsen): Fix this as part of library changes.
[ $compiler == none ]
isolate_negative_test: Skip # Bug 6890
@@ -100,18 +92,13 @@
mandel_isolate_stream_test: Pass, Fail, Timeout # Issue 7952
[ $compiler == dart2js && ( $runtime == ff || $runtime == safari || $runtime == drt || $runtime == chrome ) ]
-isolate_stress_test: Pass, Slow # http://dartbug.com/10697
+isolate_stress_test: Pass, Slow # Issue 10697
[ $arch == arm || $arch == simarm ]
-*: Skip
+*: Skip # Issue 12589
-[ $arch == mips ]
-*: Skip
-
-[ $arch == simmips ]
-*: Skip
+[ $arch == mips || $arch == simmips ]
+*: Skip # Issue 12590
[ $compiler == none && ($runtime == drt || $runtime == dartium) ]
-# Skipped for in-progress Dartium rull on 8-16-2013
-isolate_stress_test: Skip
-
+isolate_stress_test: Skip # Issue 12537
diff --git a/tests/isolate/isolate_stress_test.dart b/tests/isolate/isolate_stress_test.dart
index 84a3447..f00e457 100644
--- a/tests/isolate/isolate_stress_test.dart
+++ b/tests/isolate/isolate_stress_test.dart
@@ -9,7 +9,7 @@
import 'dart:async';
import 'dart:isolate';
-// TODO(ahe): Remove this import when we have wrapper-less testing.
+// TODO(12588): Remove this import when we have wrapper-less testing.
import 'dart:html';
worker() {
diff --git a/tests/language/final_var_negative_test.dart b/tests/language/final_var_negative_test.dart
deleted file mode 100644
index 62d4e53..0000000
--- a/tests/language/final_var_negative_test.dart
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright (c) 2011, 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.
-// Disallow re-assignment of a final local variable.
-
-main() {
- final x = 1;
- x = 2; // <- reassignment not allowed.
- return x;
-}
diff --git a/tests/language/final_variable_assignment_test.dart b/tests/language/final_variable_assignment_test.dart
index f173747..f195c75 100644
--- a/tests/language/final_variable_assignment_test.dart
+++ b/tests/language/final_variable_assignment_test.dart
@@ -6,8 +6,8 @@
main() {
final x = 30;
- x = 0; /// 01: compile-time error
- x += 1; /// 02: compile-time error
- ++x; /// 03: compile-time error
- x++; /// 04: compile-time error
+ x = 0; /// 01: static type warning, runtime error
+ x += 1; /// 02: static type warning, runtime error
+ ++x; /// 03: static type warning, runtime error
+ x++; /// 04: static type warning, runtime error
}
diff --git a/tests/language/language.status b/tests/language/language.status
index cdac989..70f61d0 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -6,55 +6,44 @@
# current state of the language.
[ $compiler == dart2js && ($runtime == ie9 || $runtime == ie10) ]
-licm2_test: Skip # Issue: 12298
+licm2_test: Skip # Issue 12298
[ $compiler == dart2dart ]
-mixin_super_constructor_named_test: Fail
-mixin_super_constructor_positionals_test: Fail
+mixin_super_constructor_named_test: Fail # Issue 12631
+mixin_super_constructor_positionals_test: Fail # Issue 12631
function_type_alias6_test/00: Fail # Issue 11986
function_type_alias9_test/00: Crash # Issue 11986
[ $compiler == none ]
-mixin_super_constructor_named_test: Fail
-mixin_super_constructor_positionals_test: Fail
-built_in_identifier_prefix_test: Fail # http://dartbug.com/6970
+mixin_super_constructor_named_test: Fail # Issue 12631
+mixin_super_constructor_positionals_test: Fail # Issue 12631
+built_in_identifier_prefix_test: Fail # Issue 6970
library_juxtaposition_test: Fail # Issue 6877
switch_int_double_test/01: Fail # Issue 7307
switch_int_double_test/02: Fail # Issue 7307
# These bugs refer currently ongoing language discussions.
-constructor5_test: Fail # (Discussion ongoing)
-
-constructor_initializer_test: Fail # Side effects in constructor parameters
-
-constructor6_test: Fail # Issue 6422
+constructor_initializer_test: Fail # Issue 12633
+constructor5_test: Fail # Issue 6422
+constructor6_test: Fail # Issue 6422
closure_in_initializer_test: Fail # Issue 6422
# Regular bugs which should be fixed.
super_first_constructor_test: Fail # Issue 1372.
-
parameter_initializer6_negative_test: Fail # Issue 3502
-
-named_parameters_aggregated_test/05: Fail # Compile-time error reported instead of static type warning.
-
lazy_static3_test: Fail # Issue 12593
-
-export_cyclic_test: Fail, Crash # issue 6060
-duplicate_export_negative_test: Fail # issue 6134
-
+export_cyclic_test: Fail, Crash # Issue 6060
+duplicate_export_negative_test: Fail # Issue 6134
on_catch_malformed_type_test: Fail # Issue 8601
-
-mixin_mixin_test: Fail
-mixin_issue10216_2_test: Fail
+mixin_mixin_test: Fail # Issue 12636
+mixin_issue10216_2_test: Fail # Issue 12636
mixin_illegal_object_test/01: Crash # Issue 10952
mixin_illegal_object_test/02: Crash # Issue 10952
-
mixin_forwarding_constructor2_test: Fail # Issue 11888
mixin_typedef_constructor_test: Fail # Issue 11888
mixin_type_parameter2_test: Fail # Issue 11888
[ $compiler == none && $unchecked ]
-
# Only checked mode reports an error on type assignment
# problems in compile time constants.
compile_time_constant_checked_test/02: Fail, OK
@@ -71,18 +60,9 @@
compile_time_constant_checked3_test/05: Fail, OK
compile_time_constant_checked3_test/06: Fail, OK
-
-[ $compiler == none && $runtime == drt ]
-final_variable_assignment_test/01: Fail
-final_variable_assignment_test/02: Fail
-final_variable_assignment_test/03: Fail
-final_variable_assignment_test/04: Fail
-
-
[ $runtime == dartium ]
import_combinators_test: Fail
-
[ $runtime == vm || ($runtime == drt && $compiler == none) ]
first_class_types_literals_test: Fail # issue 11761
call_test: Fail # Issue 12602
@@ -144,12 +124,6 @@
setter_override_test/03: Fail # Issue 11496
setter_override2_test/02: Fail # Issue 11496
-# Missing compile-time error when modifying final local variables
-final_variable_assignment_test/01: Fail
-final_variable_assignment_test/02: Fail
-final_variable_assignment_test/03: Fail
-final_variable_assignment_test/04: Fail
-
compile_time_constant10_test/01: Fail # http://dartbug.com/5519
compile_time_constant10_test/02: Fail # http://dartbug.com/5519
compile_time_constant_arguments_test/01: Fail # http://dartbug.com/5519
@@ -190,7 +164,6 @@
# declarations are simply not parsed. In pseudo kw dart2js
# chokes on things like typedef(x) => "typedef $x" and alike.
abstract_syntax_test/01: Fail
-abstract_syntax_test/02: Fail
pseudo_kw_test: Fail
# external keyword is not yet supported by dart2js/dart2dart.
external_test/*: Skip
@@ -235,8 +208,6 @@
# TODO(antonm): proper support in test framework.
no_such_method_test: Pass, Fail, OK # Hard codes the name of invoked method ("foo").
-named_parameters_aggregated_test/05: Fail # Compile-time error reported instead of static type warning.
-
new_expression_type_args_test/00: Fail # Wrongly reports compile-time error.
new_expression_type_args_test/01: Fail # Wrongly reports compile-time error.
@@ -248,7 +219,6 @@
get_set_syntax_test/05: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
get_set_syntax_test/06: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
get_set_syntax_test/07: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
-get_set_syntax_test/08: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
get_set_syntax_test/13: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
get_set_syntax_test/14: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
get_set_syntax_test/15: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
diff --git a/tests/language/language_analyzer.status b/tests/language/language_analyzer.status
index 34b721d..381133f 100644
--- a/tests/language/language_analyzer.status
+++ b/tests/language/language_analyzer.status
@@ -60,28 +60,6 @@
block_scope_test: fail
lazy_static3_test: fail
-# test issue 10890; on-catch UnknownType is a static warning, not error
-try_catch_on_syntax_test/01: fail
-
-# test issue 10899; it is static warning, not error, to call methods of class literal
-class_literal_test/02: fail
-class_literal_test/05: fail
-class_literal_test/07: fail
-class_literal_test/10: fail
-class_literal_test/11: fail
-class_literal_test/12: fail
-class_literal_test/14: fail
-class_literal_test/17: fail
-class_literal_test/18: fail
-class_literal_test/19: fail
-class_literal_test/22: fail
-class_literal_test/23: fail
-class_literal_test/24: fail
-class_literal_test/27: fail
-class_literal_test/28: fail
-class_literal_test/29: fail
-class_literal_test/none: fail
-
# Test issue 11124, Uninitialized finals are warnings not errors
field3a_negative_test: fail
const_syntax_test/01: fail
@@ -127,15 +105,9 @@
# test issue 11579, assignment, no setter
getter_no_setter_test/none: fail
-# test issue 11580, Function is not a malformed type
-black_listed_test/11: fail
-
# test issue 11581, it is not warning to call dynamic
call_through_getter_test: fail
-# test issue 11583, int is valid key for constant map literal
-compile_time_constant_c_test/01: fail
-
# test issue 11584, positional arguments cannot be used for named parameters
compile_time_constant_e_test: fail
@@ -156,11 +128,6 @@
# test issue 11591, assigning to the final variable is warning, not error
final_for_in_variable_test/01: fail
final_param_negative_test: fail
-final_var_negative_test: fail
-final_variable_assignment_test/01: fail
-final_variable_assignment_test/02: fail
-final_variable_assignment_test/03: fail
-final_variable_assignment_test/04: fail
getter_no_setter_test/01: fail
# test issue 11592, Function type alias (typedef) is not a constant
@@ -261,7 +228,6 @@
static_field_test/03: fail
static_field_test/04: fail
-null_test/03: Fail # Issue 12484
[ $compiler == dartanalyzer && $checked ]
factory1_test/00: fail
diff --git a/tests/language/language_analyzer2.status b/tests/language/language_analyzer2.status
index 6a18173..84c6492 100644
--- a/tests/language/language_analyzer2.status
+++ b/tests/language/language_analyzer2.status
@@ -21,7 +21,6 @@
# TBF: It is a compile-time error if the superclass of a class C appears in the implements clause of C.
const_constructor_super_test/01: fail
-compile_time_constant_c_test/01: fail
# TBF: m([int p = 'String']) and call 'const' instance creation
compile_time_constant_checked2_test/03: fail
@@ -103,28 +102,6 @@
block_scope_test: fail
lazy_static3_test: fail
-# test issue 10890; on-catch UnknownType is a static warning, not error
-try_catch_on_syntax_test/01: fail
-
-# test issue 10899; it is static warning, not error, to call methods of class literal
-class_literal_test/02: fail
-class_literal_test/05: fail
-class_literal_test/07: fail
-class_literal_test/10: fail
-class_literal_test/11: fail
-class_literal_test/12: fail
-class_literal_test/14: fail
-class_literal_test/17: fail
-class_literal_test/18: fail
-class_literal_test/19: fail
-class_literal_test/22: fail
-class_literal_test/23: fail
-class_literal_test/24: fail
-class_literal_test/27: fail
-class_literal_test/28: fail
-class_literal_test/29: fail
-class_literal_test/none: fail
-
# Test issue 11124, Uninitialized finals are warnings not errors
field3a_negative_test: fail
const_syntax_test/01: fail
@@ -175,15 +152,9 @@
# test issue 11579, assignment, no setter
getter_no_setter_test/none: fail
-# test issue 11580, Function is not a malformed type
-black_listed_test/11: fail
-
# test issue 11581, it is not warning to call dynamic
call_through_getter_test: fail
-# test issue 11583, int is valid key for constant map literal
-compile_time_constant_c_test/01: fail
-
# test issue 11584, positional arguments cannot be used for named parameters
compile_time_constant_e_test: fail
@@ -204,11 +175,6 @@
# test issue 11591, assigning to the final variable is warning, not error
final_for_in_variable_test/01: fail
final_param_negative_test: fail
-final_var_negative_test: fail
-final_variable_assignment_test/01: fail
-final_variable_assignment_test/02: fail
-final_variable_assignment_test/03: fail
-final_variable_assignment_test/04: fail
getter_no_setter_test/01: fail
# test issue 11592, Function type alias (typedef) is not a constant
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index a3223eb..7b31008 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -4,30 +4,6 @@
[ $compiler == dart2js || $compiler == dart2dart ]
compile_time_constant_c_test/none: Fail # Map literal with int key.
-class_literal_test/01: Fail # Class literals are expression now; delete this test.
-class_literal_test/02: Fail # Class literals are expression now; delete this test.
-class_literal_test/05: Fail # Class literals are expression now; delete this test.
-class_literal_test/06: Fail # Class literals are expression now; delete this test.
-class_literal_test/07: Fail # Class literals are expression now; delete this test.
-class_literal_test/10: Fail # Class literals are expression now; delete this test.
-class_literal_test/11: Fail # Class literals are expression now; delete this test.
-class_literal_test/12: Fail # Class literals are expression now; delete this test.
-class_literal_test/13: Fail # Class literals are expression now; delete this test.
-class_literal_test/14: Fail # Class literals are expression now; delete this test.
-class_literal_test/17: Fail # Class literals are expression now; delete this test.
-class_literal_test/18: Fail # Class literals are expression now; delete this test.
-class_literal_test/19: Fail # Class literals are expression now; delete this test.
-class_literal_test/20: Fail # Class literals are expression now; delete this test.
-class_literal_test/21: Fail # Class literals are expression now; delete this test.
-class_literal_test/22: Fail # Class literals are expression now; delete this test.
-class_literal_test/23: Fail # Class literals are expression now; delete this test.
-class_literal_test/24: Fail # Class literals are expression now; delete this test.
-class_literal_test/25: Fail # Class literals are expression now; delete this test.
-class_literal_test/26: Fail # Class literals are expression now; delete this test.
-class_literal_test/27: Fail # Class literals are expression now; delete this test.
-class_literal_test/28: Fail # Class literals are expression now; delete this test.
-class_literal_test/29: Fail # Class literals are expression now; delete this test.
-
constructor_initializer_test: Fail, OK # Depends on ?parameter check.
black_listed_test/none: Fail # Issue 12446.
@@ -110,10 +86,6 @@
left_shift_test: Fail # Issue 1533
factory_redirection_test/01: Fail
factory_redirection_test/07: Fail
-final_variable_assignment_test/01: Fail
-final_variable_assignment_test/02: Fail
-final_variable_assignment_test/03: Fail
-final_variable_assignment_test/04: Fail
bad_override_test/01: Fail # Issue 11496
bad_override_test/02: Fail # Issue 11496
bad_override_test/06: Fail # Issue 11496
@@ -166,20 +138,15 @@
get_set_syntax_test/05: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
get_set_syntax_test/06: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
get_set_syntax_test/07: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
-get_set_syntax_test/08: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
get_set_syntax_test/13: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
get_set_syntax_test/14: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
get_set_syntax_test/15: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
-get_set_syntax_test/16: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
method_binding_test: Fail # internal error: super property read not implemented.
method_override_test: Fail # cannot resolve type GetKeysFunctionType
method_override5_test: Pass, Fail # Issue 11496 (passes if it's inlined)
-abstract_getter_test/01: Fail # instantiation of abstract class
-abstract_factory_constructor_test/01: Fail # instantiation of abstract class
parameter_initializer6_negative_test: Fail # Issue 3502
named_parameters_aggregated_test/01: Fail # Presence of default values for optional params is not properly validated in type definitions.
named_parameters_aggregated_test/03: Fail # Presence of default values for optional params is not properly validated in closure types.
-named_parameters_aggregated_test/05: Fail # Absence of positional parameters before named parameters does not trigger static type warning.
pseudo_kw_test: Fail # Unexpected token '('
super_implicit_closure_test: Fail # internal error: super property read not implemented
@@ -195,7 +162,6 @@
external_test/12: Fail
external_test/13: Skip # Runtime error (missing patch).
external_test/14: Fail
-external_test/15: Fail
external_test/20: Skip # Runtime error (missing patch).
external_test/21: Fail
external_test/22: Fail
@@ -220,7 +186,6 @@
# The following tests are all negative tests that should be fixed.
#
abstract_syntax_test/01: Fail # Negative language test.
-abstract_syntax_test/02: Fail # Negative language test.
const_constructor_syntax_test/04: Fail # Negative language test.
const_syntax_test/04: Fail # Negative language test.
constructor2_negative_test: Fail # Negative language test.
diff --git a/tests/language/named_parameters_aggregated_test.dart b/tests/language/named_parameters_aggregated_test.dart
index 4e61963..a743569 100644
--- a/tests/language/named_parameters_aggregated_test.dart
+++ b/tests/language/named_parameters_aggregated_test.dart
@@ -49,7 +49,7 @@
);
// Expect compile-time error due to missing positional argument.
- NamedParametersAggregatedTests.F31(b:25, c:35); /// 05: static type warning
+ Expect.throws(() => NamedParametersAggregatedTests.F31(b:25, c:35), (e) => e is NoSuchMethodError); /// 05: static type warning
new TypeTester<Callback>();
diff --git a/tests/lib/convert/ascii_test.dart b/tests/lib/convert/ascii_test.dart
new file mode 100644
index 0000000..239130f
--- /dev/null
+++ b/tests/lib/convert/ascii_test.dart
@@ -0,0 +1,138 @@
+// Copyright (c) 2012, 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.
+
+import "package:expect/expect.dart";
+import 'dart:convert';
+
+var asciiStrings = [
+ "pure ascii",
+ "\x00 with control characters \n",
+ "\x01 edge cases \x7f"
+];
+
+var nonAsciiStrings = [
+ "\x80 edge case first",
+ "Edge case ASCII \u{80}",
+ "Edge case byte \u{ff}",
+ "Edge case super-BMP \u{10000}"
+];
+
+void main() {
+ // Build longer versions of the example strings.
+ for (int i = 0, n = asciiStrings.length; i < n ; i++) {
+ var string = asciiStrings[i];
+ while (string.length < 1024) {
+ string += string;
+ }
+ asciiStrings.add(string);
+ }
+ for (int i = 0, n = nonAsciiStrings.length; i < n ; i++) {
+ var string = nonAsciiStrings[i];
+ while (string.length < 1024) {
+ string += string;
+ }
+ nonAsciiStrings.add(string);
+ }
+ testDirectConversions();
+ testChunkedConversions();
+}
+
+void testDirectConversions() {
+ for (var codec in [ASCII, new AsciiCodec()]) {
+ for (var asciiString in asciiStrings) {
+ List bytes = codec.encoder.convert(asciiString);
+ Expect.listEquals(asciiString.codeUnits.toList(), bytes, asciiString);
+ String roundTripString = codec.decoder.convert(bytes);
+ Expect.equals(asciiString, roundTripString);
+ roundTripString = codec.decode(bytes);
+ Expect.equals(asciiString, roundTripString);
+ }
+
+ for (var nonAsciiString in nonAsciiStrings) {
+ Expect.throws(() {
+ print(codec.encoder.convert(nonAsciiString));
+ }, null, nonAsciiString);
+ }
+ }
+
+ var allowInvalidCodec = new AsciiCodec(allowInvalid: true);
+ var invalidBytes = [0, 1, 0xff, 0xdead, 0];
+ String decoded = allowInvalidCodec.decode(invalidBytes);
+ Expect.equals("\x00\x01\uFFFD\uFFFD\x00", decoded);
+ decoded = allowInvalidCodec.decoder.convert(invalidBytes);
+ Expect.equals("\x00\x01\uFFFD\uFFFD\x00", decoded);
+ decoded = ASCII.decode(invalidBytes, allowInvalid: true);
+ Expect.equals("\x00\x01\uFFFD\uFFFD\x00", decoded);
+}
+
+List<int> encode(String str, int chunkSize,
+ Converter<String, List<int>> converter) {
+ List<int> bytes = <int>[];
+ ChunkedConversionSink byteSink =
+ new ByteConversionSink.withCallback(bytes.addAll);
+ var stringConversionSink = converter.startChunkedConversion(byteSink);
+ for (int i = 0; i < str.length; i += chunkSize) {
+ if (i + chunkSize <= str.length) {
+ stringConversionSink.add(str.substring(i, i + chunkSize));
+ } else {
+ stringConversionSink.add(str.substring(i));
+ }
+ }
+ stringConversionSink.close();
+ return bytes;
+}
+
+String decode(List<int> bytes, int chunkSize,
+ Converter<List<int>, String> converter) {
+ StringBuffer buf = new StringBuffer();
+ var stringSink =
+ new StringConversionSink.fromStringSink(buf);
+ var byteConversionSink = converter.startChunkedConversion(stringSink);
+ for (int i = 0; i < bytes.length; i += chunkSize) {
+ if (i + chunkSize <= bytes.length) {
+ byteConversionSink.add(bytes.sublist(i, i + chunkSize));
+ } else {
+ byteConversionSink.add(bytes.sublist(i));
+ }
+ }
+ byteConversionSink.close();
+ return buf.toString();
+}
+
+void testChunkedConversions() {
+ // Check encoding.
+ for (var converter in [ASCII.encoder,
+ new AsciiCodec().encoder,
+ new AsciiEncoder()]) {
+ for (int chunkSize in [1, 2, 5, 50]) {
+ for (var asciiString in asciiStrings) {
+ var units = asciiString.codeUnits.toList();
+ List bytes = encode(asciiString, chunkSize, converter);
+ Expect.listEquals(units, bytes);
+ }
+ for (var nonAsciiString in nonAsciiStrings) {
+ Expect.throws(() {
+ encode(nonAsciiStrings, chunkSize, converter);
+ });
+ }
+ }
+ }
+ // Check decoding.
+ for (var converter in [ASCII.decoder,
+ new AsciiCodec().decoder,
+ new AsciiDecoder()]) {
+ for (int chunkSize in [1, 2, 5, 50]) {
+ for (var asciiString in asciiStrings) {
+ var units = asciiString.codeUnits.toList();
+ Expect.equals(asciiString, decode(units, chunkSize, converter));
+ }
+ for (var nonAsciiString in nonAsciiStrings) {
+ var units = nonAsciiString.codeUnits.toList();
+ Expect.throws(() {
+ decode(units, chunkSize, converter);
+ });
+ }
+ }
+ }
+}
diff --git a/tests/lib/convert/chunked_conversion_utf89_test.dart b/tests/lib/convert/chunked_conversion_utf89_test.dart
new file mode 100644
index 0000000..a045124
--- /dev/null
+++ b/tests/lib/convert/chunked_conversion_utf89_test.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2013, 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.
+
+import "package:expect/expect.dart";
+import 'dart:convert';
+
+class MySink extends ChunkedConversionSink<String> {
+ final Function _add;
+ final Function _close;
+
+ MySink(this._add, this._close);
+
+ void add(x) { _add(x); }
+ void close() { _close(); }
+}
+
+main() {
+ // Make sure the UTF-8 decoder works eagerly.
+ String lastString;
+ bool isClosed = false;
+ ChunkedConversionSink sink = new MySink((x) => lastString = x,
+ () => isClosed = true);
+ var byteSink = new Utf8Decoder().startChunkedConversion(sink);
+ byteSink.add("abc".codeUnits);
+ Expect.equals("abc", lastString);
+ byteSink.add([0x61, 0xc3]); // 'a' followed by first part of Î.
+ Expect.equals("a", lastString);
+ byteSink.add([0x8e]); // second part of Î.
+ Expect.equals("Î", lastString);
+ Expect.isFalse(isClosed);
+ byteSink.close();
+ Expect.isTrue(isClosed);
+}
diff --git a/tests/lib/convert/latin1_test.dart b/tests/lib/convert/latin1_test.dart
new file mode 100644
index 0000000..18a7797
--- /dev/null
+++ b/tests/lib/convert/latin1_test.dart
@@ -0,0 +1,136 @@
+// Copyright (c) 2012, 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.
+
+import "package:expect/expect.dart";
+import 'dart:convert';
+
+var latin1Strings = [
+ "pure ascii",
+ "blåbærgrød",
+ "\x00 edge cases \xff"
+];
+
+var nonLatin1Strings = [
+ "Edge case \u{100}",
+ "Edge case super-BMP \u{10000}"
+];
+
+void main() {
+ // Build longer versions of the example strings.
+ for (int i = 0, n = latin1Strings.length; i < n ; i++) {
+ var string = latin1Strings[i];
+ while (string.length < 1024) {
+ string += string;
+ }
+ latin1Strings.add(string);
+ }
+ for (int i = 0, n = nonLatin1Strings.length; i < n ; i++) {
+ var string = nonLatin1Strings[i];
+ while (string.length < 1024) {
+ string += string;
+ }
+ nonLatin1Strings.add(string);
+ }
+ testDirectConversions();
+ testChunkedConversions();
+}
+
+void testDirectConversions() {
+ for (var codec in [LATIN1, new Latin1Codec()]) {
+ for (var latin1String in latin1Strings) {
+ List bytes = codec.encoder.convert(latin1String);
+ Expect.listEquals(latin1String.codeUnits.toList(), bytes, latin1String);
+ String roundTripString = codec.decoder.convert(bytes);
+ Expect.equals(latin1String, roundTripString);
+ roundTripString = codec.decode(bytes);
+ Expect.equals(latin1String, roundTripString);
+ }
+
+ for (var nonLatin1String in nonLatin1Strings) {
+ Expect.throws(() {
+ print(codec.encoder.convert(nonLatin1String));
+ }, null, nonLatin1String);
+ }
+ }
+
+ var allowInvalidCodec = new Latin1Codec(allowInvalid: true);
+ var invalidBytes = [0, 1, 0xff, 0xdead, 0];
+ String decoded = allowInvalidCodec.decode(invalidBytes);
+ Expect.equals("\x00\x01\xFF\uFFFD\x00", decoded);
+ decoded = allowInvalidCodec.decoder.convert(invalidBytes);
+ Expect.equals("\x00\x01\xFF\uFFFD\x00", decoded);
+ decoded = LATIN1.decode(invalidBytes, allowInvalid: true);
+ Expect.equals("\x00\x01\xFF\uFFFD\x00", decoded);
+}
+
+List<int> encode(String str, int chunkSize,
+ Converter<String, List<int>> converter) {
+ List<int> bytes = <int>[];
+ ChunkedConversionSink byteSink =
+ new ByteConversionSink.withCallback(bytes.addAll);
+ var stringConversionSink = converter.startChunkedConversion(byteSink);
+ for (int i = 0; i < str.length; i += chunkSize) {
+ if (i + chunkSize <= str.length) {
+ stringConversionSink.add(str.substring(i, i + chunkSize));
+ } else {
+ stringConversionSink.add(str.substring(i));
+ }
+ }
+ stringConversionSink.close();
+ return bytes;
+}
+
+String decode(List<int> bytes, int chunkSize,
+ Converter<List<int>, String> converter) {
+ StringBuffer buf = new StringBuffer();
+ var stringSink =
+ new StringConversionSink.fromStringSink(buf);
+ var byteConversionSink = converter.startChunkedConversion(stringSink);
+ for (int i = 0; i < bytes.length; i += chunkSize) {
+ if (i + chunkSize <= bytes.length) {
+ byteConversionSink.add(bytes.sublist(i, i + chunkSize));
+ } else {
+ byteConversionSink.add(bytes.sublist(i));
+ }
+ }
+ byteConversionSink.close();
+ return buf.toString();
+}
+
+void testChunkedConversions() {
+ // Check encoding.
+ for (var converter in [LATIN1.encoder,
+ new Latin1Codec().encoder,
+ new Latin1Encoder()]) {
+ for (int chunkSize in [1, 2, 5, 50]) {
+ for (var latin1String in latin1Strings) {
+ var units = latin1String.codeUnits.toList();
+ List bytes = encode(latin1String, chunkSize, converter);
+ Expect.listEquals(units, bytes);
+ }
+ for (var nonLatin1String in nonLatin1Strings) {
+ Expect.throws(() {
+ encode(nonLatin1Strings, chunkSize, converter);
+ });
+ }
+ }
+ }
+ // Check decoding.
+ for (var converter in [LATIN1.decoder,
+ new Latin1Codec().decoder,
+ new Latin1Decoder()]) {
+ for (int chunkSize in [1, 2, 5, 50]) {
+ for (var latin1String in latin1Strings) {
+ var units = latin1String.codeUnits.toList();
+ Expect.equals(latin1String, decode(units, chunkSize, converter));
+ }
+ for (var nonLatin1String in nonLatin1Strings) {
+ var units = nonLatin1String.codeUnits.toList();
+ Expect.throws(() {
+ decode(units, chunkSize, converter);
+ });
+ }
+ }
+ }
+}
diff --git a/tests/lib/convert/utf82_test.dart b/tests/lib/convert/utf82_test.dart
index b52f240..e3a5811 100644
--- a/tests/lib/convert/utf82_test.dart
+++ b/tests/lib/convert/utf82_test.dart
@@ -50,7 +50,13 @@
[ 0xC0, 0x80 ],
[ 0xC1, 0x80 ],
// Outside valid range.
- [ 0xF4, 0xBF, 0xBF, 0xBF ]];
+ [ 0xF4, 0xBF, 0xBF, 0xBF ],
+ // Negative
+ [ -0x01 ],
+ [ -0xFF ],
+ [ -0x80000000 ],
+ [ -0x40000000 ],
+ [ -0x80000000000000000]];
final TESTS2 = [
// Test that 0xC0|1, 0x80 does not eat the next character.
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 49dda71..b90b26e 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -15,6 +15,7 @@
mirrors/invoke_private_test: Fail # Issue 12164
mirrors/function_type_mirror_test: Fail # Issue 12166
mirrors/generics_test: Fail # Issue 12333
+mirrors/hierarchy_invariants_test: Fail # Issue 11863
mirrors/fake_function_test: Fail # Issue 11612
mirrors/method_mirror_name_test: Fail # Issue 6335
mirrors/method_mirror_properties_test: Fail # Issue 11861
@@ -125,6 +126,5 @@
convert/chunked_conversion_utf88_test: Pass, Slow # Issue 12025.
convert/streamed_conversion_json_utf8_decode_test: Pass, Slow
-[ $arch == simarm || $arch == arm ]
-typed_data/uint32x4_arithmetic_test: Crash # Unimplemented
-
+[ $arch == simarm ]
+convert/chunked_conversion_utf88_test: Pass, Slow # Issue 12644.
diff --git a/tests/lib/mirrors/hierarchy_invariants_test.dart b/tests/lib/mirrors/hierarchy_invariants_test.dart
new file mode 100644
index 0000000..0197dd3
--- /dev/null
+++ b/tests/lib/mirrors/hierarchy_invariants_test.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2013, 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.
+
+library test.hierarchy_invariants_test;
+
+import 'dart:mirrors';
+
+import 'package:expect/expect.dart';
+
+check(classMirror) {
+ if (classMirror is TypedefMirror) return;
+
+ Expect.isTrue(classMirror.simpleName is Symbol);
+ Expect.notEquals(null, classMirror.owner);
+ Expect.isTrue(classMirror.owner is LibraryMirror);
+ Expect.isTrue(classMirror.superinterfaces is List);
+ if (classMirror.superclass == null) {
+ Expect.equals(reflectClass(Object), classMirror);
+ } else {
+ check(classMirror.superclass);
+ }
+}
+
+main() {
+ currentMirrorSystem().libraries.values.forEach((libraryMirror) {
+ libraryMirror.classes.values.forEach((classMirror) {
+ check(classMirror);
+ });
+ });
+
+ Expect.throws(() => reflectClass(dynamic),
+ (e) => e is ArgumentError,
+ 'dynamic is not a class');
+}
diff --git a/tools/VERSION b/tools/VERSION
index df4a568..2a8dc7c 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -1,4 +1,4 @@
MAJOR 0
MINOR 6
-BUILD 20
-PATCH 1
+BUILD 21
+PATCH 0
diff --git a/tools/bots/compiler.py b/tools/bots/compiler.py
index e469d6a..3f9d9c3 100644
--- a/tools/bots/compiler.py
+++ b/tools/bots/compiler.py
@@ -119,13 +119,13 @@
supported_platforms = {
'linux': ['ff', 'chromeOnAndroid', 'chrome'],
'mac': ['safari'],
- 'windows': []
+ 'windows': ['ie9']
}
# Platforms that we run on the fyi waterfall only.
fyi_supported_platforms = {
'linux': [],
'mac': [],
- 'windows': ['ie9']
+ 'windows': []
}
if (runtime in supported_platforms[system]):
diff --git a/tools/dom/idl/dart/dart.idl b/tools/dom/idl/dart/dart.idl
index 7b1639a..a132f15 100644
--- a/tools/dom/idl/dart/dart.idl
+++ b/tools/dom/idl/dart/dart.idl
@@ -348,15 +348,6 @@
[Suppressed]
interface TextDecoder {};
-// TODO(jacobr): renable these as part of fixing dartbug.com/12537
-// We need to apply changes analogous to https://chromiumcodereview.appspot.com/21274004
-// to the Dart bindings so that we can reenable NodeIterator and TreeWalker
-[Suppressed]
-interface NodeIterator {};
-
-[Suppressed]
-interface TreeWalker {};
-
[Supplemental]
interface Window : EventTarget {};
diff --git a/tools/dom/scripts/systemnative.py b/tools/dom/scripts/systemnative.py
index 9a6436e..8280e8c 100644
--- a/tools/dom/scripts/systemnative.py
+++ b/tools/dom/scripts/systemnative.py
@@ -976,8 +976,14 @@
# Generate to Dart conversion of C++ value.
if return_type_info.dart_type() == 'bool':
set_return_value = 'Dart_SetBooleanReturnValue(args, %s)' % (value_expression)
- elif return_type_info.dart_type() == 'int' and return_type_info.native_type() == 'int':
- set_return_value = 'Dart_SetIntegerReturnValue(args, %s)' % (value_expression)
+ elif return_type_info.dart_type() == 'int':
+ if return_type_info.native_type() == 'unsigned':
+ set_return_value = 'DartUtilities::setDartUnsignedReturnValue(args, %s)' % (value_expression)
+ elif return_type_info.native_type() == 'unsigned long long':
+ set_return_value = 'DartUtilities::setDartUnsignedLongLongReturnValue(args, %s)' % (value_expression)
+ else:
+ assert (return_type_info.native_type() == 'int' or return_type_info.native_type() == 'long long')
+ set_return_value = 'DartUtilities::setDartIntegerReturnValue(args, %s)' % (value_expression)
elif return_type_info.dart_type() == 'double':
set_return_value = 'Dart_SetDoubleReturnValue(args, %s)' % (value_expression)
elif return_type_info.dart_type() == 'String':
diff --git a/tools/get_archive.py b/tools/get_archive.py
index e7ab03d..c5547b6 100755
--- a/tools/get_archive.py
+++ b/tools/get_archive.py
@@ -32,23 +32,23 @@
DRT_DIR = os.path.join('client', 'tests', 'drt')
DRT_VERSION = os.path.join(DRT_DIR, 'LAST_VERSION')
DRT_LATEST_PATTERN = (
- 'gs://dartium-archive/latest/drt-%(osname)s-inc-*.zip')
-DRT_PERMANENT_PATTERN = ('gs://dartium-archive/drt-%(osname)s-inc/drt-'
- '%(osname)s-inc-%(num1)s.%(num2)s.zip')
+ 'gs://dartium-archive/latest/drt-%(osname)s-%(bot)s-*.zip')
+DRT_PERMANENT_PATTERN = ('gs://dartium-archive/drt-%(osname)s-%(bot)s/drt-'
+ '%(osname)s-%(bot)s-%(num1)s.%(num2)s.zip')
DARTIUM_DIR = os.path.join('client', 'tests', 'dartium')
DARTIUM_VERSION = os.path.join(DARTIUM_DIR, 'LAST_VERSION')
DARTIUM_LATEST_PATTERN = (
- 'gs://dartium-archive/latest/dartium-%(osname)s-inc-*.zip')
-DARTIUM_PERMANENT_PATTERN = ('gs://dartium-archive/dartium-%(osname)s-inc/'
- 'dartium-%(osname)s-inc-%(num1)s.%(num2)s.zip')
+ 'gs://dartium-archive/latest/dartium-%(osname)s-%(bot)s-*.zip')
+DARTIUM_PERMANENT_PATTERN = ('gs://dartium-archive/dartium-%(osname)s-%(bot)s/'
+ 'dartium-%(osname)s-%(bot)s-%(num1)s.%(num2)s.zip')
CHROMEDRIVER_DIR = os.path.join('tools', 'testing', 'dartium-chromedriver')
CHROMEDRIVER_VERSION = os.path.join(CHROMEDRIVER_DIR, 'LAST_VERSION')
CHROMEDRIVER_LATEST_PATTERN = (
- 'gs://dartium-archive/latest/chromedriver-%(osname)s-inc-*.zip')
+ 'gs://dartium-archive/latest/chromedriver-%(osname)s-%(bot)s-*.zip')
CHROMEDRIVER_PERMANENT_PATTERN = ('gs://dartium-archive/chromedriver-%(osname)s'
- '-inc/chromedriver-%(osname)s-inc-%(num1)s.'
+ '-%(bot)s/chromedriver-%(osname)s-%(bot)s-%(num1)s.'
'%(num2)s.zip')
SDK_DIR = os.path.join(utils.GetBuildRoot(utils.GuessOS(), 'release', 'ia32'),
@@ -57,7 +57,7 @@
SDK_LATEST_PATTERN = 'gs://dart-editor-archive-continuous/latest/VERSION'
# TODO(efortuna): Once the x64 VM also is optimized, select the version
# based on whether we are running on a 32-bit or 64-bit system.
-SDK_PERMANENT = ('gs://dart-editor-archive-continuous/%(version_num)s/' +
+SDK_PERMANENT = ('gs://dart-editor-archive-continuous/%(version_num)s/' +
'dartsdk-%(osname)s-32.zip')
# Dictionary storing the earliest revision of each download we have stored.
@@ -124,7 +124,7 @@
sys.exit(1)
-def GetDartiumRevision(name, directory, version_file, latest_pattern,
+def GetDartiumRevision(name, bot, directory, version_file, latest_pattern,
permanent_prefix, revision_num=None):
"""Get the latest binary that is stored in the dartium archive.
@@ -146,16 +146,16 @@
if not revision_num:
revision_num = latest[latest.rindex('-') + 1 : latest.index('.')]
latest = (permanent_prefix[:permanent_prefix.rindex('/')] % { 'osname' :
- osname } + latest[latest.rindex('/'):])
+ osname, 'bot' : bot } + latest[latest.rindex('/'):])
else:
latest = (permanent_prefix % { 'osname' : osname, 'num1' : revision_num,
- 'num2' : revision_num })
+ 'num2' : revision_num, 'bot' : bot })
foundURL = False
while not foundURL:
# Test to ensure this URL exists because the dartium-archive builds can
# have unusual numbering (a range of CL numbers) sometimes.
result, out = Gsutil('ls', permanent_prefix % {'osname' : osname,
- 'num1': revision_num, 'num2': '*' })
+ 'num1': revision_num, 'num2': '*', 'bot': bot })
if result == 0:
# First try to find one with the the second number the same as the
# requested number.
@@ -179,9 +179,9 @@
if revision_num <= 0:
TooEarlyError()
return latest
-
- GetFromGsutil(name, directory, version_file, latest_pattern, osdict,
- FindPermanentUrl, revision_num)
+
+ GetFromGsutil(name, directory, version_file, latest_pattern, osdict,
+ FindPermanentUrl, revision_num, bot)
def GetSdkRevision(name, directory, version_file, latest_pattern,
@@ -216,13 +216,13 @@
return ''
latest = (permanent_prefix % { 'osname' : osname, 'version_num': rev_num})
return latest
-
+
GetFromGsutil(name, directory, version_file, latest_pattern, osdict,
FindPermanentUrl, revision_num)
def GetFromGsutil(name, directory, version_file, latest_pattern,
- os_name_dict, get_permanent_url, revision_num = ''):
+ os_name_dict, get_permanent_url, revision_num = '', bot = None):
"""Download and unzip the desired file from Google Storage.
Args:
name: the name of the desired download
@@ -246,8 +246,8 @@
EnsureConfig()
- # Query for the lastest version
- pattern = latest_pattern % { 'osname' : osname }
+ # Query for the latest version
+ pattern = latest_pattern % { 'osname' : osname, 'bot' : bot }
result, out = Gsutil('ls', pattern)
if result == 0:
# use permanent link instead, just in case the latest zip entry gets deleted
@@ -330,24 +330,32 @@
help='Desired revision number to retrieve for the SDK. If '
'unspecified, retrieve the latest SDK build.',
action='store', default=None)
+ parser.add_option('-d', '--debug', dest='debug',
+ help='Download a debug archive instead of a release.',
+ action='store_true', default=False)
args, positional = parser.parse_args()
if args.revision and int(args.revision) < LAST_VALID[positional[0]]:
return TooEarlyError()
+ # Use the incremental release bot ('dartium-*-inc') by default.
+ bot = 'inc'
+ if args.debug:
+ bot = 'debug'
+
if positional[0] == 'dartium':
- GetDartiumRevision('Dartium', DARTIUM_DIR, DARTIUM_VERSION,
+ GetDartiumRevision('Dartium', bot, DARTIUM_DIR, DARTIUM_VERSION,
DARTIUM_LATEST_PATTERN, DARTIUM_PERMANENT_PATTERN,
args.revision)
elif positional[0] == 'chromedriver':
- GetDartiumRevision('chromedriver', CHROMEDRIVER_DIR, CHROMEDRIVER_VERSION,
+ GetDartiumRevision('chromedriver', bot, CHROMEDRIVER_DIR, CHROMEDRIVER_VERSION,
CHROMEDRIVER_LATEST_PATTERN,
CHROMEDRIVER_PERMANENT_PATTERN, args.revision)
elif positional[0] == 'sdk':
GetSdkRevision('sdk', SDK_DIR, SDK_VERSION, SDK_LATEST_PATTERN,
SDK_PERMANENT, args.revision)
elif positional[0] == 'drt':
- GetDartiumRevision('content_shell', DRT_DIR, DRT_VERSION,
+ GetDartiumRevision('content_shell', bot, DRT_DIR, DRT_VERSION,
DRT_LATEST_PATTERN, DRT_PERMANENT_PATTERN,
args.revision)
CopyDrtFont(DRT_DIR)
diff --git a/tools/testing/dart/browser_controller.dart b/tools/testing/dart/browser_controller.dart
index 6d55aee..214a765 100644
--- a/tools/testing/dart/browser_controller.dart
+++ b/tools/testing/dart/browser_controller.dart
@@ -654,9 +654,10 @@
return;
}
- if (status.timeout) {
+ if (status == null || status.timeout) {
// We don't do anything, this browser is currently being killed and
- // replaced.
+ // replaced. The browser here can be null if we decided to kill the
+ // browser.
} else if (status.currentTest != null) {
status.currentTest.timeoutTimer.cancel();
status.currentTest.stopwatch.stop();
diff --git a/tools/testing/dart/browser_test.dart b/tools/testing/dart/browser_test.dart
index 646115b..dbfd7e5 100644
--- a/tools/testing/dart/browser_test.dart
+++ b/tools/testing/dart/browser_test.dart
@@ -12,6 +12,7 @@
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
<title> Test $title </title>
<style>
.unittest-table { font-family:monospace; border:1px; }
@@ -36,12 +37,14 @@
</html>
""";
-String getHtmlLayoutContents(String scriptType, Path sourceScript) =>
+String getHtmlLayoutContents(String scriptType,
+ Path sourceScript) =>
"""
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
</head>
<body>
<script type="text/javascript">
diff --git a/tools/testing/dart/status_file_parser.dart b/tools/testing/dart/status_file_parser.dart
index 36dd839..3c07ff4 100644
--- a/tools/testing/dart/status_file_parser.dart
+++ b/tools/testing/dart/status_file_parser.dart
@@ -17,6 +17,7 @@
* An indication to skip the test. The caller is responsible for skipping it.
*/
const SKIP = "skip";
+const SKIP_BY_DESIGN = "skipbydesign";
const OK = "ok";
/**
* An indication that a test is slow and we should allow extra time for
diff --git a/tools/testing/dart/test_runner.dart b/tools/testing/dart/test_runner.dart
index fbb1de1..edc65e8 100644
--- a/tools/testing/dart/test_runner.dart
+++ b/tools/testing/dart/test_runner.dart
@@ -540,7 +540,8 @@
bool get usesWebDriver => TestUtils.usesWebDriver(configuration['runtime']);
bool get isFlaky {
- if (expectedOutcomes.contains(SKIP)) {
+ if (expectedOutcomes.contains(SKIP) ||
+ expectedOutcomes.contains(SKIP_BY_DESIGN)) {
return false;
}
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index 4f62e29..5f5e4ef 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -355,7 +355,10 @@
SummaryReport.add(expectations);
}
- if (expectations.contains(SKIP)) return;
+ if (expectations.contains(SKIP) ||
+ expectations.contains(SKIP_BY_DESIGN)) {
+ return;
+ }
var args = TestUtils.standardOptions(configuration);
args.add(testName);
@@ -683,7 +686,10 @@
SummaryReport.add(expectations);
}
}
- if (expectations.contains(SKIP)) return;
+ if (expectations.contains(SKIP) ||
+ expectations.contains(SKIP_BY_DESIGN)) {
+ return;
+ }
if (configuration['compiler'] != 'none' && info.hasCompileError) {
// If a compile-time error is expected, and we're testing a
@@ -1907,6 +1913,7 @@
class SummaryReport {
static int total = 0;
static int skipped = 0;
+ static int skippedByDesign = 0;
static int noCrash = 0;
static int pass = 0;
static int failOk = 0;
@@ -1919,6 +1926,9 @@
++total;
if (expectations.contains(SKIP)) {
++skipped;
+ } else if (expectations.contains(SKIP_BY_DESIGN)) {
+ ++skipped;
+ ++skippedByDesign;
} else {
if (expectations.contains(PASS) && expectations.contains(FAIL) &&
!expectations.contains(CRASH) && !expectations.contains(OK)) {
@@ -1950,7 +1960,7 @@
static void printReport() {
if (total == 0) return;
String report = """Total: $total tests
- * $skipped tests will be skipped
+ * $skipped tests will be skipped ($skippedByDesign skipped by design)
* $noCrash tests are expected to be flaky but not crash
* $pass tests are expected to pass
* $failOk tests are expected to fail that we won't fix