timeline_test.dart 5.92 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
// 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 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_test/flutter_test.dart';

import 'common.dart';

final Set<String> interestingLabels = <String>{
  'BUILD',
  'LAYOUT',
  'UPDATING COMPOSITING BITS',
  'PAINT',
  'COMPOSITING',
  'FINALIZE TREE',
  '$Placeholder',
  '$CustomPaint',
  '$RenderCustomPaint',
};

class TestRoot extends StatefulWidget {
25
  const TestRoot({ super.key });
Ian Hickson's avatar
Ian Hickson committed
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66

  static late final TestRootState state;

  @override
  State<TestRoot> createState() => TestRootState();
}

class TestRootState extends State<TestRoot> {
  @override
  void initState() {
    super.initState();
    TestRoot.state = this;
  }

  Widget _widget = const Placeholder();

  void updateWidget(Widget newWidget) {
    setState(() {
      _widget = newWidget;
    });
  }

  void rebuild() {
    setState(() {
      // no change, just force a rebuild
    });
  }

  @override
  Widget build(BuildContext context) {
    return _widget;
  }
}

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  initTimelineTests();
  test('Timeline', () async {
    // We don't have expectations around the first frame because there's a race around
    // the warm-up frame that we don't want to get involved in here.
    await runFrame(() { runApp(const TestRoot()); });
67
    await SchedulerBinding.instance.endOfFrame;
68
    await fetchInterestingEvents(interestingLabels);
Ian Hickson's avatar
Ian Hickson committed
69 70 71 72 73 74

    // The next few cases build the exact same tree so should have no effect.

    debugProfileBuildsEnabled = true;
    await runFrame(() { TestRoot.state.rebuild(); });
    expect(
75
      await fetchInterestingEventNames(interestingLabels),
Ian Hickson's avatar
Ian Hickson committed
76 77 78 79 80 81 82
      <String>['BUILD', 'LAYOUT', 'UPDATING COMPOSITING BITS', 'PAINT', 'COMPOSITING', 'FINALIZE TREE'],
    );
    debugProfileBuildsEnabled = false;

    debugProfileLayoutsEnabled = true;
    await runFrame(() { TestRoot.state.rebuild(); });
    expect(
83
      await fetchInterestingEventNames(interestingLabels),
Ian Hickson's avatar
Ian Hickson committed
84 85 86 87 88 89 90
      <String>['BUILD', 'LAYOUT', 'UPDATING COMPOSITING BITS', 'PAINT', 'COMPOSITING', 'FINALIZE TREE'],
    );
    debugProfileLayoutsEnabled = false;

    debugProfilePaintsEnabled = true;
    await runFrame(() { TestRoot.state.rebuild(); });
    expect(
91
      await fetchInterestingEventNames(interestingLabels),
Ian Hickson's avatar
Ian Hickson committed
92 93 94 95 96 97 98 99 100 101 102
      <String>['BUILD', 'LAYOUT', 'UPDATING COMPOSITING BITS', 'PAINT', 'COMPOSITING', 'FINALIZE TREE'],
    );
    debugProfilePaintsEnabled = false;


    // Now we replace the widgets each time to cause a rebuild.

    List<TimelineEvent> events;
    Map<String, String> args;

    debugProfileBuildsEnabled = true;
103
    debugEnhanceBuildTimelineArguments = true;
Ian Hickson's avatar
Ian Hickson committed
104
    await runFrame(() { TestRoot.state.updateWidget(Placeholder(key: UniqueKey(), color: const Color(0xFFFFFFFF))); });
105
    events = await fetchInterestingEvents(interestingLabels);
Ian Hickson's avatar
Ian Hickson committed
106 107 108 109 110 111 112
    expect(
      events.map<String>(eventToName),
      <String>['BUILD', 'Placeholder', 'CustomPaint', 'LAYOUT', 'UPDATING COMPOSITING BITS', 'PAINT', 'COMPOSITING', 'FINALIZE TREE'],
    );
    args = (events.where((TimelineEvent event) => event.json!['name'] == '$Placeholder').single.json!['args'] as Map<String, Object?>).cast<String, String>();
    expect(args['color'], 'Color(0xffffffff)');
    debugProfileBuildsEnabled = false;
113
    debugEnhanceBuildTimelineArguments = false;
Ian Hickson's avatar
Ian Hickson committed
114

115
    debugProfileBuildsEnabledUserWidgets = true;
116
    debugEnhanceBuildTimelineArguments = true;
117 118 119 120 121 122 123 124 125
    await runFrame(() { TestRoot.state.updateWidget(Placeholder(key: UniqueKey(), color: const Color(0xFFFFFFFF))); });
    events = await fetchInterestingEvents(interestingLabels);
    expect(
      events.map<String>(eventToName),
      <String>['BUILD', 'Placeholder', 'LAYOUT', 'UPDATING COMPOSITING BITS', 'PAINT', 'COMPOSITING', 'FINALIZE TREE'],
    );
    args = (events.where((TimelineEvent event) => event.json!['name'] == '$Placeholder').single.json!['args'] as Map<String, Object?>).cast<String, String>();
    expect(args['color'], 'Color(0xffffffff)');
    debugProfileBuildsEnabledUserWidgets = false;
126
    debugEnhanceBuildTimelineArguments = false;
127

Ian Hickson's avatar
Ian Hickson committed
128
    debugProfileLayoutsEnabled = true;
129
    debugEnhanceLayoutTimelineArguments = true;
Ian Hickson's avatar
Ian Hickson committed
130
    await runFrame(() { TestRoot.state.updateWidget(Placeholder(key: UniqueKey())); });
131
    events = await fetchInterestingEvents(interestingLabels);
Ian Hickson's avatar
Ian Hickson committed
132 133 134 135 136 137 138
    expect(
      events.map<String>(eventToName),
      <String>['BUILD', 'LAYOUT', 'RenderCustomPaint', 'UPDATING COMPOSITING BITS', 'PAINT', 'COMPOSITING', 'FINALIZE TREE'],
    );
    args = (events.where((TimelineEvent event) => event.json!['name'] == '$RenderCustomPaint').single.json!['args'] as Map<String, Object?>).cast<String, String>();
    expect(args['creator'], startsWith('CustomPaint'));
    expect(args['creator'], contains('Placeholder'));
139
    expect(args['painter'], startsWith('_PlaceholderPainter#'));
Ian Hickson's avatar
Ian Hickson committed
140
    debugProfileLayoutsEnabled = false;
141
    debugEnhanceLayoutTimelineArguments = false;
Ian Hickson's avatar
Ian Hickson committed
142 143

    debugProfilePaintsEnabled = true;
144
    debugEnhancePaintTimelineArguments = true;
Ian Hickson's avatar
Ian Hickson committed
145
    await runFrame(() { TestRoot.state.updateWidget(Placeholder(key: UniqueKey())); });
146
    events = await fetchInterestingEvents(interestingLabels);
Ian Hickson's avatar
Ian Hickson committed
147 148 149 150 151 152 153
    expect(
      events.map<String>(eventToName),
      <String>['BUILD', 'LAYOUT', 'UPDATING COMPOSITING BITS', 'PAINT', 'RenderCustomPaint', 'COMPOSITING', 'FINALIZE TREE'],
    );
    args = (events.where((TimelineEvent event) => event.json!['name'] == '$RenderCustomPaint').single.json!['args'] as Map<String, Object?>).cast<String, String>();
    expect(args['creator'], startsWith('CustomPaint'));
    expect(args['creator'], contains('Placeholder'));
154
    expect(args['painter'], startsWith('_PlaceholderPainter#'));
Ian Hickson's avatar
Ian Hickson committed
155
    debugProfilePaintsEnabled = false;
156
    debugEnhancePaintTimelineArguments = false;
Ian Hickson's avatar
Ian Hickson committed
157 158 159

  }, skip: isBrowser); // [intended] uses dart:isolate and io.
}