[dart][inspect] API changes from design review
Combine Metric/Property into Value.
PS1: Make a nice class/mixin hierarchy with no duplicated code.
Combine metric.dart and property.dart into value.dart, but leave
metric_test.dart and property_test.dart alone (aside from
method and class name changes) to make it easier to see that the existing
tests didn't change.
PS2: Combine property_test.dart and metric_test.dart into
value_test.dart. No edits within the moved code.
PS3: Some search-and-replace, one bugfix.
PS4: Wording changes; specifying the exceptions thrown; and a refactor
in VMO-code (inspired by the bugfix).
PS5: Rebase; refactor of Value to recombine some classes/mixins; wording.
PS6: Minor changes
Test: fx run-host-tests fuchsia_inspect_package_unittests
CF-597 #progress
Change-Id: I3a6c592cb5cf7a01165da784c17c51bf41102510
diff --git a/public/dart/fuchsia_inspect/BUILD.gn b/public/dart/fuchsia_inspect/BUILD.gn
index bb0fa4c..45da0e4 100644
--- a/public/dart/fuchsia_inspect/BUILD.gn
+++ b/public/dart/fuchsia_inspect/BUILD.gn
@@ -17,8 +17,7 @@
"src/inspect/inspect.dart",
"src/inspect/internal/_inspect_impl.dart",
"src/inspect/node.dart",
- "src/inspect/metric.dart",
- "src/inspect/property.dart",
+ "src/inspect/value.dart",
"src/vmo/bitfield64.dart",
"src/vmo/block.dart",
"src/vmo/heap.dart",
@@ -43,8 +42,7 @@
"inspect/internal/inspect_impl_test.dart",
"inspect/inspect_test.dart",
"inspect/node_test.dart",
- "inspect/metric_test.dart",
- "inspect/property_test.dart",
+ "inspect/value_test.dart",
"integration/writer.dart",
"util.dart",
"vmo/bitfield64_test.dart",
diff --git a/public/dart/fuchsia_inspect/examples/inspect_mod/lib/src/inspect_example_app.dart b/public/dart/fuchsia_inspect/examples/inspect_mod/lib/src/inspect_example_app.dart
index 179216f..a8e2396 100644
--- a/public/dart/fuchsia_inspect/examples/inspect_mod/lib/src/inspect_example_app.dart
+++ b/public/dart/fuchsia_inspect/examples/inspect_mod/lib/src/inspect_example_app.dart
@@ -12,7 +12,7 @@
final inspect.Node _inspectNode;
InspectExampleApp(this._inspectNode) {
- _initMetrics();
+ _initValues();
}
@override
@@ -24,13 +24,13 @@
),
home: _InspectHomePage(
title: 'Hello Inspect!',
- inspectNode: _inspectNode.createChild('home-page')),
+ inspectNode: _inspectNode.child('home-page')),
);
}
- /// Initializes the [Inspect] metrics for this widget.
- void _initMetrics() {
- _inspectNode.createStringProperty('app-color').setValue('$_appColor');
+ /// Initializes the [Inspect] values for this widget.
+ void _initValues() {
+ _inspectNode.stringValue('app-color').setValue('$_appColor');
}
}
@@ -39,7 +39,7 @@
final inspect.Node inspectNode;
_InspectHomePage({Key key, this.title, this.inspectNode}) : super(key: key) {
- inspectNode.createStringProperty('title').setValue(title);
+ inspectNode.stringValue('title').setValue(title);
}
@override
@@ -56,17 +56,17 @@
final inspect.Node _inspectNode;
- /// A metric that tracks the value of [_counter].
- final inspect.IntMetric _counterMetric;
+ /// A value that tracks [_counter].
+ final inspect.IntValue _counterValue;
- inspect.StringProperty _backgroundProperty;
+ inspect.StringValue _backgroundValue;
int _counter = 0;
int _colorIndex = 0;
_InspectHomePageState(this._inspectNode)
- : _counterMetric = _inspectNode.createIntMetric('counter') {
- _backgroundProperty = _inspectNode.createStringProperty('background-color')
+ : _counterValue = _inspectNode.intValue('counter') {
+ _backgroundValue = _inspectNode.stringValue('background-color')
..setValue('$_backgroundColor');
}
@@ -76,18 +76,18 @@
setState(() {
_counter++;
- // Note: an alternate approach that is also valid is to set the metric to
+ // Note: an alternate approach that is also valid is to set the value to
// the new value:
//
- // _counterMetric.value = _counter;
- _counterMetric.add(1);
+ // _counterValue.value = _counter;
+ _counterValue.add(1);
});
}
void _decrementCounter() {
setState(() {
_counter--;
- _counterMetric.subtract(1);
+ _counterValue.subtract(1);
});
}
@@ -101,16 +101,16 @@
if (_colorIndex >= _colors.length) {
_colorIndex = 0;
- // Contrived example of removing an Inspect property:
- // Once we've looped through the colors once, delete the property.
+ // Contrived example of removing an Inspect value:
+ // Once we've looped through the colors once, delete the value.
//
// A more realistic example would be if something were being removed
// from the UI, but this is intended to be super simple.
- _backgroundProperty.delete();
- _backgroundProperty = null;
+ _backgroundValue.delete();
+ _backgroundValue = null;
}
- _backgroundProperty?.setValue('$_backgroundColor');
+ _backgroundValue?.setValue('$_backgroundColor');
});
}
diff --git a/public/dart/fuchsia_inspect/lib/inspect.dart b/public/dart/fuchsia_inspect/lib/inspect.dart
index 60067fd..2f8c855 100644
--- a/public/dart/fuchsia_inspect/lib/inspect.dart
+++ b/public/dart/fuchsia_inspect/lib/inspect.dart
@@ -3,4 +3,12 @@
// found in the LICENSE file.
/// The Inspect API for Dart.
-export 'src/inspect/inspect.dart' hide RootNode;
+export 'src/inspect/inspect.dart'
+ show
+ Inspect,
+ InspectStateError,
+ Node,
+ IntValue,
+ DoubleValue,
+ StringValue,
+ ByteDataValue;
diff --git a/public/dart/fuchsia_inspect/lib/src/inspect/inspect.dart b/public/dart/fuchsia_inspect/lib/src/inspect/inspect.dart
index 3bda525..4f33144 100644
--- a/public/dart/fuchsia_inspect/lib/src/inspect/inspect.dart
+++ b/public/dart/fuchsia_inspect/lib/src/inspect/inspect.dart
@@ -13,8 +13,7 @@
import 'internal/_inspect_impl.dart';
part 'node.dart';
-part 'metric.dart';
-part 'property.dart';
+part 'value.dart';
/// Unless reconfigured, the VMO will be this size.
/// @nodoc
@@ -31,11 +30,15 @@
// verify that Inspect() returns the same object on each call.
// (It can't be tested in host unit tests.)
-/// Inspect exposes a structured tree of internal component state.
+/// [Inspect] exposes a structured tree of internal component state.
+///
+/// The [Inspect] object maintains a hierarchy of [Node] objects whose data are
+/// exposed for reading by specialized tools such as iquery.
+///
+/// The classes exposed by this library do not support reading.
abstract class Inspect {
/// Size of the VMO that was / will be created.
/// @nodoc
- @visibleForTesting
static int vmoSize = defaultVmoSizeBytes;
static InspectImpl _singleton;
@@ -53,8 +56,9 @@
///
/// This may not be called after the first call to Inspect().
///
- /// [vmoSizeBytes]: Sets the maximum size of the VMO used to store
- /// inspection data for this program. Must be at least 64 bytes.
+ /// [vmoSizeBytes]: Sets the maximum size of the virtual memory object (VMO)
+ /// used to store inspection data for this program.
+ /// Must be at least 64 bytes.
///
/// Throws [InspectStateError] if called after Inspect() or with an
/// invalid vmoSizeBytes.
diff --git a/public/dart/fuchsia_inspect/lib/src/inspect/metric.dart b/public/dart/fuchsia_inspect/lib/src/inspect/metric.dart
deleted file mode 100644
index 930cb81..0000000
--- a/public/dart/fuchsia_inspect/lib/src/inspect/metric.dart
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2019 The Fuchsia Authors. 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 'inspect.dart';
-
-/// A VMO-backed key-value pair with a [String] key and num value.
-abstract class _Metric<T extends num> {
- /// The VMO index for this metric.
- /// @nodoc
- @visibleForTesting
- final int index;
-
- /// The writer for the underlying VMO.
- ///
- /// Will be set to null if the metric has been deleted or could not be
- /// created in the VMO.
- /// If so, all actions on this metric should be no-ops and not throw.
- VmoWriter _writer;
-
- /// Creates a [_Metric] with [name] and [value] under the [parentIndex].
- _Metric(String name, int parentIndex, this._writer, T value)
- : index = _writer.createMetric(parentIndex, name, value) {
- if (index == invalidIndex) {
- _writer = null;
- }
- }
-
- /// Creates a [_Metric] that never does anything.
- ///
- /// These are returned when calling create__Metric on a deleted [Node].
- _Metric.deleted()
- : _writer = null,
- index = invalidIndex;
-
- bool get _isDeleted => _writer == null;
-
- /// Sets the value of this [_Metric].
- void setValue(T value) {
- _writer?.setMetric(index, value);
- }
-
- /// Adds [delta] to the value of this metric in the VMO.
- void add(T delta) {
- _writer?.addMetric(index, delta);
- }
-
- /// Subtracts [delta] from the value of this metric in the VMO.
- void subtract(T delta) {
- _writer?.subMetric(index, delta);
- }
-
- /// Delete this metric from the VMO.
- ///
- /// After a metric has been deleted, it should no longer be used, so callers
- /// should clear their references to this metric after calling delete.
- /// Any calls on an already deleted metric will be no-ops.
- void delete() {
- _writer?.deleteMetric(index);
- _writer = null;
- }
-}
-
-/// A VMO-backed key-value pair with a [String] key and [int] value.
-class IntMetric extends _Metric<int> {
- IntMetric._(String name, int parentIndex, VmoWriter writer)
- : super(name, parentIndex, writer, 0);
-
- IntMetric._deleted() : super.deleted();
-}
-
-/// A VMO-backed key-value pair with a [String] key and [double] value.
-class DoubleMetric extends _Metric<double> {
- DoubleMetric._(String name, int parentIndex, VmoWriter writer)
- : super(name, parentIndex, writer, 0.0);
-
- DoubleMetric._deleted() : super.deleted();
-}
diff --git a/public/dart/fuchsia_inspect/lib/src/inspect/node.dart b/public/dart/fuchsia_inspect/lib/src/inspect/node.dart
index 8b2e320..42375d5 100644
--- a/public/dart/fuchsia_inspect/lib/src/inspect/node.dart
+++ b/public/dart/fuchsia_inspect/lib/src/inspect/node.dart
@@ -4,7 +4,8 @@
part of 'inspect.dart';
-/// A node in the [Inspect] tree that can have associated key-values (KVs).
+/// A named node in the Inspect tree that can have [Node]s and
+/// values under it.
class Node {
/// The VMO index of this node.
/// @nodoc
@@ -13,19 +14,18 @@
/// The writer for the underlying VMO.
///
- /// Will be set to null if the Metric has been deleted or could not be
+ /// Will be set to null if the Node has been deleted or could not be
/// created in the VMO.
- /// If so, all actions on this Metric should be no-ops and not throw.
+ /// If so, all actions on this Node should be no-ops and not throw.
VmoWriter _writer;
- final _properties = <String, _Property>{};
- final _metrics = <String, _Metric>{};
+ final _values = <String, Value>{};
final _children = <String, Node>{};
/// Creates a [Node] with [name] under the [parentIndex].
///
/// Private as an implementation detail to code that understands VMO indices.
- /// Client code that wishes to create [Node]s should use [createChild].
+ /// Client code that wishes to create [Node]s should use [child].
Node._(String name, int parentIndex, this._writer)
: index = _writer.createNode(parentIndex, name) {
if (index == invalidIndex) {
@@ -45,11 +45,11 @@
bool get _isDeleted => _writer == null;
- /// Creates a child [Node] with [name].
+ /// Returns a child [Node] with [name].
///
- /// If a child with [name] already exists, this
+ /// If a child with [name] already exists and was not deleted, this
/// method returns it. Otherwise, it creates a new [Node].
- Node createChild(String name) {
+ Node child(String name) {
if (_writer == null) {
return Node._deleted();
}
@@ -62,119 +62,117 @@
return _children[name] = Node._(name, index, _writer);
}
- /// Delete this node and any children from underlying storage.
+ /// Deletes this node and any children from underlying storage.
///
- /// After a node has been deleted, all calls on it and its children will have
- /// no effect, but will not result in an error.
+ /// After a node has been deleted, all calls on it and its children have
+ /// no effect and do not result in an error. Calls on a deleted node that
+ /// return a Node or Value return an already-deleted object.
void delete() {
if (_writer == null) {
return;
}
- _properties
- ..forEach((_, property) => property.delete())
- ..clear();
- _metrics
- ..forEach((_, metric) => metric.delete())
+ _values
+ ..forEach((_, value) => value.delete())
..clear();
_children
..forEach((_, node) => node.delete())
..clear();
- _writer.deleteNode(index);
+ _writer.deleteEntity(index);
_writer = null;
}
- /// Creates a [StringProperty] with [name] on this node.
+ /// Returns a [StringValue] with [name] on this node.
///
- /// If a [StringProperty] with [name] already exists and is not deleted,
+ /// If a [StringValue] with [name] already exists and is not deleted,
/// this method returns it.
///
- /// Otherwise, it creates a new property initialized to the empty string.
+ /// Otherwise, it creates a new value initialized to the empty string.
///
- /// Throws [StateError] if a non-deleted property with [name] already exists
- /// but it is not a [StringProperty].
- StringProperty createStringProperty(String name) {
+ /// Throws [InspectStateError] if a non-deleted value with [name] already
+ /// exists but it is not a [StringValue].
+ StringValue stringValue(String name) {
if (_writer == null) {
- return StringProperty._deleted();
+ return StringValue._deleted();
}
- if (_properties.containsKey(name) && !_properties[name]._isDeleted) {
- if (_properties[name] is! StringProperty) {
- throw InspectStateError("Can't create StringProperty named $name;"
+ if (_values.containsKey(name) && !_values[name]._isDeleted) {
+ if (_values[name] is! StringValue) {
+ throw InspectStateError("Can't create StringValue named $name;"
' a different type exists.');
}
- return _properties[name];
+ return _values[name];
}
- return _properties[name] = StringProperty._(name, index, _writer);
+ return _values[name] = StringValue._(name, index, _writer);
}
- /// Creates a [ByteDataProperty] with [name] on this node.
+ /// Returns a [ByteDataValue] with [name] on this node.
///
- /// If a [ByteDataProperty] with [name] already exists and is not deleted,
+ /// If a [ByteDataValue] with [name] already exists and is not deleted,
/// this method returns it.
///
- /// Otherwise, it creates a new property initialized to the empty
+ /// Otherwise, it creates a new value initialized to the empty
/// byte data container.
///
- /// Throws [StateError] if a non-deleted property with [name] already exists
- /// but it is not a [ByteDataProperty].
- ByteDataProperty createByteDataProperty(String name) {
+ /// Throws [InspectStateError] if a non-deleted value with [name] already exists
+ /// but it is not a [ByteDataValue].
+ ByteDataValue byteDataValue(String name) {
if (_writer == null) {
- return ByteDataProperty._deleted();
+ return ByteDataValue._deleted();
}
- if (_properties.containsKey(name) && !_properties[name]._isDeleted) {
- if (_properties[name] is! ByteDataProperty) {
- throw InspectStateError("Can't create ByteDataProperty named $name;"
+ if (_values.containsKey(name) && !_values[name]._isDeleted) {
+ if (_values[name] is! ByteDataValue) {
+ throw InspectStateError("Can't create ByteDataValue named $name;"
' a different type exists.');
}
- return _properties[name];
+ return _values[name];
}
- return _properties[name] = ByteDataProperty._(name, index, _writer);
+ return _values[name] = ByteDataValue._(name, index, _writer);
}
- /// Creates an [IntMetric] with [name] on this node.
+ /// Returns an [IntValue] with [name] on this node.
///
- /// If an [IntMetric] with [name] already exists and is not
+ /// If an [IntValue] with [name] already exists and is not
/// deleted, this method returns it.
///
- /// Otherwise, it creates a new metric initialized to 0.
+ /// Otherwise, it creates a new value initialized to 0.
///
- /// Throws [StateError] if a non-deleted metric with [name]
- /// already exists but it is not an [IntMetric].
- IntMetric createIntMetric(String name) {
+ /// Throws [InspectStateError] if a non-deleted value with [name]
+ /// already exists but it is not an [IntValue].
+ IntValue intValue(String name) {
if (_writer == null) {
- return IntMetric._deleted();
+ return IntValue._deleted();
}
- if (_metrics.containsKey(name) && !_metrics[name]._isDeleted) {
- if (_metrics[name] is! IntMetric) {
+ if (_values.containsKey(name) && !_values[name]._isDeleted) {
+ if (_values[name] is! IntValue) {
throw InspectStateError(
- "Can't create IntMetric named $name; a different type exists.");
+ "Can't create IntValue named $name; a different type exists.");
}
- return _metrics[name];
+ return _values[name];
}
- return _metrics[name] = IntMetric._(name, index, _writer);
+ return _values[name] = IntValue._(name, index, _writer);
}
- /// Creates a [DoubleMetric] with [name] on this node.
+ /// Returns a [DoubleValue] with [name] on this node.
///
- /// If a [DoubleMetric] with [name] already exists and is not
+ /// If a [DoubleValue] with [name] already exists and is not
/// deleted, this method returns it.
///
- /// Otherwise, it creates a new metric initialized to 0.0.
+ /// Otherwise, it creates a new value initialized to 0.0.
///
- /// Throws [StateError] if a non-deleted metric with [name]
- /// already exists but it is not a [DoubleMetric].
- DoubleMetric createDoubleMetric(String name) {
+ /// Throws [InspectStateError] if a non-deleted value with [name]
+ /// already exists but it is not a [DoubleValue].
+ DoubleValue doubleValue(String name) {
if (_writer == null) {
- return DoubleMetric._deleted();
+ return DoubleValue._deleted();
}
- if (_metrics.containsKey(name) && !_metrics[name]._isDeleted) {
- if (_metrics[name] is! DoubleMetric) {
- throw InspectStateError("Can't create DoubleMetric named $name;"
+ if (_values.containsKey(name) && !_values[name]._isDeleted) {
+ if (_values[name] is! DoubleValue) {
+ throw InspectStateError("Can't create DoubleValue named $name;"
' a different type exists.');
}
- return _metrics[name];
+ return _values[name];
}
- return _metrics[name] = DoubleMetric._(name, index, _writer);
+ return _values[name] = DoubleValue._(name, index, _writer);
}
}
@@ -183,6 +181,7 @@
/// The root node has special behavior: Delete is a NOP.
///
/// This class should be hidden from the public API.
+/// @nodoc
class RootNode extends Node {
/// Creates a Node wrapping the root of the Inspect hierarchy.
RootNode(VmoWriter writer) : super._root(writer);
diff --git a/public/dart/fuchsia_inspect/lib/src/inspect/property.dart b/public/dart/fuchsia_inspect/lib/src/inspect/property.dart
deleted file mode 100644
index ed67df3..0000000
--- a/public/dart/fuchsia_inspect/lib/src/inspect/property.dart
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2019 The Fuchsia Authors. 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 'inspect.dart';
-
-/// A VMO-backed key-value pair with a [String] key and [T] value.
-class _Property<T> {
- /// The VMO index for this property.
- /// @nodoc
- @visibleForTesting
- final int index;
-
- /// The writer for the underlying VMO.
- ///
- /// Will be set to null if the property has been deleted or could not be
- /// created in the VMO.
- /// If so, all actions on this property will be no-ops and not throw.
- VmoWriter _writer;
-
- /// Creates a [_Property] with [name] under the [parentIndex].
- _Property(String name, int parentIndex, this._writer)
- : index = _writer.createProperty(parentIndex, name) {
- if (index == invalidIndex) {
- _writer = null;
- }
- }
-
- /// Creates a _Property that never does anything.
- ///
- /// These are returned when calling create<*>Property on a deleted [Node].
- _Property.deleted()
- : _writer = null,
- index = invalidIndex;
-
- bool get _isDeleted => _writer == null;
-
- /// Sets the value of this Property in the Inspect data.
- void setValue(T value) {
- _writer?.setProperty(index, value);
- }
-
- /// Delete this property from the VMO.
- ///
- /// After a property has been deleted, it should no longer be used, so callers
- /// should clear their references to this property after calling delete.
- /// Any calls on an already deleted property will be no-ops.
- void delete() {
- _writer?.deleteProperty(index);
- _writer = null;
- }
-}
-
-/// A VMO-backed key-value pair with a [String] key and [String] value.
-class StringProperty extends _Property<String> {
- StringProperty._(String name, int parentIndex, VmoWriter writer)
- : super(name, parentIndex, writer);
-
- StringProperty._deleted() : super.deleted();
-}
-
-/// A VMO-backed key-value pair with a [String] key and [ByteData] value.
-class ByteDataProperty extends _Property<ByteData> {
- ByteDataProperty._(String name, int parentIndex, VmoWriter writer)
- : super(name, parentIndex, writer);
-
- ByteDataProperty._deleted() : super.deleted();
-}
diff --git a/public/dart/fuchsia_inspect/lib/src/inspect/value.dart b/public/dart/fuchsia_inspect/lib/src/inspect/value.dart
new file mode 100644
index 0000000..da3835f
--- /dev/null
+++ b/public/dart/fuchsia_inspect/lib/src/inspect/value.dart
@@ -0,0 +1,113 @@
+// Copyright 2019 The Fuchsia Authors. 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 'inspect.dart';
+
+/// A VMO-backed key-value pair with a [String] key and a typed value.
+abstract class Value<T> {
+ /// The VMO index for this value.
+ /// @nodoc
+ @visibleForTesting
+ final int index;
+
+ /// The writer for the underlying VMO.
+ ///
+ /// Will be set to null if the [Value] has been deleted or could not be
+ /// created in the VMO.
+ /// If so, all actions on this [Value] should be no-ops and not throw.
+ VmoWriter _writer;
+
+ /// Creates a modifiable [Value].
+ Value._(this.index, this._writer) {
+ if (index == invalidIndex) {
+ _writer = null;
+ }
+ }
+
+ /// Creates a [Value] that never does anything.
+ ///
+ /// These are returned when calling methods on a deleted Node,
+ /// or if there is no space for a newly created value in underlying storage.
+ Value.deleted()
+ : _writer = null,
+ index = invalidIndex;
+
+ bool get _isDeleted => _writer == null;
+
+ /// Sets the value of this [Value].
+ void setValue(T value);
+
+ /// Deletes this value from underlying storage.
+ /// Calls on a deleted value have no effect and do not result in an error.
+ void delete() {
+ _writer?.deleteEntity(index);
+ _writer = null;
+ }
+}
+
+/// Sets value on "Property" type values - those which store a byte-vector.
+mixin Property<T> on Value<T> {
+ @override
+ void setValue(T value) {
+ _writer?.setProperty(index, value);
+ }
+}
+
+/// Operations on "Metric" type values - those which store a number.
+mixin Arithmetic<T extends num> on Value<T> {
+ /// Adds [delta] to the value of this metric.
+ void add(T delta) {
+ _writer?.addMetric(index, delta);
+ }
+
+ /// Subtracts [delta] from the value of this metric.
+ void subtract(T delta) {
+ _writer?.subMetric(index, delta);
+ }
+
+ @override
+ void setValue(T value) {
+ _writer?.setMetric(index, value);
+ }
+}
+
+/// A value holding an [int].
+///
+/// Only [Node.intValue()] can create this object.
+class IntValue extends Value<int> with Arithmetic<int> {
+ IntValue._(String name, int parentIndex, VmoWriter writer)
+ : super._(writer.createMetric(parentIndex, name, 0), writer);
+
+ IntValue._deleted() : super.deleted();
+}
+
+/// A value holding a [double].
+///
+/// Only [Node.doubleValue()] can create this object.
+class DoubleValue extends Value<double> with Arithmetic<double> {
+ DoubleValue._(String name, int parentIndex, VmoWriter writer)
+ : super._(writer.createMetric(parentIndex, name, 0.0), writer);
+
+ DoubleValue._deleted() : super.deleted();
+}
+
+/// A value holding a [String].
+///
+/// Only [Node.stringValue()] can create this object.
+class StringValue extends Value<String> with Property<String> {
+ StringValue._(String name, int parentIndex, VmoWriter writer)
+ : super._(writer.createProperty(parentIndex, name), writer);
+
+ StringValue._deleted() : super.deleted();
+}
+
+/// A value holding a [ByteData].
+///
+/// Only [Node.byteDataValue()] can create this object.
+class ByteDataValue extends Value<ByteData> with Property<ByteData> {
+ ByteDataValue._(String name, int parentIndex, VmoWriter writer)
+ : super._(writer.createProperty(parentIndex, name), writer);
+
+ ByteDataValue._deleted() : super.deleted();
+}
diff --git a/public/dart/fuchsia_inspect/lib/src/vmo/vmo_writer.dart b/public/dart/fuchsia_inspect/lib/src/vmo/vmo_writer.dart
index 3c6a64d..dec4408 100644
--- a/public/dart/fuchsia_inspect/lib/src/vmo/vmo_writer.dart
+++ b/public/dart/fuchsia_inspect/lib/src/vmo/vmo_writer.dart
@@ -75,20 +75,6 @@
}
}
- /// Deletes the Node.
- void deleteNode(int nodeIndex) {
- _beginWork();
- try {
- if (nodeIndex < heapStartIndex) {
- throw Exception('Invalid index {nodeIndex}');
- }
- var node = Block.read(_vmo, nodeIndex);
- _deleteValue(node);
- } finally {
- _commit();
- }
- }
-
/// Adds a named Property to a Node.
int createProperty(int parent, String name) {
_beginWork();
@@ -146,18 +132,6 @@
}
}
- /// Deletes a Property.
- void deleteProperty(int propertyIndex) {
- _beginWork();
- try {
- var property = Block.read(_vmo, propertyIndex);
- _freeExtents(property.propertyExtentIndex);
- _deleteValue(property);
- } finally {
- _commit();
- }
- }
-
/// Creates and assigns value.
int createMetric<T extends num>(int parent, String name, T value) {
_beginWork();
@@ -222,16 +196,6 @@
}
}
- /// Deletes the Metric.
- void deleteMetric(int metricIndex) {
- _beginWork();
- try {
- _deleteValue(Block.read(_vmo, metricIndex));
- } finally {
- _commit();
- }
- }
-
// Creates a new *_VALUE node inside the tree.
Block _createValue(int parent, String name) {
var block = _heap.allocateBlock();
@@ -249,19 +213,35 @@
return block;
}
- /// Deletes a *_VALUE block.
+ /// Deletes a *_VALUE block (Node, Property, Metric).
///
/// This always unparents the block and frees its NAME block.
- /// The block itself is freed unless it's a Node with children; in that
- /// case it's converted to a TOMBSTONE and will be deleted later, when its
- /// last child is deleted and unparented.
- void _deleteValue(Block value) {
- _unparent(value);
- _heap.freeBlock(Block.read(_vmo, value.nameIndex));
- if (value.type == BlockType.nodeValue && value.childCount != 0) {
- value.becomeTombstone();
- } else {
- _heap.freeBlock(value);
+ ///
+ /// Special cases:
+ /// - If index < heapStartIndex, throw.
+ /// - If block is a Node with children, make it a [BlockType.tombstone]
+ /// instead of freeing. It will be deleted later, when its
+ /// last child is deleted and unparented.
+ /// - If block is a [BlockType.propertyValue], free its extents as well.
+ void deleteEntity(int index) {
+ if (index < heapStartIndex) {
+ throw Exception('Invalid index {nodeIndex}');
+ }
+ _beginWork();
+ try {
+ Block value = Block.read(_vmo, index);
+ _unparent(value);
+ _heap.freeBlock(Block.read(_vmo, value.nameIndex));
+ if (value.type == BlockType.nodeValue && value.childCount != 0) {
+ value.becomeTombstone();
+ } else {
+ if (value.type == BlockType.propertyValue) {
+ _freeExtents(value.propertyExtentIndex);
+ }
+ _heap.freeBlock(value);
+ }
+ } finally {
+ _commit();
}
}
diff --git a/public/dart/fuchsia_inspect/test/inspect/metric_test.dart b/public/dart/fuchsia_inspect/test/inspect/metric_test.dart
deleted file mode 100644
index a54c560..0000000
--- a/public/dart/fuchsia_inspect/test/inspect/metric_test.dart
+++ /dev/null
@@ -1,199 +0,0 @@
-// Copyright 2019 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// ignore_for_file: implementation_imports
-
-import 'package:fuchsia_inspect/inspect.dart';
-import 'package:fuchsia_inspect/src/inspect/internal/_inspect_impl.dart';
-import 'package:fuchsia_inspect/src/vmo/vmo_holder.dart';
-import 'package:fuchsia_inspect/src/vmo/vmo_writer.dart';
-import 'package:fuchsia_services/services.dart';
-import 'package:test/test.dart';
-
-import '../util.dart';
-
-void main() {
- VmoHolder vmo;
- Node node;
-
- setUp(() {
- var context = StartupContext.fromStartupInfo();
- vmo = FakeVmo(512);
- var writer = VmoWriter(vmo);
- Inspect inspect = InspectImpl(context, writer);
- node = inspect.root;
- });
-
- group('Int metrics', () {
- test('are created with value 0', () {
- var metric = node.createIntMetric('foo');
-
- expect(readInt(vmo, metric), isZero);
- });
-
- test('are written to the VMO when the value is set', () {
- var metric = node.createIntMetric('eggs')..setValue(12);
-
- expect(readInt(vmo, metric), 12);
- });
-
- test('can be mutated', () {
- var metric = node.createIntMetric('locusts')..setValue(10);
- expect(readInt(vmo, metric), 10);
-
- metric.setValue(1000);
-
- expect(readInt(vmo, metric), 1000);
- });
-
- test('can add arbitrary values', () {
- var metric = node.createIntMetric('bagels')..setValue(13);
- expect(readInt(vmo, metric), 13);
-
- metric.add(13);
-
- expect(readInt(vmo, metric), 26);
- });
-
- test('can subtract arbitrary values', () {
- var metric = node.createIntMetric('bagels')..setValue(13);
- expect(readInt(vmo, metric), 13);
-
- metric.subtract(6);
-
- expect(readInt(vmo, metric), 7);
- });
-
- test('can be deleted', () {
- var metric = node.createIntMetric('sheep')..delete();
-
- expect(() => readInt(vmo, metric), throwsA(anything),
- reason: 'cannot read VMO values from a deleted metric');
- });
-
- test('setting a value on an already deleted metric is a no-op', () {
- var metric = node.createIntMetric('webpages')..delete();
-
- expect(() => metric.setValue(404), returnsNormally);
- expect(() => readInt(vmo, metric), throwsA(anything),
- reason: 'cannot read VMO values from a deleted metric');
- });
-
- test('removing an already deleted metric is a no-op', () {
- var metric = node.createIntMetric('nothing-here')..delete();
-
- expect(() => metric.delete(), returnsNormally);
- });
- });
-
- group('Double metrics', () {
- test('are created with value 0', () {
- var metric = node.createDoubleMetric('foo');
-
- expect(readDouble(vmo, metric), isZero);
- });
-
- test('are written to the VMO when the value is set', () {
- var metric = node.createDoubleMetric('foo')..setValue(2.5);
-
- expect(readDouble(vmo, metric), 2.5);
- });
-
- test('can be mutated', () {
- var metric = node.createDoubleMetric('bar')..setValue(3.0);
- expect(readDouble(vmo, metric), 3.0);
-
- metric.setValue(3.5);
-
- expect(readDouble(vmo, metric), 3.5);
- });
-
- test('can add arbitrary values', () {
- var metric = node.createDoubleMetric('cake')..setValue(1.5);
- expect(readDouble(vmo, metric), 1.5);
-
- metric.add(1.5);
-
- expect(readDouble(vmo, metric), 3);
- });
-
- test('can subtract arbitrary values', () {
- var metric = node.createDoubleMetric('cake')..setValue(5);
- expect(readDouble(vmo, metric), 5);
-
- metric.subtract(0.5);
-
- expect(readDouble(vmo, metric), 4.5);
- });
-
- test('can be deleted', () {
- var metric = node.createDoubleMetric('circumference')..delete();
-
- expect(() => readDouble(vmo, metric), throwsA(anything),
- reason: 'cannot read VMO values from a deleted metric');
- });
-
- test('setting a value on an already deleted metric is a no-op', () {
- var metric = node.createDoubleMetric('pounds')..delete();
-
- expect(() => metric.setValue(50.6), returnsNormally);
- expect(() => readDouble(vmo, metric), throwsA(anything),
- reason: 'cannot read VMO values from a deleted metric');
- });
-
- test('removing an already deleted metric is a no-op', () {
- var metric = node.createDoubleMetric('nothing-here')..delete();
-
- expect(() => metric.delete(), returnsNormally);
- });
- });
-
- group('Metric creation', () {
- test('IntMetrics created twice return the same object', () {
- var childMetric = node.createIntMetric('banana');
- var childMetric2 = node.createIntMetric('banana');
-
- expect(childMetric, isNotNull);
- expect(childMetric2, isNotNull);
- expect(childMetric, same(childMetric2));
- });
-
- test('IntMetrics created after deletion return different objects', () {
- var childMetric = node.createIntMetric('banana')..delete();
- var childMetric2 = node.createIntMetric('banana');
-
- expect(childMetric, isNotNull);
- expect(childMetric2, isNotNull);
- expect(childMetric, isNot(equals(childMetric2)));
- });
-
- test('DoubleMetrics created twice return the same object', () {
- var childMetric = node.createDoubleMetric('banana');
- var childMetric2 = node.createDoubleMetric('banana');
-
- expect(childMetric, isNotNull);
- expect(childMetric2, isNotNull);
- expect(childMetric, same(childMetric2));
- });
-
- test('DoubleMetrics created after deletion return different objects', () {
- var childMetric = node.createDoubleMetric('banana')..delete();
- var childMetric2 = node.createDoubleMetric('banana');
-
- expect(childMetric, isNotNull);
- expect(childMetric2, isNotNull);
- expect(childMetric, isNot(equals(childMetric2)));
- });
-
- test('Changing IntMetric to DoubleMetric throws', () {
- node.createIntMetric('banana');
- expect(() => node.createDoubleMetric('banana'), throwsA(anything));
- });
-
- test('Changing DoubleMetric to IntMetric throws', () {
- node.createDoubleMetric('banana');
- expect(() => node.createIntMetric('banana'), throwsA(anything));
- });
- });
-}
diff --git a/public/dart/fuchsia_inspect/test/inspect/node_test.dart b/public/dart/fuchsia_inspect/test/inspect/node_test.dart
index b289b6d..e21d3b7 100644
--- a/public/dart/fuchsia_inspect/test/inspect/node_test.dart
+++ b/public/dart/fuchsia_inspect/test/inspect/node_test.dart
@@ -27,15 +27,15 @@
});
test('Child nodes have unique indices from their parents', () {
- var childNode = root.createChild('banana');
+ var childNode = root.child('banana');
expect(childNode, isNotNull);
expect(childNode.index, isNot(root.index));
});
test('Child nodes created twice return the same object', () {
- var childNode = root.createChild('banana');
- var childNode2 = root.createChild('banana');
+ var childNode = root.child('banana');
+ var childNode2 = root.child('banana');
expect(childNode, isNotNull);
expect(childNode2, isNotNull);
@@ -43,8 +43,8 @@
});
test('Nodes created after deletion return different objects', () {
- var childNode = root.createChild('banana')..delete();
- var childNode2 = root.createChild('banana');
+ var childNode = root.child('banana')..delete();
+ var childNode2 = root.child('banana');
expect(childNode, isNotNull);
expect(childNode2, isNotNull);
@@ -52,15 +52,15 @@
});
test('Child nodes have unique indices from their siblings', () {
- var child1 = root.createChild('thing1');
- var child2 = root.createChild('thing2');
+ var child1 = root.child('thing1');
+ var child2 = root.child('thing2');
expect(child1.index, isNot(child2.index));
});
test('Deleting root node has no effect', () {
root.delete();
- var child = root.createChild('sheep');
+ var child = root.child('sheep');
expect(() => readNameIndex(vmo, child), returnsNormally);
});
@@ -68,11 +68,11 @@
Node deletedNode;
setUp(() {
- deletedNode = root.createChild('sheep')..delete();
+ deletedNode = root.child('sheep')..delete();
});
test('can be deleted (more than once)', () {
- var child = deletedNode.createChild('sheep')..delete();
+ var child = deletedNode.child('sheep')..delete();
expect(() => readNameIndex(vmo, deletedNode), throwsA(anything),
reason: 'cannot read VMO values from a deleted node');
expect(() => deletedNode.delete(), returnsNormally);
@@ -83,47 +83,41 @@
test('Creating a child on an already deleted node is a no-op', () {
Node grandchild;
- expect(
- () => grandchild = deletedNode.createChild('404'), returnsNormally);
- expect(() => grandchild.createChild('404'), returnsNormally);
+ expect(() => grandchild = deletedNode.child('404'), returnsNormally);
+ expect(() => grandchild.child('404'), returnsNormally);
expect(() => readNameIndex(vmo, grandchild), throwsA(anything),
reason: 'cannot read VMO values from a deleted node');
});
- test('Creating an IntMetric on an already deleted node is a no-op', () {
- IntMetric metric;
- expect(
- () => metric = deletedNode.createIntMetric('404'), returnsNormally);
- expect(() => metric.setValue(404), returnsNormally);
- expect(() => readInt(vmo, metric), throwsA(anything),
+ test('Creating an IntValue on an already deleted node is a no-op', () {
+ IntValue value;
+ expect(() => value = deletedNode.intValue('404'), returnsNormally);
+ expect(() => value.setValue(404), returnsNormally);
+ expect(() => readInt(vmo, value), throwsA(anything),
reason: 'cannot read VMO values from a deleted node');
});
- test('Creating a DoubleMetric on an already deleted node is a no-op', () {
- DoubleMetric metric;
- expect(() => metric = deletedNode.createDoubleMetric('404'),
- returnsNormally);
- expect(() => metric.setValue(404), returnsNormally);
- expect(() => readDouble(vmo, metric), throwsA(anything),
+ test('Creating a DoubleValue on an already deleted node is a no-op', () {
+ DoubleValue value;
+ expect(() => value = deletedNode.doubleValue('404'), returnsNormally);
+ expect(() => value.setValue(404), returnsNormally);
+ expect(() => readDouble(vmo, value), throwsA(anything),
reason: 'cannot read VMO values from a deleted node');
});
- test('Creating a StringProperty on an already deleted node is a no-op', () {
- StringProperty property;
- expect(() => property = deletedNode.createStringProperty('404'),
- returnsNormally);
- expect(() => property.setValue('404'), returnsNormally);
- expect(() => readProperty(vmo, property.index), throwsA(anything),
+ test('Creating a StringValue on an already deleted node is a no-op', () {
+ StringValue value;
+ expect(() => value = deletedNode.stringValue('404'), returnsNormally);
+ expect(() => value.setValue('404'), returnsNormally);
+ expect(() => readProperty(vmo, value.index), throwsA(anything),
reason: 'cannot read VMO values from a deleted property');
});
- test('Creating a ByteDataProperty on an already deleted node is a no-op',
- () {
- ByteDataProperty property;
- expect(() => property = deletedNode.createByteDataProperty('404'),
- returnsNormally);
- expect(() => property.setValue(toByteData('fuchsia')), returnsNormally);
- expect(() => readProperty(vmo, property.index), throwsA(anything),
+ test('Creating a ByteDataValue on an already deleted node is a no-op', () {
+ ByteDataValue value;
+ expect(() => value = deletedNode.byteDataValue('404'), returnsNormally);
+ expect(() => value.setValue(toByteData('fuchsia')), returnsNormally);
+ expect(() => readProperty(vmo, value.index), throwsA(anything),
reason: 'cannot read VMO values from a deleted property');
});
});
@@ -132,42 +126,42 @@
Node normalNode;
setUp(() {
- normalNode = root.createChild('sheep');
+ normalNode = root.child('sheep');
});
test('child Node of deleted Node is deleted', () {
- var grandchild = normalNode.createChild('goats');
+ var grandchild = normalNode.child('goats');
normalNode.delete();
expect(() => readNameIndex(vmo, grandchild), throwsA(anything),
reason: 'child Node of deleted Node should be deleted');
});
- test('child IntMetric of deleted Node is deleted', () {
- var intMetric = normalNode.createIntMetric('llamas');
+ test('child IntValue of deleted Node is deleted', () {
+ var intValue = normalNode.intValue('llamas');
normalNode.delete();
- expect(() => readInt(vmo, intMetric), throwsA(anything),
- reason: 'child IntMetric of deleted Node should be deleted');
+ expect(() => readInt(vmo, intValue), throwsA(anything),
+ reason: 'child IntValue of deleted Node should be deleted');
});
- test('child DoubleMetric of deleted Node is deleted', () {
- var doubleMetric = normalNode.createDoubleMetric('emus');
+ test('child DoubleValue of deleted Node is deleted', () {
+ var doubleValue = normalNode.doubleValue('emus');
normalNode.delete();
- expect(() => readDouble(vmo, doubleMetric), throwsA(anything),
- reason: 'child DoubleMetric of deleted Node should be deleted');
+ expect(() => readDouble(vmo, doubleValue), throwsA(anything),
+ reason: 'child DoubleValue of deleted Node should be deleted');
});
- test('child StringProperty of deleted Node is deleted', () {
- var stringProperty = normalNode.createStringProperty('okapis');
+ test('child StringValue of deleted Node is deleted', () {
+ var stringValue = normalNode.stringValue('okapis');
normalNode.delete();
- expect(() => readProperty(vmo, stringProperty.index), throwsA(anything),
- reason: 'child StringProperty of deleted Node should be deleted');
+ expect(() => readProperty(vmo, stringValue.index), throwsA(anything),
+ reason: 'child StringValue of deleted Node should be deleted');
});
- test('child ByteDataProperty of deleted Node is deleted', () {
- var byteDataProperty = normalNode.createByteDataProperty('capybaras');
+ test('child ByteDataValue of deleted Node is deleted', () {
+ var byteDataValue = normalNode.byteDataValue('capybaras');
normalNode.delete();
- expect(() => readProperty(vmo, byteDataProperty.index), throwsA(anything),
- reason: 'child ByteDataProperty of deleted Node should be deleted');
+ expect(() => readProperty(vmo, byteDataValue.index), throwsA(anything),
+ reason: 'child ByteDataValue of deleted Node should be deleted');
});
});
@@ -182,38 +176,38 @@
});
test('If no space, creation gives a deleted Node', () {
- var missingNode = tinyRoot.createChild('missing');
- expect(() => missingNode.createChild('more missing'), returnsNormally);
+ var missingNode = tinyRoot.child('missing');
+ expect(() => missingNode.child('more missing'), returnsNormally);
expect(() => readNameIndex(vmo, missingNode), throwsA(anything),
+ reason: 'cannot read VMO values from a deleted node');
+ });
+
+ test('If no space, creation gives a deleted IntValue', () {
+ var missingValue = tinyRoot.intValue('missing');
+ expect(() => missingValue.setValue(1), returnsNormally);
+ expect(() => readInt(vmo, missingValue), throwsA(anything),
+ reason: 'cannot read VMO values from a deleted metric');
+ });
+
+ test('If no space, creation gives a deleted DoubleValue', () {
+ var missingValue = tinyRoot.doubleValue('missing');
+ expect(() => missingValue.setValue(1.0), returnsNormally);
+ expect(() => readDouble(vmo, missingValue), throwsA(anything),
+ reason: 'cannot read VMO values from a deleted metric');
+ });
+
+ test('If no space, creation gives a deleted StringValue', () {
+ var missingValue = tinyRoot.stringValue('missing');
+ expect(() => missingValue.setValue('something'), returnsNormally);
+ expect(() => readProperty(vmo, missingValue.index), throwsA(anything),
reason: 'cannot read VMO values from a deleted property');
});
- test('If no space, creation gives a deleted IntMetric', () {
- var missingMetric = tinyRoot.createIntMetric('missing');
- expect(() => missingMetric.setValue(1), returnsNormally);
- expect(() => readInt(vmo, missingMetric), throwsA(anything),
- reason: 'cannot read VMO values from a deleted property');
- });
-
- test('If no space, creation gives a deleted DoubleMetric', () {
- var missingMetric = tinyRoot.createDoubleMetric('missing');
- expect(() => missingMetric.setValue(1.0), returnsNormally);
- expect(() => readDouble(vmo, missingMetric), throwsA(anything),
- reason: 'cannot read VMO values from a deleted property');
- });
-
- test('If no space, creation gives a deleted StringProperty', () {
- var missingProperty = tinyRoot.createStringProperty('missing');
- expect(() => missingProperty.setValue('something'), returnsNormally);
- expect(() => readProperty(vmo, missingProperty.index), throwsA(anything),
- reason: 'cannot read VMO values from a deleted property');
- });
-
- test('If no space, creation gives a deleted ByteDataProperty', () {
+ test('If no space, creation gives a deleted ByteDataValue', () {
var bytes = toByteData('this will not set');
- var missingProperty = tinyRoot.createByteDataProperty('missing');
- expect(() => missingProperty.setValue(bytes), returnsNormally);
- expect(() => readProperty(vmo, missingProperty.index), throwsA(anything),
+ var missingValue = tinyRoot.byteDataValue('missing');
+ expect(() => missingValue.setValue(bytes), returnsNormally);
+ expect(() => readProperty(vmo, missingValue.index), throwsA(anything),
reason: 'cannot read VMO values from a deleted property');
});
});
diff --git a/public/dart/fuchsia_inspect/test/inspect/property_test.dart b/public/dart/fuchsia_inspect/test/inspect/property_test.dart
deleted file mode 100644
index 4f284b1..0000000
--- a/public/dart/fuchsia_inspect/test/inspect/property_test.dart
+++ /dev/null
@@ -1,173 +0,0 @@
-// Copyright 2019 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// ignore_for_file: implementation_imports
-
-import 'package:fuchsia_inspect/inspect.dart';
-import 'package:fuchsia_inspect/src/inspect/internal/_inspect_impl.dart';
-import 'package:fuchsia_inspect/src/vmo/util.dart';
-import 'package:fuchsia_inspect/src/vmo/vmo_holder.dart';
-import 'package:fuchsia_inspect/src/vmo/vmo_writer.dart';
-import 'package:fuchsia_services/services.dart';
-import 'package:test/test.dart';
-
-import '../util.dart';
-
-void main() {
- VmoHolder vmo;
- Node node;
-
- setUp(() {
- var context = StartupContext.fromStartupInfo();
- vmo = FakeVmo(512);
- var writer = VmoWriter(vmo);
- Inspect inspect = InspectImpl(context, writer);
- node = inspect.root;
- });
-
- group('String properties', () {
- test('are written to the VMO when the value is set', () {
- var property = node.createStringProperty('color')..setValue('fuchsia');
-
- expect(readProperty(vmo, property.index),
- equalsByteData(toByteData('fuchsia')));
- });
-
- test('can be mutated', () {
- var property = node.createStringProperty('breakfast')
- ..setValue('pancakes');
-
- expect(readProperty(vmo, property.index),
- equalsByteData(toByteData('pancakes')));
-
- property.setValue('waffles');
- expect(readProperty(vmo, property.index),
- equalsByteData(toByteData('waffles')));
- });
-
- test('can be deleted', () {
- var property = node.createStringProperty('scallops');
- var index = property.index;
-
- property.delete();
-
- expect(() => readProperty(vmo, index), throwsA(anything),
- reason: 'cannot read VMO values from a deleted property');
- });
-
- test('setting a value on an already deleted property is a no-op', () {
- var property = node.createStringProperty('paella');
- var index = property.index;
- property.delete();
-
- expect(() => property.setValue('this will not set'), returnsNormally);
- expect(() => readProperty(vmo, index), throwsA(anything),
- reason: 'cannot read VMO values from a deleted property');
- });
-
- test('removing an already deleted property is a no-op', () {
- var property = node.createStringProperty('nothing-here')..delete();
-
- expect(() => property.delete(), returnsNormally);
- });
- });
-
- group('ByteData properties', () {
- test('are written to the VMO when the value is set', () {
- var bytes = toByteData('fuchsia');
- var property = node.createByteDataProperty('color')..setValue(bytes);
-
- expect(readProperty(vmo, property.index), equalsByteData(bytes));
- });
-
- test('can be mutated', () {
- var pancakes = toByteData('pancakes');
- var property = node.createByteDataProperty('breakfast')
- ..setValue(pancakes);
-
- expect(readProperty(vmo, property.index), equalsByteData(pancakes));
-
- var waffles = toByteData('waffles');
- property.setValue(waffles);
- expect(readProperty(vmo, property.index), equalsByteData(waffles));
- });
-
- test('can be deleted', () {
- var property = node.createByteDataProperty('scallops');
- var index = property.index;
-
- property.delete();
-
- expect(() => readProperty(vmo, index), throwsA(anything),
- reason: 'cannot read VMO values from a deleted property');
- });
-
- test('setting a value on an already deleted property is a no-op', () {
- var property = node.createByteDataProperty('paella');
- var index = property.index;
- property.delete();
-
- var bytes = toByteData('this will not set');
- expect(() => property.setValue(bytes), returnsNormally);
- expect(() => readProperty(vmo, index), throwsA(anything),
- reason: 'cannot read VMO values from a deleted property');
- });
-
- test('removing an already deleted property is a no-op', () {
- var property = node.createByteDataProperty('nothing-here')..delete();
-
- expect(() => property.delete(), returnsNormally);
- });
- });
-
- group('Property creation', () {
- test('StringProperties created twice return the same object', () {
- var childMetric = node.createStringProperty('banana');
- var childMetric2 = node.createStringProperty('banana');
-
- expect(childMetric, isNotNull);
- expect(childMetric2, isNotNull);
- expect(childMetric, same(childMetric2));
- });
-
- test('StringProperties created after deletion return different objects',
- () {
- var childMetric = node.createStringProperty('banana')..delete();
- var childMetric2 = node.createStringProperty('banana');
-
- expect(childMetric, isNotNull);
- expect(childMetric2, isNotNull);
- expect(childMetric, isNot(equals(childMetric2)));
- });
-
- test('ByteDataProperties created twice return the same object', () {
- var childMetric = node.createByteDataProperty('banana');
- var childMetric2 = node.createByteDataProperty('banana');
-
- expect(childMetric, isNotNull);
- expect(childMetric2, isNotNull);
- expect(childMetric, same(childMetric2));
- });
-
- test('ByteDataProperties created after deletion return different objects',
- () {
- var childMetric = node.createByteDataProperty('banana')..delete();
- var childMetric2 = node.createByteDataProperty('banana');
-
- expect(childMetric, isNotNull);
- expect(childMetric2, isNotNull);
- expect(childMetric, isNot(equals(childMetric2)));
- });
-
- test('Changing StringProperty to ByteDataProperty throws', () {
- node.createStringProperty('banana');
- expect(() => node.createByteDataProperty('banana'), throwsA(anything));
- });
-
- test('Changing ByteDataProperty to StringProperty throws', () {
- node.createByteDataProperty('banana');
- expect(() => node.createStringProperty('banana'), throwsA(anything));
- });
- });
-}
diff --git a/public/dart/fuchsia_inspect/test/inspect/value_test.dart b/public/dart/fuchsia_inspect/test/inspect/value_test.dart
new file mode 100644
index 0000000..6fcad60
--- /dev/null
+++ b/public/dart/fuchsia_inspect/test/inspect/value_test.dart
@@ -0,0 +1,454 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// ignore_for_file: implementation_imports
+
+import 'package:fuchsia_inspect/inspect.dart';
+import 'package:fuchsia_inspect/src/inspect/internal/_inspect_impl.dart';
+import 'package:fuchsia_inspect/src/vmo/util.dart';
+import 'package:fuchsia_inspect/src/vmo/vmo_holder.dart';
+import 'package:fuchsia_inspect/src/vmo/vmo_writer.dart';
+import 'package:fuchsia_services/services.dart';
+import 'package:test/test.dart';
+
+import '../util.dart';
+
+void main() {
+ VmoHolder vmo;
+ Node node;
+
+ setUp(() {
+ var context = StartupContext.fromStartupInfo();
+ vmo = FakeVmo(512);
+ var writer = VmoWriter(vmo);
+ Inspect inspect = InspectImpl(context, writer);
+ node = inspect.root;
+ });
+
+ group('String values', () {
+ test('are written to the VMO when the value is set', () {
+ var value = node.stringValue('color')..setValue('fuchsia');
+
+ expect(readProperty(vmo, value.index),
+ equalsByteData(toByteData('fuchsia')));
+ });
+
+ test('can be mutated', () {
+ var value = node.stringValue('breakfast')..setValue('pancakes');
+
+ expect(readProperty(vmo, value.index),
+ equalsByteData(toByteData('pancakes')));
+
+ value.setValue('waffles');
+ expect(readProperty(vmo, value.index),
+ equalsByteData(toByteData('waffles')));
+ });
+
+ test('can be deleted', () {
+ var value = node.stringValue('scallops');
+ var index = value.index;
+
+ value.delete();
+
+ expect(() => readProperty(vmo, index),
+ throwsA(const TypeMatcher<StateError>()),
+ reason: 'cannot read VMO values from a deleted property');
+ });
+
+ test('setting a value on an already deleted value is a no-op', () {
+ var value = node.stringValue('paella');
+ var index = value.index;
+ value.delete();
+
+ expect(() => value.setValue('this will not set'), returnsNormally);
+ expect(() => readProperty(vmo, index),
+ throwsA(const TypeMatcher<StateError>()),
+ reason: 'cannot read VMO values from a deleted property');
+ });
+
+ test('removing an already deleted value is a no-op', () {
+ var value = node.stringValue('nothing-here')..delete();
+
+ expect(() => value.delete(), returnsNormally);
+ });
+ });
+
+ group('ByteData values', () {
+ test('are written to the VMO when the value is set', () {
+ var bytes = toByteData('fuchsia');
+ var value = node.byteDataValue('color')..setValue(bytes);
+
+ expect(readProperty(vmo, value.index), equalsByteData(bytes));
+ });
+
+ test('can be mutated', () {
+ var pancakes = toByteData('pancakes');
+ var value = node.byteDataValue('breakfast')..setValue(pancakes);
+
+ expect(readProperty(vmo, value.index), equalsByteData(pancakes));
+
+ var waffles = toByteData('waffles');
+ value.setValue(waffles);
+ expect(readProperty(vmo, value.index), equalsByteData(waffles));
+ });
+
+ test('can be deleted', () {
+ var value = node.byteDataValue('scallops');
+ var index = value.index;
+
+ value.delete();
+
+ expect(() => readProperty(vmo, index),
+ throwsA(const TypeMatcher<StateError>()),
+ reason: 'cannot read VMO values from a deleted property');
+ });
+
+ test('setting a value on an already deleted value is a no-op', () {
+ var value = node.byteDataValue('paella');
+ var index = value.index;
+ value.delete();
+
+ var bytes = toByteData('this will not set');
+ expect(() => value.setValue(bytes), returnsNormally);
+ expect(() => readProperty(vmo, index),
+ throwsA(const TypeMatcher<StateError>()),
+ reason: 'cannot read VMO values from a deleted property');
+ });
+
+ test('removing an already deleted value is a no-op', () {
+ var value = node.byteDataValue('nothing-here')..delete();
+
+ expect(() => value.delete(), returnsNormally);
+ });
+ });
+
+ group('Property creation (byte-vector Values)', () {
+ test('StringValues created twice return the same object', () {
+ var childValue = node.stringValue('banana');
+ var childValue2 = node.stringValue('banana');
+
+ expect(childValue, isNotNull);
+ expect(childValue2, isNotNull);
+ expect(childValue, same(childValue2));
+ });
+
+ test('StringValues created after deletion return different objects', () {
+ var childValue = node.stringValue('banana')..delete();
+ var childValue2 = node.stringValue('banana');
+
+ expect(childValue, isNotNull);
+ expect(childValue2, isNotNull);
+ expect(childValue, isNot(equals(childValue2)));
+ });
+
+ test('ByteDataValues created twice return the same object', () {
+ var childValue = node.byteDataValue('banana');
+ var childValue2 = node.byteDataValue('banana');
+
+ expect(childValue, isNotNull);
+ expect(childValue2, isNotNull);
+ expect(childValue, same(childValue2));
+ });
+
+ test('ByteDataValues created after deletion return different objects', () {
+ var childValue = node.byteDataValue('banana')..delete();
+ var childValue2 = node.byteDataValue('banana');
+
+ expect(childValue, isNotNull);
+ expect(childValue2, isNotNull);
+ expect(childValue, isNot(equals(childValue2)));
+ });
+
+ test('Changing StringValue to ByteDataValue throws', () {
+ node.stringValue('banana');
+ expect(() => node.byteDataValue('banana'),
+ throwsA(const TypeMatcher<InspectStateError>()));
+ });
+
+ test('Changing StringValue to IntValue throws', () {
+ node.stringValue('banana');
+ expect(() => node.intValue('banana'),
+ throwsA(const TypeMatcher<InspectStateError>()));
+ });
+
+ test('Changing StringValue to DoubleValue throws', () {
+ node.stringValue('banana');
+ expect(() => node.doubleValue('banana'),
+ throwsA(const TypeMatcher<InspectStateError>()));
+ });
+
+ test('Changing ByteDataValue to StringValue throws', () {
+ node.byteDataValue('banana');
+ expect(() => node.stringValue('banana'),
+ throwsA(const TypeMatcher<InspectStateError>()));
+ });
+
+ test('Changing ByteDataValue to IntValue throws', () {
+ node.byteDataValue('banana');
+ expect(() => node.intValue('banana'),
+ throwsA(const TypeMatcher<InspectStateError>()));
+ });
+
+ test('Changing ByteDataValue to DoubleValue throws', () {
+ node.byteDataValue('banana');
+ expect(() => node.doubleValue('banana'),
+ throwsA(const TypeMatcher<InspectStateError>()));
+ });
+
+ test('If no space, creation gives a deleted StringValue', () {
+ var tinyVmo = FakeVmo(64);
+ var writer = VmoWriter(tinyVmo);
+ var context = StartupContext.fromStartupInfo();
+ Inspect inspect = InspectImpl(context, writer);
+ var tinyRoot = inspect.root;
+ var missingValue = tinyRoot.stringValue('missing');
+ expect(() => missingValue.setValue('something'), returnsNormally);
+ expect(() => readProperty(vmo, missingValue.index),
+ throwsA(const TypeMatcher<StateError>()),
+ reason: 'cannot read VMO values from a deleted property');
+ });
+
+ test('If no space, creation gives a deleted ByteDataValue', () {
+ var tinyVmo = FakeVmo(64);
+ var writer = VmoWriter(tinyVmo);
+ var context = StartupContext.fromStartupInfo();
+ Inspect inspect = InspectImpl(context, writer);
+ var tinyRoot = inspect.root;
+ var bytes = toByteData('this will not set');
+ var missingValue = tinyRoot.byteDataValue('missing');
+ expect(() => missingValue.setValue(bytes), returnsNormally);
+ expect(() => readProperty(vmo, missingValue.index),
+ throwsA(const TypeMatcher<StateError>()),
+ reason: 'cannot read VMO values from a deleted property');
+ });
+ });
+
+ group('Int Values', () {
+ test('are created with value 0', () {
+ var value = node.intValue('foo');
+
+ expect(readInt(vmo, value), isZero);
+ });
+
+ test('are written to the VMO when the value is set', () {
+ var value = node.intValue('eggs')..setValue(12);
+
+ expect(readInt(vmo, value), 12);
+ });
+
+ test('can be mutated', () {
+ var value = node.intValue('locusts')..setValue(10);
+ expect(readInt(vmo, value), 10);
+
+ value.setValue(1000);
+
+ expect(readInt(vmo, value), 1000);
+ });
+
+ test('can add arbitrary values', () {
+ var value = node.intValue('bagels')..setValue(13);
+ expect(readInt(vmo, value), 13);
+
+ value.add(13);
+
+ expect(readInt(vmo, value), 26);
+ });
+
+ test('can subtract arbitrary values', () {
+ var value = node.intValue('bagels')..setValue(13);
+ expect(readInt(vmo, value), 13);
+
+ value.subtract(6);
+
+ expect(readInt(vmo, value), 7);
+ });
+
+ test('can be deleted', () {
+ var value = node.intValue('sheep')..delete();
+
+ expect(
+ () => readInt(vmo, value), throwsA(const TypeMatcher<StateError>()),
+ reason: 'cannot read VMO values from a deleted value');
+ });
+
+ test('setting a value on an already deleted value is a no-op', () {
+ var value = node.intValue('webpages')..delete();
+
+ expect(() => value.setValue(404), returnsNormally);
+ expect(
+ () => readInt(vmo, value), throwsA(const TypeMatcher<StateError>()),
+ reason: 'cannot read VMO values from a deleted value');
+ });
+
+ test('removing an already deleted value is a no-op', () {
+ var value = node.intValue('nothing-here')..delete();
+
+ expect(() => value.delete(), returnsNormally);
+ });
+ });
+
+ group('DoubleValues', () {
+ test('are created with value 0', () {
+ var value = node.doubleValue('foo');
+
+ expect(readDouble(vmo, value), isZero);
+ });
+
+ test('are written to the VMO when the value is set', () {
+ var value = node.doubleValue('foo')..setValue(2.5);
+
+ expect(readDouble(vmo, value), 2.5);
+ });
+
+ test('can be mutated', () {
+ var value = node.doubleValue('bar')..setValue(3.0);
+ expect(readDouble(vmo, value), 3.0);
+
+ value.setValue(3.5);
+
+ expect(readDouble(vmo, value), 3.5);
+ });
+
+ test('can add arbitrary values', () {
+ var value = node.doubleValue('cake')..setValue(1.5);
+ expect(readDouble(vmo, value), 1.5);
+
+ value.add(1.5);
+
+ expect(readDouble(vmo, value), 3);
+ });
+
+ test('can subtract arbitrary values', () {
+ var value = node.doubleValue('cake')..setValue(5);
+ expect(readDouble(vmo, value), 5);
+
+ value.subtract(0.5);
+
+ expect(readDouble(vmo, value), 4.5);
+ });
+
+ test('can be deleted', () {
+ var value = node.doubleValue('circumference')..delete();
+
+ expect(() => readDouble(vmo, value),
+ throwsA(const TypeMatcher<StateError>()),
+ reason: 'cannot read VMO values from a deleted value');
+ });
+
+ test('setting a value on an already deleted value is a no-op', () {
+ var value = node.doubleValue('pounds')..delete();
+
+ expect(() => value.setValue(50.6), returnsNormally);
+ expect(() => readDouble(vmo, value),
+ throwsA(const TypeMatcher<StateError>()),
+ reason: 'cannot read VMO values from a deleted value');
+ });
+
+ test('removing an already deleted value is a no-op', () {
+ var value = node.doubleValue('nothing-here')..delete();
+
+ expect(() => value.delete(), returnsNormally);
+ });
+ });
+
+ group('value creation', () {
+ test('IntValues created twice return the same object', () {
+ var childValue = node.intValue('banana');
+ var childValue2 = node.intValue('banana');
+
+ expect(childValue, isNotNull);
+ expect(childValue2, isNotNull);
+ expect(childValue, same(childValue2));
+ });
+
+ test('IntValues created after deletion return different objects', () {
+ var childValue = node.intValue('banana')..delete();
+ var childValue2 = node.intValue('banana');
+
+ expect(childValue, isNotNull);
+ expect(childValue2, isNotNull);
+ expect(childValue, isNot(equals(childValue2)));
+ });
+
+ test('DoubleValues created twice return the same object', () {
+ var childValue = node.doubleValue('banana');
+ var childValue2 = node.doubleValue('banana');
+
+ expect(childValue, isNotNull);
+ expect(childValue2, isNotNull);
+ expect(childValue, same(childValue2));
+ });
+
+ test('DoubleValues created after deletion return different objects', () {
+ var childValue = node.doubleValue('banana')..delete();
+ var childValue2 = node.doubleValue('banana');
+
+ expect(childValue, isNotNull);
+ expect(childValue2, isNotNull);
+ expect(childValue, isNot(equals(childValue2)));
+ });
+
+ test('Changing IntValue to DoubleValue throws', () {
+ node.intValue('banana');
+ expect(() => node.doubleValue('banana'),
+ throwsA(const TypeMatcher<InspectStateError>()));
+ });
+
+ test('Changing IntValue to StringValue throws', () {
+ node.intValue('banana');
+ expect(() => node.stringValue('banana'),
+ throwsA(const TypeMatcher<InspectStateError>()));
+ });
+
+ test('Changing IntValue to ByteDataValue throws', () {
+ node.intValue('banana');
+ expect(() => node.byteDataValue('banana'),
+ throwsA(const TypeMatcher<InspectStateError>()));
+ });
+
+ test('Changing DoubleValue to IntValue throws', () {
+ node.doubleValue('banana');
+ expect(() => node.intValue('banana'),
+ throwsA(const TypeMatcher<InspectStateError>()));
+ });
+
+ test('Changing DoubleValue to StringValue throws', () {
+ node.doubleValue('banana');
+ expect(() => node.stringValue('banana'),
+ throwsA(const TypeMatcher<InspectStateError>()));
+ });
+
+ test('Changing DoubleValue to ByteDataValue throws', () {
+ node.doubleValue('banana');
+ expect(() => node.byteDataValue('banana'),
+ throwsA(const TypeMatcher<InspectStateError>()));
+ });
+
+ test('If no space, creation gives a deleted IntValue', () {
+ var tinyVmo = FakeVmo(64);
+ var writer = VmoWriter(tinyVmo);
+ var context = StartupContext.fromStartupInfo();
+ Inspect inspect = InspectImpl(context, writer);
+ var tinyRoot = inspect.root;
+ var missingValue = tinyRoot.intValue('missing');
+ expect(() => missingValue.setValue(1), returnsNormally);
+ expect(() => readInt(vmo, missingValue),
+ throwsA(const TypeMatcher<StateError>()),
+ reason: 'cannot read VMO values from a deleted property');
+ });
+
+ test('If no space, creation gives a deleted DoubleValue', () {
+ var tinyVmo = FakeVmo(64);
+ var writer = VmoWriter(tinyVmo);
+ var context = StartupContext.fromStartupInfo();
+ Inspect inspect = InspectImpl(context, writer);
+ var tinyRoot = inspect.root;
+ var missingValue = tinyRoot.doubleValue('missing');
+ expect(() => missingValue.setValue(1.0), returnsNormally);
+ expect(() => readDouble(vmo, missingValue),
+ throwsA(const TypeMatcher<StateError>()),
+ reason: 'cannot read VMO values from a deleted property');
+ });
+ });
+}
diff --git a/public/dart/fuchsia_inspect/test/util.dart b/public/dart/fuchsia_inspect/test/util.dart
index 5fd1b18..68aa058 100644
--- a/public/dart/fuchsia_inspect/test/util.dart
+++ b/public/dart/fuchsia_inspect/test/util.dart
@@ -189,13 +189,13 @@
int readNameIndex(FakeVmo vmo, Node node) =>
Block.read(vmo, node.index).nameIndex;
-/// Returns the int value of [metric] in [vmo].
-int readInt(FakeVmo vmo, IntMetric metric) =>
- Block.read(vmo, metric.index).intValue;
+/// Returns the int value of [value] in [vmo].
+int readInt(FakeVmo vmo, IntValue value) =>
+ Block.read(vmo, value.index).intValue;
-/// Returns the double value of [metric] in [vmo].
-double readDouble(FakeVmo vmo, DoubleMetric metric) =>
- Block.read(vmo, metric.index).doubleValue;
+/// Returns the double value of [value] in [vmo].
+double readDouble(FakeVmo vmo, DoubleValue value) =>
+ Block.read(vmo, value.index).doubleValue;
/// A matcher that matches ByteData values as unit8 lists.
Matcher equalsByteData(ByteData data) => _EqualsByteData(data);
diff --git a/public/dart/fuchsia_inspect/test/vmo/vmo_writer_test.dart b/public/dart/fuchsia_inspect/test/vmo/vmo_writer_test.dart
index 11183b6..7903c02 100644
--- a/public/dart/fuchsia_inspect/test/vmo/vmo_writer_test.dart
+++ b/public/dart/fuchsia_inspect/test/vmo/vmo_writer_test.dart
@@ -76,7 +76,7 @@
Test(_nameFor(vmo, child), toByteData('child')),
Test(writer.rootNode, 1)
]);
- writer.deleteNode(child);
+ writer.deleteEntity(child);
// Deleting a node without children should free it and its name.
// root node should have 0 children.
checker.check(-2, [Test(writer.rootNode, 0)]);
@@ -99,7 +99,7 @@
checker.check(0, [Test(intMetric, -1)]);
writer.setMetric(intMetric, 2);
checker.check(0, [Test(intMetric, 2)]);
- writer.deleteMetric(intMetric);
+ writer.deleteEntity(intMetric);
checker.check(-2, [Test(writer.rootNode, 0)]);
});
@@ -121,7 +121,7 @@
checker.check(0, [Test(doubleMetric, -0.5)]);
writer.setMetric(doubleMetric, 1.5);
checker.check(0, [Test(doubleMetric, 1.5)]);
- writer.deleteMetric(doubleMetric);
+ writer.deleteEntity(doubleMetric);
checker.check(-2, [Test(writer.rootNode, 0)]);
});
@@ -139,7 +139,7 @@
final bytes = ByteData(8)..setFloat64(0, 1.23);
writer.setProperty(property, bytes);
checker.check(1, [Test(_extentFor(vmo, property), bytes)]);
- writer.deleteProperty(property);
+ writer.deleteEntity(property);
// Property, its extent, and its name should be freed. Its parent should
// have one fewer children (0 in this case).
checker.check(-3, [Test(writer.rootNode, 0)]);
@@ -156,13 +156,13 @@
checker.check(2, [Test(writer.rootNode, 1), Test(parent, 1)]);
final metric = writer.createMetric(child, 'metric', 1);
checker.check(2, [Test(child, 1), Test(parent, 1)]);
- writer.deleteNode(child);
+ writer.deleteEntity(child);
// Now child should be a tombstone; only its name should be freed.
checker.check(-1, [Test(child, 1), Test(parent, 0)]);
- writer.deleteNode(parent);
+ writer.deleteEntity(parent);
// Parent, plus its name, should be freed; root should have no children.
checker.check(-2, [Test(writer.rootNode, 0)]);
- writer.deleteNode(metric);
+ writer.deleteEntity(metric);
// Metric, its name, and child should be freed.
checker.check(-3, []);
// Make sure we can still create nodes on the root