You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
meshcore-client/test/widgets/indicators_view_test.dart

131 lines
4.3 KiB

// Widget tests for the Display and LED pane (#523/#1098).
//
// These pin the crash the adversarial review caught before this was pushed:
// the rotation control force-unwrapped `displayRotation`, but the capability
// tag that ENABLES the control arrives in the `0xC5` `0x1C` advert, which lands
// BEFORE the rotation GET reply that supplies the value. So on any slow link
// the pane was built with the control enabled and the value still null, and it
// threw. The display-mode control beside it was already null-safe; only
// rotation was not.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:provider/provider.dart';
import 'package:meshcore_open/connector/meshcore_connector.dart';
import 'package:meshcore_open/connector/offband_indicators.dart';
import 'package:meshcore_open/screens/settings/indicators_view.dart';
/// Rotation is advertised, but the radio has not answered the GET yet. This is
/// the real window between the advert reply and the rotation reply.
class _RotationUnanswered extends MeshCoreConnector {
@override
bool get supportsIndicators => true;
@override
bool get supportsDisplayRotation => true;
@override
int? get displayRotation => null;
}
class _RotationAnswered extends MeshCoreConnector {
_RotationAnswered(this._degrees);
final int _degrees;
@override
bool get supportsIndicators => true;
@override
bool get supportsDisplayRotation => true;
@override
int? get displayRotation => _degrees;
}
Future<void> _pump(WidgetTester tester, MeshCoreConnector connector) =>
tester.pumpWidget(
ChangeNotifierProvider<MeshCoreConnector>.value(
value: connector,
child: const MaterialApp(home: Scaffold(body: IndicatorsView())),
),
);
void main() {
testWidgets(
'the pane builds before the radio has answered the rotation GET',
(tester) async {
await _pump(tester, _RotationUnanswered());
// If this ever fails again, something is force-unwrapping a value that is
// null for the whole window between the advert and the GET reply.
expect(tester.takeException(), isNull);
expect(find.text('Rotation'), findsOneWidget);
},
);
testWidgets('no rotation is shown as chosen until the radio answers', (
tester,
) async {
await _pump(tester, _RotationUnanswered());
final button = tester.widget<SegmentedButton<int>>(
find.byType(SegmentedButton<int>),
);
// An empty selection, not a guessed default: showing "Normal" here would
// claim a rotation the radio never reported.
expect(button.selected, isEmpty);
expect(button.emptySelectionAllowed, isTrue);
});
testWidgets('the rotation the radio reported is the one shown', (
tester,
) async {
await _pump(tester, _RotationAnswered(180));
final button = tester.widget<SegmentedButton<int>>(
find.byType(SegmentedButton<int>),
);
expect(button.selected, {180});
});
// #1132: display and LED show independently.
testWidgets('display control only: no Status LED switch', (tester) async {
await _pump(tester, _Controls(display: true, led: false));
expect(find.text('Display'), findsOneWidget);
expect(find.text('Status LED'), findsNothing);
expect(find.byType(SwitchListTile), findsNothing);
});
testWidgets('LED control only: no Display block', (tester) async {
await _pump(tester, _Controls(display: false, led: true));
expect(find.text('Display'), findsNothing);
expect(find.byType(SegmentedButton<DisplayMode>), findsNothing);
expect(find.text('Status LED'), findsOneWidget);
});
testWidgets('both controls: both shown', (tester) async {
await _pump(tester, _Controls(display: true, led: true));
expect(find.text('Display'), findsOneWidget);
expect(find.text('Status LED'), findsOneWidget);
});
testWidgets('a radio that does not advertise rotation gets no control', (
tester,
) async {
await _pump(tester, _DummyConnector());
expect(find.text('Rotation'), findsNothing);
expect(find.byType(SegmentedButton<int>), findsNothing);
});
}
class _DummyConnector extends MeshCoreConnector {}
class _Controls extends MeshCoreConnector {
_Controls({required this.display, required this.led});
final bool display;
final bool led;
@override
bool get supportsDisplayControl => display;
@override
bool get supportsLedControl => led;
}

Powered by TurnKey Linux.