Unverified Commit 0df0e2ea authored by chunhtai's avatar chunhtai Committed by GitHub

Migrate android_semantics_testing to null safety (#111420)

parent e3b9223a
......@@ -23,11 +23,11 @@ void main() {
const MethodChannel kSemanticsChannel = MethodChannel('semantics');
Future<String> dataHandler(String message) async {
if (message.contains('getSemanticsNode')) {
Future<String> dataHandler(String? message) async {
if (message != null && message.contains('getSemanticsNode')) {
final Completer<String> completer = Completer<String>();
final int id = int.tryParse(message.split('#')[1]) ?? 0;
Future<void> completeSemantics([Object _]) async {
Future<void> completeSemantics([Object? _]) async {
final dynamic result = await kSemanticsChannel.invokeMethod<dynamic>('getSemanticsNode', <String, dynamic>{
'id': id,
});
......@@ -40,10 +40,10 @@ Future<String> dataHandler(String message) async {
}
return completer.future;
}
if (message.contains('setClipboard')) {
if (message != null && message.contains('setClipboard')) {
final Completer<String> completer = Completer<String>();
final String str = message.split('#')[1];
Future<void> completeSetClipboard([Object _]) async {
Future<void> completeSetClipboard([Object? _]) async {
await kSemanticsChannel.invokeMethod<dynamic>('setClipboard', <String, dynamic>{
'message': str,
});
......@@ -67,7 +67,7 @@ Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
};
class TestApp extends StatelessWidget {
const TestApp({Key key}) : super(key: key);
const TestApp({super.key});
@override
Widget build(BuildContext context) {
......
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// ignore_for_file: avoid_dynamic_calls
import 'dart:convert';
import 'package:meta/meta.dart';
......@@ -53,13 +55,13 @@ class AndroidSemanticsNode {
/// ]
/// }
factory AndroidSemanticsNode.deserialize(String value) {
return AndroidSemanticsNode._(json.decode(value) as Map<String, Object>);
return AndroidSemanticsNode._(json.decode(value));
}
final Map<String, Object> _values;
final dynamic _values;
final List<AndroidSemanticsNode> _children = <AndroidSemanticsNode>[];
Map<String, Object> get _flags => _values['flags'] as Map<String, Object>;
dynamic get _flags => _values['flags'];
/// The text value of the semantics node.
///
......@@ -132,13 +134,12 @@ class AndroidSemanticsNode {
/// Gets a [Rect] which defines the position and size of the semantics node.
Rect getRect() {
final Map<String, Object> rawRect = _values['rect'] as Map<String, Object>;
final Map<String, int> rect = rawRect.cast<String, int>();
final dynamic rawRect = _values['rect'];
return Rect.fromLTRB(
rect['left'].toDouble(),
rect['top'].toDouble(),
rect['right'].toDouble(),
rect['bottom'].toDouble(),
(rawRect['left']! as int).toDouble(),
(rawRect['top']! as int).toDouble(),
(rawRect['right']! as int).toDouble(),
(rawRect['bottom']! as int).toDouble(),
);
}
......@@ -150,7 +151,7 @@ class AndroidSemanticsNode {
/// Gets a list of [AndroidSemanticsActions] which are defined for the node.
List<AndroidSemanticsAction> getActions() => <AndroidSemanticsAction>[
for (final int id in (_values['actions'] as List<dynamic>).cast<int>()) AndroidSemanticsAction.deserialize(id),
for (final int id in (_values['actions']! as List<dynamic>).cast<int>()) AndroidSemanticsAction.deserialize(id)!,
];
@override
......
......@@ -168,7 +168,7 @@ class AndroidSemanticsAction {
case _kSetText:
return 'AndroidSemanticsAction.setText';
default:
return null;
throw UnimplementedError();
}
}
......@@ -211,7 +211,7 @@ class AndroidSemanticsAction {
/// Creates a new [AndroidSemanticsAction] from an integer `value`.
///
/// Returns `null` if the id is not a known Android accessibility action.
static AndroidSemanticsAction deserialize(int value) {
static AndroidSemanticsAction? deserialize(int value) {
return _kActionById[value];
}
}
......@@ -18,24 +18,24 @@ import 'constants.dart';
/// the Android accessibility bridge, and not the semantics object created by
/// the Flutter framework.
Matcher hasAndroidSemantics({
String text,
String contentDescription,
String className,
int id,
Rect rect,
Size size,
List<AndroidSemanticsAction> actions,
List<AndroidSemanticsAction> ignoredActions,
List<AndroidSemanticsNode> children,
bool isChecked,
bool isCheckable,
bool isEditable,
bool isEnabled,
bool isFocusable,
bool isFocused,
bool isHeading,
bool isPassword,
bool isLongClickable,
String? text,
String? contentDescription,
String? className,
int? id,
Rect? rect,
Size? size,
List<AndroidSemanticsAction>? actions,
List<AndroidSemanticsAction>? ignoredActions,
List<AndroidSemanticsNode>? children,
bool? isChecked,
bool? isCheckable,
bool? isEditable,
bool? isEnabled,
bool? isFocusable,
bool? isFocused,
bool? isHeading,
bool? isPassword,
bool? isLongClickable,
}) {
return _AndroidSemanticsMatcher(
text: text,
......@@ -79,23 +79,23 @@ class _AndroidSemanticsMatcher extends Matcher {
this.isLongClickable,
});
final String text;
final String className;
final String contentDescription;
final int id;
final List<AndroidSemanticsAction> actions;
final List<AndroidSemanticsAction> ignoredActions;
final Rect rect;
final Size size;
final bool isChecked;
final bool isCheckable;
final bool isEditable;
final bool isEnabled;
final bool isFocusable;
final bool isFocused;
final bool isHeading;
final bool isPassword;
final bool isLongClickable;
final String? text;
final String? className;
final String? contentDescription;
final int? id;
final List<AndroidSemanticsAction>? actions;
final List<AndroidSemanticsAction>? ignoredActions;
final Rect? rect;
final Size? size;
final bool? isChecked;
final bool? isCheckable;
final bool? isEditable;
final bool? isEnabled;
final bool? isFocusable;
final bool? isFocused;
final bool? isHeading;
final bool? isPassword;
final bool? isLongClickable;
@override
Description describe(Description description) {
......@@ -149,7 +149,7 @@ class _AndroidSemanticsMatcher extends Matcher {
}
@override
bool matches(covariant AndroidSemanticsNode item, Map<Object, Object> matchState) {
bool matches(covariant AndroidSemanticsNode item, Map<dynamic, dynamic> matchState) {
if (text != null && text != item.text) {
return _failWithMessage('Expected text: $text', matchState);
}
......@@ -170,13 +170,13 @@ class _AndroidSemanticsMatcher extends Matcher {
}
if (actions != null) {
final List<AndroidSemanticsAction> itemActions = item.getActions();
if (!unorderedEquals(actions).matches(itemActions, matchState)) {
final List<String> actionsString = actions.map<String>((AndroidSemanticsAction action) => action.toString()).toList()..sort();
if (!unorderedEquals(actions!).matches(itemActions, matchState)) {
final List<String> actionsString = actions!.map<String>((AndroidSemanticsAction action) => action.toString()).toList()..sort();
final List<String> itemActionsString = itemActions.map<String>((AndroidSemanticsAction action) => action.toString()).toList()..sort();
final Set<AndroidSemanticsAction> unexpected = itemActions.toSet().difference(actions.toSet());
final Set<AndroidSemanticsAction> unexpected = itemActions.toSet().difference(actions!.toSet());
final Set<String> unexpectedInString = itemActionsString.toSet().difference(actionsString.toSet());
final Set<String> missingInString = actionsString.toSet().difference(itemActionsString.toSet());
if (missingInString.isEmpty && ignoredActions != null && unexpected.every(ignoredActions.contains)) {
if (missingInString.isEmpty && ignoredActions != null && unexpected.every(ignoredActions!.contains)) {
return true;
}
return _failWithMessage('Expected actions: $actionsString\nActual actions: $itemActionsString\nUnexpected: $unexpectedInString\nMissing: $missingInString', matchState);
......@@ -214,8 +214,8 @@ class _AndroidSemanticsMatcher extends Matcher {
}
@override
Description describeMismatch(Object item, Description mismatchDescription,
Map<Object, Object> matchState, bool verbose) {
Description describeMismatch(dynamic item, Description mismatchDescription,
Map<dynamic, dynamic> matchState, bool verbose) {
return mismatchDescription.add(matchState['failure'] as String);
}
......
......@@ -9,7 +9,7 @@ export 'controls_constants.dart';
/// A test page with a checkbox, three radio buttons, and a switch.
class SelectionControlsPage extends StatefulWidget {
const SelectionControlsPage({Key key}) : super(key: key);
const SelectionControlsPage({super.key});
@override
State<StatefulWidget> createState() => _SelectionControlsPageState();
......@@ -28,15 +28,15 @@ class _SelectionControlsPageState extends State<SelectionControlsPage> {
bool _isLabeledOn = false;
int _radio = 0;
void _updateCheckbox(bool newValue) {
void _updateCheckbox(bool? newValue) {
setState(() {
_isChecked = newValue;
_isChecked = newValue!;
});
}
void _updateRadio(int newValue) {
void _updateRadio(int? newValue) {
setState(() {
_radio = newValue;
_radio = newValue!;
});
}
......
......@@ -9,7 +9,7 @@ export 'headings_constants.dart';
/// A test page with an app bar and some body text for testing heading flags.
class HeadingsPage extends StatelessWidget {
const HeadingsPage({Key key}) : super(key: key);
const HeadingsPage({super.key});
static const ValueKey<String> _appBarTitleKey = ValueKey<String>(appBarTitleKeyValue);
static const ValueKey<String> _bodyTextKey = ValueKey<String>(bodyTextKeyValue);
......
......@@ -10,7 +10,7 @@ export 'popup_constants.dart';
/// A page with a popup menu, a dropdown menu, and a modal alert.
class PopupControlsPage extends StatefulWidget {
const PopupControlsPage({Key key}) : super(key: key);
const PopupControlsPage({super.key});
@override
State<StatefulWidget> createState() => _PopupControlsPageState();
......@@ -60,9 +60,9 @@ class _PopupControlsPageState extends State<PopupControlsPage> {
child: Text(item),
);
}).toList(),
onChanged: (String value) {
onChanged: (String? value) {
setState(() {
dropdownValue = value;
dropdownValue = value!;
});
},
),
......
......@@ -10,7 +10,7 @@ export 'text_field_constants.dart';
/// A page with a normal text field and a password field.
class TextFieldPage extends StatefulWidget {
const TextFieldPage({Key key}) : super(key: key);
const TextFieldPage({super.key});
@override
State<StatefulWidget> createState() => _TextFieldPageState();
......
name: android_semantics_testing
description: Integration testing library for Android semantics
environment:
sdk: '>=2.9.0 <3.0.0'
sdk: '>=2.17.0-0 <3.0.0'
dependencies:
flutter:
......
......@@ -20,7 +20,7 @@ const List<AndroidSemanticsAction> ignoredAccessibilityFocusActions = <AndroidSe
];
String adbPath() {
final String androidHome = io.Platform.environment['ANDROID_HOME'] ?? io.Platform.environment['ANDROID_SDK_ROOT'];
final String androidHome = io.Platform.environment['ANDROID_HOME'] ?? io.Platform.environment['ANDROID_SDK_ROOT']!;
if (androidHome == null) {
return 'adb';
} else {
......@@ -30,7 +30,7 @@ String adbPath() {
void main() {
group('AccessibilityBridge', () {
FlutterDriver driver;
late FlutterDriver driver;
Future<AndroidSemanticsNode> getSemantics(SerializableFinder finder) async {
final int id = await driver.getSemanticsId(finder);
final String data = await driver.requestData('getSemanticsNode#$id');
......@@ -38,7 +38,7 @@ void main() {
}
// The version of TalkBack running on the device.
Version talkbackVersion;
Version? talkbackVersion;
Future<Version> getTalkbackVersion() async {
final io.ProcessResult result = await io.Process.run(adbPath(), const <String>[
......@@ -51,7 +51,7 @@ void main() {
throw Exception('Failed to get TalkBack version: ${result.stdout as String}\n${result.stderr as String}');
}
final List<String> lines = (result.stdout as String).split('\n');
String version;
String? version;
for (final String line in lines) {
if (line.contains('versionName')) {
version = line.replaceAll(RegExp(r'\s*versionName='), '');
......@@ -64,14 +64,14 @@ void main() {
// Android doesn't quite use semver, so convert the version string to semver form.
final RegExp startVersion = RegExp(r'(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)(\.(?<build>\d+))?');
final RegExpMatch match = startVersion.firstMatch(version);
final RegExpMatch? match = startVersion.firstMatch(version);
if (match == null) {
return Version(0, 0, 0);
}
return Version(
int.parse(match.namedGroup('major')),
int.parse(match.namedGroup('minor')),
int.parse(match.namedGroup('patch')),
int.parse(match.namedGroup('major')!),
int.parse(match.namedGroup('minor')!),
int.parse(match.namedGroup('patch')!),
build: match.namedGroup('build'),
);
}
......@@ -104,7 +104,7 @@ void main() {
'null',
]);
await run.exitCode;
driver?.close();
driver.close();
});
group('TextField', () {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment