blob: b09c4cd2cf07ff1961f42674b439965ffcce48d8 [file] [log] [blame]
// Copyright 2014 The Flutter 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 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'semantics_tester.dart';
void main() {
testWidgets('Semantics can merge sibling group', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester);
const SemanticsTag first = SemanticsTag('1');
const SemanticsTag second = SemanticsTag('2');
const SemanticsTag third = SemanticsTag('3');
ChildSemanticsConfigurationsResult delegate(List<SemanticsConfiguration> configs) {
expect(configs.length, 3);
final ChildSemanticsConfigurationsResultBuilder builder = ChildSemanticsConfigurationsResultBuilder();
final List<SemanticsConfiguration> sibling = <SemanticsConfiguration>[];
// Merge first and third
for (final SemanticsConfiguration config in configs) {
if (config.tagsChildrenWith(first) || config.tagsChildrenWith(third)) {
sibling.add(config);
} else {
builder.markAsMergeUp(config);
}
}
builder.markAsSiblingMergeGroup(sibling);
return builder.build();
}
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
label: 'parent',
child: TestConfigDelegate(
delegate: delegate,
child: Column(
children: <Widget>[
Semantics(
label: '1',
tagForChildren: first,
child: const SizedBox(width: 100, height: 100),
// this tests that empty nodes disappear
),
Semantics(
label: '2',
tagForChildren: second,
child: const SizedBox(width: 100, height: 100),
),
Semantics(
label: '3',
tagForChildren: third,
child: const SizedBox(width: 100, height: 100),
),
],
),
),
),
),
);
expect(semantics, hasSemantics(TestSemantics.root(
children: <TestSemantics>[
TestSemantics.rootChild(
label: 'parent\n2',
),
TestSemantics.rootChild(
label: '1\n3',
),
],
), ignoreId: true, ignoreRect: true, ignoreTransform: true));
});
testWidgets('Semantics can drop semantics config', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester);
const SemanticsTag first = SemanticsTag('1');
const SemanticsTag second = SemanticsTag('2');
const SemanticsTag third = SemanticsTag('3');
ChildSemanticsConfigurationsResult delegate(List<SemanticsConfiguration> configs) {
final ChildSemanticsConfigurationsResultBuilder builder = ChildSemanticsConfigurationsResultBuilder();
// Merge first and third
for (final SemanticsConfiguration config in configs) {
if (config.tagsChildrenWith(first) || config.tagsChildrenWith(third)) {
continue;
}
builder.markAsMergeUp(config);
}
return builder.build();
}
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
label: 'parent',
child: TestConfigDelegate(
delegate: delegate,
child: Column(
children: <Widget>[
Semantics(
label: '1',
tagForChildren: first,
child: const SizedBox(width: 100, height: 100),
// this tests that empty nodes disappear
),
Semantics(
label: '2',
tagForChildren: second,
child: const SizedBox(width: 100, height: 100),
),
Semantics(
label: '3',
tagForChildren: third,
child: const SizedBox(width: 100, height: 100),
),
],
),
),
),
),
);
expect(semantics, hasSemantics(TestSemantics.root(
children: <TestSemantics>[
TestSemantics.rootChild(
label: 'parent\n2',
),
],
), ignoreId: true, ignoreRect: true, ignoreTransform: true));
});
testWidgets('Semantics throws when mark the same config twice case 1', (WidgetTester tester) async {
const SemanticsTag first = SemanticsTag('1');
const SemanticsTag second = SemanticsTag('2');
const SemanticsTag third = SemanticsTag('3');
ChildSemanticsConfigurationsResult delegate(List<SemanticsConfiguration> configs) {
final ChildSemanticsConfigurationsResultBuilder builder = ChildSemanticsConfigurationsResultBuilder();
// Marks the same one twice.
builder.markAsMergeUp(configs.first);
builder.markAsMergeUp(configs.first);
return builder.build();
}
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
label: 'parent',
child: TestConfigDelegate(
delegate: delegate,
child: Column(
children: <Widget>[
Semantics(
label: '1',
tagForChildren: first,
child: const SizedBox(width: 100, height: 100),
// this tests that empty nodes disappear
),
Semantics(
label: '2',
tagForChildren: second,
child: const SizedBox(width: 100, height: 100),
),
Semantics(
label: '3',
tagForChildren: third,
child: const SizedBox(width: 100, height: 100),
),
],
),
),
),
),
);
expect(tester.takeException(), isAssertionError);
});
testWidgets('Semantics throws when mark the same config twice case 2', (WidgetTester tester) async {
const SemanticsTag first = SemanticsTag('1');
const SemanticsTag second = SemanticsTag('2');
const SemanticsTag third = SemanticsTag('3');
ChildSemanticsConfigurationsResult delegate(List<SemanticsConfiguration> configs) {
final ChildSemanticsConfigurationsResultBuilder builder = ChildSemanticsConfigurationsResultBuilder();
// Marks the same one twice.
builder.markAsMergeUp(configs.first);
builder.markAsSiblingMergeGroup(<SemanticsConfiguration>[configs.first]);
return builder.build();
}
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Semantics(
label: 'parent',
child: TestConfigDelegate(
delegate: delegate,
child: Column(
children: <Widget>[
Semantics(
label: '1',
tagForChildren: first,
child: const SizedBox(width: 100, height: 100),
// this tests that empty nodes disappear
),
Semantics(
label: '2',
tagForChildren: second,
child: const SizedBox(width: 100, height: 100),
),
Semantics(
label: '3',
tagForChildren: third,
child: const SizedBox(width: 100, height: 100),
),
],
),
),
),
),
);
expect(tester.takeException(), isAssertionError);
});
}
class TestConfigDelegate extends SingleChildRenderObjectWidget {
const TestConfigDelegate({super.key, required this.delegate, super.child});
final ChildSemanticsConfigurationsDelegate delegate;
@override
RenderTestConfigDelegate createRenderObject(BuildContext context) => RenderTestConfigDelegate(
delegate: delegate,
);
@override
void updateRenderObject(BuildContext context, RenderTestConfigDelegate renderObject) {
renderObject.delegate = delegate;
}
}
class RenderTestConfigDelegate extends RenderProxyBox {
RenderTestConfigDelegate({
ChildSemanticsConfigurationsDelegate? delegate,
}) : _delegate = delegate;
ChildSemanticsConfigurationsDelegate? get delegate => _delegate;
ChildSemanticsConfigurationsDelegate? _delegate;
set delegate(ChildSemanticsConfigurationsDelegate? value) {
if (value != _delegate) {
markNeedsSemanticsUpdate();
}
_delegate = value;
}
@override
void describeSemanticsConfiguration(SemanticsConfiguration config) {
config.childConfigurationsDelegate = _delegate;
}
}