// 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 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; /// Tuple-like test class for storing a [stream] and [eventKind]. /// /// Used to store the [stream] and [eventKind] that a dispatched event would be /// sent on. @immutable class DispatchedEventKey { const DispatchedEventKey({required this.stream, required this.eventKind}); final String stream; final String eventKind; @override String toString() { return '[DispatchedEventKey]($stream, $eventKind)'; } @override bool operator ==(Object other) { return other is DispatchedEventKey && stream == other.stream && eventKind == other.eventKind; } @override int get hashCode => Object.hash(stream, eventKind); } class TestWidgetInspectorService extends Object with WidgetInspectorService { final Map<String, ServiceExtensionCallback> extensions = <String, ServiceExtensionCallback>{}; final Map<DispatchedEventKey, List<Map<Object, Object?>>> eventsDispatched = <DispatchedEventKey, List<Map<Object, Object?>>>{}; final List<Object?> objectsInspected = <Object?>[]; @override void registerServiceExtension({ required String name, required ServiceExtensionCallback callback, }) { assert(!extensions.containsKey(name)); extensions[name] = callback; } @override void postEvent( String eventKind, Map<Object, Object?> eventData, { String stream = 'Extension', }) { dispatchedEvents(eventKind, stream: stream).add(eventData); } @override void inspect(Object? object) { objectsInspected.add(object); } List<Map<Object, Object?>> dispatchedEvents( String eventKind, { String stream = 'Extension', }) { return eventsDispatched.putIfAbsent( DispatchedEventKey(stream: stream, eventKind: eventKind), () => <Map<Object, Object?>>[], ); } List<Object?> inspectedObjects(){ return objectsInspected; } Iterable<Map<Object, Object?>> getServiceExtensionStateChangedEvents(String extensionName) { return dispatchedEvents('Flutter.ServiceExtensionStateChanged') .where((Map<Object, Object?> event) => event['extension'] == extensionName); } Future<Object?> testExtension(String name, Map<String, String> arguments) async { expect(extensions, contains(name)); // Encode and decode to JSON to match behavior using a real service // extension where only JSON is allowed. return (json.decode(json.encode(await extensions[name]!(arguments))) as Map<String, dynamic>)['result']; } Future<String> testBoolExtension(String name, Map<String, String> arguments) async { expect(extensions, contains(name)); // Encode and decode to JSON to match behavior using a real service // extension where only JSON is allowed. return (json.decode(json.encode(await extensions[name]!(arguments))) as Map<String, dynamic>)['enabled'] as String; } int rebuildCount = 0; @override Future<void> forceRebuild() async { rebuildCount++; final WidgetsBinding binding = WidgetsBinding.instance; if (binding.renderViewElement != null) { binding.buildOwner!.reassemble(binding.renderViewElement!, null); } } @override void resetAllState() { super.resetAllState(); eventsDispatched.clear(); objectsInspected.clear(); rebuildCount = 0; } }