blob: 169099a474023b479c439df2075496e01ddfefc8 [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.
// TODO(LongCatIsLooong): Remove this file once textScaleFactor is removed.
import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
group('TextStyle', () {
test('getTextStyle is backward compatible', () {
expect(
const TextStyle(fontSize: 14).getTextStyle(textScaleFactor: 2.0).toString(),
contains('fontSize: 28'),
);
}, skip: kIsWeb); // [intended] CkTextStyle doesn't have a custom toString implementation.
});
group('TextPainter', () {
test('textScaleFactor translates to textScaler', () {
final TextPainter textPainter = TextPainter(
text: const TextSpan(text: 'text'),
textDirection: TextDirection.ltr,
textScaleFactor: 42,
);
expect(textPainter.textScaler, const TextScaler.linear(42.0));
// Linear TextScaler translates to textScaleFactor.
textPainter.textScaler = const TextScaler.linear(12.0);
expect(textPainter.textScaleFactor, 12.0);
textPainter.textScaleFactor = 10;
expect(textPainter.textScaler, const TextScaler.linear(10));
});
});
group('MediaQuery', () {
test('specifying both textScaler and textScalingFactor asserts', () {
expect(
() => MediaQueryData(textScaleFactor: 2, textScaler: const TextScaler.linear(2.0)),
throwsAssertionError,
);
});
test('copyWith is backward compatible', () {
const MediaQueryData data = MediaQueryData(textScaler: TextScaler.linear(2.0));
final MediaQueryData data1 = data.copyWith(textScaleFactor: 42);
expect(data1.textScaler, const TextScaler.linear(42));
expect(data1.textScaleFactor, 42);
final MediaQueryData data2 = data.copyWith(textScaler: TextScaler.noScaling);
expect(data2.textScaler, TextScaler.noScaling);
expect(data2.textScaleFactor, 1.0);
});
test('copyWith specifying both textScaler and textScalingFactor asserts', () {
const MediaQueryData data = MediaQueryData();
expect(
() => data.copyWith(textScaleFactor: 2, textScaler: const TextScaler.linear(2.0)),
throwsAssertionError,
);
});
testWidgets('MediaQuery.textScaleFactorOf overriding compatibility', (WidgetTester tester) async {
late final double outsideTextScaleFactor;
late final TextScaler outsideTextScaler;
late final double insideTextScaleFactor;
late final TextScaler insideTextScaler;
await tester.pumpWidget(
Builder(
builder: (BuildContext context) {
outsideTextScaleFactor = MediaQuery.textScaleFactorOf(context);
outsideTextScaler = MediaQuery.textScalerOf(context);
return MediaQuery(
data: const MediaQueryData(
textScaleFactor: 4.0,
),
child: Builder(
builder: (BuildContext context) {
insideTextScaleFactor = MediaQuery.textScaleFactorOf(context);
insideTextScaler = MediaQuery.textScalerOf(context);
return Container();
},
),
);
},
),
);
// Overriding textScaleFactor should work for unmigrated widgets that are
// still using MediaQuery.textScaleFactorOf. Also if a unmigrated widget
// overrides MediaQuery.textScaleFactor, migrated widgets in the subtree
// should get the correct TextScaler.
expect(outsideTextScaleFactor, 1.0);
expect(outsideTextScaler.textScaleFactor, 1.0);
expect(outsideTextScaler, TextScaler.noScaling);
expect(insideTextScaleFactor, 4.0);
expect(insideTextScaler.textScaleFactor, 4.0);
expect(insideTextScaler, const TextScaler.linear(4.0));
});
testWidgets('textScaleFactor overriding backward compatibility', (WidgetTester tester) async {
late final double outsideTextScaleFactor;
late final TextScaler outsideTextScaler;
late final double insideTextScaleFactor;
late final TextScaler insideTextScaler;
await tester.pumpWidget(
Builder(
builder: (BuildContext context) {
outsideTextScaleFactor = MediaQuery.textScaleFactorOf(context);
outsideTextScaler = MediaQuery.textScalerOf(context);
return MediaQuery(
data: const MediaQueryData(textScaler: TextScaler.linear(4.0)),
child: Builder(
builder: (BuildContext context) {
insideTextScaleFactor = MediaQuery.textScaleFactorOf(context);
insideTextScaler = MediaQuery.textScalerOf(context);
return Container();
},
),
);
},
),
);
expect(outsideTextScaleFactor, 1.0);
expect(outsideTextScaler.textScaleFactor, 1.0);
expect(outsideTextScaler, TextScaler.noScaling);
expect(insideTextScaleFactor, 4.0);
expect(insideTextScaler.textScaleFactor, 4.0);
expect(insideTextScaler, const TextScaler.linear(4.0));
});
});
group('RenderObjects backward compatibility', () {
test('RenderEditable', () {
final RenderEditable renderObject = RenderEditable(
backgroundCursorColor: const Color.fromARGB(0xFF, 0xFF, 0x00, 0x00),
textDirection: TextDirection.ltr,
cursorColor: const Color.fromARGB(0xFF, 0xFF, 0x00, 0x00),
offset: ViewportOffset.zero(),
textSelectionDelegate: _FakeEditableTextState(),
text: const TextSpan(
text: 'test',
style: TextStyle(height: 1.0, fontSize: 10.0),
),
startHandleLayerLink: LayerLink(),
endHandleLayerLink: LayerLink(),
selection: const TextSelection.collapsed(offset: 0),
);
expect(renderObject.textScaleFactor, 1.0);
renderObject.textScaleFactor = 3.0;
expect(renderObject.textScaleFactor, 3.0);
expect(renderObject.textScaler, const TextScaler.linear(3.0));
renderObject.textScaler = const TextScaler.linear(4.0);
expect(renderObject.textScaleFactor, 4.0);
});
test('RenderParagraph', () {
final RenderParagraph renderObject = RenderParagraph(
const TextSpan(
text: 'test',
style: TextStyle(height: 1.0, fontSize: 10.0),
),
textDirection: TextDirection.ltr,
);
expect(renderObject.textScaleFactor, 1.0);
renderObject.textScaleFactor = 3.0;
expect(renderObject.textScaleFactor, 3.0);
expect(renderObject.textScaler, const TextScaler.linear(3.0));
renderObject.textScaler = const TextScaler.linear(4.0);
expect(renderObject.textScaleFactor, 4.0);
});
});
group('Widgets backward compatibility', () {
testWidgets('RichText', (WidgetTester tester) async {
await tester.pumpWidget(
RichText(
textDirection: TextDirection.ltr,
text: const TextSpan(),
textScaleFactor: 2.0,
),
);
expect(
tester.renderObject<RenderParagraph>(find.byType(RichText)).textScaler,
const TextScaler.linear(2.0),
);
expect(tester.renderObject<RenderParagraph>(find.byType(RichText)).textScaleFactor, 2.0);
});
testWidgets('Text', (WidgetTester tester) async {
await tester.pumpWidget(
const Text(
'text',
textDirection: TextDirection.ltr,
textScaleFactor: 2.0,
),
);
expect(
tester.renderObject<RenderParagraph>(find.text('text')).textScaler,
const TextScaler.linear(2.0),
);
});
testWidgets('EditableText', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController();
addTearDown(controller.dispose);
final FocusNode focusNode = FocusNode(debugLabel: 'EditableText Node');
addTearDown(focusNode.dispose);
const TextStyle textStyle = TextStyle();
const Color cursorColor = Color.fromARGB(0xFF, 0xFF, 0x00, 0x00);
await tester.pumpWidget(
MediaQuery(
data: const MediaQueryData(),
child: Directionality(
textDirection: TextDirection.rtl,
child: EditableText(
backgroundCursorColor: cursorColor,
controller: controller,
focusNode: focusNode,
style: textStyle,
cursorColor: cursorColor,
textScaleFactor: 2.0,
),
),
),
);
final RenderEditable renderEditable = tester.allRenderObjects.whereType<RenderEditable>().first;
expect(
renderEditable.textScaler,
const TextScaler.linear(2.0),
);
});
});
}
class _FakeEditableTextState with TextSelectionDelegate {
@override
TextEditingValue textEditingValue = TextEditingValue.empty;
TextSelection? selection;
@override
void hideToolbar([bool hideHandles = true]) { }
@override
void userUpdateTextEditingValue(TextEditingValue value, SelectionChangedCause cause) {
selection = value.selection;
}
@override
void bringIntoView(TextPosition position) { }
@override
void cutSelection(SelectionChangedCause cause) { }
@override
Future<void> pasteText(SelectionChangedCause cause) {
return Future<void>.value();
}
@override
void selectAll(SelectionChangedCause cause) { }
@override
void copySelection(SelectionChangedCause cause) { }
}