blob: e49b0c5cae13f720754e6742c49fca231c9348fe [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert';
import 'dart:ui';
import 'package:flutter/foundation.dart';
import 'package:flutter_test/flutter_test.dart';
class TestTree extends Object with DiagnosticableTreeMixin {
TestTree({
this.name,
this.style,
this.children = const <TestTree>[],
this.properties = const <DiagnosticsNode>[],
});
final String name;
final List<TestTree> children;
final List<DiagnosticsNode> properties;
final DiagnosticsTreeStyle style;
@override
List<DiagnosticsNode> debugDescribeChildren() {
final List<DiagnosticsNode> children = <DiagnosticsNode>[];
for (TestTree child in this.children) {
children.add(child.toDiagnosticsNode(
name: 'child ${child.name}',
style: child.style,
));
}
return children;
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
if (style != null)
properties.defaultDiagnosticsTreeStyle = style;
this.properties.forEach(properties.add);
}
}
enum ExampleEnum {
hello,
world,
deferToChild,
}
/// Encode and decode to JSON to make sure all objects in the JSON for the
/// [DiagnosticsNode] are valid JSON.
Map<String, Object> simulateJsonSerialization(DiagnosticsNode node) {
return json.decode(json.encode(node.toJsonMap()));
}
void validateNodeJsonSerialization(DiagnosticsNode node) {
validateNodeJsonSerializationHelper(simulateJsonSerialization(node), node);
}
void validateNodeJsonSerializationHelper(Map<String, Object> json, DiagnosticsNode node) {
expect(json['name'], equals(node.name));
expect(json['showSeparator'], equals(node.showSeparator));
expect(json['description'], equals(node.toDescription()));
expect(json['level'], equals(describeEnum(node.level)));
expect(json['showName'], equals(node.showName));
expect(json['emptyBodyDescription'], equals(node.emptyBodyDescription));
expect(json['style'], equals(describeEnum(node.style)));
final String valueToString = node is DiagnosticsProperty ? node.valueToString() : node.value.toString();
expect(json['valueToString'], equals(valueToString));
expect(json['type'], equals(node.runtimeType.toString()));
expect(json['hasChildren'], equals(node.getChildren().isNotEmpty));
}
void validatePropertyJsonSerialization(DiagnosticsProperty<Object> property) {
validatePropertyJsonSerializationHelper(simulateJsonSerialization(property), property);
}
void validateStringPropertyJsonSerialization(StringProperty property) {
final Map<String, Object> json = simulateJsonSerialization(property);
expect(json['quoted'], equals(property.quoted));
validatePropertyJsonSerializationHelper(json, property);
}
void validateFlagPropertyJsonSerialization(FlagProperty property) {
final Map<String, Object> json = simulateJsonSerialization(property);
expect(json['ifTrue'], equals(property.ifTrue));
if (property.ifTrue != null) {
expect(json['ifTrue'], equals(property.ifTrue));
} else {
expect(json.containsKey('ifTrue'), isFalse);
}
if (property.ifFalse != null) {
expect(json['ifFalse'], property.ifFalse);
} else {
expect(json.containsKey('isFalse'), isFalse);
}
validatePropertyJsonSerializationHelper(json, property);
}
void validateDoublePropertyJsonSerialization(DoubleProperty property) {
final Map<String, Object> json = simulateJsonSerialization(property);
if (property.unit != null) {
expect(json['unit'], equals(property.unit));
} else {
expect(json.containsKey('unit'), isFalse);
}
expect(json['numberToString'], equals(property.numberToString()));
validatePropertyJsonSerializationHelper(json, property);
}
void validateObjectFlagPropertyJsonSerialization(ObjectFlagProperty<Object> property) {
final Map<String, Object> json = simulateJsonSerialization(property);
if (property.ifPresent != null) {
expect(json['ifPresent'], equals(property.ifPresent));
} else {
expect(json.containsKey('ifPresent'), isFalse);
}
validatePropertyJsonSerializationHelper(json, property);
}
void validateIterablePropertyJsonSerialization(IterableProperty<Object> property) {
final Map<String, Object> json = simulateJsonSerialization(property);
if (property.value != null) {
final List<Object> valuesJson = json['values'];
final List<String> expectedValues = property.value.map<String>((Object value) => value.toString()).toList();
expect(listEquals(valuesJson, expectedValues), isTrue);
} else {
expect(json.containsKey('values'), isFalse);
}
validatePropertyJsonSerializationHelper(json, property);
}
void validatePropertyJsonSerializationHelper(final Map<String, Object> json, DiagnosticsProperty<Object> property) {
if (property.defaultValue != kNoDefaultValue) {
expect(json['defaultValue'], equals(property.defaultValue.toString()));
} else {
expect(json.containsKey('defaultValue'), isFalse);
}
if (property.ifEmpty != null) {
expect(json['ifEmpty'], equals(property.ifEmpty));
} else {
expect(json.containsKey('ifEmpty'), isFalse);
}
if (property.ifNull != null) {
expect(json['ifNull'], equals(property.ifNull));
} else {
expect(json.containsKey('ifNull'), isFalse);
}
if (property.tooltip != null) {
expect(json['tooltip'], equals(property.tooltip));
} else {
expect(json.containsKey('tooltip'), isFalse);
}
expect(json['missingIfNull'], equals(property.missingIfNull));
if (property.exception != null) {
expect(json['exception'], equals(property.exception.toString()));
} else {
expect(json.containsKey('exception'), isFalse);
}
expect(json['propertyType'], equals(property.propertyType.toString()));
expect(json['valueToString'], equals(property.valueToString()));
expect(json.containsKey('defaultLevel'), isTrue);
if (property.value is Diagnosticable) {
expect(json['isDiagnosticableValue'], isTrue);
} else {
expect(json.containsKey('isDiagnosticableValue'), isFalse);
}
validateNodeJsonSerializationHelper(json, property);
}
void main() {
test('TreeDiagnosticsMixin control test', () async {
void goldenStyleTest(String description,
{DiagnosticsTreeStyle style,
DiagnosticsTreeStyle lastChildStyle,
String golden = ''}) {
final TestTree tree = TestTree(children: <TestTree>[
TestTree(name: 'node A', style: style),
TestTree(
name: 'node B',
children: <TestTree>[
TestTree(name: 'node B1', style: style),
TestTree(name: 'node B2', style: style),
TestTree(name: 'node B3', style: lastChildStyle ?? style),
],
style: style,
),
TestTree(name: 'node C', style: lastChildStyle ?? style),
], style: lastChildStyle);
expect(tree, hasAGoodToStringDeep);
expect(
tree.toDiagnosticsNode(style: style).toStringDeep(),
equalsIgnoringHashCodes(golden),
reason: description,
);
validateNodeJsonSerialization(tree.toDiagnosticsNode());
}
goldenStyleTest(
'dense',
style: DiagnosticsTreeStyle.dense,
golden:
'TestTree#00000\n'
'├child node A: TestTree#00000\n'
'├child node B: TestTree#00000\n'
'│├child node B1: TestTree#00000\n'
'│├child node B2: TestTree#00000\n'
'│└child node B3: TestTree#00000\n'
'└child node C: TestTree#00000\n',
);
goldenStyleTest(
'sparse',
style: DiagnosticsTreeStyle.sparse,
golden:
'TestTree#00000\n'
' ├─child node A: TestTree#00000\n'
' ├─child node B: TestTree#00000\n'
' │ ├─child node B1: TestTree#00000\n'
' │ ├─child node B2: TestTree#00000\n'
' │ └─child node B3: TestTree#00000\n'
' └─child node C: TestTree#00000\n',
);
goldenStyleTest(
'dashed',
style: DiagnosticsTreeStyle.offstage,
golden:
'TestTree#00000\n'
' ╎╌child node A: TestTree#00000\n'
' ╎╌child node B: TestTree#00000\n'
' ╎ ╎╌child node B1: TestTree#00000\n'
' ╎ ╎╌child node B2: TestTree#00000\n'
' ╎ └╌child node B3: TestTree#00000\n'
' └╌child node C: TestTree#00000\n',
);
goldenStyleTest(
'leaf children',
style: DiagnosticsTreeStyle.sparse,
lastChildStyle: DiagnosticsTreeStyle.transition,
golden:
'TestTree#00000\n'
' ├─child node A: TestTree#00000\n'
' ├─child node B: TestTree#00000\n'
' │ ├─child node B1: TestTree#00000\n'
' │ ├─child node B2: TestTree#00000\n'
' │ ╘═╦══ child node B3 ═══\n'
' │ ║ TestTree#00000\n'
' │ ╚═══════════\n'
' ╘═╦══ child node C ═══\n'
' ║ TestTree#00000\n'
' ╚═══════════\n',
);
// You would never really want to make everything a leaf child like this
// but you can and still get a readable tree.
// The joint between single and double lines here is a bit clunky
// but we could correct that if there is any real use for this style.
goldenStyleTest(
'leaf',
style: DiagnosticsTreeStyle.transition,
golden:
'TestTree#00000:\n'
' ╞═╦══ child node A ═══\n'
' │ ║ TestTree#00000\n'
' │ ╚═══════════\n'
' ╞═╦══ child node B ═══\n'
' │ ║ TestTree#00000:\n'
' │ ║ ╞═╦══ child node B1 ═══\n'
' │ ║ │ ║ TestTree#00000\n'
' │ ║ │ ╚═══════════\n'
' │ ║ ╞═╦══ child node B2 ═══\n'
' │ ║ │ ║ TestTree#00000\n'
' │ ║ │ ╚═══════════\n'
' │ ║ ╘═╦══ child node B3 ═══\n'
' │ ║ ║ TestTree#00000\n'
' │ ║ ╚═══════════\n'
' │ ╚═══════════\n'
' ╘═╦══ child node C ═══\n'
' ║ TestTree#00000\n'
' ╚═══════════\n',
);
goldenStyleTest(
'whitespace',
style: DiagnosticsTreeStyle.whitespace,
golden:
'TestTree#00000:\n'
' child node A: TestTree#00000\n'
' child node B: TestTree#00000:\n'
' child node B1: TestTree#00000\n'
' child node B2: TestTree#00000\n'
' child node B3: TestTree#00000\n'
' child node C: TestTree#00000\n',
);
// Single line mode does not display children.
goldenStyleTest(
'single line',
style: DiagnosticsTreeStyle.singleLine,
golden: 'TestTree#00000',
);
});
test('TreeDiagnosticsMixin tree with properties test', () async {
void goldenStyleTest(String description, {
DiagnosticsTreeStyle style,
DiagnosticsTreeStyle lastChildStyle,
@required String golden,
}) {
final TestTree tree = TestTree(
properties: <DiagnosticsNode>[
StringProperty('stringProperty1', 'value1', quoted: false),
DoubleProperty('doubleProperty1', 42.5),
DoubleProperty('roundedProperty', 1.0 / 3.0),
StringProperty('DO_NOT_SHOW', 'DO_NOT_SHOW', level: DiagnosticLevel.hidden, quoted: false),
DiagnosticsProperty<Object>('DO_NOT_SHOW_NULL', null, defaultValue: null),
DiagnosticsProperty<Object>('nullProperty', null),
StringProperty('node_type', '<root node>', showName: false, quoted: false),
],
children: <TestTree>[
TestTree(name: 'node A', style: style),
TestTree(
name: 'node B',
properties: <DiagnosticsNode>[
StringProperty('p1', 'v1', quoted: false),
StringProperty('p2', 'v2', quoted: false),
],
children: <TestTree>[
TestTree(name: 'node B1', style: style),
TestTree(
name: 'node B2',
properties: <DiagnosticsNode>[StringProperty('property1', 'value1', quoted: false)],
style: style,
),
TestTree(
name: 'node B3',
properties: <DiagnosticsNode>[
StringProperty('node_type', '<leaf node>', showName: false, quoted: false),
IntProperty('foo', 42),
],
style: lastChildStyle ?? style,
),
],
style: style,
),
TestTree(
name: 'node C',
properties: <DiagnosticsNode>[
StringProperty('foo', 'multi\nline\nvalue!', quoted: false),
],
style: lastChildStyle ?? style,
),
],
style: lastChildStyle,
);
if (tree.style != DiagnosticsTreeStyle.singleLine)
expect(tree, hasAGoodToStringDeep);
expect(
tree.toDiagnosticsNode(style: style).toStringDeep(),
equalsIgnoringHashCodes(golden),
reason: description,
);
validateNodeJsonSerialization(tree.toDiagnosticsNode());
}
goldenStyleTest(
'sparse',
style: DiagnosticsTreeStyle.sparse,
golden:
'TestTree#00000\n'
' │ stringProperty1: value1\n'
' │ doubleProperty1: 42.5\n'
' │ roundedProperty: 0.3\n'
' │ nullProperty: null\n'
' │ <root node>\n'
' │\n'
' ├─child node A: TestTree#00000\n'
' ├─child node B: TestTree#00000\n'
' │ │ p1: v1\n'
' │ │ p2: v2\n'
' │ │\n'
' │ ├─child node B1: TestTree#00000\n'
' │ ├─child node B2: TestTree#00000\n'
' │ │ property1: value1\n'
' │ │\n'
' │ └─child node B3: TestTree#00000\n'
' │ <leaf node>\n'
' │ foo: 42\n'
' │\n'
' └─child node C: TestTree#00000\n'
' foo:\n'
' multi\n'
' line\n'
' value!\n',
);
goldenStyleTest(
'dense',
style: DiagnosticsTreeStyle.dense,
golden:
'TestTree#00000(stringProperty1: value1, doubleProperty1: 42.5, roundedProperty: 0.3, nullProperty: null, <root node>)\n'
'├child node A: TestTree#00000\n'
'├child node B: TestTree#00000(p1: v1, p2: v2)\n'
'│├child node B1: TestTree#00000\n'
'│├child node B2: TestTree#00000(property1: value1)\n'
'│└child node B3: TestTree#00000(<leaf node>, foo: 42)\n'
'└child node C: TestTree#00000(foo: multi\\nline\\nvalue!)\n',
);
goldenStyleTest(
'dashed',
style: DiagnosticsTreeStyle.offstage,
golden:
'TestTree#00000\n'
' │ stringProperty1: value1\n'
' │ doubleProperty1: 42.5\n'
' │ roundedProperty: 0.3\n'
' │ nullProperty: null\n'
' │ <root node>\n'
' │\n'
' ╎╌child node A: TestTree#00000\n'
' ╎╌child node B: TestTree#00000\n'
' ╎ │ p1: v1\n'
' ╎ │ p2: v2\n'
' ╎ │\n'
' ╎ ╎╌child node B1: TestTree#00000\n'
' ╎ ╎╌child node B2: TestTree#00000\n'
' ╎ ╎ property1: value1\n'
' ╎ ╎\n'
' ╎ └╌child node B3: TestTree#00000\n'
' ╎ <leaf node>\n'
' ╎ foo: 42\n'
' ╎\n'
' └╌child node C: TestTree#00000\n'
' foo:\n'
' multi\n'
' line\n'
' value!\n',
);
goldenStyleTest(
'leaf children',
style: DiagnosticsTreeStyle.sparse,
lastChildStyle: DiagnosticsTreeStyle.transition,
golden:
'TestTree#00000\n'
' │ stringProperty1: value1\n'
' │ doubleProperty1: 42.5\n'
' │ roundedProperty: 0.3\n'
' │ nullProperty: null\n'
' │ <root node>\n'
' │\n'
' ├─child node A: TestTree#00000\n'
' ├─child node B: TestTree#00000\n'
' │ │ p1: v1\n'
' │ │ p2: v2\n'
' │ │\n'
' │ ├─child node B1: TestTree#00000\n'
' │ ├─child node B2: TestTree#00000\n'
' │ │ property1: value1\n'
' │ │\n'
' │ ╘═╦══ child node B3 ═══\n'
' │ ║ TestTree#00000:\n'
' │ ║ <leaf node>\n'
' │ ║ foo: 42\n'
' │ ╚═══════════\n'
' ╘═╦══ child node C ═══\n'
' ║ TestTree#00000:\n'
' ║ foo:\n'
' ║ multi\n'
' ║ line\n'
' ║ value!\n'
' ╚═══════════\n',
);
// You would never really want to make everything a transition child like
// this but you can and still get a readable tree.
goldenStyleTest(
'transition',
style: DiagnosticsTreeStyle.transition,
golden:
'TestTree#00000:\n'
' stringProperty1: value1\n'
' doubleProperty1: 42.5\n'
' roundedProperty: 0.3\n'
' nullProperty: null\n'
' <root node>\n'
' ╞═╦══ child node A ═══\n'
' │ ║ TestTree#00000\n'
' │ ╚═══════════\n'
' ╞═╦══ child node B ═══\n'
' │ ║ TestTree#00000:\n'
' │ ║ p1: v1\n'
' │ ║ p2: v2\n'
' │ ║ ╞═╦══ child node B1 ═══\n'
' │ ║ │ ║ TestTree#00000\n'
' │ ║ │ ╚═══════════\n'
' │ ║ ╞═╦══ child node B2 ═══\n'
' │ ║ │ ║ TestTree#00000:\n'
' │ ║ │ ║ property1: value1\n'
' │ ║ │ ╚═══════════\n'
' │ ║ ╘═╦══ child node B3 ═══\n'
' │ ║ ║ TestTree#00000:\n'
' │ ║ ║ <leaf node>\n'
' │ ║ ║ foo: 42\n'
' │ ║ ╚═══════════\n'
' │ ╚═══════════\n'
' ╘═╦══ child node C ═══\n'
' ║ TestTree#00000:\n'
' ║ foo:\n'
' ║ multi\n'
' ║ line\n'
' ║ value!\n'
' ╚═══════════\n',
);
goldenStyleTest(
'whitespace',
style: DiagnosticsTreeStyle.whitespace,
golden:
'TestTree#00000:\n'
' stringProperty1: value1\n'
' doubleProperty1: 42.5\n'
' roundedProperty: 0.3\n'
' nullProperty: null\n'
' <root node>\n'
' child node A: TestTree#00000\n'
' child node B: TestTree#00000:\n'
' p1: v1\n'
' p2: v2\n'
' child node B1: TestTree#00000\n'
' child node B2: TestTree#00000:\n'
' property1: value1\n'
' child node B3: TestTree#00000:\n'
' <leaf node>\n'
' foo: 42\n'
' child node C: TestTree#00000:\n'
' foo:\n'
' multi\n'
' line\n'
' value!\n',
);
// Single line mode does not display children.
goldenStyleTest(
'single line',
style: DiagnosticsTreeStyle.singleLine,
golden: 'TestTree#00000(stringProperty1: value1, doubleProperty1: 42.5, roundedProperty: 0.3, nullProperty: null, <root node>)',
);
// TODO(jacobr): this is an ugly test case.
// There isn't anything interesting for this case as the children look the
// same with and without children. Only difference is odd not clearly
// desirable density of B3 being right next to node C.
goldenStyleTest(
'single line last child',
style: DiagnosticsTreeStyle.sparse,
lastChildStyle: DiagnosticsTreeStyle.singleLine,
golden:
'TestTree#00000\n'
' │ stringProperty1: value1\n'
' │ doubleProperty1: 42.5\n'
' │ roundedProperty: 0.3\n'
' │ nullProperty: null\n'
' │ <root node>\n'
' │\n'
' ├─child node A: TestTree#00000\n'
' ├─child node B: TestTree#00000\n'
' │ │ p1: v1\n'
' │ │ p2: v2\n'
' │ │\n'
' │ ├─child node B1: TestTree#00000\n'
' │ ├─child node B2: TestTree#00000\n'
' │ │ property1: value1\n'
' │ │\n'
' │ └─child node B3: TestTree#00000(<leaf node>, foo: 42)\n'
' └─child node C: TestTree#00000(foo: multi\\nline\\nvalue!)\n',
);
});
test('transition test', () {
// Test multiple styles integrating together in the same tree due to using
// transition to go between styles that would otherwise be incompatible.
final TestTree tree = TestTree(
style: DiagnosticsTreeStyle.sparse,
properties: <DiagnosticsNode>[
StringProperty('stringProperty1', 'value1'),
],
children: <TestTree>[
TestTree(
style: DiagnosticsTreeStyle.transition,
name: 'node transition',
properties: <DiagnosticsNode>[
StringProperty('p1', 'v1'),
TestTree(
properties: <DiagnosticsNode>[
DiagnosticsProperty<bool>('survived', true),
],
).toDiagnosticsNode(name: 'tree property', style: DiagnosticsTreeStyle.whitespace),
],
children: <TestTree>[
TestTree(name: 'dense child', style: DiagnosticsTreeStyle.dense),
TestTree(
name: 'dense',
properties: <DiagnosticsNode>[StringProperty('property1', 'value1')],
style: DiagnosticsTreeStyle.dense,
),
TestTree(
name: 'node B3',
properties: <DiagnosticsNode>[
StringProperty('node_type', '<leaf node>', showName: false, quoted: false),
IntProperty('foo', 42),
],
style: DiagnosticsTreeStyle.dense
),
],
),
TestTree(
name: 'node C',
properties: <DiagnosticsNode>[
StringProperty('foo', 'multi\nline\nvalue!', quoted: false),
],
style: DiagnosticsTreeStyle.sparse,
),
],
);
expect(tree, hasAGoodToStringDeep);
expect(
tree.toDiagnosticsNode().toStringDeep(),
equalsIgnoringHashCodes(
'TestTree#00000\n'
' │ stringProperty1: "value1"\n'
' ╞═╦══ child node transition ═══\n'
' │ ║ TestTree#00000:\n'
' │ ║ p1: "v1"\n'
' │ ║ tree property: TestTree#00000:\n'
' │ ║ survived: true\n'
' │ ║ ├child dense child: TestTree#00000\n'
' │ ║ ├child dense: TestTree#00000(property1: "value1")\n'
' │ ║ └child node B3: TestTree#00000(<leaf node>, foo: 42)\n'
' │ ╚═══════════\n'
' └─child node C: TestTree#00000\n'
' foo:\n'
' multi\n'
' line\n'
' value!\n',
),
);
});
test('describeEnum test', () {
expect(describeEnum(ExampleEnum.hello), equals('hello'));
expect(describeEnum(ExampleEnum.world), equals('world'));
expect(describeEnum(ExampleEnum.deferToChild), equals('deferToChild'));
});
test('string property test', () {
expect(
StringProperty('name', 'value', quoted: false).toString(),
equals('name: value'),
);
final StringProperty stringProperty = StringProperty(
'name',
'value',
description: 'VALUE',
ifEmpty: '<hidden>',
quoted: false,
);
expect(stringProperty.toString(), equals('name: VALUE'));
validateStringPropertyJsonSerialization(stringProperty);
expect(
StringProperty(
'name',
'value',
showName: false,
ifEmpty: '<hidden>',
quoted: false,
).toString(),
equals('value'),
);
expect(
StringProperty('name', '', ifEmpty: '<hidden>').toString(),
equals('name: <hidden>'),
);
expect(
StringProperty(
'name',
'',
ifEmpty: '<hidden>',
showName: false,
).toString(),
equals('<hidden>'),
);
expect(StringProperty('name', null).isFiltered(DiagnosticLevel.info), isFalse);
expect(StringProperty('name', 'value', level: DiagnosticLevel.hidden).isFiltered(DiagnosticLevel.info), isTrue);
expect(StringProperty('name', null, defaultValue: null).isFiltered(DiagnosticLevel.info), isTrue);
final StringProperty quoted = StringProperty(
'name',
'value',
quoted: true,
);
expect(quoted.toString(), equals('name: "value"'));
validateStringPropertyJsonSerialization(quoted);
expect(
StringProperty('name', 'value', showName: false).toString(),
equals('"value"'),
);
expect(
StringProperty(
'name',
null,
showName: false,
quoted: true,
).toString(),
equals('null'),
);
});
test('bool property test', () {
final DiagnosticsProperty<bool> trueProperty = DiagnosticsProperty<bool>('name', true);
final DiagnosticsProperty<bool> falseProperty = DiagnosticsProperty<bool>('name', false);
expect(trueProperty.toString(), equals('name: true'));
expect(trueProperty.isFiltered(DiagnosticLevel.info), isFalse);
expect(trueProperty.value, isTrue);
expect(falseProperty.toString(), equals('name: false'));
expect(falseProperty.value, isFalse);
expect(falseProperty.isFiltered(DiagnosticLevel.info), isFalse);
validatePropertyJsonSerialization(trueProperty);
validatePropertyJsonSerialization(falseProperty);
final DiagnosticsProperty<bool> truthyProperty = DiagnosticsProperty<bool>(
'name',
true,
description: 'truthy',
);
expect(
truthyProperty.toString(),
equals('name: truthy'),
);
validatePropertyJsonSerialization(truthyProperty);
expect(
DiagnosticsProperty<bool>('name', true, showName: false).toString(),
equals('true'),
);
expect(DiagnosticsProperty<bool>('name', null).isFiltered(DiagnosticLevel.info), isFalse);
expect(DiagnosticsProperty<bool>('name', true, level: DiagnosticLevel.hidden).isFiltered(DiagnosticLevel.info), isTrue);
expect(DiagnosticsProperty<bool>('name', null, defaultValue: null).isFiltered(DiagnosticLevel.info), isTrue);
final DiagnosticsProperty<bool> missingBool = DiagnosticsProperty<bool>('name', null, ifNull: 'missing');
expect(
missingBool.toString(),
equals('name: missing'),
);
validatePropertyJsonSerialization(missingBool);
});
test('flag property test', () {
final FlagProperty trueFlag = FlagProperty(
'myFlag',
value: true,
ifTrue: 'myFlag',
);
final FlagProperty falseFlag = FlagProperty(
'myFlag',
value: false,
ifTrue: 'myFlag',
);
expect(trueFlag.toString(), equals('myFlag'));
validateFlagPropertyJsonSerialization(trueFlag);
validateFlagPropertyJsonSerialization(falseFlag);
expect(trueFlag.value, isTrue);
expect(falseFlag.value, isFalse);
expect(trueFlag.isFiltered(DiagnosticLevel.fine), isFalse);
expect(falseFlag.isFiltered(DiagnosticLevel.fine), isTrue);
});
test('property with tooltip test', () {
final DiagnosticsProperty<String> withTooltip = DiagnosticsProperty<String>(
'name',
'value',
tooltip: 'tooltip',
);
expect(
withTooltip.toString(),
equals('name: value (tooltip)'),
);
expect(withTooltip.value, equals('value'));
expect(withTooltip.isFiltered(DiagnosticLevel.fine), isFalse);
validatePropertyJsonSerialization(withTooltip);
});
test('double property test', () {
final DoubleProperty doubleProperty = DoubleProperty(
'name',
42.0,
);
expect(doubleProperty.toString(), equals('name: 42.0'));
expect(doubleProperty.isFiltered(DiagnosticLevel.info), isFalse);
expect(doubleProperty.value, equals(42.0));
validateDoublePropertyJsonSerialization(doubleProperty);
expect(DoubleProperty('name', 1.3333).toString(), equals('name: 1.3'));
expect(DoubleProperty('name', null).toString(), equals('name: null'));
expect(DoubleProperty('name', null).isFiltered(DiagnosticLevel.info), equals(false));
expect(
DoubleProperty('name', null, ifNull: 'missing').toString(),
equals('name: missing'),
);
final DoubleProperty doubleWithUnit = DoubleProperty('name', 42.0, unit: 'px');
expect(doubleWithUnit.toString(), equals('name: 42.0px'));
validateDoublePropertyJsonSerialization(doubleWithUnit);
});
test('unsafe double property test', () {
final DoubleProperty safe = DoubleProperty.lazy(
'name',
() => 42.0,
);
expect(safe.toString(), equals('name: 42.0'));
expect(safe.isFiltered(DiagnosticLevel.info), isFalse);
expect(safe.value, equals(42.0));
validateDoublePropertyJsonSerialization(safe);
expect(
DoubleProperty.lazy('name', () => 1.3333).toString(),
equals('name: 1.3'),
);
expect(
DoubleProperty.lazy('name', () => null).toString(),
equals('name: null'),
);
expect(
DoubleProperty.lazy('name', () => null).isFiltered(DiagnosticLevel.info),
equals(false),
);
final DoubleProperty throwingProperty = DoubleProperty.lazy(
'name',
() => throw FlutterError('Invalid constraints'),
);
// TODO(jacobr): it would be better if throwingProperty.object threw an
// exception.
expect(throwingProperty.value, isNull);
expect(throwingProperty.isFiltered(DiagnosticLevel.info), isFalse);
expect(
throwingProperty.toString(),
equals('name: EXCEPTION (FlutterError)'),
);
expect(throwingProperty.level, equals(DiagnosticLevel.error));
validateDoublePropertyJsonSerialization(throwingProperty);
});
test('percent property', () {
expect(
PercentProperty('name', 0.4).toString(),
equals('name: 40.0%'),
);
final PercentProperty complexPercentProperty = PercentProperty('name', 0.99, unit: 'invisible', tooltip: 'almost transparent');
expect(
complexPercentProperty.toString(),
equals('name: 99.0% invisible (almost transparent)'),
);
validateDoublePropertyJsonSerialization(complexPercentProperty);
expect(
PercentProperty('name', null, unit: 'invisible', tooltip: '!').toString(),
equals('name: null (!)'),
);
expect(
PercentProperty('name', 0.4).value,
0.4,
);
expect(
PercentProperty('name', 0.0).toString(),
equals('name: 0.0%'),
);
expect(
PercentProperty('name', -10.0).toString(),
equals('name: 0.0%'),
);
expect(
PercentProperty('name', 1.0).toString(),
equals('name: 100.0%'),
);
expect(
PercentProperty('name', 3.0).toString(),
equals('name: 100.0%'),
);
expect(
PercentProperty('name', null).toString(),
equals('name: null'),
);
expect(
PercentProperty(
'name',
null,
ifNull: 'missing',
).toString(),
equals('name: missing'),
);
expect(
PercentProperty(
'name',
null,
ifNull: 'missing',
showName: false,
).toString(),
equals('missing'),
);
expect(
PercentProperty(
'name',
0.5,
showName: false,
).toString(),
equals('50.0%'),
);
});
test('callback property test', () {
final Function onClick = () {};
final ObjectFlagProperty<Function> present = ObjectFlagProperty<Function>(
'onClick',
onClick,
ifPresent: 'clickable',
);
final ObjectFlagProperty<Function> missing = ObjectFlagProperty<Function>(
'onClick',
null,
ifPresent: 'clickable',
);
expect(present.toString(), equals('clickable'));
expect(present.isFiltered(DiagnosticLevel.info), isFalse);
expect(present.value, equals(onClick));
validateObjectFlagPropertyJsonSerialization(present);
expect(missing.toString(), equals('onClick: null'));
expect(missing.isFiltered(DiagnosticLevel.fine), isTrue);
validateObjectFlagPropertyJsonSerialization(missing);
});
test('missing callback property test', () {
void onClick() { }
final ObjectFlagProperty<Function> present = ObjectFlagProperty<Function>(
'onClick',
onClick,
ifNull: 'disabled',
);
final ObjectFlagProperty<Function> missing = ObjectFlagProperty<Function>(
'onClick',
null,
ifNull: 'disabled',
);
expect(present.toString(), equals('onClick: Closure: () => void'));
expect(present.isFiltered(DiagnosticLevel.fine), isTrue);
expect(present.value, equals(onClick));
expect(missing.toString(), equals('disabled'));
expect(missing.isFiltered(DiagnosticLevel.info), isFalse);
validateObjectFlagPropertyJsonSerialization(present);
validateObjectFlagPropertyJsonSerialization(missing);
});
test('describe bool property', () {
final FlagProperty yes = FlagProperty(
'name',
value: true,
ifTrue: 'YES',
ifFalse: 'NO',
showName: true,
);
final FlagProperty no = FlagProperty(
'name',
value: false,
ifTrue: 'YES',
ifFalse: 'NO',
showName: true,
);
expect(yes.toString(), equals('name: YES'));
expect(yes.level, equals(DiagnosticLevel.info));
expect(yes.value, isTrue);
validateFlagPropertyJsonSerialization(yes);
expect(no.toString(), equals('name: NO'));
expect(no.level, equals(DiagnosticLevel.info));
expect(no.value, isFalse);
validateFlagPropertyJsonSerialization(no);
expect(
FlagProperty(
'name',
value: true,
ifTrue: 'YES',
ifFalse: 'NO',
).toString(),
equals('YES'),
);
expect(
FlagProperty(
'name',
value: false,
ifTrue: 'YES',
ifFalse: 'NO',
).toString(),
equals('NO'),
);
expect(
FlagProperty(
'name',
value: true,
ifTrue: 'YES',
ifFalse: 'NO',
level: DiagnosticLevel.hidden,
showName: true,
).level,
equals(DiagnosticLevel.hidden),
);
});
test('enum property test', () {
final EnumProperty<ExampleEnum> hello = EnumProperty<ExampleEnum>(
'name',
ExampleEnum.hello,
);
final EnumProperty<ExampleEnum> world = EnumProperty<ExampleEnum>(
'name',
ExampleEnum.world,
);
final EnumProperty<ExampleEnum> deferToChild = EnumProperty<ExampleEnum>(
'name',
ExampleEnum.deferToChild,
);
final EnumProperty<ExampleEnum> nullEnum = EnumProperty<ExampleEnum>(
'name',
null,
);
expect(hello.level, equals(DiagnosticLevel.info));
expect(hello.value, equals(ExampleEnum.hello));
expect(hello.toString(), equals('name: hello'));
validatePropertyJsonSerialization(hello);
expect(world.level, equals(DiagnosticLevel.info));
expect(world.value, equals(ExampleEnum.world));
expect(world.toString(), equals('name: world'));
validatePropertyJsonSerialization(world);
expect(deferToChild.level, equals(DiagnosticLevel.info));
expect(deferToChild.value, equals(ExampleEnum.deferToChild));
expect(deferToChild.toString(), equals('name: deferToChild'));
validatePropertyJsonSerialization(deferToChild);
expect(nullEnum.level, equals(DiagnosticLevel.info));
expect(nullEnum.value, isNull);
expect(nullEnum.toString(), equals('name: null'));
validatePropertyJsonSerialization(nullEnum);
final EnumProperty<ExampleEnum> matchesDefault = EnumProperty<ExampleEnum>(
'name',
ExampleEnum.hello,
defaultValue: ExampleEnum.hello,
);
expect(matchesDefault.toString(), equals('name: hello'));
expect(matchesDefault.value, equals(ExampleEnum.hello));
expect(matchesDefault.isFiltered(DiagnosticLevel.info), isTrue);
validatePropertyJsonSerialization(matchesDefault);
expect(
EnumProperty<ExampleEnum>(
'name',
ExampleEnum.hello,
level: DiagnosticLevel.hidden,
).level,
equals(DiagnosticLevel.hidden),
);
});
test('int property test', () {
final IntProperty regular = IntProperty(
'name',
42,
);
expect(regular.toString(), equals('name: 42'));
expect(regular.value, equals(42));
expect(regular.level, equals(DiagnosticLevel.info));
final IntProperty nullValue = IntProperty(
'name',
null,
);
expect(nullValue.toString(), equals('name: null'));
expect(nullValue.value, isNull);
expect(nullValue.level, equals(DiagnosticLevel.info));
final IntProperty hideNull = IntProperty(
'name',
null,
defaultValue: null,
);
expect(hideNull.toString(), equals('name: null'));
expect(hideNull.value, isNull);
expect(hideNull.isFiltered(DiagnosticLevel.info), isTrue);
final IntProperty nullDescription = IntProperty(
'name',
null,
ifNull: 'missing',
);
expect(nullDescription.toString(), equals('name: missing'));
expect(nullDescription.value, isNull);
expect(nullDescription.level, equals(DiagnosticLevel.info));
final IntProperty hideName = IntProperty(
'name',
42,
showName: false,
);
expect(hideName.toString(), equals('42'));
expect(hideName.value, equals(42));
expect(hideName.level, equals(DiagnosticLevel.info));
final IntProperty withUnit = IntProperty(
'name',
42,
unit: 'pt',
);
expect(withUnit.toString(), equals('name: 42pt'));
expect(withUnit.value, equals(42));
expect(withUnit.level, equals(DiagnosticLevel.info));
final IntProperty defaultValue = IntProperty(
'name',
42,
defaultValue: 42,
);
expect(defaultValue.toString(), equals('name: 42'));
expect(defaultValue.value, equals(42));
expect(defaultValue.isFiltered(DiagnosticLevel.info), isTrue);
final IntProperty notDefaultValue = IntProperty(
'name',
43,
defaultValue: 42,
);
expect(notDefaultValue.toString(), equals('name: 43'));
expect(notDefaultValue.value, equals(43));
expect(notDefaultValue.level, equals(DiagnosticLevel.info));
final IntProperty hidden = IntProperty(
'name',
42,
level: DiagnosticLevel.hidden,
);
expect(hidden.toString(), equals('name: 42'));
expect(hidden.value, equals(42));
expect(hidden.level, equals(DiagnosticLevel.hidden));
});
test('object property test', () {
final Rect rect = Rect.fromLTRB(0.0, 0.0, 20.0, 20.0);
final DiagnosticsNode simple = DiagnosticsProperty<Rect>(
'name',
rect,
);
expect(simple.value, equals(rect));
expect(simple.level, equals(DiagnosticLevel.info));
expect(simple.toString(), equals('name: Rect.fromLTRB(0.0, 0.0, 20.0, 20.0)'));
validatePropertyJsonSerialization(simple);
final DiagnosticsNode withDescription = DiagnosticsProperty<Rect>(
'name',
rect,
description: 'small rect',
);
expect(withDescription.value, equals(rect));
expect(withDescription.level, equals(DiagnosticLevel.info));
expect(withDescription.toString(), equals('name: small rect'));
validatePropertyJsonSerialization(withDescription);
final DiagnosticsProperty<Object> nullProperty = DiagnosticsProperty<Object>(
'name',
null,
);
expect(nullProperty.value, isNull);
expect(nullProperty.level, equals(DiagnosticLevel.info));
expect(nullProperty.toString(), equals('name: null'));
validatePropertyJsonSerialization(nullProperty);
final DiagnosticsProperty<Object> hideNullProperty = DiagnosticsProperty<Object>(
'name',
null,
defaultValue: null,
);
expect(hideNullProperty.value, isNull);
expect(hideNullProperty.isFiltered(DiagnosticLevel.info), isTrue);
expect(hideNullProperty.toString(), equals('name: null'));
validatePropertyJsonSerialization(hideNullProperty);
final DiagnosticsNode nullDescription = DiagnosticsProperty<Object>(
'name',
null,
ifNull: 'missing',
);
expect(nullDescription.value, isNull);
expect(nullDescription.level, equals(DiagnosticLevel.info));
expect(nullDescription.toString(), equals('name: missing'));
validatePropertyJsonSerialization(nullDescription);
final DiagnosticsProperty<Rect> hideName = DiagnosticsProperty<Rect>(
'name',
rect,
showName: false,
level: DiagnosticLevel.warning
);
expect(hideName.value, equals(rect));
expect(hideName.level, equals(DiagnosticLevel.warning));
expect(hideName.toString(), equals('Rect.fromLTRB(0.0, 0.0, 20.0, 20.0)'));
validatePropertyJsonSerialization(hideName);
final DiagnosticsProperty<Rect> hideSeparator = DiagnosticsProperty<Rect>(
'Creator',
rect,
showSeparator: false,
);
expect(hideSeparator.value, equals(rect));
expect(hideSeparator.level, equals(DiagnosticLevel.info));
expect(
hideSeparator.toString(),
equals('Creator Rect.fromLTRB(0.0, 0.0, 20.0, 20.0)'),
);
validatePropertyJsonSerialization(hideSeparator);
});
test('lazy object property test', () {
final Rect rect = Rect.fromLTRB(0.0, 0.0, 20.0, 20.0);
final DiagnosticsNode simple = DiagnosticsProperty<Rect>.lazy(
'name',
() => rect,
description: 'small rect',
);
expect(simple.value, equals(rect));
expect(simple.level, equals(DiagnosticLevel.info));
expect(simple.toString(), equals('name: small rect'));
validatePropertyJsonSerialization(simple);
final DiagnosticsProperty<Object> nullProperty = DiagnosticsProperty<Object>.lazy(
'name',
() => null,
description: 'missing',
);
expect(nullProperty.value, isNull);
expect(nullProperty.isFiltered(DiagnosticLevel.info), isFalse);
expect(nullProperty.toString(), equals('name: missing'));
validatePropertyJsonSerialization(nullProperty);
final DiagnosticsNode hideNullProperty = DiagnosticsProperty<Object>.lazy(
'name',
() => null,
description: 'missing',
defaultValue: null,
);
expect(hideNullProperty.value, isNull);
expect(hideNullProperty.isFiltered(DiagnosticLevel.info), isTrue);
expect(hideNullProperty.toString(), equals('name: missing'));
validatePropertyJsonSerialization(hideNullProperty);
final DiagnosticsNode hideName = DiagnosticsProperty<Rect>.lazy(
'name',
() => rect,
description: 'small rect',
showName: false,
);
expect(hideName.value, equals(rect));
expect(hideName.isFiltered(DiagnosticLevel.info), isFalse);
expect(hideName.toString(), equals('small rect'));
validatePropertyJsonSerialization(hideName);
final DiagnosticsProperty<Object> throwingWithDescription = DiagnosticsProperty<Object>.lazy(
'name',
() => throw FlutterError('Property not available'),
description: 'missing',
defaultValue: null,
);
expect(throwingWithDescription.value, isNull);
expect(throwingWithDescription.exception, isFlutterError);
expect(throwingWithDescription.isFiltered(DiagnosticLevel.info), false);
expect(throwingWithDescription.toString(), equals('name: missing'));
validatePropertyJsonSerialization(throwingWithDescription);
final DiagnosticsProperty<Object> throwingProperty = DiagnosticsProperty<Object>.lazy(
'name',
() => throw FlutterError('Property not available'),
defaultValue: null,
);
expect(throwingProperty.value, isNull);
expect(throwingProperty.exception, isFlutterError);
expect(throwingProperty.isFiltered(DiagnosticLevel.info), false);
expect(throwingProperty.toString(), equals('name: EXCEPTION (FlutterError)'));
validatePropertyJsonSerialization(throwingProperty);
});
test('color property test', () {
// Add more tests if colorProperty becomes more than a wrapper around
// objectProperty.
const Color color = Color.fromARGB(255, 255, 255, 255);
final DiagnosticsProperty<Color> simple = DiagnosticsProperty<Color>(
'name',
color,
);
validatePropertyJsonSerialization(simple);
expect(simple.isFiltered(DiagnosticLevel.info), isFalse);
expect(simple.value, equals(color));
expect(simple.propertyType, equals(Color));
expect(simple.toString(), equals('name: Color(0xffffffff)'));
validatePropertyJsonSerialization(simple);
});
test('flag property test', () {
final FlagProperty show = FlagProperty(
'wasLayout',
value: true,
ifTrue: 'layout computed',
);
expect(show.name, equals('wasLayout'));
expect(show.value, isTrue);
expect(show.isFiltered(DiagnosticLevel.info), isFalse);
expect(show.toString(), equals('layout computed'));
validateFlagPropertyJsonSerialization(show);
final FlagProperty hide = FlagProperty(
'wasLayout',
value: false,
ifTrue: 'layout computed',
);
expect(hide.name, equals('wasLayout'));
expect(hide.value, isFalse);
expect(hide.level, equals(DiagnosticLevel.hidden));
expect(hide.toString(), equals('wasLayout: false'));
validateFlagPropertyJsonSerialization(hide);
final FlagProperty hideTrue = FlagProperty(
'wasLayout',
value: true,
ifFalse: 'no layout computed',
);
expect(hideTrue.name, equals('wasLayout'));
expect(hideTrue.value, isTrue);
expect(hideTrue.level, equals(DiagnosticLevel.hidden));
expect(hideTrue.toString(), equals('wasLayout: true'));
validateFlagPropertyJsonSerialization(hideTrue);
});
test('has property test', () {
final Function onClick = () {};
final ObjectFlagProperty<Function> has = ObjectFlagProperty<Function>.has(
'onClick',
onClick,
);
expect(has.name, equals('onClick'));
expect(has.value, equals(onClick));
expect(has.isFiltered(DiagnosticLevel.info), isFalse);
expect(has.toString(), equals('has onClick'));
validateObjectFlagPropertyJsonSerialization(has);
final ObjectFlagProperty<Function> missing = ObjectFlagProperty<Function>.has(
'onClick',
null,
);
expect(missing.name, equals('onClick'));
expect(missing.value, isNull);
expect(missing.isFiltered(DiagnosticLevel.info), isTrue);
expect(missing.toString(), equals('onClick: null'));
validateObjectFlagPropertyJsonSerialization(missing);
});
test('iterable property test', () {
final List<int> ints = <int>[1,2,3];
final IterableProperty<int> intsProperty = IterableProperty<int>(
'ints',
ints,
);
expect(intsProperty.value, equals(ints));
expect(intsProperty.isFiltered(DiagnosticLevel.info), isFalse);
expect(intsProperty.toString(), equals('ints: 1, 2, 3'));
final IterableProperty<Object> emptyProperty = IterableProperty<Object>(
'name',
<Object>[],
);
expect(emptyProperty.value, isEmpty);
expect(emptyProperty.isFiltered(DiagnosticLevel.info), isFalse);
expect(emptyProperty.toString(), equals('name: []'));
validateIterablePropertyJsonSerialization(emptyProperty);
final IterableProperty<Object> nullProperty = IterableProperty<Object>(
'list',
null,
);
expect(nullProperty.value, isNull);
expect(nullProperty.isFiltered(DiagnosticLevel.info), isFalse);
expect(nullProperty.toString(), equals('list: null'));
validateIterablePropertyJsonSerialization(nullProperty);
final IterableProperty<Object> hideNullProperty = IterableProperty<Object>(
'list',
null,
defaultValue: null,
);
expect(hideNullProperty.value, isNull);
expect(hideNullProperty.isFiltered(DiagnosticLevel.info), isTrue);
expect(hideNullProperty.level, equals(DiagnosticLevel.fine));
expect(hideNullProperty.toString(), equals('list: null'));
validateIterablePropertyJsonSerialization(hideNullProperty);
final List<Object> objects = <Object>[
Rect.fromLTRB(0.0, 0.0, 20.0, 20.0),
const Color.fromARGB(255, 255, 255, 255),
];
final IterableProperty<Object> objectsProperty = IterableProperty<Object>(
'objects',
objects,
);
expect(objectsProperty.value, equals(objects));
expect(objectsProperty.isFiltered(DiagnosticLevel.info), isFalse);
expect(
objectsProperty.toString(),
equals('objects: Rect.fromLTRB(0.0, 0.0, 20.0, 20.0), Color(0xffffffff)'),
);
validateIterablePropertyJsonSerialization(objectsProperty);
final IterableProperty<Object> multiLineProperty = IterableProperty<Object>(
'objects',
objects,
style: DiagnosticsTreeStyle.whitespace,
);
expect(multiLineProperty.value, equals(objects));
expect(multiLineProperty.isFiltered(DiagnosticLevel.info), isFalse);
expect(
multiLineProperty.toString(),
equals(
'objects:\n'
'Rect.fromLTRB(0.0, 0.0, 20.0, 20.0)\n'
'Color(0xffffffff)',
),
);
expect(
multiLineProperty.toStringDeep(),
equals(
'objects:\n'
' Rect.fromLTRB(0.0, 0.0, 20.0, 20.0)\n'
' Color(0xffffffff)\n',
),
);
validateIterablePropertyJsonSerialization(multiLineProperty);
expect(
TestTree(
properties: <DiagnosticsNode>[multiLineProperty],
).toStringDeep(),
equalsIgnoringHashCodes(
'TestTree#00000\n'
' objects:\n'
' Rect.fromLTRB(0.0, 0.0, 20.0, 20.0)\n'
' Color(0xffffffff)\n',
),
);
expect(
TestTree(
properties: <DiagnosticsNode>[objectsProperty, IntProperty('foo', 42)],
style: DiagnosticsTreeStyle.singleLine,
).toStringDeep(),
equalsIgnoringHashCodes(
'TestTree#00000(objects: [Rect.fromLTRB(0.0, 0.0, 20.0, 20.0), Color(0xffffffff)], foo: 42)',
),
);
// Iterable with a single entry. Verify that rendering is sensible and that
// multi line rendering isn't used even though it is not helpful.
final List<Object> singleElementList = <Object>[const Color.fromARGB(255, 255, 255, 255)];
final IterableProperty<Object> objectProperty = IterableProperty<Object>(
'object',
singleElementList,
style: DiagnosticsTreeStyle.whitespace,
);
expect(objectProperty.value, equals(singleElementList));
expect(objectProperty.isFiltered(DiagnosticLevel.info), isFalse);
expect(
objectProperty.toString(),
equals('object: Color(0xffffffff)'),
);
expect(
objectProperty.toStringDeep(),
equals('object: Color(0xffffffff)\n'),
);
validateIterablePropertyJsonSerialization(objectProperty);
expect(
TestTree(
name: 'root',
properties: <DiagnosticsNode>[objectProperty],
).toStringDeep(),
equalsIgnoringHashCodes(
'TestTree#00000\n'
' object: Color(0xffffffff)\n',
),
);
});
test('message test', () {
final DiagnosticsNode message = DiagnosticsNode.message('hello world');
expect(message.toString(), equals('hello world'));
expect(message.name, isEmpty);
expect(message.value, isNull);
expect(message.showName, isFalse);
validateNodeJsonSerialization(message);
final DiagnosticsNode messageProperty = MessageProperty('diagnostics', 'hello world');
expect(messageProperty.toString(), equals('diagnostics: hello world'));
expect(messageProperty.name, equals('diagnostics'));
expect(messageProperty.value, isNull);
expect(messageProperty.showName, isTrue);
validatePropertyJsonSerialization(messageProperty);
});
}