| // Copyright 2020 The Chromium 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 'package:devtools_app/src/service/service_manager.dart'; |
| import 'package:devtools_app/src/shared/charts/treemap.dart'; |
| import 'package:devtools_app_shared/ui.dart'; |
| import 'package:devtools_app_shared/utils.dart'; |
| import 'package:devtools_test/devtools_test.dart'; |
| import 'package:flutter/foundation.dart'; |
| import 'package:flutter/material.dart'; |
| import 'package:flutter_test/flutter_test.dart'; |
| |
| import '../test_infra/matchers/matchers.dart'; |
| import '../test_infra/test_data/app_size/apk_analysis.dart'; |
| import '../test_infra/test_data/app_size/new_v8.dart'; |
| import '../test_infra/test_data/app_size/sizes.dart'; |
| import '../test_infra/test_data/app_size/small_sizes.dart'; |
| |
| void main() { |
| TreemapNode? root; |
| |
| void changeRoot(TreemapNode? newRoot) { |
| root = newRoot; |
| } |
| |
| // Pump treemap widget with tree built with test data. |
| Future<void> pumpTreemapWidget(WidgetTester tester, Key treemapKey) async { |
| await tester.pumpWidget( |
| wrap( |
| LayoutBuilder( |
| key: treemapKey, |
| builder: (context, constraints) { |
| return Treemap.fromRoot( |
| rootNode: root, |
| levelsVisible: 2, |
| isOutermostLevel: true, |
| width: constraints.maxWidth, |
| height: constraints.maxHeight, |
| onRootChangedCallback: changeRoot, |
| ); |
| }, |
| ), |
| ), |
| ); |
| await tester.pumpAndSettle(); |
| } |
| |
| const windowSize = Size(2225.0, 1000.0); |
| |
| setUp(() { |
| setGlobal(ServiceConnectionManager, FakeServiceConnectionManager()); |
| setGlobal(IdeTheme, IdeTheme()); |
| }); |
| |
| group('TreemapNode', () { |
| final child1 = TreemapNode(name: 'package:child1'); |
| final child2 = TreemapNode(name: 'package:child2'); |
| final grandchild1 = TreemapNode(name: 'non-package-grandchild'); |
| final grandchild2 = TreemapNode(name: 'package:grandchild2'); |
| final greatGrandchild1 = TreemapNode(name: 'package:greatGrandchild1'); |
| final greatGrandchild2 = TreemapNode(name: 'package:greatGrandchild2'); |
| final testRoot = TreemapNode(name: 'libapp.so (Dart AOT)') |
| ..addAllChildren([ |
| child1 |
| ..addChild( |
| grandchild1 |
| ..addChild( |
| greatGrandchild1, |
| ), |
| ), |
| child2 |
| ..addChild( |
| grandchild2 |
| ..addChild( |
| greatGrandchild2, |
| ), |
| ), |
| ]); |
| |
| final nodeWithDuplicatePackageNameGrandchild = |
| TreemapNode(name: 'grandchild'); |
| final nodeWithDuplicatePackageNameChild1 = TreemapNode(name: 'package:a'); |
| final nodeWithDuplicatePackageNameChild2 = TreemapNode(name: '<Type>'); |
| final nodeWithDuplicatePackageName = TreemapNode(name: 'package:a'); |
| TreemapNode(name: 'libapp.so (Dart AOT)').addChild( |
| nodeWithDuplicatePackageName |
| ..addAllChildren([ |
| nodeWithDuplicatePackageNameChild1 |
| ..addChild(nodeWithDuplicatePackageNameGrandchild), |
| nodeWithDuplicatePackageNameChild2, |
| ]), |
| ); |
| |
| final dartLibraryChild = TreemapNode(name: 'dart lib child'); |
| final dartLibraryNode = TreemapNode(name: 'dart:core'); |
| TreemapNode(name: 'libapp.so (Dart AOT)') |
| .addChild(dartLibraryNode..addChild(dartLibraryChild)); |
| |
| test('packagePath returns correct values', () { |
| expect(testRoot.packagePath(), equals([])); |
| expect(grandchild1.packagePath(), equals(['package:child1'])); |
| expect( |
| grandchild2.packagePath(), |
| equals(['package:child2', 'package:grandchild2']), |
| ); |
| expect( |
| greatGrandchild1.packagePath(), |
| equals(['package:child1', 'package:greatGrandchild1']), |
| ); |
| expect( |
| greatGrandchild2.packagePath(), |
| equals([ |
| 'package:child2', |
| 'package:grandchild2', |
| 'package:greatGrandchild2', |
| ]), |
| ); |
| }); |
| |
| test('packagePath returns correct values for duplicate package name', () { |
| expect( |
| nodeWithDuplicatePackageNameGrandchild.packagePath(), |
| equals(['package:a']), |
| ); |
| }); |
| |
| test('packagePath returns correct value for dart library node', () { |
| expect(dartLibraryChild.packagePath(), equals(['dart:core'])); |
| }); |
| }); |
| |
| group('Treemap from small instruction sizes', () { |
| setUp(() async { |
| root = await loadSnapshotJsonAsTree(smallInstructionSizes); |
| }); |
| testWidgetsWithWindowSize( |
| 'zooms in down to a node without children', |
| windowSize, |
| (WidgetTester tester) async { |
| const treemapKey = Key('Treemap'); |
| await pumpTreemapWidget(tester, treemapKey); |
| |
| expect(find.richText('dart:_internal [0.3 KB]'), findsOneWidget); |
| await tester.tap(find.richText('dart:_internal [0.3 KB]')); |
| await tester.pumpAndSettle(); |
| |
| await pumpTreemapWidget(tester, treemapKey); |
| |
| expect(find.richText('CastIterable [0.2 KB]'), findsOneWidget); |
| await tester.tap(find.richText('CastIterable [0.2 KB]')); |
| await tester.pumpAndSettle(); |
| |
| await pumpTreemapWidget(tester, treemapKey); |
| |
| expect(find.richText('new CastIterable.\n[0.2 KB]'), findsOneWidget); |
| await tester.tap(find.richText('new CastIterable.\n[0.2 KB]')); |
| await tester.pumpAndSettle(); |
| |
| await pumpTreemapWidget(tester, treemapKey); |
| |
| // TODO(jacobr): what text should be found in this case? |
| // expect(find.text('new CastIterable. [0.2 KB]'), findsOneWidget); |
| }, |
| ); |
| }); |
| |
| group('Treemap from instruction sizes', () { |
| setUp(() async { |
| root = await loadSnapshotJsonAsTree(instructionSizes); |
| }); |
| |
| testWidgetsWithWindowSize( |
| 'builds treemap with expected data', |
| windowSize, |
| (WidgetTester tester) async { |
| const treemapKey = Key('Treemap'); |
| await pumpTreemapWidget(tester, treemapKey); |
| |
| expect(find.byKey(treemapKey), findsOneWidget); |
| |
| await expectLater( |
| find.byKey(treemapKey), |
| matchesDevToolsGolden('../test_infra/goldens/treemap_sizes.png'), |
| ); |
| }, |
| skip: kIsWeb, |
| ); |
| }); |
| |
| group('Treemap from v8 snapshot', () { |
| setUp(() async { |
| root = await loadSnapshotJsonAsTree(newV8); |
| }); |
| |
| testWidgetsWithWindowSize( |
| 'builds treemap with expected data', |
| windowSize, |
| (WidgetTester tester) async { |
| const treemapKey = Key('Treemap'); |
| await pumpTreemapWidget(tester, treemapKey); |
| |
| expect(find.byKey(treemapKey), findsOneWidget); |
| |
| await expectLater( |
| find.byKey(treemapKey), |
| matchesDevToolsGolden('../test_infra/goldens/treemap_v8.png'), |
| ); |
| // Await delay for golden comparison. |
| await tester.pumpAndSettle(const Duration(seconds: 2)); |
| }, |
| skip: kIsWeb, |
| ); |
| }); |
| |
| group('Treemap from APK analysis', () { |
| setUp(() async { |
| root = await loadSnapshotJsonAsTree(apkAnalysis); |
| }); |
| |
| testWidgetsWithWindowSize( |
| 'builds treemap with expected data', |
| windowSize, |
| (WidgetTester tester) async { |
| const treemapKey = Key('Treemap'); |
| await pumpTreemapWidget(tester, treemapKey); |
| |
| expect(find.byKey(treemapKey), findsOneWidget); |
| |
| await expectLater( |
| find.byKey(treemapKey), |
| matchesDevToolsGolden('../test_infra/goldens/treemap_apk.png'), |
| ); |
| // Await delay for golden comparison. |
| await tester.pumpAndSettle(const Duration(seconds: 2)); |
| }, |
| skip: kIsWeb, |
| ); |
| }); |
| } |