blob: 109b9411a32e5cfe4ac905e150fe79a5863d3d36 [file] [log] [blame]
// Copyright 2013 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:async';
import 'package:async/async.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:google_maps_flutter_android/google_maps_flutter_android.dart';
import 'package:google_maps_flutter_android/src/messages.g.dart';
import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'google_maps_flutter_android_test.mocks.dart';
@GenerateNiceMocks(<MockSpec<Object>>[MockSpec<MapsApi>()])
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
(GoogleMapsFlutterAndroid, MockMapsApi) setUpMockMap({required int mapId}) {
final MockMapsApi api = MockMapsApi();
final GoogleMapsFlutterAndroid maps =
GoogleMapsFlutterAndroid(apiProvider: (_) => api);
maps.ensureApiInitialized(mapId);
return (maps, api);
}
Future<void> sendPlatformMessage(
int mapId, String method, Map<dynamic, dynamic> data) async {
final ByteData byteData =
const StandardMethodCodec().encodeMethodCall(MethodCall(method, data));
await TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.handlePlatformMessage('plugins.flutter.dev/google_maps_android_$mapId',
byteData, (ByteData? data) {});
}
test('registers instance', () async {
GoogleMapsFlutterAndroid.registerWith();
expect(GoogleMapsFlutterPlatform.instance, isA<GoogleMapsFlutterAndroid>());
});
test('init calls waitForMap', () async {
final MockMapsApi api = MockMapsApi();
final GoogleMapsFlutterAndroid maps =
GoogleMapsFlutterAndroid(apiProvider: (_) => api);
await maps.init(1);
verify(api.waitForMap());
});
test('getScreenCoordinate converts and passes values correctly', () async {
const int mapId = 1;
final (GoogleMapsFlutterAndroid maps, MockMapsApi api) =
setUpMockMap(mapId: mapId);
// Arbitrary values that are all different from each other.
const LatLng latLng = LatLng(10, 20);
const ScreenCoordinate expectedCoord = ScreenCoordinate(x: 30, y: 40);
when(api.getScreenCoordinate(any)).thenAnswer(
(_) async => PlatformPoint(x: expectedCoord.x, y: expectedCoord.y));
final ScreenCoordinate coord =
await maps.getScreenCoordinate(latLng, mapId: mapId);
expect(coord, expectedCoord);
final VerificationResult verification =
verify(api.getScreenCoordinate(captureAny));
final PlatformLatLng passedLatLng =
verification.captured[0] as PlatformLatLng;
expect(passedLatLng.latitude, latLng.latitude);
expect(passedLatLng.longitude, latLng.longitude);
});
test('getLatLng converts and passes values correctly', () async {
const int mapId = 1;
final (GoogleMapsFlutterAndroid maps, MockMapsApi api) =
setUpMockMap(mapId: mapId);
// Arbitrary values that are all different from each other.
const LatLng expectedLatLng = LatLng(10, 20);
const ScreenCoordinate coord = ScreenCoordinate(x: 30, y: 40);
when(api.getLatLng(any)).thenAnswer((_) async => PlatformLatLng(
latitude: expectedLatLng.latitude,
longitude: expectedLatLng.longitude));
final LatLng latLng = await maps.getLatLng(coord, mapId: mapId);
expect(latLng, expectedLatLng);
final VerificationResult verification = verify(api.getLatLng(captureAny));
final PlatformPoint passedCoord = verification.captured[0] as PlatformPoint;
expect(passedCoord.x, coord.x);
expect(passedCoord.y, coord.y);
});
test('getVisibleRegion converts and passes values correctly', () async {
const int mapId = 1;
final (GoogleMapsFlutterAndroid maps, MockMapsApi api) =
setUpMockMap(mapId: mapId);
// Arbitrary values that are all different from each other.
final LatLngBounds expectedBounds = LatLngBounds(
southwest: const LatLng(10, 20), northeast: const LatLng(30, 40));
when(api.getVisibleRegion()).thenAnswer((_) async => PlatformLatLngBounds(
southwest: PlatformLatLng(
latitude: expectedBounds.southwest.latitude,
longitude: expectedBounds.southwest.longitude),
northeast: PlatformLatLng(
latitude: expectedBounds.northeast.latitude,
longitude: expectedBounds.northeast.longitude)));
final LatLngBounds bounds = await maps.getVisibleRegion(mapId: mapId);
expect(bounds, expectedBounds);
});
test('getZoomLevel passes values correctly', () async {
const int mapId = 1;
final (GoogleMapsFlutterAndroid maps, MockMapsApi api) =
setUpMockMap(mapId: mapId);
const double expectedZoom = 4.2;
when(api.getZoomLevel()).thenAnswer((_) async => expectedZoom);
final double zoom = await maps.getZoomLevel(mapId: mapId);
expect(zoom, expectedZoom);
});
test('showInfoWindow calls through', () async {
const int mapId = 1;
final (GoogleMapsFlutterAndroid maps, MockMapsApi api) =
setUpMockMap(mapId: mapId);
const String markedId = 'a_marker';
await maps.showMarkerInfoWindow(const MarkerId(markedId), mapId: mapId);
verify(api.showInfoWindow(markedId));
});
test('hideInfoWindow calls through', () async {
const int mapId = 1;
final (GoogleMapsFlutterAndroid maps, MockMapsApi api) =
setUpMockMap(mapId: mapId);
const String markedId = 'a_marker';
await maps.hideMarkerInfoWindow(const MarkerId(markedId), mapId: mapId);
verify(api.hideInfoWindow(markedId));
});
test('isInfoWindowShown calls through', () async {
const int mapId = 1;
final (GoogleMapsFlutterAndroid maps, MockMapsApi api) =
setUpMockMap(mapId: mapId);
const String markedId = 'a_marker';
when(api.isInfoWindowShown(markedId)).thenAnswer((_) async => true);
expect(
await maps.isMarkerInfoWindowShown(const MarkerId(markedId),
mapId: mapId),
true);
});
test('takeSnapshot calls through', () async {
const int mapId = 1;
final (GoogleMapsFlutterAndroid maps, MockMapsApi api) =
setUpMockMap(mapId: mapId);
final Uint8List fakeSnapshot = Uint8List(10);
when(api.takeSnapshot()).thenAnswer((_) async => fakeSnapshot);
expect(await maps.takeSnapshot(mapId: mapId), fakeSnapshot);
});
test('clearTileCache calls through', () async {
const int mapId = 1;
final (GoogleMapsFlutterAndroid maps, MockMapsApi api) =
setUpMockMap(mapId: mapId);
const String tileOverlayId = 'overlay';
await maps.clearTileCache(const TileOverlayId(tileOverlayId), mapId: mapId);
verify(api.clearTileCache(tileOverlayId));
});
test('markers send drag event to correct streams', () async {
const int mapId = 1;
final Map<dynamic, dynamic> jsonMarkerDragStartEvent = <dynamic, dynamic>{
'mapId': mapId,
'markerId': 'drag-start-marker',
'position': <double>[1.0, 1.0]
};
final Map<dynamic, dynamic> jsonMarkerDragEvent = <dynamic, dynamic>{
'mapId': mapId,
'markerId': 'drag-marker',
'position': <double>[1.0, 1.0]
};
final Map<dynamic, dynamic> jsonMarkerDragEndEvent = <dynamic, dynamic>{
'mapId': mapId,
'markerId': 'drag-end-marker',
'position': <double>[1.0, 1.0]
};
final GoogleMapsFlutterAndroid maps = GoogleMapsFlutterAndroid();
maps.ensureChannelInitialized(mapId);
final StreamQueue<MarkerDragStartEvent> markerDragStartStream =
StreamQueue<MarkerDragStartEvent>(maps.onMarkerDragStart(mapId: mapId));
final StreamQueue<MarkerDragEvent> markerDragStream =
StreamQueue<MarkerDragEvent>(maps.onMarkerDrag(mapId: mapId));
final StreamQueue<MarkerDragEndEvent> markerDragEndStream =
StreamQueue<MarkerDragEndEvent>(maps.onMarkerDragEnd(mapId: mapId));
await sendPlatformMessage(
mapId, 'marker#onDragStart', jsonMarkerDragStartEvent);
await sendPlatformMessage(mapId, 'marker#onDrag', jsonMarkerDragEvent);
await sendPlatformMessage(
mapId, 'marker#onDragEnd', jsonMarkerDragEndEvent);
expect((await markerDragStartStream.next).value.value,
equals('drag-start-marker'));
expect((await markerDragStream.next).value.value, equals('drag-marker'));
expect((await markerDragEndStream.next).value.value,
equals('drag-end-marker'));
});
test(
'Does not use PlatformViewLink when using TLHC',
() async {
final GoogleMapsFlutterAndroid maps = GoogleMapsFlutterAndroid();
maps.useAndroidViewSurface = false;
final Widget widget = maps.buildViewWithConfiguration(1, (int _) {},
widgetConfiguration: const MapWidgetConfiguration(
initialCameraPosition:
CameraPosition(target: LatLng(0, 0), zoom: 1),
textDirection: TextDirection.ltr));
expect(widget, isA<AndroidView>());
},
);
testWidgets('Use PlatformViewLink when using surface view',
(WidgetTester tester) async {
final GoogleMapsFlutterAndroid maps = GoogleMapsFlutterAndroid();
maps.useAndroidViewSurface = true;
final Widget widget = maps.buildViewWithConfiguration(1, (int _) {},
widgetConfiguration: const MapWidgetConfiguration(
initialCameraPosition:
CameraPosition(target: LatLng(0, 0), zoom: 1),
textDirection: TextDirection.ltr));
expect(widget, isA<PlatformViewLink>());
});
testWidgets('Defaults to AndroidView', (WidgetTester tester) async {
final GoogleMapsFlutterAndroid maps = GoogleMapsFlutterAndroid();
final Widget widget = maps.buildViewWithConfiguration(1, (int _) {},
widgetConfiguration: const MapWidgetConfiguration(
initialCameraPosition:
CameraPosition(target: LatLng(0, 0), zoom: 1),
textDirection: TextDirection.ltr));
expect(widget, isA<AndroidView>());
});
testWidgets('cloudMapId is passed', (WidgetTester tester) async {
const String cloudMapId = '000000000000000'; // Dummy map ID.
final Completer<String> passedCloudMapIdCompleter = Completer<String>();
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(
SystemChannels.platform_views,
(MethodCall methodCall) async {
if (methodCall.method == 'create') {
final Map<String, dynamic> args = Map<String, dynamic>.from(
methodCall.arguments as Map<dynamic, dynamic>);
if (args.containsKey('params')) {
final Uint8List paramsUint8List = args['params'] as Uint8List;
const StandardMessageCodec codec = StandardMessageCodec();
final ByteData byteData = ByteData.sublistView(paramsUint8List);
final Map<String, dynamic> creationParams =
Map<String, dynamic>.from(
codec.decodeMessage(byteData) as Map<dynamic, dynamic>);
if (creationParams.containsKey('options')) {
final Map<String, dynamic> options = Map<String, dynamic>.from(
creationParams['options'] as Map<dynamic, dynamic>);
if (options.containsKey('cloudMapId')) {
passedCloudMapIdCompleter
.complete(options['cloudMapId'] as String);
}
}
}
}
return 0;
},
);
final GoogleMapsFlutterAndroid maps = GoogleMapsFlutterAndroid();
await tester.pumpWidget(maps.buildViewWithConfiguration(1, (int id) {},
widgetConfiguration: const MapWidgetConfiguration(
initialCameraPosition:
CameraPosition(target: LatLng(0, 0), zoom: 1),
textDirection: TextDirection.ltr),
mapConfiguration: const MapConfiguration(cloudMapId: cloudMapId)));
expect(
await passedCloudMapIdCompleter.future,
cloudMapId,
reason: 'Should pass cloudMapId on PlatformView creation message',
);
});
}