• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.d
15 */
16
17import {assertDefined} from 'common/assert_utils';
18import {InMemoryStorage} from 'common/in_memory_storage';
19import {TracePositionUpdate} from 'messaging/winscope_event';
20import {TraceBuilder} from 'test/unit/trace_builder';
21import {TreeNodeUtils} from 'test/unit/tree_node_utils';
22import {UnitTestUtils} from 'test/unit/utils';
23import {Traces} from 'trace/traces';
24import {ImeTraceType, TraceType} from 'trace/trace_type';
25import {HierarchyTreeNode} from 'trace/tree_node/hierarchy_tree_node';
26import {PropertyTreeNode} from 'trace/tree_node/property_tree_node';
27import {ImeUiData} from 'viewers/common/ime_ui_data';
28import {PresenterInputMethodClients} from 'viewers/viewer_input_method_clients/presenter_input_method_clients';
29import {PresenterInputMethodManagerService} from 'viewers/viewer_input_method_manager_service/presenter_input_method_manager_service';
30import {PresenterInputMethodService} from 'viewers/viewer_input_method_service/presenter_input_method_service';
31import {NotifyHierarchyViewCallbackType} from './abstract_hierarchy_viewer_presenter';
32import {AbstractHierarchyViewerPresenterTest} from './abstract_hierarchy_viewer_presenter_test';
33import {AbstractPresenterInputMethod} from './abstract_presenter_input_method';
34import {UiDataHierarchy} from './ui_data_hierarchy';
35import {UiHierarchyTreeNode} from './ui_hierarchy_tree_node';
36import {UiPropertyTreeNode} from './ui_property_tree_node';
37
38export abstract class AbstractPresenterInputMethodTest extends AbstractHierarchyViewerPresenterTest {
39  private traces: Traces | undefined;
40  private positionUpdate: TracePositionUpdate | undefined;
41  private secondPositionUpdate: TracePositionUpdate | undefined;
42  private selectedTree: UiHierarchyTreeNode | undefined;
43  private entries: Map<TraceType, HierarchyTreeNode> | undefined;
44
45  override readonly shouldExecuteFlatTreeTest = true;
46  override readonly shouldExecuteRectTests = false;
47  override readonly shouldExecuteShowDiffTests = false;
48  override readonly shouldExecuteSimplifyNamesTest = false;
49
50  override readonly hierarchyFilterString = 'Reject all';
51  override readonly expectedHierarchyChildrenAfterStringFilter = 0;
52
53  override async setUpTestEnvironment(): Promise<void> {
54    let secondEntries: Map<TraceType, HierarchyTreeNode>;
55    [this.entries, secondEntries] = await UnitTestUtils.getImeTraceEntries();
56    this.traces = new Traces();
57    const traceEntries = [assertDefined(this.entries.get(this.imeTraceType))];
58    const secondEntry = secondEntries.get(this.imeTraceType);
59    if (secondEntry) {
60      traceEntries.push(secondEntry);
61    }
62
63    const trace = new TraceBuilder<HierarchyTreeNode>()
64      .setType(this.imeTraceType)
65      .setEntries(traceEntries)
66      .setFrame(0, 0)
67      .build();
68    this.traces.addTrace(trace);
69
70    const sfEntry = this.entries.get(TraceType.SURFACE_FLINGER);
71    if (sfEntry) {
72      this.traces.addTrace(
73        new TraceBuilder<HierarchyTreeNode>()
74          .setType(TraceType.SURFACE_FLINGER)
75          .setEntries([sfEntry])
76          .setFrame(0, 0)
77          .build(),
78      );
79    }
80
81    const wmEntry = this.entries.get(TraceType.WINDOW_MANAGER);
82    if (wmEntry) {
83      this.traces.addTrace(
84        new TraceBuilder<HierarchyTreeNode>()
85          .setType(TraceType.WINDOW_MANAGER)
86          .setEntries([wmEntry])
87          .setFrame(0, 0)
88          .build(),
89      );
90    }
91
92    const entry = trace.getEntry(0);
93    this.positionUpdate = TracePositionUpdate.fromTraceEntry(entry);
94    this.secondPositionUpdate = secondEntry
95      ? TracePositionUpdate.fromTraceEntry(trace.getEntry(1))
96      : undefined;
97
98    this.selectedTree = UiHierarchyTreeNode.from(this.getSelectedNode());
99  }
100
101  override createPresenterWithEmptyTrace(
102    callback: NotifyHierarchyViewCallbackType,
103  ): AbstractPresenterInputMethod {
104    const trace = new TraceBuilder<HierarchyTreeNode>()
105      .setType(this.imeTraceType)
106      .setEntries([])
107      .build();
108    const traces = new Traces();
109    traces.addTrace(trace);
110    return new this.PresenterInputMethod(
111      trace,
112      traces,
113      new InMemoryStorage(),
114      callback,
115    );
116  }
117
118  override createPresenter(
119    callback: NotifyHierarchyViewCallbackType,
120  ): AbstractPresenterInputMethod {
121    const traces = assertDefined(this.traces);
122    const trace = assertDefined(traces.getTrace(this.imeTraceType));
123    return new this.PresenterInputMethod(
124      trace,
125      traces,
126      new InMemoryStorage(),
127      callback,
128    );
129  }
130
131  override getPositionUpdate(): TracePositionUpdate {
132    return assertDefined(this.positionUpdate);
133  }
134
135  override getSecondPositionUpdate(): TracePositionUpdate | undefined {
136    return this.secondPositionUpdate;
137  }
138
139  override getShowDiffPositionUpdate(): TracePositionUpdate {
140    return assertDefined(this.positionUpdate);
141  }
142
143  override getExpectedChildrenBeforeVisibilityFilter(): number {
144    return this.numberOfFlattenedChildren;
145  }
146
147  override getExpectedChildrenAfterVisibilityFilter(): number {
148    return this.numberOfVisibleChildren;
149  }
150
151  override getExpectedChildrenBeforeFlatFilter(): number {
152    return this.numberOfNestedChildren;
153  }
154
155  override getExpectedChildrenAfterFlatFilter(): number {
156    return this.numberOfFlattenedChildren;
157  }
158
159  override getExpectedHierarchyChildrenBeforeStringFilter(): number {
160    return this.numberOfFlattenedChildren;
161  }
162
163  override getSelectedTree(): UiHierarchyTreeNode {
164    return assertDefined(this.selectedTree);
165  }
166
167  override getSelectedTreeAfterPositionUpdate(): UiHierarchyTreeNode {
168    return assertDefined(this.selectedTree);
169  }
170
171  override executeChecksForPropertiesTreeAfterPositionUpdate(
172    uiData: UiDataHierarchy,
173  ) {
174    const trees = assertDefined(uiData.hierarchyTrees);
175    expect(trees.length).toEqual(this.numberOfNestedChildren);
176  }
177
178  override executeChecksForPropertiesTreeAfterSecondPositionUpdate(
179    uiData: UiDataHierarchy,
180  ) {
181    const trees = assertDefined(uiData.hierarchyTrees);
182    expect(trees.length).toEqual(1);
183  }
184
185  override executeSpecializedTests() {
186    describe('AbstractPresenterInputMethod', () => {
187      let presenter: AbstractPresenterInputMethod;
188      let uiData: ImeUiData;
189      let traces: Traces;
190      let entries: Map<TraceType, HierarchyTreeNode>;
191      let Presenter:
192        | typeof PresenterInputMethodClients
193        | typeof PresenterInputMethodService
194        | typeof PresenterInputMethodManagerService;
195      let imeTraceType: ImeTraceType;
196
197      beforeAll(async () => {
198        jasmine.addCustomEqualityTester(TreeNodeUtils.treeNodeEqualityTester);
199        Presenter = this.PresenterInputMethod;
200        imeTraceType = this.imeTraceType;
201        await this.setUpTestEnvironment();
202        entries = assertDefined(this.entries);
203        await loadTraces();
204      });
205
206      it('is robust to traces without SF', async () => {
207        setUpPresenter([imeTraceType, TraceType.WINDOW_MANAGER]);
208        await presenter.onAppEvent(this.getPositionUpdate());
209        expect(uiData.hierarchyUserOptions).toBeTruthy();
210        expect(uiData.propertiesUserOptions).toBeTruthy();
211        expect(uiData.hierarchyTrees).toBeDefined();
212      });
213
214      it('is robust to traces without WM', async () => {
215        setUpPresenter([imeTraceType, TraceType.SURFACE_FLINGER]);
216        await presenter.onAppEvent(this.getPositionUpdate());
217        expect(uiData.hierarchyUserOptions).toBeTruthy();
218        expect(uiData.propertiesUserOptions).toBeTruthy();
219        expect(uiData.hierarchyTrees).toBeDefined();
220      });
221
222      it('is robust to traces without WM and SF', async () => {
223        setUpPresenter([imeTraceType]);
224        await presenter.onAppEvent(this.getPositionUpdate());
225        expect(uiData.hierarchyUserOptions).toBeTruthy();
226        expect(uiData.propertiesUserOptions).toBeTruthy();
227        expect(uiData.hierarchyTrees).toBeDefined();
228      });
229
230      it('can set new additional properties tree and associated ui data from hierarchy tree node', async () => {
231        setUpPresenter([imeTraceType, TraceType.WINDOW_MANAGER]);
232        expect(uiData.propertiesTree).toBeUndefined();
233        await presenter.onAppEvent(this.getPositionUpdate());
234        await presenter.onAdditionalPropertySelected({
235          name: 'Test Tree',
236          treeNode: this.getSelectedTree(),
237        });
238        const propertiesTree = assertDefined(uiData.propertiesTree);
239        expect(propertiesTree.getDisplayName()).toEqual('Test Tree');
240        expect(uiData.highlightedItem).toEqual(this.getSelectedTree().id);
241      });
242
243      if (this.getPropertiesTree) {
244        it('can set new additional properties tree and associated ui data from property tree node', async () => {
245          const selectedPropertyTree = assertDefined(this.getPropertiesTree)();
246          if (!selectedPropertyTree) {
247            return;
248          }
249          setUpPresenter([imeTraceType]);
250          expect(uiData.propertiesTree).toBeUndefined();
251          await presenter.onAppEvent(this.getPositionUpdate());
252          await presenter.onAdditionalPropertySelected({
253            name: 'Additional Properties Tree',
254            treeNode: selectedPropertyTree,
255          });
256          const propertiesTree = assertDefined(uiData.propertiesTree);
257          expect(propertiesTree.getDisplayName()).toEqual(
258            'Additional Properties Tree',
259          );
260          expect(propertiesTree).toEqual(
261            UiPropertyTreeNode.from(selectedPropertyTree),
262          );
263          expect(uiData.highlightedItem).toEqual(selectedPropertyTree.id);
264        });
265      }
266
267      function setUpPresenter(traceTypes: TraceType[]) {
268        traceTypes.forEach((traceType) => {
269          const trace = new TraceBuilder<HierarchyTreeNode>()
270            .setType(traceType)
271            .setEntries([assertDefined(entries.get(traceType))])
272            .setFrame(0, 0)
273            .build();
274
275          assertDefined(traces).addTrace(trace);
276        });
277        presenter = createPresenter(traces);
278      }
279
280      function createPresenter(traces: Traces): AbstractPresenterInputMethod {
281        const callback = (newData: ImeUiData) => {
282          uiData = newData;
283        };
284        const trace = assertDefined(traces.getTrace(imeTraceType));
285        return new Presenter(
286          trace,
287          traces,
288          new InMemoryStorage(),
289          callback as NotifyHierarchyViewCallbackType,
290        );
291      }
292
293      async function loadTraces() {
294        traces = new Traces();
295        entries = (await UnitTestUtils.getImeTraceEntries())[0];
296      }
297    });
298  }
299
300  protected getPropertiesTree?(): PropertyTreeNode;
301  protected abstract getSelectedNode(): HierarchyTreeNode;
302
303  protected abstract readonly numberOfFlattenedChildren: number;
304  protected abstract readonly numberOfVisibleChildren: number;
305  protected abstract readonly numberOfNestedChildren: number;
306  protected abstract readonly PresenterInputMethod:
307    | typeof PresenterInputMethodClients
308    | typeof PresenterInputMethodService
309    | typeof PresenterInputMethodManagerService;
310  protected abstract readonly imeTraceType: ImeTraceType;
311}
312