Add support for writing fluent value checks.
Change-Id: Id3bab09fdfd0531ca02c42883159482240a3dfde
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/219581
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index a9381bd..f695939 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -21,6 +21,7 @@
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:analyzer_plugin/protocol/protocol.dart' as plugin;
import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
+import 'package:analyzer_utilities/check/check.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -2794,7 +2795,7 @@
}
void assertEmpty() {
- expect(suggestions, isEmpty);
+ check(suggestions).isEmpty;
}
void assertLength(Object matcher) {
diff --git a/pkg/analyzer_utilities/lib/check/bool.dart b/pkg/analyzer_utilities/lib/check/bool.dart
new file mode 100644
index 0000000..18d5054
--- /dev/null
+++ b/pkg/analyzer_utilities/lib/check/bool.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer_utilities/check/check.dart';
+
+extension BoolExtension on CheckTarget<bool> {
+ void get isTrue {
+ if (!value) {
+ fail('is not true');
+ }
+ }
+
+ void get isFalse {
+ if (value) {
+ fail('is not false');
+ }
+ }
+}
diff --git a/pkg/analyzer_utilities/lib/check/check.dart b/pkg/analyzer_utilities/lib/check/check.dart
new file mode 100644
index 0000000..8d3cc4d
--- /dev/null
+++ b/pkg/analyzer_utilities/lib/check/check.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer_utilities/check/check_target.dart';
+import 'package:meta/meta.dart';
+
+export 'package:analyzer_utilities/check/check_target.dart';
+export 'package:analyzer_utilities/check/equality.dart';
+export 'package:analyzer_utilities/check/int.dart';
+export 'package:analyzer_utilities/check/iterable.dart';
+export 'package:analyzer_utilities/check/string.dart';
+export 'package:analyzer_utilities/check/type.dart';
+
+@useResult
+CheckTarget<T> check<T>(T value) {
+ return CheckTarget(value, 0, () => '$value');
+}
diff --git a/pkg/analyzer_utilities/lib/check/check_target.dart b/pkg/analyzer_utilities/lib/check/check_target.dart
new file mode 100644
index 0000000..1d0e608
--- /dev/null
+++ b/pkg/analyzer_utilities/lib/check/check_target.dart
@@ -0,0 +1,40 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:test/test.dart' as test_package;
+
+class CheckTarget<T> {
+ final T value;
+ final int _depth;
+
+ /// The function that return the description of the value, and of the
+ /// chain how we arrived to this value.
+ final String Function() _describe;
+
+ CheckTarget(this.value, this._depth, this._describe);
+
+ String get _indent => ' ' * (_depth + 1);
+
+ String valueStr(value) {
+ if (value is String) {
+ return "'$value'";
+ }
+ return '$value';
+ }
+
+ Never fail(String message) {
+ test_package.fail(_describe() + '\n' + _indent + message);
+ }
+
+ /// Chains to the given [value]; if a subsequent check fails, [describe]
+ /// will be invoked to describe the [value].
+ CheckTarget<U> nest<U>(
+ U value,
+ String Function(U value) describe,
+ ) {
+ return CheckTarget(value, _depth + 1, () {
+ return _describe() + '\n' + _indent + describe(value);
+ });
+ }
+}
diff --git a/pkg/analyzer_utilities/lib/check/equality.dart b/pkg/analyzer_utilities/lib/check/equality.dart
new file mode 100644
index 0000000..2d265b8
--- /dev/null
+++ b/pkg/analyzer_utilities/lib/check/equality.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer_utilities/check/check.dart';
+
+extension EqualityExtension<T> on CheckTarget<T> {
+ void isEqualTo(Object? other) {
+ if (value != other) {
+ fail('is not equal to $other');
+ }
+ }
+
+ void isNotEqualTo(Object? other) {
+ if (value == other) {
+ fail('is equal to $other');
+ }
+ }
+}
diff --git a/pkg/analyzer_utilities/lib/check/int.dart b/pkg/analyzer_utilities/lib/check/int.dart
new file mode 100644
index 0000000..59587b2
--- /dev/null
+++ b/pkg/analyzer_utilities/lib/check/int.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer_utilities/check/check.dart';
+
+extension IntExtension on CheckTarget<int> {
+ void get isZero {
+ if (value != 0) {
+ fail('is not zero');
+ }
+ }
+
+ void isGreaterThan(int other) {
+ if (!(value > other)) {
+ fail('is not greater than $other');
+ }
+ }
+}
diff --git a/pkg/analyzer_utilities/lib/check/iterable.dart b/pkg/analyzer_utilities/lib/check/iterable.dart
new file mode 100644
index 0000000..fbadfd9
--- /dev/null
+++ b/pkg/analyzer_utilities/lib/check/iterable.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer_utilities/check/check.dart';
+
+extension IterableExtension<T> on CheckTarget<Iterable<T>> {
+ void get isEmpty {
+ if (value.isNotEmpty) {
+ fail('is not empty');
+ }
+ }
+}
diff --git a/pkg/analyzer_utilities/lib/check/string.dart b/pkg/analyzer_utilities/lib/check/string.dart
new file mode 100644
index 0000000..c4dfdf7
--- /dev/null
+++ b/pkg/analyzer_utilities/lib/check/string.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer_utilities/check/check.dart';
+import 'package:meta/meta.dart';
+
+extension StringExtension on CheckTarget<String> {
+ void contains(Pattern other) {
+ if (!value.contains(other)) {
+ fail('does not contain ${valueStr(other)}');
+ }
+ }
+
+ void startsWith(Pattern other) {
+ if (!value.startsWith(other)) {
+ fail('does not start with ${valueStr(other)}');
+ }
+ }
+
+ @useResult
+ CheckTarget<int> hasLength() {
+ return nest(
+ value.length,
+ (length) => 'has length $length',
+ );
+ }
+}
diff --git a/pkg/analyzer_utilities/lib/check/type.dart b/pkg/analyzer_utilities/lib/check/type.dart
new file mode 100644
index 0000000..ea28b9e
--- /dev/null
+++ b/pkg/analyzer_utilities/lib/check/type.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer_utilities/check/check.dart';
+
+extension IsExtension<T> on CheckTarget<T> {
+ CheckTarget<U> isA<U extends T>() {
+ final value = this.value;
+ if (value is U) {
+ return nest(value, (_) => 'is of type $U');
+ } else {
+ fail('is not of type $U');
+ }
+ }
+}
diff --git a/pkg/analyzer_utilities/pubspec.yaml b/pkg/analyzer_utilities/pubspec.yaml
index a8426e4..d0aac18 100644
--- a/pkg/analyzer_utilities/pubspec.yaml
+++ b/pkg/analyzer_utilities/pubspec.yaml
@@ -9,5 +9,7 @@
analyzer:
path: ../analyzer
html: any
+ meta:
+ path: ../meta
path: any
test: any