// 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 'dart:developer' as developer; import 'dart:isolate' as isolate; import 'package:flutter/painting.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:vm_service/vm_service.dart'; import 'package:vm_service/vm_service_io.dart'; void main() { VmService vmService; String isolateId; setUpAll(() async { final developer.ServiceProtocolInfo info = await developer.Service.getInfo(); if (info.serverUri == null) { fail('This test _must_ be run with --enable-vmservice.'); } vmService = await vmServiceConnectUri('ws://localhost:${info.serverUri.port}${info.serverUri.path}ws'); await vmService.setVMTimelineFlags(['Dart']); isolateId = developer.Service.getIsolateID(isolate.Isolate.current); // Initialize the image cache. TestWidgetsFlutterBinding.ensureInitialized(); }); test('Image cache tracing', () async { final TestImageStreamCompleter completer1 = TestImageStreamCompleter(); final TestImageStreamCompleter completer2 = TestImageStreamCompleter(); PaintingBinding.instance.imageCache.putIfAbsent( 'Test', () => completer1, ); PaintingBinding.instance.imageCache.clear(); completer2.testSetImage(ImageInfo(image: await createTestImage())); PaintingBinding.instance.imageCache.putIfAbsent( 'Test2', () => completer2, ); PaintingBinding.instance.imageCache.evict('Test2'); final Timeline timeline = await vmService.getVMTimeline(); _expectTimelineEvents( timeline.traceEvents, >[ { 'name': 'ImageCache.putIfAbsent', 'args': {'key': 'Test', 'isolateId': isolateId} }, { 'name': 'listener', 'args': {'parentId': '1', 'isolateId': isolateId} }, { 'name': 'ImageCache.clear', 'args': { 'pendingImages': 1, 'keepAliveImages': 0, 'liveImages': 1, 'currentSizeInBytes': 0, 'isolateId': isolateId, } }, { 'name': 'ImageCache.putIfAbsent', 'args': {'key': 'Test2', 'isolateId': isolateId} }, { 'name': 'ImageCache.evict', 'args': {'sizeInBytes': 4, 'isolateId': isolateId} }, ], ); }, skip: isBrowser); // uses dart:isolate and io } void _expectTimelineEvents(List events, List> expected) { for (final TimelineEvent event in events) { for (int index = 0; index < expected.length; index += 1) { if (expected[index]['name'] == event.json['name']) { final Map expectedArgs = expected[index]['args'] as Map; final Map args = event.json['args'] as Map; if (_mapsEqual(expectedArgs, args)) { expected.removeAt(index); } } } } if (expected.isNotEmpty) { final String encodedEvents = jsonEncode(events); fail('Timeline did not contain expected events: $expected\nactual: $encodedEvents'); } } bool _mapsEqual(Map expectedArgs, Map args) { for (final String key in expectedArgs.keys) { if (expectedArgs[key] != args[key]) { return false; } } return true; } class TestImageStreamCompleter extends ImageStreamCompleter { void testSetImage(ImageInfo image) { setImage(image); } }